clang 24.0.0git
ClangCLArgs.cpp
Go to the documentation of this file.
1//===--- ClangCLArgs.cpp - clang-cl arguments -----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ClangCLArgs.h"
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/Option/Arg.h"
14#include "llvm/Option/ArgList.h"
15#include "llvm/Option/OptTable.h"
16#include "llvm/Option/Option.h"
17#include "llvm/TargetParser/Triple.h"
18#include <cstddef>
19#include <string>
20
21using namespace clang;
22using namespace clang::driver;
23using namespace llvm::opt;
24
25ClangCLArgs::ClangCLArgs(const ArgList &Args, const llvm::Triple &HostTriple)
26 : SupportsForcingFramePointer(HostTriple.getArch() !=
27 llvm::Triple::x86_64) {
28 // Expand only the last /O[12xd], preserving overrides such as /O2 /Oy-.
29 for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
30 llvm::StringRef OptStr = A->getValue();
31 for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
32 char OptChar = OptStr[I];
33 char PrevChar = I > 0 ? OptStr[I - 1] : '0';
34 if (PrevChar == 'b') {
35 // OptChar does not expand; it's an argument to the previous char.
36 continue;
37 }
38 if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
39 ExpandChar = OptStr.data() + I;
40 }
41 }
42}
43
44bool ClangCLArgs::translateArg(Arg *A, DerivedArgList &DAL,
45 const DerivedArgList *Owner) const {
46 const DerivedArgList &SynthesizedArgs = Owner ? *Owner : DAL;
47 const Arg *BaseArg = &A->getBaseArg();
48 const OptTable &Opts = getDriverOptTable();
49 switch (A->getOption().getID()) {
50 case options::OPT__SLASH_permissive:
51 DAL.append(SynthesizedArgs.MakeFlagArg(
52 BaseArg, Opts.getOption(options::OPT_fdelayed_template_parsing)));
53 DAL.append(SynthesizedArgs.MakeFlagArg(
54 BaseArg, Opts.getOption(options::OPT_fno_operator_names)));
55 return true;
56 case options::OPT__SLASH_permissive_:
57 DAL.append(SynthesizedArgs.MakeFlagArg(
58 BaseArg, Opts.getOption(options::OPT_fno_delayed_template_parsing)));
59 DAL.append(SynthesizedArgs.MakeFlagArg(
60 BaseArg, Opts.getOption(options::OPT_foperator_names)));
61 return true;
62 default:
63 break;
64 }
65
66 if (!A->getOption().matches(options::OPT__SLASH_O))
67 return false;
68
69 // Keep the original argument for unused-option diagnostics.
70 DAL.append(A);
71
72 llvm::StringRef OptStr = A->getValue();
73 for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
74 const char &OptChar = *(OptStr.data() + I);
75 switch (OptChar) {
76 default:
77 break;
78 case '1':
79 case '2':
80 case 'x':
81 case 'd':
82 // Ignore /O[12xd] flags that aren't the last one on the command line.
83 // Only the last one gets expanded.
84 if (&OptChar != ExpandChar) {
85 A->claim();
86 break;
87 }
88 if (OptChar == 'd') {
89 DAL.append(SynthesizedArgs.MakeFlagArg(
90 BaseArg, Opts.getOption(options::OPT_O0)));
91 } else {
92 if (OptChar == '1') {
93 DAL.append(SynthesizedArgs.MakeJoinedArg(
94 BaseArg, Opts.getOption(options::OPT_O), "s"));
95 } else if (OptChar == '2' || OptChar == 'x') {
96 DAL.append(SynthesizedArgs.MakeFlagArg(
97 BaseArg, Opts.getOption(options::OPT_fbuiltin)));
98 DAL.append(SynthesizedArgs.MakeJoinedArg(
99 BaseArg, Opts.getOption(options::OPT_O), "3"));
100 }
101 if (SupportsForcingFramePointer &&
102 !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
103 DAL.append(SynthesizedArgs.MakeFlagArg(
104 BaseArg, Opts.getOption(options::OPT_fomit_frame_pointer)));
105 if (OptChar == '1' || OptChar == '2')
106 DAL.append(SynthesizedArgs.MakeFlagArg(
107 BaseArg, Opts.getOption(options::OPT_ffunction_sections)));
108 }
109 break;
110 case 'b':
111 if (I + 1 != E && llvm::isDigit(OptStr[I + 1])) {
112 switch (OptStr[I + 1]) {
113 case '0':
114 DAL.append(SynthesizedArgs.MakeFlagArg(
115 BaseArg, Opts.getOption(options::OPT_fno_inline)));
116 break;
117 case '1':
118 DAL.append(SynthesizedArgs.MakeFlagArg(
119 BaseArg, Opts.getOption(options::OPT_finline_hint_functions)));
120 break;
121 case '2':
122 case '3':
123 DAL.append(SynthesizedArgs.MakeFlagArg(
124 BaseArg, Opts.getOption(options::OPT_finline_functions)));
125 break;
126 }
127 ++I;
128 }
129 break;
130 case 'g':
131 A->claim();
132 break;
133 case 'i':
134 if (I + 1 != E && OptStr[I + 1] == '-') {
135 ++I;
136 DAL.append(SynthesizedArgs.MakeFlagArg(
137 BaseArg, Opts.getOption(options::OPT_fno_builtin)));
138 } else {
139 DAL.append(SynthesizedArgs.MakeFlagArg(
140 BaseArg, Opts.getOption(options::OPT_fbuiltin)));
141 }
142 break;
143 case 's':
144 DAL.append(SynthesizedArgs.MakeJoinedArg(
145 BaseArg, Opts.getOption(options::OPT_O), "s"));
146 break;
147 case 't':
148 DAL.append(SynthesizedArgs.MakeJoinedArg(
149 BaseArg, Opts.getOption(options::OPT_O), "3"));
150 break;
151 case 'y': {
152 bool OmitFramePointer = true;
153 if (I + 1 != E && OptStr[I + 1] == '-') {
154 OmitFramePointer = false;
155 ++I;
156 }
157 if (SupportsForcingFramePointer) {
158 if (OmitFramePointer)
159 DAL.append(SynthesizedArgs.MakeFlagArg(
160 BaseArg, Opts.getOption(options::OPT_fomit_frame_pointer)));
161 else
162 DAL.append(SynthesizedArgs.MakeFlagArg(
163 BaseArg, Opts.getOption(options::OPT_fno_omit_frame_pointer)));
164 } else {
165 // Silently accept /Oy- on x86-64 for portable clang-cl build flags.
166 A->claim();
167 }
168 break;
169 }
170 }
171 }
172 return true;
173}
174
175DerivedArgList *ClangCLArgs::translateArgs(const DerivedArgList &Args,
176 const llvm::Triple &HostTriple,
177 const DerivedArgList &Owner) {
178 ClangCLArgs Translator(Args, HostTriple);
179 auto *DAL = new DerivedArgList(Args.getBaseArgs());
180 for (Arg *A : Args) {
181 if (!A->getOption().matches(options::OPT__SLASH_O) &&
182 A->getBaseArg().getOption().matches(options::OPT__SLASH_O))
183 continue;
184 if (!Translator.translateArg(A, *DAL, &Owner))
185 DAL->append(A);
186 }
187 return DAL;
188}
189
191 const ArgList &Args) {
192 llvm::StringRef Val = Value;
193 size_t Hash = Val.find('#');
194 if (Hash == llvm::StringRef::npos || Hash > Val.find('='))
195 return Value;
196
197 std::string NewVal = std::string(Val);
198 NewVal[Hash] = '=';
199 return Args.MakeArgString(NewVal);
200}
bool translateArg(llvm::opt::Arg *A, llvm::opt::DerivedArgList &DAL, const llvm::opt::DerivedArgList *Owner=nullptr) const
Append the canonical translation of A to DAL.
static llvm::opt::DerivedArgList * translateArgs(const llvm::opt::DerivedArgList &Args, const llvm::Triple &HostTriple, const llvm::opt::DerivedArgList &Owner)
Translate a filtered list that may contain new clang-cl options, replacing earlier /O expansions.
static const char * translateMacroDefinition(const char *Value, const llvm::opt::ArgList &Args)
Normalize MSVC's '#' macro separator, also used by Clang targeting MSVC and by arguments parsed after...
ClangCLArgs(const llvm::opt::ArgList &Args, const llvm::Triple &HostTriple)
The argument values must outlive this translator.
Top level wrappers for InstallAPI frontend operations.
const llvm::opt::OptTable & getDriverOptTable()
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30