1 | //===-- ClangAttrEmitter.cpp - Generate Clang attribute handling ----------===// |
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 | // These tablegen backends emit Clang attribute processing code |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "TableGenBackends.h" |
14 | #include "ASTTableGen.h" |
15 | |
16 | #include "llvm/ADT/ArrayRef.h" |
17 | #include "llvm/ADT/DenseMap.h" |
18 | #include "llvm/ADT/DenseSet.h" |
19 | #include "llvm/ADT/MapVector.h" |
20 | #include "llvm/ADT/STLExtras.h" |
21 | #include "llvm/ADT/SmallString.h" |
22 | #include "llvm/ADT/StringExtras.h" |
23 | #include "llvm/ADT/StringMap.h" |
24 | #include "llvm/ADT/StringRef.h" |
25 | #include "llvm/ADT/StringSwitch.h" |
26 | #include "llvm/Support/ErrorHandling.h" |
27 | #include "llvm/Support/raw_ostream.h" |
28 | #include "llvm/TableGen/Error.h" |
29 | #include "llvm/TableGen/Record.h" |
30 | #include "llvm/TableGen/StringMatcher.h" |
31 | #include "llvm/TableGen/TableGenBackend.h" |
32 | #include <cassert> |
33 | #include <cctype> |
34 | #include <cstddef> |
35 | #include <cstdint> |
36 | #include <map> |
37 | #include <memory> |
38 | #include <optional> |
39 | #include <set> |
40 | #include <string> |
41 | #include <utility> |
42 | #include <vector> |
43 | |
44 | using namespace llvm; |
45 | |
46 | namespace { |
47 | |
48 | class FlattenedSpelling { |
49 | StringRef V, N, NS; |
50 | bool K = false; |
51 | const Record &OriginalSpelling; |
52 | |
53 | public: |
54 | FlattenedSpelling(StringRef Variety, StringRef Name, StringRef Namespace, |
55 | bool KnownToGCC, const Record &OriginalSpelling) |
56 | : V(Variety), N(Name), NS(Namespace), K(KnownToGCC), |
57 | OriginalSpelling(OriginalSpelling) {} |
58 | explicit FlattenedSpelling(const Record &Spelling) |
59 | : V(Spelling.getValueAsString(FieldName: "Variety" )), |
60 | N(Spelling.getValueAsString(FieldName: "Name" )), OriginalSpelling(Spelling) { |
61 | assert(V != "GCC" && V != "Clang" && |
62 | "Given a GCC spelling, which means this hasn't been flattened!" ); |
63 | if (V == "CXX11" || V == "C23" || V == "Pragma" ) |
64 | NS = Spelling.getValueAsString(FieldName: "Namespace" ); |
65 | } |
66 | |
67 | StringRef variety() const { return V; } |
68 | StringRef name() const { return N; } |
69 | StringRef nameSpace() const { return NS; } |
70 | bool knownToGCC() const { return K; } |
71 | const Record &getSpellingRecord() const { return OriginalSpelling; } |
72 | }; |
73 | |
74 | struct FlattenedSpellingInfo { |
75 | FlattenedSpellingInfo(StringRef Syntax, StringRef Scope, |
76 | const std::string &TargetTest, uint32_t ArgMask) |
77 | : Syntax(Syntax), Scope(Scope), TargetTest(TargetTest), ArgMask(ArgMask) { |
78 | } |
79 | StringRef Syntax; |
80 | StringRef Scope; |
81 | std::string TargetTest; |
82 | uint32_t ArgMask; |
83 | }; |
84 | using FSIVecTy = std::vector<FlattenedSpellingInfo>; |
85 | |
86 | } // end anonymous namespace |
87 | |
88 | static bool GenerateTargetSpecificAttrChecks(const Record *R, |
89 | std::vector<StringRef> &Arches, |
90 | std::string &Test, |
91 | std::string *FnName); |
92 | static bool isStringLiteralArgument(const Record *Arg); |
93 | static bool isVariadicStringLiteralArgument(const Record *Arg); |
94 | |
95 | static std::vector<FlattenedSpelling> |
96 | GetFlattenedSpellings(const Record &Attr) { |
97 | std::vector<FlattenedSpelling> Ret; |
98 | |
99 | for (const auto &Spelling : Attr.getValueAsListOfDefs(FieldName: "Spellings" )) { |
100 | StringRef Variety = Spelling->getValueAsString(FieldName: "Variety" ); |
101 | StringRef Name = Spelling->getValueAsString(FieldName: "Name" ); |
102 | if (Variety == "GCC" ) { |
103 | Ret.emplace_back(args: "GNU" , args&: Name, args: "" , args: true, args: *Spelling); |
104 | Ret.emplace_back(args: "CXX11" , args&: Name, args: "gnu" , args: true, args: *Spelling); |
105 | if (Spelling->getValueAsBit(FieldName: "AllowInC" )) |
106 | Ret.emplace_back(args: "C23" , args&: Name, args: "gnu" , args: true, args: *Spelling); |
107 | } else if (Variety == "Clang" ) { |
108 | Ret.emplace_back(args: "GNU" , args&: Name, args: "" , args: false, args: *Spelling); |
109 | Ret.emplace_back(args: "CXX11" , args&: Name, args: "clang" , args: false, args: *Spelling); |
110 | if (Spelling->getValueAsBit(FieldName: "AllowInC" )) |
111 | Ret.emplace_back(args: "C23" , args&: Name, args: "clang" , args: false, args: *Spelling); |
112 | } else if (Variety == "ClangGCC" ) { |
113 | Ret.emplace_back(args: "GNU" , args&: Name, args: "" , args: false, args: *Spelling); |
114 | Ret.emplace_back(args: "CXX11" , args&: Name, args: "clang" , args: false, args: *Spelling); |
115 | Ret.emplace_back(args: "CXX11" , args&: Name, args: "gnu" , args: false, args: *Spelling); |
116 | if (Spelling->getValueAsBit(FieldName: "AllowInC" )) { |
117 | Ret.emplace_back(args: "C23" , args&: Name, args: "clang" , args: false, args: *Spelling); |
118 | Ret.emplace_back(args: "C23" , args&: Name, args: "gnu" , args: false, args: *Spelling); |
119 | } |
120 | } else { |
121 | Ret.push_back(x: FlattenedSpelling(*Spelling)); |
122 | } |
123 | } |
124 | |
125 | return Ret; |
126 | } |
127 | |
128 | static std::string ReadPCHRecord(StringRef type) { |
129 | return StringSwitch<std::string>(type) |
130 | .EndsWith(S: "Decl *" , Value: "Record.readDeclAs<" + type.drop_back().str() + ">()" ) |
131 | .Case(S: "TypeSourceInfo *" , Value: "Record.readTypeSourceInfo()" ) |
132 | .Case(S: "Expr *" , Value: "Record.readExpr()" ) |
133 | .Case(S: "IdentifierInfo *" , Value: "Record.readIdentifier()" ) |
134 | .Case(S: "StringRef" , Value: "Record.readString()" ) |
135 | .Case(S: "ParamIdx" , Value: "ParamIdx::deserialize(Record.readInt())" ) |
136 | .Case(S: "OMPTraitInfo *" , Value: "Record.readOMPTraitInfo()" ) |
137 | .Default(Value: "Record.readInt()" ); |
138 | } |
139 | |
140 | // Get a type that is suitable for storing an object of the specified type. |
141 | static StringRef getStorageType(StringRef type) { |
142 | return StringSwitch<StringRef>(type) |
143 | .Case(S: "StringRef" , Value: "std::string" ) |
144 | .Default(Value: type); |
145 | } |
146 | |
147 | // Assumes that the way to get the value is SA->getname() |
148 | static std::string WritePCHRecord(StringRef type, StringRef name) { |
149 | return "Record." + |
150 | StringSwitch<std::string>(type) |
151 | .EndsWith(S: "Decl *" , Value: "AddDeclRef(" + name.str() + ");\n" ) |
152 | .Case(S: "TypeSourceInfo *" , |
153 | Value: "AddTypeSourceInfo(" + name.str() + ");\n" ) |
154 | .Case(S: "Expr *" , Value: "AddStmt(" + name.str() + ");\n" ) |
155 | .Case(S: "IdentifierInfo *" , |
156 | Value: "AddIdentifierRef(" + name.str() + ");\n" ) |
157 | .Case(S: "StringRef" , Value: "AddString(" + name.str() + ");\n" ) |
158 | .Case(S: "ParamIdx" , Value: "push_back(" + name.str() + ".serialize());\n" ) |
159 | .Case(S: "OMPTraitInfo *" , Value: "writeOMPTraitInfo(" + name.str() + ");\n" ) |
160 | .Default(Value: "push_back(" + name.str() + ");\n" ); |
161 | } |
162 | |
163 | // Normalize attribute name by removing leading and trailing |
164 | // underscores. For example, __foo, foo__, __foo__ would |
165 | // become foo. |
166 | static StringRef NormalizeAttrName(StringRef AttrName) { |
167 | AttrName.consume_front(Prefix: "__" ); |
168 | AttrName.consume_back(Suffix: "__" ); |
169 | return AttrName; |
170 | } |
171 | |
172 | // Normalize the name by removing any and all leading and trailing underscores. |
173 | // This is different from NormalizeAttrName in that it also handles names like |
174 | // _pascal and __pascal. |
175 | static StringRef NormalizeNameForSpellingComparison(StringRef Name) { |
176 | return Name.trim(Chars: "_" ); |
177 | } |
178 | |
179 | // Normalize the spelling of a GNU attribute (i.e. "x" in "__attribute__((x))"), |
180 | // removing "__" if it appears at the beginning and end of the attribute's name. |
181 | static StringRef NormalizeGNUAttrSpelling(StringRef AttrSpelling) { |
182 | if (AttrSpelling.starts_with(Prefix: "__" ) && AttrSpelling.ends_with(Suffix: "__" )) { |
183 | AttrSpelling = AttrSpelling.substr(Start: 2, N: AttrSpelling.size() - 4); |
184 | } |
185 | |
186 | return AttrSpelling; |
187 | } |
188 | |
189 | typedef std::vector<std::pair<std::string, const Record *>> ParsedAttrMap; |
190 | |
191 | static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records, |
192 | ParsedAttrMap *Dupes = nullptr, |
193 | bool SemaOnly = true) { |
194 | std::set<std::string> Seen; |
195 | ParsedAttrMap R; |
196 | for (const Record *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
197 | if (!SemaOnly || Attr->getValueAsBit(FieldName: "SemaHandler" )) { |
198 | std::string AN; |
199 | if (Attr->isSubClassOf(Name: "TargetSpecificAttr" ) && |
200 | !Attr->isValueUnset(FieldName: "ParseKind" )) { |
201 | AN = Attr->getValueAsString(FieldName: "ParseKind" ).str(); |
202 | |
203 | // If this attribute has already been handled, it does not need to be |
204 | // handled again. |
205 | if (!Seen.insert(x: AN).second) { |
206 | if (Dupes) |
207 | Dupes->push_back(x: std::make_pair(x&: AN, y&: Attr)); |
208 | continue; |
209 | } |
210 | } else |
211 | AN = NormalizeAttrName(AttrName: Attr->getName()).str(); |
212 | |
213 | R.push_back(x: std::make_pair(x&: AN, y&: Attr)); |
214 | } |
215 | } |
216 | return R; |
217 | } |
218 | |
219 | namespace { |
220 | |
221 | class Argument { |
222 | std::string lowerName, upperName; |
223 | StringRef attrName; |
224 | bool isOpt; |
225 | bool Fake; |
226 | |
227 | public: |
228 | Argument(StringRef Arg, StringRef Attr) |
229 | : lowerName(Arg.str()), upperName(lowerName), attrName(Attr), |
230 | isOpt(false), Fake(false) { |
231 | if (!lowerName.empty()) { |
232 | lowerName[0] = std::tolower(c: lowerName[0]); |
233 | upperName[0] = std::toupper(c: upperName[0]); |
234 | } |
235 | // Work around MinGW's macro definition of 'interface' to 'struct'. We |
236 | // have an attribute argument called 'Interface', so only the lower case |
237 | // name conflicts with the macro definition. |
238 | if (lowerName == "interface" ) |
239 | lowerName = "interface_" ; |
240 | } |
241 | Argument(const Record &Arg, StringRef Attr) |
242 | : Argument(Arg.getValueAsString(FieldName: "Name" ), Attr) {} |
243 | virtual ~Argument() = default; |
244 | |
245 | StringRef getLowerName() const { return lowerName; } |
246 | StringRef getUpperName() const { return upperName; } |
247 | StringRef getAttrName() const { return attrName; } |
248 | |
249 | bool isOptional() const { return isOpt; } |
250 | void setOptional(bool set) { isOpt = set; } |
251 | |
252 | bool isFake() const { return Fake; } |
253 | void setFake(bool fake) { Fake = fake; } |
254 | |
255 | // These functions print the argument contents formatted in different ways. |
256 | virtual void writeAccessors(raw_ostream &OS) const = 0; |
257 | virtual void writeAccessorDefinitions(raw_ostream &OS) const {} |
258 | virtual void writeASTVisitorTraversal(raw_ostream &OS) const {} |
259 | virtual void writeCloneArgs(raw_ostream &OS) const = 0; |
260 | virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0; |
261 | virtual void writeTemplateInstantiation(raw_ostream &OS) const {} |
262 | virtual void writeCtorBody(raw_ostream &OS) const {} |
263 | virtual void writeCtorInitializers(raw_ostream &OS) const = 0; |
264 | virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0; |
265 | virtual void writeCtorParameters(raw_ostream &OS) const = 0; |
266 | virtual void writeDeclarations(raw_ostream &OS) const = 0; |
267 | virtual void writePCHReadArgs(raw_ostream &OS) const = 0; |
268 | virtual void writePCHReadDecls(raw_ostream &OS) const = 0; |
269 | virtual void writePCHWrite(raw_ostream &OS) const = 0; |
270 | virtual std::string getIsOmitted() const { return "false" ; } |
271 | virtual void writeValue(raw_ostream &OS) const = 0; |
272 | virtual void writeDump(raw_ostream &OS) const = 0; |
273 | virtual void writeDumpChildren(raw_ostream &OS) const {} |
274 | virtual void writeHasChildren(raw_ostream &OS) const { OS << "false" ; } |
275 | |
276 | virtual bool isEnumArg() const { return false; } |
277 | virtual bool isVariadicEnumArg() const { return false; } |
278 | virtual bool isVariadic() const { return false; } |
279 | |
280 | virtual void writeImplicitCtorArgs(raw_ostream &OS) const { |
281 | OS << getUpperName(); |
282 | } |
283 | }; |
284 | |
285 | class SimpleArgument : public Argument { |
286 | std::string type; |
287 | |
288 | public: |
289 | SimpleArgument(const Record &Arg, StringRef Attr, std::string T) |
290 | : Argument(Arg, Attr), type(std::move(T)) {} |
291 | |
292 | std::string getType() const { return type; } |
293 | |
294 | void writeAccessors(raw_ostream &OS) const override { |
295 | OS << " " << type << " get" << getUpperName() << "() const {\n" ; |
296 | OS << " return " << getLowerName() << ";\n" ; |
297 | OS << " }" ; |
298 | } |
299 | |
300 | void writeCloneArgs(raw_ostream &OS) const override { |
301 | OS << getLowerName(); |
302 | } |
303 | |
304 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
305 | OS << "A->get" << getUpperName() << "()" ; |
306 | } |
307 | |
308 | void writeCtorInitializers(raw_ostream &OS) const override { |
309 | OS << getLowerName() << "(" << getUpperName() << ")" ; |
310 | } |
311 | |
312 | void writeCtorDefaultInitializers(raw_ostream &OS) const override { |
313 | OS << getLowerName() << "()" ; |
314 | } |
315 | |
316 | void writeCtorParameters(raw_ostream &OS) const override { |
317 | OS << type << " " << getUpperName(); |
318 | } |
319 | |
320 | void writeDeclarations(raw_ostream &OS) const override { |
321 | OS << type << " " << getLowerName() << ";" ; |
322 | } |
323 | |
324 | void writePCHReadDecls(raw_ostream &OS) const override { |
325 | std::string read = ReadPCHRecord(type); |
326 | OS << " " << type << " " << getLowerName() << " = " << read << ";\n" ; |
327 | } |
328 | |
329 | void writePCHReadArgs(raw_ostream &OS) const override { |
330 | OS << getLowerName(); |
331 | } |
332 | |
333 | void writePCHWrite(raw_ostream &OS) const override { |
334 | OS << " " |
335 | << WritePCHRecord(type, name: "SA->get" + getUpperName().str() + "()" ); |
336 | } |
337 | |
338 | std::string getIsOmitted() const override { |
339 | auto IsOneOf = [](StringRef subject, auto... list) { |
340 | return ((subject == list) || ...); |
341 | }; |
342 | |
343 | if (IsOneOf(type, "IdentifierInfo *" , "Expr *" )) |
344 | return "!get" + getUpperName().str() + "()" ; |
345 | if (IsOneOf(type, "TypeSourceInfo *" )) |
346 | return "!get" + getUpperName().str() + "Loc()" ; |
347 | if (IsOneOf(type, "ParamIdx" )) |
348 | return "!get" + getUpperName().str() + "().isValid()" ; |
349 | |
350 | assert(IsOneOf(type, "unsigned" , "int" , "bool" , "FunctionDecl *" , |
351 | "VarDecl *" )); |
352 | return "false" ; |
353 | } |
354 | |
355 | void writeValue(raw_ostream &OS) const override { |
356 | if (type == "FunctionDecl *" ) |
357 | OS << "\" << get" << getUpperName() |
358 | << "()->getNameInfo().getAsString() << \"" ; |
359 | else if (type == "IdentifierInfo *" ) |
360 | // Some non-optional (comma required) identifier arguments can be the |
361 | // empty string but are then recorded as a nullptr. |
362 | OS << "\" << (get" << getUpperName() << "() ? get" << getUpperName() |
363 | << "()->getName() : \"\") << \"" ; |
364 | else if (type == "VarDecl *" ) |
365 | OS << "\" << get" << getUpperName() << "()->getName() << \"" ; |
366 | else if (type == "TypeSourceInfo *" ) |
367 | OS << "\" << get" << getUpperName() << "().getAsString() << \"" ; |
368 | else if (type == "ParamIdx" ) |
369 | OS << "\" << get" << getUpperName() << "().getSourceIndex() << \"" ; |
370 | else |
371 | OS << "\" << get" << getUpperName() << "() << \"" ; |
372 | } |
373 | |
374 | void writeDump(raw_ostream &OS) const override { |
375 | if (StringRef(type).ends_with(Suffix: "Decl *" )) { |
376 | OS << " OS << \" \";\n" ; |
377 | OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n" ; |
378 | } else if (type == "IdentifierInfo *" ) { |
379 | // Some non-optional (comma required) identifier arguments can be the |
380 | // empty string but are then recorded as a nullptr. |
381 | OS << " if (SA->get" << getUpperName() << "())\n" |
382 | << " OS << \" \" << SA->get" << getUpperName() |
383 | << "()->getName();\n" ; |
384 | } else if (type == "TypeSourceInfo *" ) { |
385 | if (isOptional()) |
386 | OS << " if (SA->get" << getUpperName() << "Loc())" ; |
387 | OS << " OS << \" \" << SA->get" << getUpperName() |
388 | << "().getAsString();\n" ; |
389 | } else if (type == "bool" ) { |
390 | OS << " if (SA->get" << getUpperName() << "()) OS << \" " |
391 | << getUpperName() << "\";\n" ; |
392 | } else if (type == "int" || type == "unsigned" ) { |
393 | OS << " OS << \" \" << SA->get" << getUpperName() << "();\n" ; |
394 | } else if (type == "ParamIdx" ) { |
395 | if (isOptional()) |
396 | OS << " if (SA->get" << getUpperName() << "().isValid())\n " ; |
397 | OS << " OS << \" \" << SA->get" << getUpperName() |
398 | << "().getSourceIndex();\n" ; |
399 | } else if (type == "OMPTraitInfo *" ) { |
400 | OS << " OS << \" \" << SA->get" << getUpperName() << "();\n" ; |
401 | } else { |
402 | llvm_unreachable("Unknown SimpleArgument type!" ); |
403 | } |
404 | } |
405 | }; |
406 | |
407 | class DefaultSimpleArgument : public SimpleArgument { |
408 | int64_t Default; |
409 | |
410 | public: |
411 | DefaultSimpleArgument(const Record &Arg, StringRef Attr, |
412 | std::string T, int64_t Default) |
413 | : SimpleArgument(Arg, Attr, T), Default(Default) {} |
414 | |
415 | void writeAccessors(raw_ostream &OS) const override { |
416 | SimpleArgument::writeAccessors(OS); |
417 | |
418 | OS << "\n\n static const " << getType() << " Default" << getUpperName() |
419 | << " = " ; |
420 | if (getType() == "bool" ) |
421 | OS << (Default != 0 ? "true" : "false" ); |
422 | else |
423 | OS << Default; |
424 | OS << ";" ; |
425 | } |
426 | }; |
427 | |
428 | class StringArgument : public Argument { |
429 | public: |
430 | StringArgument(const Record &Arg, StringRef Attr) |
431 | : Argument(Arg, Attr) |
432 | {} |
433 | |
434 | void writeAccessors(raw_ostream &OS) const override { |
435 | OS << " llvm::StringRef get" << getUpperName() << "() const {\n" ; |
436 | OS << " return llvm::StringRef(" << getLowerName() << ", " |
437 | << getLowerName() << "Length);\n" ; |
438 | OS << " }\n" ; |
439 | OS << " unsigned get" << getUpperName() << "Length() const {\n" ; |
440 | OS << " return " << getLowerName() << "Length;\n" ; |
441 | OS << " }\n" ; |
442 | OS << " void set" << getUpperName() |
443 | << "(ASTContext &C, llvm::StringRef S) {\n" ; |
444 | OS << " " << getLowerName() << "Length = S.size();\n" ; |
445 | OS << " this->" << getLowerName() << " = new (C, 1) char [" |
446 | << getLowerName() << "Length];\n" ; |
447 | OS << " if (!S.empty())\n" ; |
448 | OS << " std::memcpy(this->" << getLowerName() << ", S.data(), " |
449 | << getLowerName() << "Length);\n" ; |
450 | OS << " }" ; |
451 | } |
452 | |
453 | void writeCloneArgs(raw_ostream &OS) const override { |
454 | OS << "get" << getUpperName() << "()" ; |
455 | } |
456 | |
457 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
458 | OS << "A->get" << getUpperName() << "()" ; |
459 | } |
460 | |
461 | void writeCtorBody(raw_ostream &OS) const override { |
462 | OS << " if (!" << getUpperName() << ".empty())\n" ; |
463 | OS << " std::memcpy(" << getLowerName() << ", " << getUpperName() |
464 | << ".data(), " << getLowerName() << "Length);\n" ; |
465 | } |
466 | |
467 | void writeCtorInitializers(raw_ostream &OS) const override { |
468 | OS << getLowerName() << "Length(" << getUpperName() << ".size())," |
469 | << getLowerName() << "(new (Ctx, 1) char[" << getLowerName() |
470 | << "Length])" ; |
471 | } |
472 | |
473 | void writeCtorDefaultInitializers(raw_ostream &OS) const override { |
474 | OS << getLowerName() << "Length(0)," << getLowerName() << "(nullptr)" ; |
475 | } |
476 | |
477 | void writeCtorParameters(raw_ostream &OS) const override { |
478 | OS << "llvm::StringRef " << getUpperName(); |
479 | } |
480 | |
481 | void writeDeclarations(raw_ostream &OS) const override { |
482 | OS << "unsigned " << getLowerName() << "Length;\n" ; |
483 | OS << "char *" << getLowerName() << ";" ; |
484 | } |
485 | |
486 | void writePCHReadDecls(raw_ostream &OS) const override { |
487 | OS << " std::string " << getLowerName() |
488 | << "= Record.readString();\n" ; |
489 | } |
490 | |
491 | void writePCHReadArgs(raw_ostream &OS) const override { |
492 | OS << getLowerName(); |
493 | } |
494 | |
495 | void writePCHWrite(raw_ostream &OS) const override { |
496 | OS << " Record.AddString(SA->get" << getUpperName() << "());\n" ; |
497 | } |
498 | |
499 | void writeValue(raw_ostream &OS) const override { |
500 | OS << "\\\"\" << get" << getUpperName() << "() << \"\\\"" ; |
501 | } |
502 | |
503 | void writeDump(raw_ostream &OS) const override { |
504 | OS << " OS << \" \\\"\" << SA->get" << getUpperName() |
505 | << "() << \"\\\"\";\n" ; |
506 | } |
507 | }; |
508 | |
509 | class AlignedArgument : public Argument { |
510 | public: |
511 | AlignedArgument(const Record &Arg, StringRef Attr) |
512 | : Argument(Arg, Attr) |
513 | {} |
514 | |
515 | void writeAccessors(raw_ostream &OS) const override { |
516 | OS << " bool is" << getUpperName() << "Dependent() const;\n" ; |
517 | OS << " bool is" << getUpperName() << "ErrorDependent() const;\n" ; |
518 | |
519 | OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n" ; |
520 | |
521 | OS << " bool is" << getUpperName() << "Expr() const {\n" ; |
522 | OS << " return is" << getLowerName() << "Expr;\n" ; |
523 | OS << " }\n" ; |
524 | |
525 | OS << " Expr *get" << getUpperName() << "Expr() const {\n" ; |
526 | OS << " assert(is" << getLowerName() << "Expr);\n" ; |
527 | OS << " return " << getLowerName() << "Expr;\n" ; |
528 | OS << " }\n" ; |
529 | |
530 | OS << " TypeSourceInfo *get" << getUpperName() << "Type() const {\n" ; |
531 | OS << " assert(!is" << getLowerName() << "Expr);\n" ; |
532 | OS << " return " << getLowerName() << "Type;\n" ; |
533 | OS << " }" ; |
534 | |
535 | OS << " std::optional<unsigned> getCached" << getUpperName() |
536 | << "Value() const {\n" ; |
537 | OS << " return " << getLowerName() << "Cache;\n" ; |
538 | OS << " }" ; |
539 | |
540 | OS << " void setCached" << getUpperName() |
541 | << "Value(unsigned AlignVal) {\n" ; |
542 | OS << " " << getLowerName() << "Cache = AlignVal;\n" ; |
543 | OS << " }" ; |
544 | } |
545 | |
546 | void writeAccessorDefinitions(raw_ostream &OS) const override { |
547 | OS << "bool " << getAttrName() << "Attr::is" << getUpperName() |
548 | << "Dependent() const {\n" ; |
549 | OS << " if (is" << getLowerName() << "Expr)\n" ; |
550 | OS << " return " << getLowerName() << "Expr && (" << getLowerName() |
551 | << "Expr->isValueDependent() || " << getLowerName() |
552 | << "Expr->isTypeDependent());\n" ; |
553 | OS << " else\n" ; |
554 | OS << " return " << getLowerName() |
555 | << "Type->getType()->isDependentType();\n" ; |
556 | OS << "}\n" ; |
557 | |
558 | OS << "bool " << getAttrName() << "Attr::is" << getUpperName() |
559 | << "ErrorDependent() const {\n" ; |
560 | OS << " if (is" << getLowerName() << "Expr)\n" ; |
561 | OS << " return " << getLowerName() << "Expr && " << getLowerName() |
562 | << "Expr->containsErrors();\n" ; |
563 | OS << " return " << getLowerName() |
564 | << "Type->getType()->containsErrors();\n" ; |
565 | OS << "}\n" ; |
566 | } |
567 | |
568 | void writeASTVisitorTraversal(raw_ostream &OS) const override { |
569 | StringRef Name = getUpperName(); |
570 | OS << " if (A->is" << Name << "Expr()) {\n" |
571 | << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n" |
572 | << " return false;\n" |
573 | << " } else if (auto *TSI = A->get" << Name << "Type()) {\n" |
574 | << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n" |
575 | << " return false;\n" |
576 | << " }\n" ; |
577 | } |
578 | |
579 | void writeCloneArgs(raw_ostream &OS) const override { |
580 | OS << "is" << getLowerName() << "Expr, is" << getLowerName() |
581 | << "Expr ? static_cast<void*>(" << getLowerName() |
582 | << "Expr) : " << getLowerName() |
583 | << "Type" ; |
584 | } |
585 | |
586 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
587 | // FIXME: move the definition in Sema::InstantiateAttrs to here. |
588 | // In the meantime, aligned attributes are cloned. |
589 | } |
590 | |
591 | void writeCtorBody(raw_ostream &OS) const override { |
592 | OS << " if (is" << getLowerName() << "Expr)\n" ; |
593 | OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>(" |
594 | << getUpperName() << ");\n" ; |
595 | OS << " else\n" ; |
596 | OS << " " << getLowerName() |
597 | << "Type = reinterpret_cast<TypeSourceInfo *>(" << getUpperName() |
598 | << ");\n" ; |
599 | } |
600 | |
601 | void writeCtorInitializers(raw_ostream &OS) const override { |
602 | OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)" ; |
603 | } |
604 | |
605 | void writeCtorDefaultInitializers(raw_ostream &OS) const override { |
606 | OS << "is" << getLowerName() << "Expr(false)" ; |
607 | } |
608 | |
609 | void writeCtorParameters(raw_ostream &OS) const override { |
610 | OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName(); |
611 | } |
612 | |
613 | void writeImplicitCtorArgs(raw_ostream &OS) const override { |
614 | OS << "Is" << getUpperName() << "Expr, " << getUpperName(); |
615 | } |
616 | |
617 | void writeDeclarations(raw_ostream &OS) const override { |
618 | OS << "bool is" << getLowerName() << "Expr;\n" ; |
619 | OS << "union {\n" ; |
620 | OS << "Expr *" << getLowerName() << "Expr;\n" ; |
621 | OS << "TypeSourceInfo *" << getLowerName() << "Type;\n" ; |
622 | OS << "};\n" ; |
623 | OS << "std::optional<unsigned> " << getLowerName() << "Cache;\n" ; |
624 | } |
625 | |
626 | void writePCHReadArgs(raw_ostream &OS) const override { |
627 | OS << "is" << getLowerName() << "Expr, " << getLowerName() << "Ptr" ; |
628 | } |
629 | |
630 | void writePCHReadDecls(raw_ostream &OS) const override { |
631 | OS << " bool is" << getLowerName() << "Expr = Record.readInt();\n" ; |
632 | OS << " void *" << getLowerName() << "Ptr;\n" ; |
633 | OS << " if (is" << getLowerName() << "Expr)\n" ; |
634 | OS << " " << getLowerName() << "Ptr = Record.readExpr();\n" ; |
635 | OS << " else\n" ; |
636 | OS << " " << getLowerName() |
637 | << "Ptr = Record.readTypeSourceInfo();\n" ; |
638 | } |
639 | |
640 | void writePCHWrite(raw_ostream &OS) const override { |
641 | OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n" ; |
642 | OS << " if (SA->is" << getUpperName() << "Expr())\n" ; |
643 | OS << " Record.AddStmt(SA->get" << getUpperName() << "Expr());\n" ; |
644 | OS << " else\n" ; |
645 | OS << " Record.AddTypeSourceInfo(SA->get" << getUpperName() |
646 | << "Type());\n" ; |
647 | } |
648 | |
649 | std::string getIsOmitted() const override { |
650 | return "!((is" + getLowerName().str() + "Expr && " + |
651 | getLowerName().str() + "Expr) || (!is" + getLowerName().str() + |
652 | "Expr && " + getLowerName().str() + "Type))" ; |
653 | } |
654 | |
655 | void writeValue(raw_ostream &OS) const override { |
656 | OS << "\";\n" ; |
657 | OS << " if (is" << getLowerName() << "Expr && " << getLowerName() |
658 | << "Expr)" ; |
659 | OS << " " << getLowerName() |
660 | << "Expr->printPretty(OS, nullptr, Policy);\n" ; |
661 | OS << " if (!is" << getLowerName() << "Expr && " << getLowerName() |
662 | << "Type)" ; |
663 | OS << " " << getLowerName() |
664 | << "Type->getType().print(OS, Policy);\n" ; |
665 | OS << " OS << \"" ; |
666 | } |
667 | |
668 | void writeDump(raw_ostream &OS) const override { |
669 | OS << " if (!SA->is" << getUpperName() << "Expr())\n" ; |
670 | OS << " dumpType(SA->get" << getUpperName() |
671 | << "Type()->getType());\n" ; |
672 | } |
673 | |
674 | void writeDumpChildren(raw_ostream &OS) const override { |
675 | OS << " if (SA->is" << getUpperName() << "Expr())\n" ; |
676 | OS << " Visit(SA->get" << getUpperName() << "Expr());\n" ; |
677 | } |
678 | |
679 | void writeHasChildren(raw_ostream &OS) const override { |
680 | OS << "SA->is" << getUpperName() << "Expr()" ; |
681 | } |
682 | }; |
683 | |
684 | class VariadicArgument : public Argument { |
685 | std::string Type, ArgName, ArgSizeName, RangeName; |
686 | |
687 | protected: |
688 | // Assumed to receive a parameter: raw_ostream OS. |
689 | virtual void writeValueImpl(raw_ostream &OS) const { |
690 | OS << " OS << Val;\n" ; |
691 | } |
692 | // Assumed to receive a parameter: raw_ostream OS. |
693 | virtual void writeDumpImpl(raw_ostream &OS) const { |
694 | OS << " OS << \" \" << Val;\n" ; |
695 | } |
696 | |
697 | public: |
698 | VariadicArgument(const Record &Arg, StringRef Attr, std::string T) |
699 | : Argument(Arg, Attr), Type(std::move(T)), |
700 | ArgName(getLowerName().str() + "_" ), ArgSizeName(ArgName + "Size" ), |
701 | RangeName(getLowerName().str()) {} |
702 | |
703 | VariadicArgument(StringRef Arg, StringRef Attr, std::string T) |
704 | : Argument(Arg, Attr), Type(std::move(T)), |
705 | ArgName(getLowerName().str() + "_" ), ArgSizeName(ArgName + "Size" ), |
706 | RangeName(getLowerName().str()) {} |
707 | |
708 | const std::string &getType() const { return Type; } |
709 | const std::string &getArgName() const { return ArgName; } |
710 | const std::string &getArgSizeName() const { return ArgSizeName; } |
711 | bool isVariadic() const override { return true; } |
712 | |
713 | void writeAccessors(raw_ostream &OS) const override { |
714 | std::string IteratorType = getLowerName().str() + "_iterator" ; |
715 | std::string BeginFn = getLowerName().str() + "_begin()" ; |
716 | std::string EndFn = getLowerName().str() + "_end()" ; |
717 | |
718 | OS << " typedef " << Type << "* " << IteratorType << ";\n" ; |
719 | OS << " " << IteratorType << " " << BeginFn << " const {" |
720 | << " return " << ArgName << "; }\n" ; |
721 | OS << " " << IteratorType << " " << EndFn << " const {" |
722 | << " return " << ArgName << " + " << ArgSizeName << "; }\n" ; |
723 | OS << " unsigned " << getLowerName() << "_size() const {" |
724 | << " return " << ArgSizeName << "; }\n" ; |
725 | OS << " llvm::iterator_range<" << IteratorType << "> " << RangeName |
726 | << "() const { return llvm::make_range(" << BeginFn << ", " << EndFn |
727 | << "); }\n" ; |
728 | } |
729 | |
730 | void writeSetter(raw_ostream &OS) const { |
731 | OS << " void set" << getUpperName() << "(ASTContext &Ctx, " ; |
732 | writeCtorParameters(OS); |
733 | OS << ") {\n" ; |
734 | OS << " " << ArgSizeName << " = " << getUpperName() << "Size;\n" ; |
735 | OS << " " << ArgName << " = new (Ctx, 16) " << getType() << "[" |
736 | << ArgSizeName << "];\n" ; |
737 | OS << " " ; |
738 | writeCtorBody(OS); |
739 | OS << " }\n" ; |
740 | } |
741 | |
742 | void writeCloneArgs(raw_ostream &OS) const override { |
743 | OS << ArgName << ", " << ArgSizeName; |
744 | } |
745 | |
746 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
747 | // This isn't elegant, but we have to go through public methods... |
748 | OS << "A->" << getLowerName() << "_begin(), " |
749 | << "A->" << getLowerName() << "_size()" ; |
750 | } |
751 | |
752 | void writeASTVisitorTraversal(raw_ostream &OS) const override { |
753 | // FIXME: Traverse the elements. |
754 | } |
755 | |
756 | void writeCtorBody(raw_ostream &OS) const override { |
757 | OS << " std::copy(" << getUpperName() << ", " << getUpperName() << " + " |
758 | << ArgSizeName << ", " << ArgName << ");\n" ; |
759 | } |
760 | |
761 | void writeCtorInitializers(raw_ostream &OS) const override { |
762 | OS << ArgSizeName << "(" << getUpperName() << "Size), " |
763 | << ArgName << "(new (Ctx, 16) " << getType() << "[" |
764 | << ArgSizeName << "])" ; |
765 | } |
766 | |
767 | void writeCtorDefaultInitializers(raw_ostream &OS) const override { |
768 | OS << ArgSizeName << "(0), " << ArgName << "(nullptr)" ; |
769 | } |
770 | |
771 | void writeCtorParameters(raw_ostream &OS) const override { |
772 | OS << getType() << " *" << getUpperName() << ", unsigned " |
773 | << getUpperName() << "Size" ; |
774 | } |
775 | |
776 | void writeImplicitCtorArgs(raw_ostream &OS) const override { |
777 | OS << getUpperName() << ", " << getUpperName() << "Size" ; |
778 | } |
779 | |
780 | void writeDeclarations(raw_ostream &OS) const override { |
781 | OS << " unsigned " << ArgSizeName << ";\n" ; |
782 | OS << " " << getType() << " *" << ArgName << ";" ; |
783 | } |
784 | |
785 | void writePCHReadDecls(raw_ostream &OS) const override { |
786 | OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n" ; |
787 | OS << " SmallVector<" << getType() << ", 4> " |
788 | << getLowerName() << ";\n" ; |
789 | OS << " " << getLowerName() << ".reserve(" << getLowerName() |
790 | << "Size);\n" ; |
791 | |
792 | // If we can't store the values in the current type (if it's something |
793 | // like StringRef), store them in a different type and convert the |
794 | // container afterwards. |
795 | std::string StorageType = getStorageType(type: getType()).str(); |
796 | std::string StorageName = getLowerName().str(); |
797 | if (StorageType != getType()) { |
798 | StorageName += "Storage" ; |
799 | OS << " SmallVector<" << StorageType << ", 4> " |
800 | << StorageName << ";\n" ; |
801 | OS << " " << StorageName << ".reserve(" << getLowerName() |
802 | << "Size);\n" ; |
803 | } |
804 | |
805 | OS << " for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n" ; |
806 | std::string read = ReadPCHRecord(type: Type); |
807 | OS << " " << StorageName << ".push_back(" << read << ");\n" ; |
808 | |
809 | if (StorageType != getType()) { |
810 | OS << " for (unsigned i = 0; i != " << getLowerName() << "Size; ++i)\n" ; |
811 | OS << " " << getLowerName() << ".push_back(" |
812 | << StorageName << "[i]);\n" ; |
813 | } |
814 | } |
815 | |
816 | void writePCHReadArgs(raw_ostream &OS) const override { |
817 | OS << getLowerName() << ".data(), " << getLowerName() << "Size" ; |
818 | } |
819 | |
820 | void writePCHWrite(raw_ostream &OS) const override { |
821 | OS << " Record.push_back(SA->" << getLowerName() << "_size());\n" ; |
822 | OS << " for (auto &Val : SA->" << RangeName << "())\n" ; |
823 | OS << " " << WritePCHRecord(type: Type, name: "Val" ); |
824 | } |
825 | |
826 | void writeValue(raw_ostream &OS) const override { |
827 | OS << "\";\n" ; |
828 | OS << " for (const auto &Val : " << RangeName << "()) {\n" |
829 | << " DelimitAttributeArgument(OS, IsFirstArgument);\n" ; |
830 | writeValueImpl(OS); |
831 | OS << " }\n" ; |
832 | OS << " OS << \"" ; |
833 | } |
834 | |
835 | void writeDump(raw_ostream &OS) const override { |
836 | OS << " for (const auto &Val : SA->" << RangeName << "())\n" ; |
837 | writeDumpImpl(OS); |
838 | } |
839 | }; |
840 | |
841 | class VariadicOMPInteropInfoArgument : public VariadicArgument { |
842 | public: |
843 | VariadicOMPInteropInfoArgument(const Record &Arg, StringRef Attr) |
844 | : VariadicArgument(Arg, Attr, "OMPInteropInfo" ) {} |
845 | |
846 | void writeDump(raw_ostream &OS) const override { |
847 | OS << " for (" << getAttrName() << "Attr::" << getLowerName() |
848 | << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" |
849 | << getLowerName() << "_end(); I != E; ++I) {\n" ; |
850 | OS << " if (I->IsTarget && I->IsTargetSync)\n" ; |
851 | OS << " OS << \" Target_TargetSync\";\n" ; |
852 | OS << " else if (I->IsTarget)\n" ; |
853 | OS << " OS << \" Target\";\n" ; |
854 | OS << " else\n" ; |
855 | OS << " OS << \" TargetSync\";\n" ; |
856 | OS << " }\n" ; |
857 | } |
858 | |
859 | void writePCHReadDecls(raw_ostream &OS) const override { |
860 | OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n" ; |
861 | OS << " SmallVector<OMPInteropInfo, 4> " << getLowerName() << ";\n" ; |
862 | OS << " " << getLowerName() << ".reserve(" << getLowerName() |
863 | << "Size);\n" ; |
864 | OS << " for (unsigned I = 0, E = " << getLowerName() << "Size; " ; |
865 | OS << "I != E; ++I) {\n" ; |
866 | OS << " bool IsTarget = Record.readBool();\n" ; |
867 | OS << " bool IsTargetSync = Record.readBool();\n" ; |
868 | OS << " " << getLowerName() |
869 | << ".emplace_back(IsTarget, IsTargetSync);\n" ; |
870 | OS << " }\n" ; |
871 | } |
872 | |
873 | void writePCHWrite(raw_ostream &OS) const override { |
874 | OS << " Record.push_back(SA->" << getLowerName() << "_size());\n" ; |
875 | OS << " for (" << getAttrName() << "Attr::" << getLowerName() |
876 | << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" |
877 | << getLowerName() << "_end(); I != E; ++I) {\n" ; |
878 | OS << " Record.writeBool(I->IsTarget);\n" ; |
879 | OS << " Record.writeBool(I->IsTargetSync);\n" ; |
880 | OS << " }\n" ; |
881 | } |
882 | }; |
883 | |
884 | class VariadicParamIdxArgument : public VariadicArgument { |
885 | public: |
886 | VariadicParamIdxArgument(const Record &Arg, StringRef Attr) |
887 | : VariadicArgument(Arg, Attr, "ParamIdx" ) {} |
888 | |
889 | public: |
890 | void writeValueImpl(raw_ostream &OS) const override { |
891 | OS << " OS << Val.getSourceIndex();\n" ; |
892 | } |
893 | |
894 | void writeDumpImpl(raw_ostream &OS) const override { |
895 | OS << " OS << \" \" << Val.getSourceIndex();\n" ; |
896 | } |
897 | }; |
898 | |
899 | struct VariadicParamOrParamIdxArgument : public VariadicArgument { |
900 | VariadicParamOrParamIdxArgument(const Record &Arg, StringRef Attr) |
901 | : VariadicArgument(Arg, Attr, "int" ) {} |
902 | }; |
903 | |
904 | // Unique the enums, but maintain the original declaration ordering. |
905 | std::vector<StringRef> |
906 | uniqueEnumsInOrder(const std::vector<StringRef> &enums) { |
907 | std::vector<StringRef> uniques; |
908 | SmallDenseSet<StringRef, 8> unique_set; |
909 | for (const auto &i : enums) { |
910 | if (unique_set.insert(V: i).second) |
911 | uniques.push_back(x: i); |
912 | } |
913 | return uniques; |
914 | } |
915 | |
916 | class EnumArgument : public Argument { |
917 | std::string fullType; |
918 | StringRef shortType; |
919 | std::vector<StringRef> values, enums, uniques; |
920 | bool isExternal; |
921 | bool isCovered; |
922 | |
923 | public: |
924 | EnumArgument(const Record &Arg, StringRef Attr) |
925 | : Argument(Arg, Attr), values(Arg.getValueAsListOfStrings(FieldName: "Values" )), |
926 | enums(Arg.getValueAsListOfStrings(FieldName: "Enums" )), |
927 | uniques(uniqueEnumsInOrder(enums)), |
928 | isExternal(Arg.getValueAsBit(FieldName: "IsExternalType" )), |
929 | isCovered(Arg.getValueAsBit(FieldName: "IsCovered" )) { |
930 | StringRef Type = Arg.getValueAsString(FieldName: "Type" ); |
931 | shortType = isExternal ? Type.rsplit(Separator: "::" ).second : Type; |
932 | // If shortType didn't contain :: at all rsplit will give us an empty |
933 | // string. |
934 | if (shortType.empty()) |
935 | shortType = Type; |
936 | fullType = isExternal ? Type : (getAttrName() + "Attr::" + Type).str(); |
937 | |
938 | // FIXME: Emit a proper error |
939 | assert(!uniques.empty()); |
940 | } |
941 | |
942 | bool isEnumArg() const override { return true; } |
943 | |
944 | void writeAccessors(raw_ostream &OS) const override { |
945 | OS << " " << fullType << " get" << getUpperName() << "() const {\n" ; |
946 | OS << " return " << getLowerName() << ";\n" ; |
947 | OS << " }" ; |
948 | } |
949 | |
950 | void writeCloneArgs(raw_ostream &OS) const override { |
951 | OS << getLowerName(); |
952 | } |
953 | |
954 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
955 | OS << "A->get" << getUpperName() << "()" ; |
956 | } |
957 | void writeCtorInitializers(raw_ostream &OS) const override { |
958 | OS << getLowerName() << "(" << getUpperName() << ")" ; |
959 | } |
960 | void writeCtorDefaultInitializers(raw_ostream &OS) const override { |
961 | OS << getLowerName() << "(" << fullType << "(0))" ; |
962 | } |
963 | void writeCtorParameters(raw_ostream &OS) const override { |
964 | OS << fullType << " " << getUpperName(); |
965 | } |
966 | void writeDeclarations(raw_ostream &OS) const override { |
967 | if (!isExternal) { |
968 | auto i = uniques.cbegin(), e = uniques.cend(); |
969 | // The last one needs to not have a comma. |
970 | --e; |
971 | |
972 | OS << "public:\n" ; |
973 | OS << " enum " << shortType << " {\n" ; |
974 | for (; i != e; ++i) |
975 | OS << " " << *i << ",\n" ; |
976 | OS << " " << *e << "\n" ; |
977 | OS << " };\n" ; |
978 | } |
979 | |
980 | OS << "private:\n" ; |
981 | OS << " " << fullType << " " << getLowerName() << ";" ; |
982 | } |
983 | |
984 | void writePCHReadDecls(raw_ostream &OS) const override { |
985 | OS << " " << fullType << " " << getLowerName() << "(static_cast<" |
986 | << fullType << ">(Record.readInt()));\n" ; |
987 | } |
988 | |
989 | void writePCHReadArgs(raw_ostream &OS) const override { |
990 | OS << getLowerName(); |
991 | } |
992 | |
993 | void writePCHWrite(raw_ostream &OS) const override { |
994 | OS << "Record.push_back(static_cast<uint64_t>(SA->get" << getUpperName() |
995 | << "()));\n" ; |
996 | } |
997 | |
998 | void writeValue(raw_ostream &OS) const override { |
999 | // FIXME: this isn't 100% correct -- some enum arguments require printing |
1000 | // as a string literal, while others require printing as an identifier. |
1001 | // Tablegen currently does not distinguish between the two forms. |
1002 | OS << "\\\"\" << " << getAttrName() << "Attr::Convert" << shortType |
1003 | << "ToStr(get" << getUpperName() << "()) << \"\\\"" ; |
1004 | } |
1005 | |
1006 | void writeDump(raw_ostream &OS) const override { |
1007 | OS << " switch(SA->get" << getUpperName() << "()) {\n" ; |
1008 | for (const auto &I : uniques) { |
1009 | OS << " case " << fullType << "::" << I << ":\n" ; |
1010 | OS << " OS << \" " << I << "\";\n" ; |
1011 | OS << " break;\n" ; |
1012 | } |
1013 | if (!isCovered) { |
1014 | OS << " default:\n" ; |
1015 | OS << " llvm_unreachable(\"Invalid attribute value\");\n" ; |
1016 | } |
1017 | OS << " }\n" ; |
1018 | } |
1019 | |
1020 | void writeConversion(raw_ostream &OS, bool ) const { |
1021 | if (Header) { |
1022 | OS << " static bool ConvertStrTo" << shortType << "(StringRef Val, " |
1023 | << fullType << " &Out);\n" ; |
1024 | OS << " static const char *Convert" << shortType << "ToStr(" |
1025 | << fullType << " Val);\n" ; |
1026 | return; |
1027 | } |
1028 | |
1029 | OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << shortType |
1030 | << "(StringRef Val, " << fullType << " &Out) {\n" ; |
1031 | OS << " std::optional<" << fullType << "> " |
1032 | << "R = llvm::StringSwitch<std::optional<" << fullType << ">>(Val)\n" ; |
1033 | for (size_t I = 0; I < enums.size(); ++I) { |
1034 | OS << " .Case(\"" << values[I] << "\", " ; |
1035 | OS << fullType << "::" << enums[I] << ")\n" ; |
1036 | } |
1037 | OS << " .Default(std::optional<" << fullType << ">());\n" ; |
1038 | OS << " if (R) {\n" ; |
1039 | OS << " Out = *R;\n return true;\n }\n" ; |
1040 | OS << " return false;\n" ; |
1041 | OS << "}\n\n" ; |
1042 | |
1043 | // Mapping from enumeration values back to enumeration strings isn't |
1044 | // trivial because some enumeration values have multiple named |
1045 | // enumerators, such as type_visibility(internal) and |
1046 | // type_visibility(hidden) both mapping to TypeVisibilityAttr::Hidden. |
1047 | OS << "const char *" << getAttrName() << "Attr::Convert" << shortType |
1048 | << "ToStr(" << fullType << " Val) {\n" |
1049 | << " switch(Val) {\n" ; |
1050 | SmallDenseSet<StringRef, 8> Uniques; |
1051 | for (size_t I = 0; I < enums.size(); ++I) { |
1052 | if (Uniques.insert(V: enums[I]).second) |
1053 | OS << " case " << fullType << "::" << enums[I] << ": return \"" |
1054 | << values[I] << "\";\n" ; |
1055 | } |
1056 | if (!isCovered) { |
1057 | OS << " default: llvm_unreachable(\"Invalid attribute value\");\n" ; |
1058 | } |
1059 | OS << " }\n" |
1060 | << " llvm_unreachable(\"No enumerator with that value\");\n" |
1061 | << "}\n" ; |
1062 | } |
1063 | }; |
1064 | |
1065 | class VariadicEnumArgument: public VariadicArgument { |
1066 | std::string fullType; |
1067 | StringRef shortType; |
1068 | std::vector<StringRef> values, enums, uniques; |
1069 | bool isExternal; |
1070 | bool isCovered; |
1071 | |
1072 | protected: |
1073 | void writeValueImpl(raw_ostream &OS) const override { |
1074 | // FIXME: this isn't 100% correct -- some enum arguments require printing |
1075 | // as a string literal, while others require printing as an identifier. |
1076 | // Tablegen currently does not distinguish between the two forms. |
1077 | OS << " OS << \"\\\"\" << " << getAttrName() << "Attr::Convert" |
1078 | << shortType << "ToStr(Val)" |
1079 | << "<< \"\\\"\";\n" ; |
1080 | } |
1081 | |
1082 | public: |
1083 | VariadicEnumArgument(const Record &Arg, StringRef Attr) |
1084 | : VariadicArgument(Arg, Attr, Arg.getValueAsString(FieldName: "Type" ).str()), |
1085 | values(Arg.getValueAsListOfStrings(FieldName: "Values" )), |
1086 | enums(Arg.getValueAsListOfStrings(FieldName: "Enums" )), |
1087 | uniques(uniqueEnumsInOrder(enums)), |
1088 | isExternal(Arg.getValueAsBit(FieldName: "IsExternalType" )), |
1089 | isCovered(Arg.getValueAsBit(FieldName: "IsCovered" )) { |
1090 | StringRef Type = Arg.getValueAsString(FieldName: "Type" ); |
1091 | shortType = isExternal ? Type.rsplit(Separator: "::" ).second : Type; |
1092 | // If shortType didn't contain :: at all rsplit will give us an empty |
1093 | // string. |
1094 | if (shortType.empty()) |
1095 | shortType = Type; |
1096 | fullType = isExternal ? Type : (getAttrName() + "Attr::" + Type).str(); |
1097 | |
1098 | // FIXME: Emit a proper error |
1099 | assert(!uniques.empty()); |
1100 | } |
1101 | |
1102 | bool isVariadicEnumArg() const override { return true; } |
1103 | |
1104 | void writeDeclarations(raw_ostream &OS) const override { |
1105 | if (!isExternal) { |
1106 | auto i = uniques.cbegin(), e = uniques.cend(); |
1107 | // The last one needs to not have a comma. |
1108 | --e; |
1109 | |
1110 | OS << "public:\n" ; |
1111 | OS << " enum " << shortType << " {\n" ; |
1112 | for (; i != e; ++i) |
1113 | OS << " " << *i << ",\n" ; |
1114 | OS << " " << *e << "\n" ; |
1115 | OS << " };\n" ; |
1116 | } |
1117 | OS << "private:\n" ; |
1118 | |
1119 | VariadicArgument::writeDeclarations(OS); |
1120 | } |
1121 | |
1122 | void writeDump(raw_ostream &OS) const override { |
1123 | OS << " for (" << getAttrName() << "Attr::" << getLowerName() |
1124 | << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" |
1125 | << getLowerName() << "_end(); I != E; ++I) {\n" ; |
1126 | OS << " switch(*I) {\n" ; |
1127 | for (const auto &UI : uniques) { |
1128 | OS << " case " << fullType << "::" << UI << ":\n" ; |
1129 | OS << " OS << \" " << UI << "\";\n" ; |
1130 | OS << " break;\n" ; |
1131 | } |
1132 | if (!isCovered) { |
1133 | OS << " default:\n" ; |
1134 | OS << " llvm_unreachable(\"Invalid attribute value\");\n" ; |
1135 | } |
1136 | OS << " }\n" ; |
1137 | OS << " }\n" ; |
1138 | } |
1139 | |
1140 | void writePCHReadDecls(raw_ostream &OS) const override { |
1141 | OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n" ; |
1142 | OS << " SmallVector<" << fullType << ", 4> " << getLowerName() |
1143 | << ";\n" ; |
1144 | OS << " " << getLowerName() << ".reserve(" << getLowerName() |
1145 | << "Size);\n" ; |
1146 | OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n" ; |
1147 | OS << " " << getLowerName() << ".push_back(" |
1148 | << "static_cast<" << fullType << ">(Record.readInt()));\n" ; |
1149 | } |
1150 | |
1151 | void writePCHWrite(raw_ostream &OS) const override { |
1152 | OS << " Record.push_back(SA->" << getLowerName() << "_size());\n" ; |
1153 | OS << " for (" << getAttrName() << "Attr::" << getLowerName() |
1154 | << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->" |
1155 | << getLowerName() << "_end(); i != e; ++i)\n" ; |
1156 | OS << " " << WritePCHRecord(type: fullType, name: "(*i)" ); |
1157 | } |
1158 | |
1159 | void writeConversion(raw_ostream &OS, bool ) const { |
1160 | if (Header) { |
1161 | OS << " static bool ConvertStrTo" << shortType << "(StringRef Val, " |
1162 | << fullType << " &Out);\n" ; |
1163 | OS << " static const char *Convert" << shortType << "ToStr(" |
1164 | << fullType << " Val);\n" ; |
1165 | return; |
1166 | } |
1167 | |
1168 | OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << shortType |
1169 | << "(StringRef Val, " ; |
1170 | OS << fullType << " &Out) {\n" ; |
1171 | OS << " std::optional<" << fullType |
1172 | << "> R = llvm::StringSwitch<std::optional<" ; |
1173 | OS << fullType << ">>(Val)\n" ; |
1174 | for (size_t I = 0; I < enums.size(); ++I) { |
1175 | OS << " .Case(\"" << values[I] << "\", " ; |
1176 | OS << fullType << "::" << enums[I] << ")\n" ; |
1177 | } |
1178 | OS << " .Default(std::optional<" << fullType << ">());\n" ; |
1179 | OS << " if (R) {\n" ; |
1180 | OS << " Out = *R;\n return true;\n }\n" ; |
1181 | OS << " return false;\n" ; |
1182 | OS << "}\n\n" ; |
1183 | |
1184 | OS << "const char *" << getAttrName() << "Attr::Convert" << shortType |
1185 | << "ToStr(" << fullType << " Val) {\n" |
1186 | << " switch(Val) {\n" ; |
1187 | SmallDenseSet<StringRef, 8> Uniques; |
1188 | for (size_t I = 0; I < enums.size(); ++I) { |
1189 | if (Uniques.insert(V: enums[I]).second) |
1190 | OS << " case " << fullType << "::" << enums[I] << ": return \"" |
1191 | << values[I] << "\";\n" ; |
1192 | } |
1193 | if (!isCovered) { |
1194 | OS << " default: llvm_unreachable(\"Invalid attribute value\");\n" ; |
1195 | } |
1196 | OS << " }\n" |
1197 | << " llvm_unreachable(\"No enumerator with that value\");\n" |
1198 | << "}\n" ; |
1199 | } |
1200 | }; |
1201 | |
1202 | class VersionArgument : public Argument { |
1203 | public: |
1204 | VersionArgument(const Record &Arg, StringRef Attr) |
1205 | : Argument(Arg, Attr) |
1206 | {} |
1207 | |
1208 | void writeAccessors(raw_ostream &OS) const override { |
1209 | OS << " VersionTuple get" << getUpperName() << "() const {\n" ; |
1210 | OS << " return " << getLowerName() << ";\n" ; |
1211 | OS << " }\n" ; |
1212 | OS << " void set" << getUpperName() |
1213 | << "(ASTContext &C, VersionTuple V) {\n" ; |
1214 | OS << " " << getLowerName() << " = V;\n" ; |
1215 | OS << " }" ; |
1216 | } |
1217 | |
1218 | void writeCloneArgs(raw_ostream &OS) const override { |
1219 | OS << "get" << getUpperName() << "()" ; |
1220 | } |
1221 | |
1222 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
1223 | OS << "A->get" << getUpperName() << "()" ; |
1224 | } |
1225 | |
1226 | void writeCtorInitializers(raw_ostream &OS) const override { |
1227 | OS << getLowerName() << "(" << getUpperName() << ")" ; |
1228 | } |
1229 | |
1230 | void writeCtorDefaultInitializers(raw_ostream &OS) const override { |
1231 | OS << getLowerName() << "()" ; |
1232 | } |
1233 | |
1234 | void writeCtorParameters(raw_ostream &OS) const override { |
1235 | OS << "VersionTuple " << getUpperName(); |
1236 | } |
1237 | |
1238 | void writeDeclarations(raw_ostream &OS) const override { |
1239 | OS << "VersionTuple " << getLowerName() << ";\n" ; |
1240 | } |
1241 | |
1242 | void writePCHReadDecls(raw_ostream &OS) const override { |
1243 | OS << " VersionTuple " << getLowerName() |
1244 | << "= Record.readVersionTuple();\n" ; |
1245 | } |
1246 | |
1247 | void writePCHReadArgs(raw_ostream &OS) const override { |
1248 | OS << getLowerName(); |
1249 | } |
1250 | |
1251 | void writePCHWrite(raw_ostream &OS) const override { |
1252 | OS << " Record.AddVersionTuple(SA->get" << getUpperName() << "());\n" ; |
1253 | } |
1254 | |
1255 | void writeValue(raw_ostream &OS) const override { |
1256 | OS << getLowerName() << "=\" << get" << getUpperName() << "() << \"" ; |
1257 | } |
1258 | |
1259 | void writeDump(raw_ostream &OS) const override { |
1260 | OS << " OS << \" \" << SA->get" << getUpperName() << "();\n" ; |
1261 | } |
1262 | }; |
1263 | |
1264 | class ExprArgument : public SimpleArgument { |
1265 | public: |
1266 | ExprArgument(const Record &Arg, StringRef Attr) |
1267 | : SimpleArgument(Arg, Attr, "Expr *" ) |
1268 | {} |
1269 | |
1270 | void writeASTVisitorTraversal(raw_ostream &OS) const override { |
1271 | OS << " if (!" |
1272 | << "getDerived().TraverseStmt(A->get" << getUpperName() << "()))\n" ; |
1273 | OS << " return false;\n" ; |
1274 | } |
1275 | |
1276 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
1277 | OS << "tempInst" << getUpperName(); |
1278 | } |
1279 | |
1280 | void writeTemplateInstantiation(raw_ostream &OS) const override { |
1281 | OS << " " << getType() << " tempInst" << getUpperName() << ";\n" ; |
1282 | OS << " {\n" ; |
1283 | OS << " EnterExpressionEvaluationContext " |
1284 | << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n" ; |
1285 | OS << " ExprResult " << "Result = S.SubstExpr(" |
1286 | << "A->get" << getUpperName() << "(), TemplateArgs);\n" ; |
1287 | OS << " if (Result.isInvalid())\n" ; |
1288 | OS << " return nullptr;\n" ; |
1289 | OS << " tempInst" << getUpperName() << " = Result.get();\n" ; |
1290 | OS << " }\n" ; |
1291 | } |
1292 | |
1293 | void writeValue(raw_ostream &OS) const override { |
1294 | OS << "\";\n" ; |
1295 | OS << " get" << getUpperName() |
1296 | << "()->printPretty(OS, nullptr, Policy);\n" ; |
1297 | OS << " OS << \"" ; |
1298 | } |
1299 | |
1300 | void writeDump(raw_ostream &OS) const override {} |
1301 | |
1302 | void writeDumpChildren(raw_ostream &OS) const override { |
1303 | OS << " Visit(SA->get" << getUpperName() << "());\n" ; |
1304 | } |
1305 | |
1306 | void writeHasChildren(raw_ostream &OS) const override { OS << "true" ; } |
1307 | }; |
1308 | |
1309 | class VariadicExprArgument : public VariadicArgument { |
1310 | public: |
1311 | VariadicExprArgument(const Record &Arg, StringRef Attr) |
1312 | : VariadicArgument(Arg, Attr, "Expr *" ) |
1313 | {} |
1314 | |
1315 | VariadicExprArgument(StringRef ArgName, StringRef Attr) |
1316 | : VariadicArgument(ArgName, Attr, "Expr *" ) {} |
1317 | |
1318 | void writeASTVisitorTraversal(raw_ostream &OS) const override { |
1319 | OS << " {\n" ; |
1320 | OS << " " << getType() << " *I = A->" << getLowerName() |
1321 | << "_begin();\n" ; |
1322 | OS << " " << getType() << " *E = A->" << getLowerName() |
1323 | << "_end();\n" ; |
1324 | OS << " for (; I != E; ++I) {\n" ; |
1325 | OS << " if (!getDerived().TraverseStmt(*I))\n" ; |
1326 | OS << " return false;\n" ; |
1327 | OS << " }\n" ; |
1328 | OS << " }\n" ; |
1329 | } |
1330 | |
1331 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
1332 | OS << "tempInst" << getUpperName() << ", " |
1333 | << "numTempInst" << getUpperName(); |
1334 | } |
1335 | |
1336 | void writeTemplateInstantiation(raw_ostream &OS) const override { |
1337 | OS << " size_t numTempInst" << getUpperName() << ";\n" ; |
1338 | OS << " " << getType() << "*tempInst" << getUpperName() << ";\n" ; |
1339 | OS << " {\n" ; |
1340 | OS << " EnterExpressionEvaluationContext " |
1341 | << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n" ; |
1342 | OS << " ArrayRef<" << getType() << "> ArgsToInstantiate(A->" |
1343 | << getLowerName() << "_begin(), A->" << getLowerName() << "_end());\n" ; |
1344 | OS << " SmallVector<" << getType() << ", 4> InstArgs;\n" ; |
1345 | OS << " if (S.SubstExprs(ArgsToInstantiate, /*IsCall=*/false, " |
1346 | "TemplateArgs, InstArgs))\n" ; |
1347 | OS << " return nullptr;\n" ; |
1348 | OS << " numTempInst" << getUpperName() << " = InstArgs.size();\n" ; |
1349 | OS << " tempInst" << getUpperName() << " = new (C, 16) " |
1350 | << getType() << "[numTempInst" << getUpperName() << "];\n" ; |
1351 | OS << " std::copy(InstArgs.begin(), InstArgs.end(), tempInst" |
1352 | << getUpperName() << ");\n" ; |
1353 | OS << " }\n" ; |
1354 | } |
1355 | |
1356 | void writeDump(raw_ostream &OS) const override {} |
1357 | |
1358 | void writeDumpChildren(raw_ostream &OS) const override { |
1359 | OS << " for (" << getAttrName() << "Attr::" << getLowerName() |
1360 | << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" |
1361 | << getLowerName() << "_end(); I != E; ++I)\n" ; |
1362 | OS << " Visit(*I);\n" ; |
1363 | } |
1364 | |
1365 | void writeHasChildren(raw_ostream &OS) const override { |
1366 | OS << "SA->" << getLowerName() << "_begin() != " |
1367 | << "SA->" << getLowerName() << "_end()" ; |
1368 | } |
1369 | }; |
1370 | |
1371 | class VariadicIdentifierArgument : public VariadicArgument { |
1372 | public: |
1373 | VariadicIdentifierArgument(const Record &Arg, StringRef Attr) |
1374 | : VariadicArgument(Arg, Attr, "IdentifierInfo *" ) |
1375 | {} |
1376 | }; |
1377 | |
1378 | class VariadicStringArgument : public VariadicArgument { |
1379 | public: |
1380 | VariadicStringArgument(const Record &Arg, StringRef Attr) |
1381 | : VariadicArgument(Arg, Attr, "StringRef" ) |
1382 | {} |
1383 | |
1384 | void writeCtorBody(raw_ostream &OS) const override { |
1385 | OS << " for (size_t I = 0, E = " << getArgSizeName() << "; I != E;\n" |
1386 | " ++I) {\n" |
1387 | " StringRef Ref = " << getUpperName() << "[I];\n" |
1388 | " if (!Ref.empty()) {\n" |
1389 | " char *Mem = new (Ctx, 1) char[Ref.size()];\n" |
1390 | " std::memcpy(Mem, Ref.data(), Ref.size());\n" |
1391 | " " << getArgName() << "[I] = StringRef(Mem, Ref.size());\n" |
1392 | " }\n" |
1393 | " }\n" ; |
1394 | } |
1395 | |
1396 | void writeValueImpl(raw_ostream &OS) const override { |
1397 | OS << " OS << \"\\\"\" << Val << \"\\\"\";\n" ; |
1398 | } |
1399 | }; |
1400 | |
1401 | class TypeArgument : public SimpleArgument { |
1402 | public: |
1403 | TypeArgument(const Record &Arg, StringRef Attr) |
1404 | : SimpleArgument(Arg, Attr, "TypeSourceInfo *" ) |
1405 | {} |
1406 | |
1407 | void writeAccessors(raw_ostream &OS) const override { |
1408 | OS << " QualType get" << getUpperName() << "() const {\n" ; |
1409 | OS << " return " << getLowerName() << "->getType();\n" ; |
1410 | OS << " }" ; |
1411 | OS << " " << getType() << " get" << getUpperName() << "Loc() const {\n" ; |
1412 | OS << " return " << getLowerName() << ";\n" ; |
1413 | OS << " }" ; |
1414 | } |
1415 | |
1416 | void writeASTVisitorTraversal(raw_ostream &OS) const override { |
1417 | OS << " if (auto *TSI = A->get" << getUpperName() << "Loc())\n" ; |
1418 | OS << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n" ; |
1419 | OS << " return false;\n" ; |
1420 | } |
1421 | |
1422 | void writeTemplateInstantiation(raw_ostream &OS) const override { |
1423 | OS << " " << getType() << " tempInst" << getUpperName() << " =\n" ; |
1424 | OS << " S.SubstType(A->get" << getUpperName() << "Loc(), " |
1425 | << "TemplateArgs, A->getLoc(), A->getAttrName());\n" ; |
1426 | OS << " if (!tempInst" << getUpperName() << ")\n" ; |
1427 | OS << " return nullptr;\n" ; |
1428 | } |
1429 | |
1430 | void writeTemplateInstantiationArgs(raw_ostream &OS) const override { |
1431 | OS << "tempInst" << getUpperName(); |
1432 | } |
1433 | |
1434 | void writePCHWrite(raw_ostream &OS) const override { |
1435 | OS << " " |
1436 | << WritePCHRecord(type: getType(), |
1437 | name: "SA->get" + getUpperName().str() + "Loc()" ); |
1438 | } |
1439 | }; |
1440 | |
1441 | class WrappedAttr : public SimpleArgument { |
1442 | public: |
1443 | WrappedAttr(const Record &Arg, StringRef Attr) |
1444 | : SimpleArgument(Arg, Attr, "Attr *" ) {} |
1445 | |
1446 | void writePCHReadDecls(raw_ostream &OS) const override { |
1447 | OS << " Attr *" << getLowerName() << " = Record.readAttr();" ; |
1448 | } |
1449 | |
1450 | void writePCHWrite(raw_ostream &OS) const override { |
1451 | OS << " AddAttr(SA->get" << getUpperName() << "());" ; |
1452 | } |
1453 | |
1454 | void writeDump(raw_ostream &OS) const override {} |
1455 | |
1456 | void writeDumpChildren(raw_ostream &OS) const override { |
1457 | OS << " Visit(SA->get" << getUpperName() << "());\n" ; |
1458 | } |
1459 | |
1460 | void writeHasChildren(raw_ostream &OS) const override { OS << "true" ; } |
1461 | }; |
1462 | |
1463 | } // end anonymous namespace |
1464 | |
1465 | static std::unique_ptr<Argument> |
1466 | createArgument(const Record &Arg, StringRef Attr, |
1467 | const Record *Search = nullptr) { |
1468 | if (!Search) |
1469 | Search = &Arg; |
1470 | |
1471 | std::unique_ptr<Argument> Ptr; |
1472 | StringRef ArgName = Search->getName(); |
1473 | |
1474 | if (ArgName == "AlignedArgument" ) |
1475 | Ptr = std::make_unique<AlignedArgument>(args: Arg, args&: Attr); |
1476 | else if (ArgName == "EnumArgument" ) |
1477 | Ptr = std::make_unique<EnumArgument>(args: Arg, args&: Attr); |
1478 | else if (ArgName == "ExprArgument" ) |
1479 | Ptr = std::make_unique<ExprArgument>(args: Arg, args&: Attr); |
1480 | else if (ArgName == "DeclArgument" ) |
1481 | Ptr = std::make_unique<SimpleArgument>( |
1482 | args: Arg, args&: Attr, args: (Arg.getValueAsDef(FieldName: "Kind" )->getName() + "Decl *" ).str()); |
1483 | else if (ArgName == "IdentifierArgument" ) |
1484 | Ptr = std::make_unique<SimpleArgument>(args: Arg, args&: Attr, args: "IdentifierInfo *" ); |
1485 | else if (ArgName == "DefaultBoolArgument" ) |
1486 | Ptr = std::make_unique<DefaultSimpleArgument>( |
1487 | args: Arg, args&: Attr, args: "bool" , args: Arg.getValueAsBit(FieldName: "Default" )); |
1488 | else if (ArgName == "BoolArgument" ) |
1489 | Ptr = std::make_unique<SimpleArgument>(args: Arg, args&: Attr, args: "bool" ); |
1490 | else if (ArgName == "DefaultIntArgument" ) |
1491 | Ptr = std::make_unique<DefaultSimpleArgument>( |
1492 | args: Arg, args&: Attr, args: "int" , args: Arg.getValueAsInt(FieldName: "Default" )); |
1493 | else if (ArgName == "IntArgument" ) |
1494 | Ptr = std::make_unique<SimpleArgument>(args: Arg, args&: Attr, args: "int" ); |
1495 | else if (ArgName == "StringArgument" ) |
1496 | Ptr = std::make_unique<StringArgument>(args: Arg, args&: Attr); |
1497 | else if (ArgName == "TypeArgument" ) |
1498 | Ptr = std::make_unique<TypeArgument>(args: Arg, args&: Attr); |
1499 | else if (ArgName == "UnsignedArgument" ) |
1500 | Ptr = std::make_unique<SimpleArgument>(args: Arg, args&: Attr, args: "unsigned" ); |
1501 | else if (ArgName == "VariadicUnsignedArgument" ) |
1502 | Ptr = std::make_unique<VariadicArgument>(args: Arg, args&: Attr, args: "unsigned" ); |
1503 | else if (ArgName == "VariadicStringArgument" ) |
1504 | Ptr = std::make_unique<VariadicStringArgument>(args: Arg, args&: Attr); |
1505 | else if (ArgName == "VariadicEnumArgument" ) |
1506 | Ptr = std::make_unique<VariadicEnumArgument>(args: Arg, args&: Attr); |
1507 | else if (ArgName == "VariadicExprArgument" ) |
1508 | Ptr = std::make_unique<VariadicExprArgument>(args: Arg, args&: Attr); |
1509 | else if (ArgName == "VariadicParamIdxArgument" ) |
1510 | Ptr = std::make_unique<VariadicParamIdxArgument>(args: Arg, args&: Attr); |
1511 | else if (ArgName == "VariadicParamOrParamIdxArgument" ) |
1512 | Ptr = std::make_unique<VariadicParamOrParamIdxArgument>(args: Arg, args&: Attr); |
1513 | else if (ArgName == "ParamIdxArgument" ) |
1514 | Ptr = std::make_unique<SimpleArgument>(args: Arg, args&: Attr, args: "ParamIdx" ); |
1515 | else if (ArgName == "VariadicIdentifierArgument" ) |
1516 | Ptr = std::make_unique<VariadicIdentifierArgument>(args: Arg, args&: Attr); |
1517 | else if (ArgName == "VersionArgument" ) |
1518 | Ptr = std::make_unique<VersionArgument>(args: Arg, args&: Attr); |
1519 | else if (ArgName == "WrappedAttr" ) |
1520 | Ptr = std::make_unique<WrappedAttr>(args: Arg, args&: Attr); |
1521 | else if (ArgName == "OMPTraitInfoArgument" ) |
1522 | Ptr = std::make_unique<SimpleArgument>(args: Arg, args&: Attr, args: "OMPTraitInfo *" ); |
1523 | else if (ArgName == "VariadicOMPInteropInfoArgument" ) |
1524 | Ptr = std::make_unique<VariadicOMPInteropInfoArgument>(args: Arg, args&: Attr); |
1525 | |
1526 | if (!Ptr) { |
1527 | // Search in reverse order so that the most-derived type is handled first. |
1528 | std::vector<const Record *> SCs = Search->getSuperClasses(); |
1529 | for (const Record *Base : reverse(C&: SCs)) { |
1530 | if ((Ptr = createArgument(Arg, Attr, Search: Base))) |
1531 | break; |
1532 | } |
1533 | } |
1534 | |
1535 | if (Ptr && Arg.getValueAsBit(FieldName: "Optional" )) |
1536 | Ptr->setOptional(true); |
1537 | |
1538 | if (Ptr && Arg.getValueAsBit(FieldName: "Fake" )) |
1539 | Ptr->setFake(true); |
1540 | |
1541 | return Ptr; |
1542 | } |
1543 | |
1544 | static void writeAvailabilityValue(raw_ostream &OS) { |
1545 | OS << "\" << getPlatform()->getName();\n" |
1546 | << " if (getStrict()) OS << \", strict\";\n" |
1547 | << " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n" |
1548 | << " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n" |
1549 | << " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n" |
1550 | << " if (getUnavailable()) OS << \", unavailable\";\n" |
1551 | << " OS << \"" ; |
1552 | } |
1553 | |
1554 | static void writeDeprecatedAttrValue(raw_ostream &OS, StringRef Variety) { |
1555 | OS << "\\\"\" << getMessage() << \"\\\"\";\n" ; |
1556 | // Only GNU deprecated has an optional fixit argument at the second position. |
1557 | if (Variety == "GNU" ) |
1558 | OS << " if (!getReplacement().empty()) OS << \", \\\"\"" |
1559 | " << getReplacement() << \"\\\"\";\n" ; |
1560 | OS << " OS << \"" ; |
1561 | } |
1562 | |
1563 | static void writeGetSpellingFunction(const Record &R, raw_ostream &OS) { |
1564 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: R); |
1565 | |
1566 | OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n" ; |
1567 | if (Spellings.empty()) { |
1568 | OS << " return \"(No spelling)\";\n}\n\n" ; |
1569 | return; |
1570 | } |
1571 | |
1572 | OS << " switch (getAttributeSpellingListIndex()) {\n" |
1573 | " default:\n" |
1574 | " llvm_unreachable(\"Unknown attribute spelling!\");\n" |
1575 | " return \"(No spelling)\";\n" ; |
1576 | |
1577 | for (const auto &[Idx, S] : enumerate(First&: Spellings)) { |
1578 | // clang-format off |
1579 | OS << " case " << Idx << ":\n" |
1580 | " return \"" << S.name() << "\";\n" ; |
1581 | // clang-format on |
1582 | } |
1583 | // End of the switch statement. |
1584 | OS << " }\n" ; |
1585 | // End of the getSpelling function. |
1586 | OS << "}\n\n" ; |
1587 | } |
1588 | |
1589 | static void |
1590 | writePrettyPrintFunction(const Record &R, |
1591 | const std::vector<std::unique_ptr<Argument>> &Args, |
1592 | raw_ostream &OS) { |
1593 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: R); |
1594 | |
1595 | OS << "void " << R.getName() << "Attr::printPretty(" |
1596 | << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n" ; |
1597 | |
1598 | if (Spellings.empty()) { |
1599 | OS << "}\n\n" ; |
1600 | return; |
1601 | } |
1602 | |
1603 | OS << " bool IsFirstArgument = true; (void)IsFirstArgument;\n" |
1604 | << " unsigned TrailingOmittedArgs = 0; (void)TrailingOmittedArgs;\n" |
1605 | << " switch (getAttributeSpellingListIndex()) {\n" |
1606 | << " default:\n" |
1607 | << " llvm_unreachable(\"Unknown attribute spelling!\");\n" |
1608 | << " break;\n" ; |
1609 | |
1610 | for (const auto &[Idx, S] : enumerate(First&: Spellings)) { |
1611 | SmallString<16> Prefix; |
1612 | SmallString<8> Suffix; |
1613 | // The actual spelling of the name and namespace (if applicable) |
1614 | // of an attribute without considering prefix and suffix. |
1615 | SmallString<64> Spelling; |
1616 | StringRef Name = S.name(); |
1617 | StringRef Variety = S.variety(); |
1618 | |
1619 | if (Variety == "GNU" ) { |
1620 | Prefix = "__attribute__((" ; |
1621 | Suffix = "))" ; |
1622 | } else if (Variety == "CXX11" || Variety == "C23" ) { |
1623 | Prefix = "[[" ; |
1624 | Suffix = "]]" ; |
1625 | StringRef Namespace = S.nameSpace(); |
1626 | if (!Namespace.empty()) { |
1627 | Spelling += Namespace; |
1628 | Spelling += "::" ; |
1629 | } |
1630 | } else if (Variety == "Declspec" ) { |
1631 | Prefix = "__declspec(" ; |
1632 | Suffix = ")" ; |
1633 | } else if (Variety == "Microsoft" ) { |
1634 | Prefix = "[" ; |
1635 | Suffix = "]" ; |
1636 | } else if (Variety == "Keyword" ) { |
1637 | Prefix = "" ; |
1638 | Suffix = "" ; |
1639 | } else if (Variety == "Pragma" ) { |
1640 | Prefix = "#pragma " ; |
1641 | Suffix = "\n" ; |
1642 | StringRef Namespace = S.nameSpace(); |
1643 | if (!Namespace.empty()) { |
1644 | Spelling += Namespace; |
1645 | Spelling += " " ; |
1646 | } |
1647 | } else if (Variety == "HLSLAnnotation" ) { |
1648 | Prefix = ":" ; |
1649 | Suffix = "" ; |
1650 | } else { |
1651 | llvm_unreachable("Unknown attribute syntax variety!" ); |
1652 | } |
1653 | |
1654 | Spelling += Name; |
1655 | |
1656 | OS << " case " << Idx << " : {\n" |
1657 | << " OS << \"" << Prefix << Spelling << "\";\n" ; |
1658 | |
1659 | if (Variety == "Pragma" ) { |
1660 | OS << " printPrettyPragma(OS, Policy);\n" ; |
1661 | OS << " OS << \"\\n\";" ; |
1662 | OS << " break;\n" ; |
1663 | OS << " }\n" ; |
1664 | continue; |
1665 | } |
1666 | |
1667 | if (Spelling == "availability" ) { |
1668 | OS << " OS << \"(" ; |
1669 | writeAvailabilityValue(OS); |
1670 | OS << ")\";\n" ; |
1671 | } else if (Spelling == "deprecated" || Spelling == "gnu::deprecated" ) { |
1672 | OS << " OS << \"(" ; |
1673 | writeDeprecatedAttrValue(OS, Variety); |
1674 | OS << ")\";\n" ; |
1675 | } else { |
1676 | // To avoid printing parentheses around an empty argument list or |
1677 | // printing spurious commas at the end of an argument list, we need to |
1678 | // determine where the last provided non-fake argument is. |
1679 | bool FoundNonOptArg = false; |
1680 | for (const auto &arg : reverse(C: Args)) { |
1681 | if (arg->isFake()) |
1682 | continue; |
1683 | if (FoundNonOptArg) |
1684 | continue; |
1685 | // FIXME: arg->getIsOmitted() == "false" means we haven't implemented |
1686 | // any way to detect whether the argument was omitted. |
1687 | if (!arg->isOptional() || arg->getIsOmitted() == "false" ) { |
1688 | FoundNonOptArg = true; |
1689 | continue; |
1690 | } |
1691 | OS << " if (" << arg->getIsOmitted() << ")\n" |
1692 | << " ++TrailingOmittedArgs;\n" ; |
1693 | } |
1694 | unsigned ArgIndex = 0; |
1695 | for (const auto &arg : Args) { |
1696 | if (arg->isFake()) |
1697 | continue; |
1698 | std::string IsOmitted = arg->getIsOmitted(); |
1699 | if (arg->isOptional() && IsOmitted != "false" ) |
1700 | OS << " if (!(" << IsOmitted << ")) {\n" ; |
1701 | // Variadic arguments print their own leading comma. |
1702 | if (!arg->isVariadic()) |
1703 | OS << " DelimitAttributeArgument(OS, IsFirstArgument);\n" ; |
1704 | OS << " OS << \"" ; |
1705 | arg->writeValue(OS); |
1706 | OS << "\";\n" ; |
1707 | if (arg->isOptional() && IsOmitted != "false" ) |
1708 | OS << " }\n" ; |
1709 | ++ArgIndex; |
1710 | } |
1711 | if (ArgIndex != 0) |
1712 | OS << " if (!IsFirstArgument)\n" |
1713 | << " OS << \")\";\n" ; |
1714 | } |
1715 | OS << " OS << \"" << Suffix << "\";\n" |
1716 | << " break;\n" |
1717 | << " }\n" ; |
1718 | } |
1719 | |
1720 | // End of the switch statement. |
1721 | OS << "}\n" ; |
1722 | // End of the print function. |
1723 | OS << "}\n\n" ; |
1724 | } |
1725 | |
1726 | /// Return the index of a spelling in a spelling list. |
1727 | static unsigned getSpellingListIndex(ArrayRef<FlattenedSpelling> SpellingList, |
1728 | const FlattenedSpelling &Spelling) { |
1729 | assert(!SpellingList.empty() && "Spelling list is empty!" ); |
1730 | |
1731 | for (const auto &[Index, S] : enumerate(First&: SpellingList)) { |
1732 | if (S.variety() == Spelling.variety() && |
1733 | S.nameSpace() == Spelling.nameSpace() && S.name() == Spelling.name()) |
1734 | return Index; |
1735 | } |
1736 | |
1737 | PrintFatalError(Msg: "Unknown spelling: " + Spelling.name()); |
1738 | } |
1739 | |
1740 | static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) { |
1741 | std::vector<const Record *> Accessors = R.getValueAsListOfDefs(FieldName: "Accessors" ); |
1742 | if (Accessors.empty()) |
1743 | return; |
1744 | |
1745 | const std::vector<FlattenedSpelling> SpellingList = GetFlattenedSpellings(Attr: R); |
1746 | assert(!SpellingList.empty() && |
1747 | "Attribute with empty spelling list can't have accessors!" ); |
1748 | for (const auto *Accessor : Accessors) { |
1749 | const StringRef Name = Accessor->getValueAsString(FieldName: "Name" ); |
1750 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: *Accessor); |
1751 | |
1752 | OS << " bool " << Name |
1753 | << "() const { return getAttributeSpellingListIndex() == " ; |
1754 | for (unsigned Index = 0; Index < Spellings.size(); ++Index) { |
1755 | OS << getSpellingListIndex(SpellingList, Spelling: Spellings[Index]); |
1756 | if (Index != Spellings.size() - 1) |
1757 | OS << " ||\n getAttributeSpellingListIndex() == " ; |
1758 | else |
1759 | OS << "; }\n" ; |
1760 | } |
1761 | } |
1762 | } |
1763 | |
1764 | static bool |
1765 | SpellingNamesAreCommon(const std::vector<FlattenedSpelling>& Spellings) { |
1766 | assert(!Spellings.empty() && "An empty list of spellings was provided" ); |
1767 | StringRef FirstName = |
1768 | NormalizeNameForSpellingComparison(Name: Spellings.front().name()); |
1769 | for (const auto &Spelling : drop_begin(RangeOrContainer: Spellings)) { |
1770 | StringRef Name = NormalizeNameForSpellingComparison(Name: Spelling.name()); |
1771 | if (Name != FirstName) |
1772 | return false; |
1773 | } |
1774 | return true; |
1775 | } |
1776 | |
1777 | typedef std::map<unsigned, std::string> SemanticSpellingMap; |
1778 | static std::string |
1779 | CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings, |
1780 | SemanticSpellingMap &Map) { |
1781 | // The enumerants are automatically generated based on the variety, |
1782 | // namespace (if present) and name for each attribute spelling. However, |
1783 | // care is taken to avoid trampling on the reserved namespace due to |
1784 | // underscores. |
1785 | std::string Ret(" enum Spelling {\n" ); |
1786 | std::set<std::string> Uniques; |
1787 | unsigned Idx = 0; |
1788 | |
1789 | // If we have a need to have this many spellings we likely need to add an |
1790 | // extra bit to the SpellingIndex in AttributeCommonInfo, then increase the |
1791 | // value of SpellingNotCalculated there and here. |
1792 | assert(Spellings.size() < 15 && |
1793 | "Too many spellings, would step on SpellingNotCalculated in " |
1794 | "AttributeCommonInfo" ); |
1795 | for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I, ++Idx) { |
1796 | const FlattenedSpelling &S = *I; |
1797 | StringRef Variety = S.variety(); |
1798 | StringRef Spelling = S.name(); |
1799 | StringRef Namespace = S.nameSpace(); |
1800 | std::string EnumName; |
1801 | |
1802 | EnumName += Variety; |
1803 | EnumName += "_" ; |
1804 | if (!Namespace.empty()) |
1805 | EnumName += NormalizeNameForSpellingComparison(Name: Namespace).str() + "_" ; |
1806 | EnumName += NormalizeNameForSpellingComparison(Name: Spelling); |
1807 | |
1808 | // Even if the name is not unique, this spelling index corresponds to a |
1809 | // particular enumerant name that we've calculated. |
1810 | Map[Idx] = EnumName; |
1811 | |
1812 | // Since we have been stripping underscores to avoid trampling on the |
1813 | // reserved namespace, we may have inadvertently created duplicate |
1814 | // enumerant names. These duplicates are not considered part of the |
1815 | // semantic spelling, and can be elided. |
1816 | if (!Uniques.insert(x: EnumName).second) |
1817 | continue; |
1818 | |
1819 | if (I != Spellings.begin()) |
1820 | Ret += ",\n" ; |
1821 | // Duplicate spellings are not considered part of the semantic spelling |
1822 | // enumeration, but the spelling index and semantic spelling values are |
1823 | // meant to be equivalent, so we must specify a concrete value for each |
1824 | // enumerator. |
1825 | Ret += " " + EnumName + " = " + utostr(X: Idx); |
1826 | } |
1827 | Ret += ",\n SpellingNotCalculated = 15\n" ; |
1828 | Ret += "\n };\n\n" ; |
1829 | return Ret; |
1830 | } |
1831 | |
1832 | static void WriteSemanticSpellingSwitch(StringRef VarName, |
1833 | const SemanticSpellingMap &Map, |
1834 | raw_ostream &OS) { |
1835 | OS << " switch (" << VarName << ") {\n default: " |
1836 | << "llvm_unreachable(\"Unknown spelling list index\");\n" ; |
1837 | for (const auto &I : Map) |
1838 | OS << " case " << I.first << ": return " << I.second << ";\n" ; |
1839 | OS << " }\n" ; |
1840 | } |
1841 | |
1842 | // Note: these values need to match the values used by LateAttrParseKind in |
1843 | // `Attr.td` |
1844 | enum class LateAttrParseKind { Never = 0, Standard = 1, ExperimentalExt = 2 }; |
1845 | |
1846 | static LateAttrParseKind getLateAttrParseKind(const Record *Attr) { |
1847 | // This function basically does |
1848 | // `Attr->getValueAsDef("LateParsed")->getValueAsInt("Kind")` but does a bunch |
1849 | // of sanity checking to ensure that `LateAttrParseMode` in `Attr.td` is in |
1850 | // sync with the `LateAttrParseKind` enum in this source file. |
1851 | |
1852 | static constexpr StringRef LateParsedStr = "LateParsed" ; |
1853 | static constexpr StringRef LateAttrParseKindStr = "LateAttrParseKind" ; |
1854 | static constexpr StringRef KindFieldStr = "Kind" ; |
1855 | |
1856 | auto *LAPK = Attr->getValueAsDef(FieldName: LateParsedStr); |
1857 | |
1858 | // Typecheck the `LateParsed` field. |
1859 | if (LAPK->getDirectSuperClasses().size() != 1) |
1860 | PrintFatalError(Rec: Attr, Msg: "Field `" + Twine(LateParsedStr) + |
1861 | "`should only have one super class" ); |
1862 | |
1863 | const Record *SuperClass = LAPK->getDirectSuperClasses()[0].first; |
1864 | if (SuperClass->getName() != LateAttrParseKindStr) |
1865 | PrintFatalError( |
1866 | Rec: Attr, Msg: "Field `" + Twine(LateParsedStr) + "`should only have type `" + |
1867 | Twine(LateAttrParseKindStr) + "` but found type `" + |
1868 | SuperClass->getName() + "`" ); |
1869 | |
1870 | // Get Kind and verify the enum name matches the name in `Attr.td`. |
1871 | unsigned Kind = LAPK->getValueAsInt(FieldName: KindFieldStr); |
1872 | switch (LateAttrParseKind(Kind)) { |
1873 | #define CASE(X) \ |
1874 | case LateAttrParseKind::X: \ |
1875 | if (LAPK->getName().compare("LateAttrParse" #X) != 0) { \ |
1876 | PrintFatalError( \ |
1877 | Attr, \ |
1878 | "Field `" + Twine(LateParsedStr) + "` set to `" + LAPK->getName() + \ |
1879 | "` but this converts to `LateAttrParseKind::" + Twine(#X) + \ |
1880 | "`"); \ |
1881 | } \ |
1882 | return LateAttrParseKind::X; |
1883 | |
1884 | CASE(Never) |
1885 | CASE(Standard) |
1886 | CASE(ExperimentalExt) |
1887 | #undef CASE |
1888 | } |
1889 | |
1890 | // The Kind value is completely invalid |
1891 | auto KindValueStr = utostr(X: Kind); |
1892 | PrintFatalError(Rec: Attr, Msg: "Field `" + Twine(LateParsedStr) + "` set to `" + |
1893 | LAPK->getName() + "` has unexpected `" + |
1894 | Twine(KindFieldStr) + "` value of " + KindValueStr); |
1895 | } |
1896 | |
1897 | // Emits the LateParsed property for attributes. |
1898 | static void emitClangAttrLateParsedListImpl(const RecordKeeper &Records, |
1899 | raw_ostream &OS, |
1900 | LateAttrParseKind LateParseMode) { |
1901 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
1902 | if (LateAttrParseKind LateParsed = getLateAttrParseKind(Attr); |
1903 | LateParsed != LateParseMode) |
1904 | continue; |
1905 | |
1906 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: *Attr); |
1907 | |
1908 | // FIXME: Handle non-GNU attributes |
1909 | for (const auto &I : Spellings) { |
1910 | if (I.variety() != "GNU" ) |
1911 | continue; |
1912 | OS << ".Case(\"" << I.name() << "\", 1)\n" ; |
1913 | } |
1914 | } |
1915 | } |
1916 | |
1917 | static void emitClangAttrLateParsedList(const RecordKeeper &Records, |
1918 | raw_ostream &OS) { |
1919 | OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n" ; |
1920 | emitClangAttrLateParsedListImpl(Records, OS, LateParseMode: LateAttrParseKind::Standard); |
1921 | OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n" ; |
1922 | } |
1923 | |
1924 | static void emitClangAttrLateParsedExperimentalList(const RecordKeeper &Records, |
1925 | raw_ostream &OS) { |
1926 | OS << "#if defined(CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST)\n" ; |
1927 | emitClangAttrLateParsedListImpl(Records, OS, |
1928 | LateParseMode: LateAttrParseKind::ExperimentalExt); |
1929 | OS << "#endif // CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST\n\n" ; |
1930 | } |
1931 | |
1932 | static bool hasGNUorCXX11Spelling(const Record &Attribute) { |
1933 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: Attribute); |
1934 | for (const auto &I : Spellings) { |
1935 | if (I.variety() == "GNU" || I.variety() == "CXX11" ) |
1936 | return true; |
1937 | } |
1938 | return false; |
1939 | } |
1940 | |
1941 | namespace { |
1942 | |
1943 | struct AttributeSubjectMatchRule { |
1944 | const Record *MetaSubject; |
1945 | const Record *Constraint; |
1946 | |
1947 | AttributeSubjectMatchRule(const Record *MetaSubject, const Record *Constraint) |
1948 | : MetaSubject(MetaSubject), Constraint(Constraint) { |
1949 | assert(MetaSubject && "Missing subject" ); |
1950 | } |
1951 | |
1952 | bool isSubRule() const { return Constraint != nullptr; } |
1953 | |
1954 | std::vector<const Record *> getSubjects() const { |
1955 | return (Constraint ? Constraint : MetaSubject) |
1956 | ->getValueAsListOfDefs(FieldName: "Subjects" ); |
1957 | } |
1958 | |
1959 | std::vector<const Record *> getLangOpts() const { |
1960 | if (Constraint) { |
1961 | // Lookup the options in the sub-rule first, in case the sub-rule |
1962 | // overrides the rules options. |
1963 | std::vector<const Record *> Opts = |
1964 | Constraint->getValueAsListOfDefs(FieldName: "LangOpts" ); |
1965 | if (!Opts.empty()) |
1966 | return Opts; |
1967 | } |
1968 | return MetaSubject->getValueAsListOfDefs(FieldName: "LangOpts" ); |
1969 | } |
1970 | |
1971 | // Abstract rules are used only for sub-rules |
1972 | bool isAbstractRule() const { return getSubjects().empty(); } |
1973 | |
1974 | StringRef getName() const { |
1975 | return (Constraint ? Constraint : MetaSubject)->getValueAsString(FieldName: "Name" ); |
1976 | } |
1977 | |
1978 | bool isNegatedSubRule() const { |
1979 | assert(isSubRule() && "Not a sub-rule" ); |
1980 | return Constraint->getValueAsBit(FieldName: "Negated" ); |
1981 | } |
1982 | |
1983 | std::string getSpelling() const { |
1984 | std::string Result = MetaSubject->getValueAsString(FieldName: "Name" ).str(); |
1985 | if (isSubRule()) { |
1986 | Result += '('; |
1987 | if (isNegatedSubRule()) |
1988 | Result += "unless(" ; |
1989 | Result += getName(); |
1990 | if (isNegatedSubRule()) |
1991 | Result += ')'; |
1992 | Result += ')'; |
1993 | } |
1994 | return Result; |
1995 | } |
1996 | |
1997 | std::string getEnumValueName() const { |
1998 | SmallString<128> Result; |
1999 | Result += "SubjectMatchRule_" ; |
2000 | Result += MetaSubject->getValueAsString(FieldName: "Name" ); |
2001 | if (isSubRule()) { |
2002 | Result += "_" ; |
2003 | if (isNegatedSubRule()) |
2004 | Result += "not_" ; |
2005 | Result += Constraint->getValueAsString(FieldName: "Name" ); |
2006 | } |
2007 | if (isAbstractRule()) |
2008 | Result += "_abstract" ; |
2009 | return std::string(Result); |
2010 | } |
2011 | |
2012 | std::string getEnumValue() const { return "attr::" + getEnumValueName(); } |
2013 | |
2014 | static const char *EnumName; |
2015 | }; |
2016 | |
2017 | const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule" ; |
2018 | |
2019 | struct PragmaClangAttributeSupport { |
2020 | std::vector<AttributeSubjectMatchRule> Rules; |
2021 | |
2022 | class RuleOrAggregateRuleSet { |
2023 | std::vector<AttributeSubjectMatchRule> Rules; |
2024 | bool IsRule; |
2025 | RuleOrAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules, |
2026 | bool IsRule) |
2027 | : Rules(Rules), IsRule(IsRule) {} |
2028 | |
2029 | public: |
2030 | bool isRule() const { return IsRule; } |
2031 | |
2032 | const AttributeSubjectMatchRule &getRule() const { |
2033 | assert(IsRule && "not a rule!" ); |
2034 | return Rules[0]; |
2035 | } |
2036 | |
2037 | ArrayRef<AttributeSubjectMatchRule> getAggregateRuleSet() const { |
2038 | return Rules; |
2039 | } |
2040 | |
2041 | static RuleOrAggregateRuleSet |
2042 | getRule(const AttributeSubjectMatchRule &Rule) { |
2043 | return RuleOrAggregateRuleSet(Rule, /*IsRule=*/true); |
2044 | } |
2045 | static RuleOrAggregateRuleSet |
2046 | getAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules) { |
2047 | return RuleOrAggregateRuleSet(Rules, /*IsRule=*/false); |
2048 | } |
2049 | }; |
2050 | DenseMap<const Record *, RuleOrAggregateRuleSet> SubjectsToRules; |
2051 | |
2052 | PragmaClangAttributeSupport(const RecordKeeper &Records); |
2053 | |
2054 | bool isAttributedSupported(const Record &Attribute); |
2055 | |
2056 | void emitMatchRuleList(raw_ostream &OS); |
2057 | |
2058 | void generateStrictConformsTo(const Record &Attr, raw_ostream &OS); |
2059 | |
2060 | void generateParsingHelpers(raw_ostream &OS); |
2061 | }; |
2062 | |
2063 | } // end anonymous namespace |
2064 | |
2065 | static bool isSupportedPragmaClangAttributeSubject(const Record &Subject) { |
2066 | // FIXME: #pragma clang attribute does not currently support statement |
2067 | // attributes, so test whether the subject is one that appertains to a |
2068 | // declaration node. However, it may be reasonable for support for statement |
2069 | // attributes to be added. |
2070 | if (Subject.isSubClassOf(Name: "DeclNode" ) || Subject.isSubClassOf(Name: "DeclBase" ) || |
2071 | Subject.getName() == "DeclBase" ) |
2072 | return true; |
2073 | |
2074 | if (Subject.isSubClassOf(Name: "SubsetSubject" )) |
2075 | return isSupportedPragmaClangAttributeSubject( |
2076 | Subject: *Subject.getValueAsDef(FieldName: "Base" )); |
2077 | |
2078 | return false; |
2079 | } |
2080 | |
2081 | static bool doesDeclDeriveFrom(const Record *D, const Record *Base) { |
2082 | const Record *CurrentBase = D->getValueAsOptionalDef(BaseFieldName); |
2083 | if (!CurrentBase) |
2084 | return false; |
2085 | if (CurrentBase == Base) |
2086 | return true; |
2087 | return doesDeclDeriveFrom(D: CurrentBase, Base); |
2088 | } |
2089 | |
2090 | PragmaClangAttributeSupport::PragmaClangAttributeSupport( |
2091 | const RecordKeeper &Records) { |
2092 | auto MapFromSubjectsToRules = [this](const Record *SubjectContainer, |
2093 | const Record *MetaSubject, |
2094 | const Record *Constraint) { |
2095 | Rules.emplace_back(args&: MetaSubject, args&: Constraint); |
2096 | for (const Record *Subject : |
2097 | SubjectContainer->getValueAsListOfDefs(FieldName: "Subjects" )) { |
2098 | bool Inserted = |
2099 | SubjectsToRules |
2100 | .try_emplace(Key: Subject, Args: RuleOrAggregateRuleSet::getRule( |
2101 | Rule: AttributeSubjectMatchRule(MetaSubject, |
2102 | Constraint))) |
2103 | .second; |
2104 | if (!Inserted) { |
2105 | PrintFatalError(Msg: "Attribute subject match rules should not represent" |
2106 | "same attribute subjects." ); |
2107 | } |
2108 | } |
2109 | }; |
2110 | for (const auto *MetaSubject : |
2111 | Records.getAllDerivedDefinitions(ClassName: "AttrSubjectMatcherRule" )) { |
2112 | MapFromSubjectsToRules(MetaSubject, MetaSubject, /*Constraints=*/nullptr); |
2113 | for (const Record *Constraint : |
2114 | MetaSubject->getValueAsListOfDefs(FieldName: "Constraints" )) |
2115 | MapFromSubjectsToRules(Constraint, MetaSubject, Constraint); |
2116 | } |
2117 | |
2118 | ArrayRef<const Record *> DeclNodes = |
2119 | Records.getAllDerivedDefinitions(DeclNodeClassName); |
2120 | for (const auto *Aggregate : |
2121 | Records.getAllDerivedDefinitions(ClassName: "AttrSubjectMatcherAggregateRule" )) { |
2122 | const Record *SubjectDecl = Aggregate->getValueAsDef(FieldName: "Subject" ); |
2123 | |
2124 | // Gather sub-classes of the aggregate subject that act as attribute |
2125 | // subject rules. |
2126 | std::vector<AttributeSubjectMatchRule> Rules; |
2127 | for (const auto *D : DeclNodes) { |
2128 | if (doesDeclDeriveFrom(D, Base: SubjectDecl)) { |
2129 | auto It = SubjectsToRules.find(Val: D); |
2130 | if (It == SubjectsToRules.end()) |
2131 | continue; |
2132 | if (!It->second.isRule() || It->second.getRule().isSubRule()) |
2133 | continue; // Assume that the rule will be included as well. |
2134 | Rules.push_back(x: It->second.getRule()); |
2135 | } |
2136 | } |
2137 | |
2138 | bool Inserted = |
2139 | SubjectsToRules |
2140 | .try_emplace(Key: SubjectDecl, |
2141 | Args: RuleOrAggregateRuleSet::getAggregateRuleSet(Rules)) |
2142 | .second; |
2143 | if (!Inserted) { |
2144 | PrintFatalError(Msg: "Attribute subject match rules should not represent" |
2145 | "same attribute subjects." ); |
2146 | } |
2147 | } |
2148 | } |
2149 | |
2150 | static PragmaClangAttributeSupport & |
2151 | getPragmaAttributeSupport(const RecordKeeper &Records) { |
2152 | static PragmaClangAttributeSupport Instance(Records); |
2153 | return Instance; |
2154 | } |
2155 | |
2156 | void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) { |
2157 | OS << "#ifndef ATTR_MATCH_SUB_RULE\n" ; |
2158 | OS << "#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, " |
2159 | "IsNegated) " |
2160 | << "ATTR_MATCH_RULE(Value, Spelling, IsAbstract)\n" ; |
2161 | OS << "#endif\n" ; |
2162 | for (const auto &Rule : Rules) { |
2163 | OS << (Rule.isSubRule() ? "ATTR_MATCH_SUB_RULE" : "ATTR_MATCH_RULE" ) << '('; |
2164 | OS << Rule.getEnumValueName() << ", \"" << Rule.getSpelling() << "\", " |
2165 | << Rule.isAbstractRule(); |
2166 | if (Rule.isSubRule()) |
2167 | OS << ", " |
2168 | << AttributeSubjectMatchRule(Rule.MetaSubject, nullptr).getEnumValue() |
2169 | << ", " << Rule.isNegatedSubRule(); |
2170 | OS << ")\n" ; |
2171 | } |
2172 | OS << "#undef ATTR_MATCH_SUB_RULE\n" ; |
2173 | } |
2174 | |
2175 | bool PragmaClangAttributeSupport::isAttributedSupported( |
2176 | const Record &Attribute) { |
2177 | // If the attribute explicitly specified whether to support #pragma clang |
2178 | // attribute, use that setting. |
2179 | bool Unset; |
2180 | bool SpecifiedResult = |
2181 | Attribute.getValueAsBitOrUnset(FieldName: "PragmaAttributeSupport" , Unset); |
2182 | if (!Unset) |
2183 | return SpecifiedResult; |
2184 | |
2185 | // Opt-out rules: |
2186 | |
2187 | // An attribute requires delayed parsing (LateParsed is on). |
2188 | switch (getLateAttrParseKind(Attr: &Attribute)) { |
2189 | case LateAttrParseKind::Never: |
2190 | break; |
2191 | case LateAttrParseKind::Standard: |
2192 | return false; |
2193 | case LateAttrParseKind::ExperimentalExt: |
2194 | // This is only late parsed in certain parsing contexts when |
2195 | // `LangOpts.ExperimentalLateParseAttributes` is true. Information about the |
2196 | // parsing context and `LangOpts` is not available in this method so just |
2197 | // opt this attribute out. |
2198 | return false; |
2199 | } |
2200 | |
2201 | // An attribute has no GNU/CXX11 spelling |
2202 | if (!hasGNUorCXX11Spelling(Attribute)) |
2203 | return false; |
2204 | // An attribute subject list has a subject that isn't covered by one of the |
2205 | // subject match rules or has no subjects at all. |
2206 | if (Attribute.isValueUnset(FieldName: "Subjects" )) |
2207 | return false; |
2208 | const Record *SubjectObj = Attribute.getValueAsDef(FieldName: "Subjects" ); |
2209 | bool HasAtLeastOneValidSubject = false; |
2210 | for (const auto *Subject : SubjectObj->getValueAsListOfDefs(FieldName: "Subjects" )) { |
2211 | if (!isSupportedPragmaClangAttributeSubject(Subject: *Subject)) |
2212 | continue; |
2213 | if (!SubjectsToRules.contains(Val: Subject)) |
2214 | return false; |
2215 | HasAtLeastOneValidSubject = true; |
2216 | } |
2217 | return HasAtLeastOneValidSubject; |
2218 | } |
2219 | |
2220 | static std::string GenerateTestExpression(ArrayRef<const Record *> LangOpts) { |
2221 | std::string Test; |
2222 | |
2223 | for (auto *E : LangOpts) { |
2224 | if (!Test.empty()) |
2225 | Test += " || " ; |
2226 | |
2227 | const StringRef Code = E->getValueAsString(FieldName: "CustomCode" ); |
2228 | if (!Code.empty()) { |
2229 | Test += "(" ; |
2230 | Test += Code; |
2231 | Test += ")" ; |
2232 | if (!E->getValueAsString(FieldName: "Name" ).empty()) { |
2233 | PrintWarning( |
2234 | WarningLoc: E->getLoc(), |
2235 | Msg: "non-empty 'Name' field ignored because 'CustomCode' was supplied" ); |
2236 | } |
2237 | } else { |
2238 | Test += "LangOpts." ; |
2239 | Test += E->getValueAsString(FieldName: "Name" ); |
2240 | } |
2241 | } |
2242 | |
2243 | if (Test.empty()) |
2244 | return "true" ; |
2245 | |
2246 | return Test; |
2247 | } |
2248 | |
2249 | void |
2250 | PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, |
2251 | raw_ostream &OS) { |
2252 | if (!isAttributedSupported(Attribute: Attr) || Attr.isValueUnset(FieldName: "Subjects" )) |
2253 | return; |
2254 | // Generate a function that constructs a set of matching rules that describe |
2255 | // to which declarations the attribute should apply to. |
2256 | OS << "void getPragmaAttributeMatchRules(" |
2257 | << "llvm::SmallVectorImpl<std::pair<" |
2258 | << AttributeSubjectMatchRule::EnumName |
2259 | << ", bool>> &MatchRules, const LangOptions &LangOpts) const override {\n" ; |
2260 | const Record *SubjectObj = Attr.getValueAsDef(FieldName: "Subjects" ); |
2261 | for (const auto *Subject : SubjectObj->getValueAsListOfDefs(FieldName: "Subjects" )) { |
2262 | if (!isSupportedPragmaClangAttributeSubject(Subject: *Subject)) |
2263 | continue; |
2264 | auto It = SubjectsToRules.find(Val: Subject); |
2265 | assert(It != SubjectsToRules.end() && |
2266 | "This attribute is unsupported by #pragma clang attribute" ); |
2267 | for (const auto &Rule : It->getSecond().getAggregateRuleSet()) { |
2268 | // The rule might be language specific, so only subtract it from the given |
2269 | // rules if the specific language options are specified. |
2270 | std::vector<const Record *> LangOpts = Rule.getLangOpts(); |
2271 | OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() |
2272 | << ", /*IsSupported=*/" << GenerateTestExpression(LangOpts) |
2273 | << "));\n" ; |
2274 | } |
2275 | } |
2276 | OS << "}\n\n" ; |
2277 | } |
2278 | |
2279 | void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { |
2280 | // Generate routines that check the names of sub-rules. |
2281 | OS << "std::optional<attr::SubjectMatchRule> " |
2282 | "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n" ; |
2283 | OS << " return std::nullopt;\n" ; |
2284 | OS << "}\n\n" ; |
2285 | |
2286 | MapVector<const Record *, std::vector<AttributeSubjectMatchRule>> |
2287 | SubMatchRules; |
2288 | for (const auto &Rule : Rules) { |
2289 | if (!Rule.isSubRule()) |
2290 | continue; |
2291 | SubMatchRules[Rule.MetaSubject].push_back(x: Rule); |
2292 | } |
2293 | |
2294 | for (const auto &SubMatchRule : SubMatchRules) { |
2295 | OS << "std::optional<attr::SubjectMatchRule> " |
2296 | "isAttributeSubjectMatchSubRuleFor_" |
2297 | << SubMatchRule.first->getValueAsString(FieldName: "Name" ) |
2298 | << "(StringRef Name, bool IsUnless) {\n" ; |
2299 | OS << " if (IsUnless)\n" ; |
2300 | OS << " return " |
2301 | "llvm::StringSwitch<std::optional<attr::SubjectMatchRule>>(Name).\n" ; |
2302 | for (const auto &Rule : SubMatchRule.second) { |
2303 | if (Rule.isNegatedSubRule()) |
2304 | OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() |
2305 | << ").\n" ; |
2306 | } |
2307 | OS << " Default(std::nullopt);\n" ; |
2308 | OS << " return " |
2309 | "llvm::StringSwitch<std::optional<attr::SubjectMatchRule>>(Name).\n" ; |
2310 | for (const auto &Rule : SubMatchRule.second) { |
2311 | if (!Rule.isNegatedSubRule()) |
2312 | OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() |
2313 | << ").\n" ; |
2314 | } |
2315 | OS << " Default(std::nullopt);\n" ; |
2316 | OS << "}\n\n" ; |
2317 | } |
2318 | |
2319 | // Generate the function that checks for the top-level rules. |
2320 | OS << "std::pair<std::optional<attr::SubjectMatchRule>, " |
2321 | "std::optional<attr::SubjectMatchRule> (*)(StringRef, " |
2322 | "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n" ; |
2323 | OS << " return " |
2324 | "llvm::StringSwitch<std::pair<std::optional<attr::SubjectMatchRule>, " |
2325 | "std::optional<attr::SubjectMatchRule> (*) (StringRef, " |
2326 | "bool)>>(Name).\n" ; |
2327 | for (const auto &Rule : Rules) { |
2328 | if (Rule.isSubRule()) |
2329 | continue; |
2330 | std::string SubRuleFunction; |
2331 | if (SubMatchRules.count(Key: Rule.MetaSubject)) |
2332 | SubRuleFunction = |
2333 | ("isAttributeSubjectMatchSubRuleFor_" + Rule.getName()).str(); |
2334 | else |
2335 | SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor" ; |
2336 | OS << " Case(\"" << Rule.getName() << "\", std::make_pair(" |
2337 | << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n" ; |
2338 | } |
2339 | OS << " Default(std::make_pair(std::nullopt, " |
2340 | "defaultIsAttributeSubjectMatchSubRuleFor));\n" ; |
2341 | OS << "}\n\n" ; |
2342 | |
2343 | // Generate the function that checks for the submatch rules. |
2344 | OS << "const char *validAttributeSubjectMatchSubRules(" |
2345 | << AttributeSubjectMatchRule::EnumName << " Rule) {\n" ; |
2346 | OS << " switch (Rule) {\n" ; |
2347 | for (const auto &SubMatchRule : SubMatchRules) { |
2348 | OS << " case " |
2349 | << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue() |
2350 | << ":\n" ; |
2351 | OS << " return \"'" ; |
2352 | bool IsFirst = true; |
2353 | for (const auto &Rule : SubMatchRule.second) { |
2354 | if (!IsFirst) |
2355 | OS << ", '" ; |
2356 | IsFirst = false; |
2357 | if (Rule.isNegatedSubRule()) |
2358 | OS << "unless(" ; |
2359 | OS << Rule.getName(); |
2360 | if (Rule.isNegatedSubRule()) |
2361 | OS << ')'; |
2362 | OS << "'" ; |
2363 | } |
2364 | OS << "\";\n" ; |
2365 | } |
2366 | OS << " default: return nullptr;\n" ; |
2367 | OS << " }\n" ; |
2368 | OS << "}\n\n" ; |
2369 | } |
2370 | |
2371 | template <typename Fn> static void forEachSpelling(const Record &Attr, Fn &&F) { |
2372 | for (const FlattenedSpelling &S : GetFlattenedSpellings(Attr)) { |
2373 | F(S); |
2374 | } |
2375 | } |
2376 | |
2377 | static std::map<StringRef, std::vector<const Record *>> NameToAttrsMap; |
2378 | |
2379 | /// Build a map from the attribute name to the Attrs that use that name. If more |
2380 | /// than one Attr use a name, the arguments could be different so a more complex |
2381 | /// check is needed in the generated switch. |
2382 | static void generateNameToAttrsMap(const RecordKeeper &Records) { |
2383 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2384 | for (const FlattenedSpelling &S : GetFlattenedSpellings(Attr: *A)) { |
2385 | auto [It, Inserted] = NameToAttrsMap.try_emplace(k: S.name()); |
2386 | if (Inserted || !is_contained(Range&: It->second, Element: A)) |
2387 | It->second.emplace_back(args&: A); |
2388 | } |
2389 | } |
2390 | } |
2391 | |
2392 | /// Generate the info needed to produce the case values in case more than one |
2393 | /// attribute has the same name. Store the info in a map that can be processed |
2394 | /// after all attributes are seen. |
2395 | static void generateFlattenedSpellingInfo(const Record &Attr, |
2396 | std::map<StringRef, FSIVecTy> &Map, |
2397 | uint32_t ArgMask = 0) { |
2398 | std::string TargetTest; |
2399 | if (Attr.isSubClassOf(Name: "TargetSpecificAttr" ) && |
2400 | !Attr.isValueUnset(FieldName: "ParseKind" )) { |
2401 | const Record *T = Attr.getValueAsDef(FieldName: "Target" ); |
2402 | std::vector<StringRef> Arches = T->getValueAsListOfStrings(FieldName: "Arches" ); |
2403 | (void)GenerateTargetSpecificAttrChecks(R: T, Arches, Test&: TargetTest, FnName: nullptr); |
2404 | } |
2405 | |
2406 | forEachSpelling(Attr, F: [&](const FlattenedSpelling &S) { |
2407 | Map[S.name()].emplace_back(args: S.variety(), args: S.nameSpace(), args&: TargetTest, args&: ArgMask); |
2408 | }); |
2409 | } |
2410 | |
2411 | static bool nameAppliesToOneAttribute(StringRef Name) { |
2412 | auto It = NameToAttrsMap.find(x: Name); |
2413 | assert(It != NameToAttrsMap.end()); |
2414 | return It->second.size() == 1; |
2415 | } |
2416 | |
2417 | static bool emitIfSimpleValue(StringRef Name, uint32_t ArgMask, |
2418 | raw_ostream &OS) { |
2419 | if (nameAppliesToOneAttribute(Name)) { |
2420 | OS << ".Case(\"" << Name << "\", " ; |
2421 | if (ArgMask != 0) |
2422 | OS << ArgMask << ")\n" ; |
2423 | else |
2424 | OS << "true)\n" ; |
2425 | return true; |
2426 | } |
2427 | return false; |
2428 | } |
2429 | |
2430 | static void emitSingleCondition(const FlattenedSpellingInfo &FSI, |
2431 | raw_ostream &OS) { |
2432 | OS << "(Syntax==AttributeCommonInfo::AS_" << FSI.Syntax << " && " ; |
2433 | if (!FSI.Scope.empty()) |
2434 | OS << "ScopeName && ScopeName->getName()==\"" << FSI.Scope << "\"" ; |
2435 | else |
2436 | OS << "!ScopeName" ; |
2437 | if (!FSI.TargetTest.empty()) |
2438 | OS << " && " << FSI.TargetTest; |
2439 | OS << ")" ; |
2440 | } |
2441 | |
2442 | static void emitStringSwitchCases(std::map<StringRef, FSIVecTy> &Map, |
2443 | raw_ostream &OS) { |
2444 | for (const auto &[Name, Vec] : Map) { |
2445 | if (emitIfSimpleValue(Name, ArgMask: Vec[0].ArgMask, OS)) |
2446 | continue; |
2447 | |
2448 | // Not simple, build expressions for each case. |
2449 | OS << ".Case(\"" << Name << "\", " ; |
2450 | for (unsigned I = 0, E = Vec.size(); I < E; ++I) { |
2451 | emitSingleCondition(FSI: Vec[I], OS); |
2452 | uint32_t ArgMask = Vec[I].ArgMask; |
2453 | if (E == 1 && ArgMask == 0) |
2454 | continue; |
2455 | |
2456 | // More than one or it's the Mask form. Create a conditional expression. |
2457 | uint32_t SuccessValue = ArgMask != 0 ? ArgMask : 1; |
2458 | OS << " ? " << SuccessValue << " : " ; |
2459 | if (I == E - 1) |
2460 | OS << 0; |
2461 | } |
2462 | OS << ")\n" ; |
2463 | } |
2464 | } |
2465 | |
2466 | static bool isTypeArgument(const Record *Arg) { |
2467 | return !Arg->getDirectSuperClasses().empty() && |
2468 | Arg->getDirectSuperClasses().back().first->getName() == "TypeArgument" ; |
2469 | } |
2470 | |
2471 | /// Emits the first-argument-is-type property for attributes. |
2472 | static void emitClangAttrTypeArgList(const RecordKeeper &Records, |
2473 | raw_ostream &OS) { |
2474 | OS << "#if defined(CLANG_ATTR_TYPE_ARG_LIST)\n" ; |
2475 | std::map<StringRef, FSIVecTy> FSIMap; |
2476 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2477 | // Determine whether the first argument is a type. |
2478 | std::vector<const Record *> Args = Attr->getValueAsListOfDefs(FieldName: "Args" ); |
2479 | if (Args.empty()) |
2480 | continue; |
2481 | |
2482 | if (!isTypeArgument(Arg: Args[0])) |
2483 | continue; |
2484 | generateFlattenedSpellingInfo(Attr: *Attr, Map&: FSIMap); |
2485 | } |
2486 | emitStringSwitchCases(Map&: FSIMap, OS); |
2487 | OS << "#endif // CLANG_ATTR_TYPE_ARG_LIST\n\n" ; |
2488 | } |
2489 | |
2490 | /// Emits the parse-arguments-in-unevaluated-context property for |
2491 | /// attributes. |
2492 | static void emitClangAttrArgContextList(const RecordKeeper &Records, |
2493 | raw_ostream &OS) { |
2494 | OS << "#if defined(CLANG_ATTR_ARG_CONTEXT_LIST)\n" ; |
2495 | std::map<StringRef, FSIVecTy> FSIMap; |
2496 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
2497 | for (const auto &I : Attrs) { |
2498 | const Record &Attr = *I.second; |
2499 | |
2500 | if (!Attr.getValueAsBit(FieldName: "ParseArgumentsAsUnevaluated" )) |
2501 | continue; |
2502 | generateFlattenedSpellingInfo(Attr, Map&: FSIMap); |
2503 | } |
2504 | emitStringSwitchCases(Map&: FSIMap, OS); |
2505 | OS << "#endif // CLANG_ATTR_ARG_CONTEXT_LIST\n\n" ; |
2506 | } |
2507 | |
2508 | static bool isIdentifierArgument(const Record *Arg) { |
2509 | return !Arg->getDirectSuperClasses().empty() && |
2510 | StringSwitch<bool>( |
2511 | Arg->getDirectSuperClasses().back().first->getName()) |
2512 | .Case(S: "IdentifierArgument" , Value: true) |
2513 | .Case(S: "EnumArgument" , Value: true) |
2514 | .Case(S: "VariadicEnumArgument" , Value: true) |
2515 | .Default(Value: false); |
2516 | } |
2517 | |
2518 | static bool isVariadicIdentifierArgument(const Record *Arg) { |
2519 | return !Arg->getDirectSuperClasses().empty() && |
2520 | StringSwitch<bool>( |
2521 | Arg->getDirectSuperClasses().back().first->getName()) |
2522 | .Case(S: "VariadicIdentifierArgument" , Value: true) |
2523 | .Case(S: "VariadicParamOrParamIdxArgument" , Value: true) |
2524 | .Default(Value: false); |
2525 | } |
2526 | |
2527 | static bool isVariadicExprArgument(const Record *Arg) { |
2528 | return !Arg->getDirectSuperClasses().empty() && |
2529 | StringSwitch<bool>( |
2530 | Arg->getDirectSuperClasses().back().first->getName()) |
2531 | .Case(S: "VariadicExprArgument" , Value: true) |
2532 | .Default(Value: false); |
2533 | } |
2534 | |
2535 | static bool isStringLiteralArgument(const Record *Arg) { |
2536 | if (Arg->getDirectSuperClasses().empty()) |
2537 | return false; |
2538 | StringRef ArgKind = Arg->getDirectSuperClasses().back().first->getName(); |
2539 | if (ArgKind == "EnumArgument" ) |
2540 | return Arg->getValueAsBit(FieldName: "IsString" ); |
2541 | return ArgKind == "StringArgument" ; |
2542 | } |
2543 | |
2544 | static bool isVariadicStringLiteralArgument(const Record *Arg) { |
2545 | if (Arg->getDirectSuperClasses().empty()) |
2546 | return false; |
2547 | StringRef ArgKind = Arg->getDirectSuperClasses().back().first->getName(); |
2548 | if (ArgKind == "VariadicEnumArgument" ) |
2549 | return Arg->getValueAsBit(FieldName: "IsString" ); |
2550 | return ArgKind == "VariadicStringArgument" ; |
2551 | } |
2552 | |
2553 | static void emitClangAttrVariadicIdentifierArgList(const RecordKeeper &Records, |
2554 | raw_ostream &OS) { |
2555 | OS << "#if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST)\n" ; |
2556 | std::map<StringRef, FSIVecTy> FSIMap; |
2557 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2558 | // Determine whether the first argument is a variadic identifier. |
2559 | std::vector<const Record *> Args = A->getValueAsListOfDefs(FieldName: "Args" ); |
2560 | if (Args.empty() || !isVariadicIdentifierArgument(Arg: Args[0])) |
2561 | continue; |
2562 | generateFlattenedSpellingInfo(Attr: *A, Map&: FSIMap); |
2563 | } |
2564 | emitStringSwitchCases(Map&: FSIMap, OS); |
2565 | OS << "#endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST\n\n" ; |
2566 | } |
2567 | |
2568 | // Emits the list of arguments that should be parsed as unevaluated string |
2569 | // literals for each attribute. |
2570 | static void |
2571 | emitClangAttrUnevaluatedStringLiteralList(const RecordKeeper &Records, |
2572 | raw_ostream &OS) { |
2573 | OS << "#if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST)\n" ; |
2574 | |
2575 | auto MakeMask = [](ArrayRef<const Record *> Args) { |
2576 | uint32_t Bits = 0; |
2577 | assert(Args.size() <= 32 && "unsupported number of arguments in attribute" ); |
2578 | for (uint32_t N = 0; N < Args.size(); ++N) { |
2579 | Bits |= (isStringLiteralArgument(Arg: Args[N]) << N); |
2580 | // If we have a variadic string argument, set all the remaining bits to 1 |
2581 | if (isVariadicStringLiteralArgument(Arg: Args[N])) { |
2582 | Bits |= maskTrailingZeros<decltype(Bits)>(N); |
2583 | break; |
2584 | } |
2585 | } |
2586 | return Bits; |
2587 | }; |
2588 | |
2589 | std::map<StringRef, FSIVecTy> FSIMap; |
2590 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2591 | // Determine whether there are any string arguments. |
2592 | uint32_t ArgMask = MakeMask(Attr->getValueAsListOfDefs(FieldName: "Args" )); |
2593 | if (!ArgMask) |
2594 | continue; |
2595 | generateFlattenedSpellingInfo(Attr: *Attr, Map&: FSIMap, ArgMask); |
2596 | } |
2597 | emitStringSwitchCases(Map&: FSIMap, OS); |
2598 | OS << "#endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST\n\n" ; |
2599 | } |
2600 | |
2601 | // Emits the first-argument-is-identifier property for attributes. |
2602 | static void emitClangAttrIdentifierArgList(const RecordKeeper &Records, |
2603 | raw_ostream &OS) { |
2604 | OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n" ; |
2605 | std::map<StringRef, FSIVecTy> FSIMap; |
2606 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2607 | // Determine whether the first argument is an identifier. |
2608 | std::vector<const Record *> Args = Attr->getValueAsListOfDefs(FieldName: "Args" ); |
2609 | if (Args.empty() || !isIdentifierArgument(Arg: Args[0])) |
2610 | continue; |
2611 | generateFlattenedSpellingInfo(Attr: *Attr, Map&: FSIMap); |
2612 | } |
2613 | emitStringSwitchCases(Map&: FSIMap, OS); |
2614 | OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n" ; |
2615 | } |
2616 | |
2617 | // Emits the list for attributes having StrictEnumParameters. |
2618 | static void emitClangAttrStrictIdentifierArgList(const RecordKeeper &Records, |
2619 | raw_ostream &OS) { |
2620 | OS << "#if defined(CLANG_ATTR_STRICT_IDENTIFIER_ARG_LIST)\n" ; |
2621 | std::map<StringRef, FSIVecTy> FSIMap; |
2622 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2623 | if (!Attr->getValueAsBit(FieldName: "StrictEnumParameters" )) |
2624 | continue; |
2625 | // Check that there is really an identifier argument. |
2626 | std::vector<const Record *> Args = Attr->getValueAsListOfDefs(FieldName: "Args" ); |
2627 | if (none_of(Range&: Args, P: [&](const Record *R) { return isIdentifierArgument(Arg: R); })) |
2628 | continue; |
2629 | generateFlattenedSpellingInfo(Attr: *Attr, Map&: FSIMap); |
2630 | } |
2631 | emitStringSwitchCases(Map&: FSIMap, OS); |
2632 | OS << "#endif // CLANG_ATTR_STRICT_IDENTIFIER_ARG_LIST\n\n" ; |
2633 | } |
2634 | |
2635 | static bool keywordThisIsaIdentifierInArgument(const Record *Arg) { |
2636 | return !Arg->getDirectSuperClasses().empty() && |
2637 | StringSwitch<bool>( |
2638 | Arg->getDirectSuperClasses().back().first->getName()) |
2639 | .Case(S: "VariadicParamOrParamIdxArgument" , Value: true) |
2640 | .Default(Value: false); |
2641 | } |
2642 | |
2643 | static void emitClangAttrThisIsaIdentifierArgList(const RecordKeeper &Records, |
2644 | raw_ostream &OS) { |
2645 | OS << "#if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST)\n" ; |
2646 | std::map<StringRef, FSIVecTy> FSIMap; |
2647 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2648 | // Determine whether the first argument is a variadic identifier. |
2649 | std::vector<const Record *> Args = A->getValueAsListOfDefs(FieldName: "Args" ); |
2650 | if (Args.empty() || !keywordThisIsaIdentifierInArgument(Arg: Args[0])) |
2651 | continue; |
2652 | generateFlattenedSpellingInfo(Attr: *A, Map&: FSIMap); |
2653 | } |
2654 | emitStringSwitchCases(Map&: FSIMap, OS); |
2655 | OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n" ; |
2656 | } |
2657 | |
2658 | static void emitClangAttrAcceptsExprPack(const RecordKeeper &Records, |
2659 | raw_ostream &OS) { |
2660 | OS << "#if defined(CLANG_ATTR_ACCEPTS_EXPR_PACK)\n" ; |
2661 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
2662 | std::map<StringRef, FSIVecTy> FSIMap; |
2663 | for (const auto &I : Attrs) { |
2664 | const Record &Attr = *I.second; |
2665 | |
2666 | if (!Attr.getValueAsBit(FieldName: "AcceptsExprPack" )) |
2667 | continue; |
2668 | generateFlattenedSpellingInfo(Attr, Map&: FSIMap); |
2669 | } |
2670 | emitStringSwitchCases(Map&: FSIMap, OS); |
2671 | OS << "#endif // CLANG_ATTR_ACCEPTS_EXPR_PACK\n\n" ; |
2672 | } |
2673 | |
2674 | static bool isRegularKeywordAttribute(const FlattenedSpelling &S) { |
2675 | return (S.variety() == "Keyword" && |
2676 | !S.getSpellingRecord().getValueAsBit(FieldName: "HasOwnParseRules" )); |
2677 | } |
2678 | |
2679 | static void emitFormInitializer(raw_ostream &OS, |
2680 | const FlattenedSpelling &Spelling, |
2681 | StringRef SpellingIndex) { |
2682 | bool IsAlignas = |
2683 | (Spelling.variety() == "Keyword" && Spelling.name() == "alignas" ); |
2684 | OS << "{AttributeCommonInfo::AS_" << Spelling.variety() << ", " |
2685 | << SpellingIndex << ", " << (IsAlignas ? "true" : "false" ) |
2686 | << " /*IsAlignas*/, " |
2687 | << (isRegularKeywordAttribute(S: Spelling) ? "true" : "false" ) |
2688 | << " /*IsRegularKeywordAttribute*/}" ; |
2689 | } |
2690 | |
2691 | static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS, |
2692 | bool ) { |
2693 | ParsedAttrMap AttrMap = getParsedAttrList(Records); |
2694 | |
2695 | // Helper to print the starting character of an attribute argument. If there |
2696 | // hasn't been an argument yet, it prints an opening parenthese; otherwise it |
2697 | // prints a comma. |
2698 | OS << "static inline void DelimitAttributeArgument(" |
2699 | << "raw_ostream& OS, bool& IsFirst) {\n" |
2700 | << " if (IsFirst) {\n" |
2701 | << " IsFirst = false;\n" |
2702 | << " OS << \"(\";\n" |
2703 | << " } else\n" |
2704 | << " OS << \", \";\n" |
2705 | << "}\n" ; |
2706 | |
2707 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
2708 | const Record &R = *Attr; |
2709 | |
2710 | // FIXME: Currently, documentation is generated as-needed due to the fact |
2711 | // that there is no way to allow a generated project "reach into" the docs |
2712 | // directory (for instance, it may be an out-of-tree build). However, we want |
2713 | // to ensure that every attribute has a Documentation field, and produce an |
2714 | // error if it has been neglected. Otherwise, the on-demand generation which |
2715 | // happens server-side will fail. This code is ensuring that functionality, |
2716 | // even though this Emitter doesn't technically need the documentation. |
2717 | // When attribute documentation can be generated as part of the build |
2718 | // itself, this code can be removed. |
2719 | (void)R.getValueAsListOfDefs(FieldName: "Documentation" ); |
2720 | |
2721 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
2722 | continue; |
2723 | |
2724 | std::vector<const Record *> Supers = R.getSuperClasses(); |
2725 | assert(!Supers.empty() && "Forgot to specify a superclass for the attr" ); |
2726 | std::string SuperName; |
2727 | bool Inheritable = false; |
2728 | for (const Record *R : reverse(C&: Supers)) { |
2729 | if (R->getName() != "TargetSpecificAttr" && |
2730 | R->getName() != "DeclOrTypeAttr" && SuperName.empty()) |
2731 | SuperName = R->getName().str(); |
2732 | if (R->getName() == "InheritableAttr" ) |
2733 | Inheritable = true; |
2734 | } |
2735 | |
2736 | if (Header) |
2737 | OS << "class CLANG_ABI " << R.getName() << "Attr : public " << SuperName |
2738 | << " {\n" ; |
2739 | else |
2740 | OS << "\n// " << R.getName() << "Attr implementation\n\n" ; |
2741 | |
2742 | std::vector<const Record *> ArgRecords = R.getValueAsListOfDefs(FieldName: "Args" ); |
2743 | std::vector<std::unique_ptr<Argument>> Args; |
2744 | Args.reserve(n: ArgRecords.size()); |
2745 | |
2746 | bool AttrAcceptsExprPack = Attr->getValueAsBit(FieldName: "AcceptsExprPack" ); |
2747 | if (AttrAcceptsExprPack) { |
2748 | for (size_t I = 0; I < ArgRecords.size(); ++I) { |
2749 | const Record *ArgR = ArgRecords[I]; |
2750 | if (isIdentifierArgument(Arg: ArgR) || isVariadicIdentifierArgument(Arg: ArgR) || |
2751 | isTypeArgument(Arg: ArgR)) |
2752 | PrintFatalError(ErrorLoc: Attr->getLoc(), |
2753 | Msg: "Attributes accepting packs cannot also " |
2754 | "have identifier or type arguments." ); |
2755 | // When trying to determine if value-dependent expressions can populate |
2756 | // the attribute without prior instantiation, the decision is made based |
2757 | // on the assumption that only the last argument is ever variadic. |
2758 | if (I < (ArgRecords.size() - 1) && isVariadicExprArgument(Arg: ArgR)) |
2759 | PrintFatalError(ErrorLoc: Attr->getLoc(), |
2760 | Msg: "Attributes accepting packs can only have the last " |
2761 | "argument be variadic." ); |
2762 | } |
2763 | } |
2764 | |
2765 | bool HasOptArg = false; |
2766 | bool HasFakeArg = false; |
2767 | for (const auto *ArgRecord : ArgRecords) { |
2768 | Args.emplace_back(args: createArgument(Arg: *ArgRecord, Attr: R.getName())); |
2769 | if (Header) { |
2770 | Args.back()->writeDeclarations(OS); |
2771 | OS << "\n\n" ; |
2772 | } |
2773 | |
2774 | // For these purposes, fake takes priority over optional. |
2775 | if (Args.back()->isFake()) { |
2776 | HasFakeArg = true; |
2777 | } else if (Args.back()->isOptional()) { |
2778 | HasOptArg = true; |
2779 | } |
2780 | } |
2781 | |
2782 | std::unique_ptr<VariadicExprArgument> DelayedArgs = nullptr; |
2783 | if (AttrAcceptsExprPack) { |
2784 | DelayedArgs = |
2785 | std::make_unique<VariadicExprArgument>(args: "DelayedArgs" , args: R.getName()); |
2786 | if (Header) { |
2787 | DelayedArgs->writeDeclarations(OS); |
2788 | OS << "\n\n" ; |
2789 | } |
2790 | } |
2791 | |
2792 | if (Header) |
2793 | OS << "public:\n" ; |
2794 | |
2795 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: R); |
2796 | |
2797 | // If there are zero or one spellings, all spelling-related functionality |
2798 | // can be elided. If all of the spellings share the same name, the spelling |
2799 | // functionality can also be elided. |
2800 | bool ElideSpelling = (Spellings.size() <= 1) || |
2801 | SpellingNamesAreCommon(Spellings); |
2802 | |
2803 | // This maps spelling index values to semantic Spelling enumerants. |
2804 | SemanticSpellingMap SemanticToSyntacticMap; |
2805 | |
2806 | std::string SpellingEnum; |
2807 | if (Spellings.size() > 1) |
2808 | SpellingEnum = CreateSemanticSpellings(Spellings, Map&: SemanticToSyntacticMap); |
2809 | if (Header) |
2810 | OS << SpellingEnum; |
2811 | |
2812 | const auto &ParsedAttrSpellingItr = |
2813 | find_if(Range&: AttrMap, P: [R](const std::pair<std::string, const Record *> &P) { |
2814 | return &R == P.second; |
2815 | }); |
2816 | |
2817 | // Emit CreateImplicit factory methods. |
2818 | auto emitCreate = [&](bool Implicit, bool DelayedArgsOnly, bool emitFake) { |
2819 | if (Header) |
2820 | OS << " static " ; |
2821 | OS << R.getName() << "Attr *" ; |
2822 | if (!Header) |
2823 | OS << R.getName() << "Attr::" ; |
2824 | OS << "Create" ; |
2825 | if (Implicit) |
2826 | OS << "Implicit" ; |
2827 | if (DelayedArgsOnly) |
2828 | OS << "WithDelayedArgs" ; |
2829 | OS << "(" ; |
2830 | OS << "ASTContext &Ctx" ; |
2831 | if (!DelayedArgsOnly) { |
2832 | for (auto const &ai : Args) { |
2833 | if (ai->isFake() && !emitFake) |
2834 | continue; |
2835 | OS << ", " ; |
2836 | ai->writeCtorParameters(OS); |
2837 | } |
2838 | } else { |
2839 | OS << ", " ; |
2840 | DelayedArgs->writeCtorParameters(OS); |
2841 | } |
2842 | OS << ", const AttributeCommonInfo &CommonInfo" ; |
2843 | OS << ")" ; |
2844 | if (Header) { |
2845 | OS << ";\n" ; |
2846 | return; |
2847 | } |
2848 | |
2849 | OS << " {\n" ; |
2850 | OS << " auto *A = new (Ctx) " << R.getName(); |
2851 | OS << "Attr(Ctx, CommonInfo" ; |
2852 | |
2853 | if (!DelayedArgsOnly) { |
2854 | for (auto const &ai : Args) { |
2855 | if (ai->isFake() && !emitFake) |
2856 | continue; |
2857 | OS << ", " ; |
2858 | ai->writeImplicitCtorArgs(OS); |
2859 | } |
2860 | } |
2861 | OS << ");\n" ; |
2862 | if (Implicit) { |
2863 | OS << " A->setImplicit(true);\n" ; |
2864 | } |
2865 | if (Implicit || ElideSpelling) { |
2866 | OS << " if (!A->isAttributeSpellingListCalculated() && " |
2867 | "!A->getAttrName())\n" ; |
2868 | OS << " A->setAttributeSpellingListIndex(0);\n" ; |
2869 | } |
2870 | if (DelayedArgsOnly) { |
2871 | OS << " A->setDelayedArgs(Ctx, " ; |
2872 | DelayedArgs->writeImplicitCtorArgs(OS); |
2873 | OS << ");\n" ; |
2874 | } |
2875 | OS << " return A;\n}\n\n" ; |
2876 | }; |
2877 | |
2878 | auto emitCreateNoCI = [&](bool Implicit, bool DelayedArgsOnly, |
2879 | bool emitFake) { |
2880 | if (Header) |
2881 | OS << " static " ; |
2882 | OS << R.getName() << "Attr *" ; |
2883 | if (!Header) |
2884 | OS << R.getName() << "Attr::" ; |
2885 | OS << "Create" ; |
2886 | if (Implicit) |
2887 | OS << "Implicit" ; |
2888 | if (DelayedArgsOnly) |
2889 | OS << "WithDelayedArgs" ; |
2890 | OS << "(" ; |
2891 | OS << "ASTContext &Ctx" ; |
2892 | if (!DelayedArgsOnly) { |
2893 | for (auto const &ai : Args) { |
2894 | if (ai->isFake() && !emitFake) |
2895 | continue; |
2896 | OS << ", " ; |
2897 | ai->writeCtorParameters(OS); |
2898 | } |
2899 | } else { |
2900 | OS << ", " ; |
2901 | DelayedArgs->writeCtorParameters(OS); |
2902 | } |
2903 | OS << ", SourceRange Range" ; |
2904 | if (Header) |
2905 | OS << " = {}" ; |
2906 | if (Spellings.size() > 1) { |
2907 | OS << ", Spelling S" ; |
2908 | if (Header) |
2909 | OS << " = " << SemanticToSyntacticMap[0]; |
2910 | } |
2911 | OS << ")" ; |
2912 | if (Header) { |
2913 | OS << ";\n" ; |
2914 | return; |
2915 | } |
2916 | |
2917 | OS << " {\n" ; |
2918 | OS << " AttributeCommonInfo I(Range, " ; |
2919 | |
2920 | if (ParsedAttrSpellingItr != std::end(cont&: AttrMap)) |
2921 | OS << "AT_" << ParsedAttrSpellingItr->first; |
2922 | else |
2923 | OS << "NoSemaHandlerAttribute" ; |
2924 | |
2925 | if (Spellings.size() == 0) { |
2926 | OS << ", AttributeCommonInfo::Form::Implicit()" ; |
2927 | } else if (Spellings.size() == 1) { |
2928 | OS << ", " ; |
2929 | emitFormInitializer(OS, Spelling: Spellings[0], SpellingIndex: "0" ); |
2930 | } else { |
2931 | OS << ", [&]() {\n" ; |
2932 | OS << " switch (S) {\n" ; |
2933 | std::set<std::string> Uniques; |
2934 | unsigned Idx = 0; |
2935 | for (auto I = Spellings.begin(), E = Spellings.end(); I != E; |
2936 | ++I, ++Idx) { |
2937 | const FlattenedSpelling &S = *I; |
2938 | const auto &Name = SemanticToSyntacticMap[Idx]; |
2939 | if (Uniques.insert(x: Name).second) { |
2940 | OS << " case " << Name << ":\n" ; |
2941 | OS << " return AttributeCommonInfo::Form" ; |
2942 | emitFormInitializer(OS, Spelling: S, SpellingIndex: Name); |
2943 | OS << ";\n" ; |
2944 | } |
2945 | } |
2946 | OS << " default:\n" ; |
2947 | OS << " llvm_unreachable(\"Unknown attribute spelling!\");\n" |
2948 | << " return AttributeCommonInfo::Form" ; |
2949 | emitFormInitializer(OS, Spelling: Spellings[0], SpellingIndex: "0" ); |
2950 | OS << ";\n" |
2951 | << " }\n" |
2952 | << " }()" ; |
2953 | } |
2954 | |
2955 | OS << ");\n" ; |
2956 | OS << " return Create" ; |
2957 | if (Implicit) |
2958 | OS << "Implicit" ; |
2959 | if (DelayedArgsOnly) |
2960 | OS << "WithDelayedArgs" ; |
2961 | OS << "(Ctx" ; |
2962 | if (!DelayedArgsOnly) { |
2963 | for (auto const &ai : Args) { |
2964 | if (ai->isFake() && !emitFake) |
2965 | continue; |
2966 | OS << ", " ; |
2967 | ai->writeImplicitCtorArgs(OS); |
2968 | } |
2969 | } else { |
2970 | OS << ", " ; |
2971 | DelayedArgs->writeImplicitCtorArgs(OS); |
2972 | } |
2973 | OS << ", I);\n" ; |
2974 | OS << "}\n\n" ; |
2975 | }; |
2976 | |
2977 | auto emitCreates = [&](bool DelayedArgsOnly, bool emitFake) { |
2978 | emitCreate(true, DelayedArgsOnly, emitFake); |
2979 | emitCreate(false, DelayedArgsOnly, emitFake); |
2980 | emitCreateNoCI(true, DelayedArgsOnly, emitFake); |
2981 | emitCreateNoCI(false, DelayedArgsOnly, emitFake); |
2982 | }; |
2983 | |
2984 | if (Header) |
2985 | OS << " // Factory methods\n" ; |
2986 | |
2987 | // Emit a CreateImplicit that takes all the arguments. |
2988 | emitCreates(false, true); |
2989 | |
2990 | // Emit a CreateImplicit that takes all the non-fake arguments. |
2991 | if (HasFakeArg) |
2992 | emitCreates(false, false); |
2993 | |
2994 | // Emit a CreateWithDelayedArgs that takes only the dependent argument |
2995 | // expressions. |
2996 | if (DelayedArgs) |
2997 | emitCreates(true, false); |
2998 | |
2999 | // Emit constructors. |
3000 | auto emitCtor = [&](bool emitOpt, bool emitFake, bool emitNoArgs) { |
3001 | auto shouldEmitArg = [=](const std::unique_ptr<Argument> &arg) { |
3002 | if (emitNoArgs) |
3003 | return false; |
3004 | if (arg->isFake()) |
3005 | return emitFake; |
3006 | if (arg->isOptional()) |
3007 | return emitOpt; |
3008 | return true; |
3009 | }; |
3010 | if (Header) |
3011 | OS << " " ; |
3012 | else |
3013 | OS << R.getName() << "Attr::" ; |
3014 | OS << R.getName() |
3015 | << "Attr(ASTContext &Ctx, const AttributeCommonInfo &CommonInfo" ; |
3016 | OS << '\n'; |
3017 | for (auto const &ai : Args) { |
3018 | if (!shouldEmitArg(ai)) |
3019 | continue; |
3020 | OS << " , " ; |
3021 | ai->writeCtorParameters(OS); |
3022 | OS << "\n" ; |
3023 | } |
3024 | |
3025 | OS << " )" ; |
3026 | if (Header) { |
3027 | OS << ";\n" ; |
3028 | return; |
3029 | } |
3030 | OS << "\n : " << SuperName << "(Ctx, CommonInfo, " ; |
3031 | OS << "attr::" << R.getName() << ", " ; |
3032 | |
3033 | // Handle different late parsing modes. |
3034 | OS << "/*IsLateParsed=*/" ; |
3035 | switch (getLateAttrParseKind(Attr: &R)) { |
3036 | case LateAttrParseKind::Never: |
3037 | OS << "false" ; |
3038 | break; |
3039 | case LateAttrParseKind::ExperimentalExt: |
3040 | // Currently no clients need to know the distinction between `Standard` |
3041 | // and `ExperimentalExt` so treat `ExperimentalExt` just like |
3042 | // `Standard` for now. |
3043 | case LateAttrParseKind::Standard: |
3044 | // Note: This is misleading. `IsLateParsed` doesn't mean the |
3045 | // attribute was actually late parsed. Instead it means the attribute in |
3046 | // `Attr.td` is marked as being late parsed. Maybe it should be called |
3047 | // `IsLateParseable`? |
3048 | OS << "true" ; |
3049 | break; |
3050 | } |
3051 | |
3052 | if (Inheritable) { |
3053 | OS << ", " |
3054 | << (R.getValueAsBit(FieldName: "InheritEvenIfAlreadyPresent" ) ? "true" |
3055 | : "false" ); |
3056 | } |
3057 | OS << ")\n" ; |
3058 | |
3059 | for (auto const &ai : Args) { |
3060 | OS << " , " ; |
3061 | if (!shouldEmitArg(ai)) { |
3062 | ai->writeCtorDefaultInitializers(OS); |
3063 | } else { |
3064 | ai->writeCtorInitializers(OS); |
3065 | } |
3066 | OS << "\n" ; |
3067 | } |
3068 | if (DelayedArgs) { |
3069 | OS << " , " ; |
3070 | DelayedArgs->writeCtorDefaultInitializers(OS); |
3071 | OS << "\n" ; |
3072 | } |
3073 | |
3074 | OS << " {\n" ; |
3075 | |
3076 | for (auto const &ai : Args) { |
3077 | if (!shouldEmitArg(ai)) |
3078 | continue; |
3079 | ai->writeCtorBody(OS); |
3080 | } |
3081 | OS << "}\n\n" ; |
3082 | }; |
3083 | |
3084 | if (Header) |
3085 | OS << "\n // Constructors\n" ; |
3086 | |
3087 | // Emit a constructor that includes all the arguments. |
3088 | // This is necessary for cloning. |
3089 | emitCtor(true, true, false); |
3090 | |
3091 | // Emit a constructor that takes all the non-fake arguments. |
3092 | if (HasFakeArg) |
3093 | emitCtor(true, false, false); |
3094 | |
3095 | // Emit a constructor that takes all the non-fake, non-optional arguments. |
3096 | if (HasOptArg) |
3097 | emitCtor(false, false, false); |
3098 | |
3099 | // Emit constructors that takes no arguments if none already exists. |
3100 | // This is used for delaying arguments. |
3101 | bool HasRequiredArgs = |
3102 | count_if(Range&: Args, P: [=](const std::unique_ptr<Argument> &arg) { |
3103 | return !arg->isFake() && !arg->isOptional(); |
3104 | }); |
3105 | if (DelayedArgs && HasRequiredArgs) |
3106 | emitCtor(false, false, true); |
3107 | |
3108 | if (Header) { |
3109 | OS << '\n'; |
3110 | OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n" ; |
3111 | OS << " void printPretty(raw_ostream &OS,\n" |
3112 | << " const PrintingPolicy &Policy) const;\n" ; |
3113 | OS << " const char *getSpelling() const;\n" ; |
3114 | } |
3115 | |
3116 | if (!ElideSpelling) { |
3117 | assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list" ); |
3118 | if (Header) |
3119 | OS << " Spelling getSemanticSpelling() const;\n" ; |
3120 | else { |
3121 | OS << R.getName() << "Attr::Spelling " << R.getName() |
3122 | << "Attr::getSemanticSpelling() const {\n" ; |
3123 | WriteSemanticSpellingSwitch(VarName: "getAttributeSpellingListIndex()" , |
3124 | Map: SemanticToSyntacticMap, OS); |
3125 | OS << "}\n" ; |
3126 | } |
3127 | } |
3128 | |
3129 | if (Header) |
3130 | writeAttrAccessorDefinition(R, OS); |
3131 | |
3132 | for (auto const &ai : Args) { |
3133 | if (Header) { |
3134 | ai->writeAccessors(OS); |
3135 | } else { |
3136 | ai->writeAccessorDefinitions(OS); |
3137 | } |
3138 | OS << "\n\n" ; |
3139 | |
3140 | // Don't write conversion routines for fake arguments. |
3141 | if (ai->isFake()) continue; |
3142 | |
3143 | if (ai->isEnumArg()) |
3144 | static_cast<const EnumArgument *>(ai.get())->writeConversion(OS, |
3145 | Header); |
3146 | else if (ai->isVariadicEnumArg()) |
3147 | static_cast<const VariadicEnumArgument *>(ai.get())->writeConversion( |
3148 | OS, Header); |
3149 | } |
3150 | |
3151 | if (Header) { |
3152 | if (DelayedArgs) { |
3153 | DelayedArgs->writeAccessors(OS); |
3154 | DelayedArgs->writeSetter(OS); |
3155 | } |
3156 | |
3157 | OS << R.getValueAsString(FieldName: "AdditionalMembers" ); |
3158 | OS << "\n\n" ; |
3159 | |
3160 | OS << " static bool classof(const Attr *A) { return A->getKind() == " |
3161 | << "attr::" << R.getName() << "; }\n" ; |
3162 | |
3163 | OS << "};\n\n" ; |
3164 | } else { |
3165 | if (DelayedArgs) |
3166 | DelayedArgs->writeAccessorDefinitions(OS); |
3167 | |
3168 | OS << R.getName() << "Attr *" << R.getName() |
3169 | << "Attr::clone(ASTContext &C) const {\n" ; |
3170 | OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this" ; |
3171 | for (auto const &ai : Args) { |
3172 | OS << ", " ; |
3173 | ai->writeCloneArgs(OS); |
3174 | } |
3175 | OS << ");\n" ; |
3176 | OS << " A->Inherited = Inherited;\n" ; |
3177 | OS << " A->IsPackExpansion = IsPackExpansion;\n" ; |
3178 | OS << " A->setImplicit(Implicit);\n" ; |
3179 | if (DelayedArgs) { |
3180 | OS << " A->setDelayedArgs(C, " ; |
3181 | DelayedArgs->writeCloneArgs(OS); |
3182 | OS << ");\n" ; |
3183 | } |
3184 | OS << " return A;\n}\n\n" ; |
3185 | |
3186 | writePrettyPrintFunction(R, Args, OS); |
3187 | writeGetSpellingFunction(R, OS); |
3188 | } |
3189 | } |
3190 | } |
3191 | // Emits the class definitions for attributes. |
3192 | void clang::EmitClangAttrClass(const RecordKeeper &Records, raw_ostream &OS) { |
3193 | emitSourceFileHeader(Desc: "Attribute classes' definitions" , OS, Record: Records); |
3194 | |
3195 | OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n" ; |
3196 | OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n" ; |
3197 | |
3198 | emitAttributes(Records, OS, Header: true); |
3199 | |
3200 | OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n" ; |
3201 | } |
3202 | |
3203 | // Emits the class method definitions for attributes. |
3204 | void clang::EmitClangAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { |
3205 | emitSourceFileHeader(Desc: "Attribute classes' member function definitions" , OS, |
3206 | Record: Records); |
3207 | |
3208 | emitAttributes(Records, OS, Header: false); |
3209 | |
3210 | // Instead of relying on virtual dispatch we just create a huge dispatch |
3211 | // switch. This is both smaller and faster than virtual functions. |
3212 | auto EmitFunc = [&](const char *Method) { |
3213 | OS << " switch (getKind()) {\n" ; |
3214 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
3215 | const Record &R = *Attr; |
3216 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
3217 | continue; |
3218 | |
3219 | OS << " case attr::" << R.getName() << ":\n" ; |
3220 | OS << " return cast<" << R.getName() << "Attr>(this)->" << Method |
3221 | << ";\n" ; |
3222 | } |
3223 | OS << " }\n" ; |
3224 | OS << " llvm_unreachable(\"Unexpected attribute kind!\");\n" ; |
3225 | OS << "}\n\n" ; |
3226 | }; |
3227 | |
3228 | OS << "const char *Attr::getSpelling() const {\n" ; |
3229 | EmitFunc("getSpelling()" ); |
3230 | |
3231 | OS << "Attr *Attr::clone(ASTContext &C) const {\n" ; |
3232 | EmitFunc("clone(C)" ); |
3233 | |
3234 | OS << "void Attr::printPretty(raw_ostream &OS, " |
3235 | "const PrintingPolicy &Policy) const {\n" ; |
3236 | EmitFunc("printPretty(OS, Policy)" ); |
3237 | } |
3238 | |
3239 | static void emitAttrList(raw_ostream &OS, StringRef Class, |
3240 | ArrayRef<const Record *> AttrList) { |
3241 | for (auto Cur : AttrList) { |
3242 | OS << Class << "(" << Cur->getName() << ")\n" ; |
3243 | } |
3244 | } |
3245 | |
3246 | // Determines if an attribute has a Pragma spelling. |
3247 | static bool AttrHasPragmaSpelling(const Record *R) { |
3248 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: *R); |
3249 | return any_of(Range&: Spellings, P: [](const FlattenedSpelling &S) { |
3250 | return S.variety() == "Pragma" ; |
3251 | }); |
3252 | } |
3253 | |
3254 | namespace { |
3255 | |
3256 | struct AttrClassDescriptor { |
3257 | const char * const MacroName; |
3258 | const char * const TableGenName; |
3259 | }; |
3260 | |
3261 | } // end anonymous namespace |
3262 | |
3263 | static const AttrClassDescriptor AttrClassDescriptors[] = { |
3264 | {.MacroName: "ATTR" , .TableGenName: "Attr" }, |
3265 | {.MacroName: "TYPE_ATTR" , .TableGenName: "TypeAttr" }, |
3266 | {.MacroName: "STMT_ATTR" , .TableGenName: "StmtAttr" }, |
3267 | {.MacroName: "DECL_OR_STMT_ATTR" , .TableGenName: "DeclOrStmtAttr" }, |
3268 | {.MacroName: "INHERITABLE_ATTR" , .TableGenName: "InheritableAttr" }, |
3269 | {.MacroName: "DECL_OR_TYPE_ATTR" , .TableGenName: "DeclOrTypeAttr" }, |
3270 | {.MacroName: "INHERITABLE_PARAM_ATTR" , .TableGenName: "InheritableParamAttr" }, |
3271 | {.MacroName: "INHERITABLE_PARAM_OR_STMT_ATTR" , .TableGenName: "InheritableParamOrStmtAttr" }, |
3272 | {.MacroName: "PARAMETER_ABI_ATTR" , .TableGenName: "ParameterABIAttr" }, |
3273 | {.MacroName: "HLSL_ANNOTATION_ATTR" , .TableGenName: "HLSLAnnotationAttr" }}; |
3274 | |
3275 | static void emitDefaultDefine(raw_ostream &OS, StringRef name, |
3276 | const char *superName) { |
3277 | OS << "#ifndef " << name << "\n" ; |
3278 | OS << "#define " << name << "(NAME) " ; |
3279 | if (superName) OS << superName << "(NAME)" ; |
3280 | OS << "\n#endif\n\n" ; |
3281 | } |
3282 | |
3283 | namespace { |
3284 | |
3285 | /// A class of attributes. |
3286 | struct AttrClass { |
3287 | const AttrClassDescriptor &Descriptor; |
3288 | const Record *TheRecord; |
3289 | AttrClass *SuperClass = nullptr; |
3290 | std::vector<AttrClass*> SubClasses; |
3291 | std::vector<const Record *> Attrs; |
3292 | |
3293 | AttrClass(const AttrClassDescriptor &Descriptor, const Record *R) |
3294 | : Descriptor(Descriptor), TheRecord(R) {} |
3295 | |
3296 | void emitDefaultDefines(raw_ostream &OS) const { |
3297 | // Default the macro unless this is a root class (i.e. Attr). |
3298 | if (SuperClass) { |
3299 | emitDefaultDefine(OS, name: Descriptor.MacroName, |
3300 | superName: SuperClass->Descriptor.MacroName); |
3301 | } |
3302 | } |
3303 | |
3304 | void emitUndefs(raw_ostream &OS) const { |
3305 | OS << "#undef " << Descriptor.MacroName << "\n" ; |
3306 | } |
3307 | |
3308 | void emitAttrList(raw_ostream &OS) const { |
3309 | for (auto SubClass : SubClasses) { |
3310 | SubClass->emitAttrList(OS); |
3311 | } |
3312 | |
3313 | ::emitAttrList(OS, Class: Descriptor.MacroName, AttrList: Attrs); |
3314 | } |
3315 | |
3316 | void classifyAttrOnRoot(const Record *Attr) { |
3317 | bool result = classifyAttr(Attr); |
3318 | assert(result && "failed to classify on root" ); (void) result; |
3319 | } |
3320 | |
3321 | void emitAttrRange(raw_ostream &OS) const { |
3322 | OS << "ATTR_RANGE(" << Descriptor.TableGenName |
3323 | << ", " << getFirstAttr()->getName() |
3324 | << ", " << getLastAttr()->getName() << ")\n" ; |
3325 | } |
3326 | |
3327 | private: |
3328 | bool classifyAttr(const Record *Attr) { |
3329 | // Check all the subclasses. |
3330 | for (auto SubClass : SubClasses) { |
3331 | if (SubClass->classifyAttr(Attr)) |
3332 | return true; |
3333 | } |
3334 | |
3335 | // It's not more specific than this class, but it might still belong here. |
3336 | if (Attr->isSubClassOf(R: TheRecord)) { |
3337 | Attrs.push_back(x: Attr); |
3338 | return true; |
3339 | } |
3340 | |
3341 | return false; |
3342 | } |
3343 | |
3344 | const Record *getFirstAttr() const { |
3345 | if (!SubClasses.empty()) |
3346 | return SubClasses.front()->getFirstAttr(); |
3347 | return Attrs.front(); |
3348 | } |
3349 | |
3350 | const Record *getLastAttr() const { |
3351 | if (!Attrs.empty()) |
3352 | return Attrs.back(); |
3353 | return SubClasses.back()->getLastAttr(); |
3354 | } |
3355 | }; |
3356 | |
3357 | /// The entire hierarchy of attribute classes. |
3358 | class AttrClassHierarchy { |
3359 | std::vector<std::unique_ptr<AttrClass>> Classes; |
3360 | |
3361 | public: |
3362 | AttrClassHierarchy(const RecordKeeper &Records) { |
3363 | // Find records for all the classes. |
3364 | for (auto &Descriptor : AttrClassDescriptors) { |
3365 | const Record *ClassRecord = Records.getClass(Name: Descriptor.TableGenName); |
3366 | AttrClass *Class = new AttrClass(Descriptor, ClassRecord); |
3367 | Classes.emplace_back(args&: Class); |
3368 | } |
3369 | |
3370 | // Link up the hierarchy. |
3371 | for (auto &Class : Classes) { |
3372 | if (AttrClass *SuperClass = findSuperClass(R: Class->TheRecord)) { |
3373 | Class->SuperClass = SuperClass; |
3374 | SuperClass->SubClasses.push_back(x: Class.get()); |
3375 | } |
3376 | } |
3377 | |
3378 | #ifndef NDEBUG |
3379 | for (auto i = Classes.begin(), e = Classes.end(); i != e; ++i) { |
3380 | assert((i == Classes.begin()) == ((*i)->SuperClass == nullptr) && |
3381 | "only the first class should be a root class!" ); |
3382 | } |
3383 | #endif |
3384 | } |
3385 | |
3386 | void emitDefaultDefines(raw_ostream &OS) const { |
3387 | for (auto &Class : Classes) { |
3388 | Class->emitDefaultDefines(OS); |
3389 | } |
3390 | } |
3391 | |
3392 | void emitUndefs(raw_ostream &OS) const { |
3393 | for (auto &Class : Classes) { |
3394 | Class->emitUndefs(OS); |
3395 | } |
3396 | } |
3397 | |
3398 | void emitAttrLists(raw_ostream &OS) const { |
3399 | // Just start from the root class. |
3400 | Classes[0]->emitAttrList(OS); |
3401 | } |
3402 | |
3403 | void emitAttrRanges(raw_ostream &OS) const { |
3404 | for (auto &Class : Classes) |
3405 | Class->emitAttrRange(OS); |
3406 | } |
3407 | |
3408 | void classifyAttr(const Record *Attr) { |
3409 | // Add the attribute to the root class. |
3410 | Classes[0]->classifyAttrOnRoot(Attr); |
3411 | } |
3412 | |
3413 | private: |
3414 | AttrClass *findClassByRecord(const Record *R) const { |
3415 | for (auto &Class : Classes) { |
3416 | if (Class->TheRecord == R) |
3417 | return Class.get(); |
3418 | } |
3419 | return nullptr; |
3420 | } |
3421 | |
3422 | AttrClass *findSuperClass(const Record *R) const { |
3423 | // TableGen flattens the superclass list, so we just need to walk it |
3424 | // in reverse. |
3425 | std::vector<const Record *> SuperClasses = R->getSuperClasses(); |
3426 | for (const Record *R : reverse(C&: SuperClasses)) { |
3427 | if (AttrClass *SuperClass = findClassByRecord(R)) |
3428 | return SuperClass; |
3429 | } |
3430 | return nullptr; |
3431 | } |
3432 | }; |
3433 | |
3434 | } // end anonymous namespace |
3435 | |
3436 | namespace clang { |
3437 | |
3438 | // Emits the enumeration list for attributes. |
3439 | void EmitClangAttrList(const RecordKeeper &Records, raw_ostream &OS) { |
3440 | emitSourceFileHeader(Desc: "List of all attributes that Clang recognizes" , OS, |
3441 | Record: Records); |
3442 | |
3443 | AttrClassHierarchy Hierarchy(Records); |
3444 | |
3445 | // Add defaulting macro definitions. |
3446 | Hierarchy.emitDefaultDefines(OS); |
3447 | emitDefaultDefine(OS, name: "PRAGMA_SPELLING_ATTR" , superName: nullptr); |
3448 | |
3449 | std::vector<const Record *> PragmaAttrs; |
3450 | for (auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
3451 | if (!Attr->getValueAsBit(FieldName: "ASTNode" )) |
3452 | continue; |
3453 | |
3454 | // Add the attribute to the ad-hoc groups. |
3455 | if (AttrHasPragmaSpelling(R: Attr)) |
3456 | PragmaAttrs.push_back(x: Attr); |
3457 | |
3458 | // Place it in the hierarchy. |
3459 | Hierarchy.classifyAttr(Attr); |
3460 | } |
3461 | |
3462 | // Emit the main attribute list. |
3463 | Hierarchy.emitAttrLists(OS); |
3464 | |
3465 | // Emit the ad hoc groups. |
3466 | emitAttrList(OS, Class: "PRAGMA_SPELLING_ATTR" , AttrList: PragmaAttrs); |
3467 | |
3468 | // Emit the attribute ranges. |
3469 | OS << "#ifdef ATTR_RANGE\n" ; |
3470 | Hierarchy.emitAttrRanges(OS); |
3471 | OS << "#undef ATTR_RANGE\n" ; |
3472 | OS << "#endif\n" ; |
3473 | |
3474 | Hierarchy.emitUndefs(OS); |
3475 | OS << "#undef PRAGMA_SPELLING_ATTR\n" ; |
3476 | } |
3477 | |
3478 | // Emits the enumeration list for attributes. |
3479 | void EmitClangAttrSubjectMatchRuleList(const RecordKeeper &Records, |
3480 | raw_ostream &OS) { |
3481 | emitSourceFileHeader( |
3482 | Desc: "List of all attribute subject matching rules that Clang recognizes" , OS, |
3483 | Record: Records); |
3484 | PragmaClangAttributeSupport &PragmaAttributeSupport = |
3485 | getPragmaAttributeSupport(Records); |
3486 | emitDefaultDefine(OS, name: "ATTR_MATCH_RULE" , superName: nullptr); |
3487 | PragmaAttributeSupport.emitMatchRuleList(OS); |
3488 | OS << "#undef ATTR_MATCH_RULE\n" ; |
3489 | } |
3490 | |
3491 | // Emits the code to read an attribute from a precompiled header. |
3492 | void EmitClangAttrPCHRead(const RecordKeeper &Records, raw_ostream &OS) { |
3493 | emitSourceFileHeader(Desc: "Attribute deserialization code" , OS, Record: Records); |
3494 | |
3495 | const Record *InhClass = Records.getClass(Name: "InheritableAttr" ); |
3496 | std::vector<const Record *> ArgRecords; |
3497 | std::vector<std::unique_ptr<Argument>> Args; |
3498 | std::unique_ptr<VariadicExprArgument> DelayedArgs; |
3499 | |
3500 | OS << " switch (Kind) {\n" ; |
3501 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
3502 | const Record &R = *Attr; |
3503 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
3504 | continue; |
3505 | |
3506 | OS << " case attr::" << R.getName() << ": {\n" ; |
3507 | if (R.isSubClassOf(R: InhClass)) |
3508 | OS << " bool isInherited = Record.readInt();\n" ; |
3509 | OS << " bool isImplicit = Record.readInt();\n" ; |
3510 | OS << " bool isPackExpansion = Record.readInt();\n" ; |
3511 | DelayedArgs = nullptr; |
3512 | if (Attr->getValueAsBit(FieldName: "AcceptsExprPack" )) { |
3513 | DelayedArgs = |
3514 | std::make_unique<VariadicExprArgument>(args: "DelayedArgs" , args: R.getName()); |
3515 | DelayedArgs->writePCHReadDecls(OS); |
3516 | } |
3517 | ArgRecords = R.getValueAsListOfDefs(FieldName: "Args" ); |
3518 | Args.clear(); |
3519 | for (const auto *Arg : ArgRecords) { |
3520 | Args.emplace_back(args: createArgument(Arg: *Arg, Attr: R.getName())); |
3521 | Args.back()->writePCHReadDecls(OS); |
3522 | } |
3523 | OS << " New = new (Context) " << R.getName() << "Attr(Context, Info" ; |
3524 | for (auto const &ri : Args) { |
3525 | OS << ", " ; |
3526 | ri->writePCHReadArgs(OS); |
3527 | } |
3528 | OS << ");\n" ; |
3529 | if (R.isSubClassOf(R: InhClass)) |
3530 | OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n" ; |
3531 | OS << " New->setImplicit(isImplicit);\n" ; |
3532 | OS << " New->setPackExpansion(isPackExpansion);\n" ; |
3533 | if (DelayedArgs) { |
3534 | OS << " cast<" << R.getName() |
3535 | << "Attr>(New)->setDelayedArgs(Context, " ; |
3536 | DelayedArgs->writePCHReadArgs(OS); |
3537 | OS << ");\n" ; |
3538 | } |
3539 | |
3540 | if (Attr->getValueAsBit(FieldName: "HasCustomSerialization" )) |
3541 | OS << " read" << R.getName() << "Attr(cast<" << R.getName() |
3542 | << "Attr>(New));\n" ; |
3543 | |
3544 | OS << " break;\n" ; |
3545 | OS << " }\n" ; |
3546 | } |
3547 | OS << " }\n" ; |
3548 | } |
3549 | |
3550 | // Emits the code to write an attribute to a precompiled header. |
3551 | void EmitClangAttrPCHWrite(const RecordKeeper &Records, raw_ostream &OS) { |
3552 | emitSourceFileHeader(Desc: "Attribute serialization code" , OS, Record: Records); |
3553 | |
3554 | const Record *InhClass = Records.getClass(Name: "InheritableAttr" ); |
3555 | OS << " switch (A->getKind()) {\n" ; |
3556 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
3557 | const Record &R = *Attr; |
3558 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
3559 | continue; |
3560 | OS << " case attr::" << R.getName() << ": {\n" ; |
3561 | std::vector<const Record *> Args = R.getValueAsListOfDefs(FieldName: "Args" ); |
3562 | if (R.isSubClassOf(R: InhClass) || !Args.empty()) |
3563 | OS << " const auto *SA = cast<" << R.getName() |
3564 | << "Attr>(A);\n" ; |
3565 | if (R.isSubClassOf(R: InhClass)) |
3566 | OS << " Record.push_back(SA->isInherited());\n" ; |
3567 | OS << " Record.push_back(A->isImplicit());\n" ; |
3568 | OS << " Record.push_back(A->isPackExpansion());\n" ; |
3569 | if (Attr->getValueAsBit(FieldName: "AcceptsExprPack" )) |
3570 | VariadicExprArgument("DelayedArgs" , R.getName()).writePCHWrite(OS); |
3571 | |
3572 | for (const auto *Arg : Args) |
3573 | createArgument(Arg: *Arg, Attr: R.getName())->writePCHWrite(OS); |
3574 | |
3575 | if (Attr->getValueAsBit(FieldName: "HasCustomSerialization" )) |
3576 | OS << " Record.Add" << R.getName() << "Attr(SA);\n" ; |
3577 | |
3578 | OS << " break;\n" ; |
3579 | OS << " }\n" ; |
3580 | } |
3581 | OS << " }\n" ; |
3582 | } |
3583 | |
3584 | } // namespace clang |
3585 | |
3586 | // Helper function for GenerateTargetSpecificAttrChecks that alters the 'Test' |
3587 | // parameter with only a single check type, if applicable. |
3588 | static bool GenerateTargetSpecificAttrCheck(const Record *R, std::string &Test, |
3589 | std::string *FnName, |
3590 | StringRef ListName, |
3591 | StringRef CheckAgainst, |
3592 | StringRef Scope) { |
3593 | if (!R->isValueUnset(FieldName: ListName)) { |
3594 | Test += " && (" ; |
3595 | std::vector<StringRef> Items = R->getValueAsListOfStrings(FieldName: ListName); |
3596 | for (auto I = Items.begin(), E = Items.end(); I != E; ++I) { |
3597 | StringRef Part = *I; |
3598 | Test += CheckAgainst; |
3599 | Test += " == " ; |
3600 | Test += Scope; |
3601 | Test += Part; |
3602 | if (I + 1 != E) |
3603 | Test += " || " ; |
3604 | if (FnName) |
3605 | *FnName += Part; |
3606 | } |
3607 | Test += ")" ; |
3608 | return true; |
3609 | } |
3610 | return false; |
3611 | } |
3612 | |
3613 | // Generate a conditional expression to check if the current target satisfies |
3614 | // the conditions for a TargetSpecificAttr record, and append the code for |
3615 | // those checks to the Test string. If the FnName string pointer is non-null, |
3616 | // append a unique suffix to distinguish this set of target checks from other |
3617 | // TargetSpecificAttr records. |
3618 | static bool GenerateTargetSpecificAttrChecks(const Record *R, |
3619 | std::vector<StringRef> &Arches, |
3620 | std::string &Test, |
3621 | std::string *FnName) { |
3622 | bool AnyTargetChecks = false; |
3623 | |
3624 | // It is assumed that there will be an Triple object |
3625 | // named "T" and a TargetInfo object named "Target" within |
3626 | // scope that can be used to determine whether the attribute exists in |
3627 | // a given target. |
3628 | Test += "true" ; |
3629 | // If one or more architectures is specified, check those. Arches are handled |
3630 | // differently because GenerateTargetRequirements needs to combine the list |
3631 | // with ParseKind. |
3632 | if (!Arches.empty()) { |
3633 | AnyTargetChecks = true; |
3634 | Test += " && (" ; |
3635 | for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) { |
3636 | StringRef Part = *I; |
3637 | Test += "T.getArch() == llvm::Triple::" ; |
3638 | Test += Part; |
3639 | if (I + 1 != E) |
3640 | Test += " || " ; |
3641 | if (FnName) |
3642 | *FnName += Part; |
3643 | } |
3644 | Test += ")" ; |
3645 | } |
3646 | |
3647 | // If the attribute is specific to particular OSes, check those. |
3648 | AnyTargetChecks |= GenerateTargetSpecificAttrCheck( |
3649 | R, Test, FnName, ListName: "OSes" , CheckAgainst: "T.getOS()" , Scope: "llvm::Triple::" ); |
3650 | |
3651 | // If one or more object formats is specified, check those. |
3652 | AnyTargetChecks |= |
3653 | GenerateTargetSpecificAttrCheck(R, Test, FnName, ListName: "ObjectFormats" , |
3654 | CheckAgainst: "T.getObjectFormat()" , Scope: "llvm::Triple::" ); |
3655 | |
3656 | // If custom code is specified, emit it. |
3657 | StringRef Code = R->getValueAsString(FieldName: "CustomCode" ); |
3658 | if (!Code.empty()) { |
3659 | AnyTargetChecks = true; |
3660 | Test += " && (" ; |
3661 | Test += Code; |
3662 | Test += ")" ; |
3663 | } |
3664 | |
3665 | return AnyTargetChecks; |
3666 | } |
3667 | |
3668 | static void GenerateHasAttrSpellingStringSwitch( |
3669 | ArrayRef<std::pair<const Record *, FlattenedSpelling>> Attrs, |
3670 | raw_ostream &OS, StringRef Variety, StringRef Scope = "" ) { |
3671 | |
3672 | // It turns out that there are duplicate records for a given spelling. This |
3673 | // map combines matching test strings using '||'. For example, if there are |
3674 | // three conditions A, B, and C, the final result will be: A || B || C. |
3675 | llvm::StringMap<std::string> TestStringMap; |
3676 | |
3677 | for (const auto &[Attr, Spelling] : Attrs) { |
3678 | // C++11-style attributes have specific version information associated with |
3679 | // them. If the attribute has no scope, the version information must not |
3680 | // have the default value (1), as that's incorrect. Instead, the unscoped |
3681 | // attribute version information should be taken from the SD-6 standing |
3682 | // document, which can be found at: |
3683 | // https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations |
3684 | // |
3685 | // C23-style attributes have the same kind of version information |
3686 | // associated with them. The unscoped attribute version information should |
3687 | // be taken from the specification of the attribute in the C Standard. |
3688 | // |
3689 | // Clang-specific attributes have the same kind of version information |
3690 | // associated with them. This version is typically the default value (1). |
3691 | // These version values are clang-specific and should typically be |
3692 | // incremented once the attribute changes its syntax and/or semantics in a |
3693 | // a way that is impactful to the end user. |
3694 | int Version = 1; |
3695 | |
3696 | assert(Spelling.variety() == Variety); |
3697 | std::string Name = "" ; |
3698 | if (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace()) { |
3699 | Name = Spelling.name(); |
3700 | Version = static_cast<int>( |
3701 | Spelling.getSpellingRecord().getValueAsInt(FieldName: "Version" )); |
3702 | // Verify that explicitly specified CXX11 and C23 spellings (i.e. |
3703 | // not inferred from Clang/GCC spellings) have a version that's |
3704 | // different from the default (1). |
3705 | bool RequiresValidVersion = |
3706 | (Variety == "CXX11" || Variety == "C23" ) && |
3707 | Spelling.getSpellingRecord().getValueAsString(FieldName: "Variety" ) == Variety; |
3708 | if (RequiresValidVersion && Scope.empty() && Version == 1) |
3709 | PrintError(ErrorLoc: Spelling.getSpellingRecord().getLoc(), |
3710 | Msg: "Standard attributes must have " |
3711 | "valid version information." ); |
3712 | } |
3713 | |
3714 | std::string Test; |
3715 | if (Attr->isSubClassOf(Name: "TargetSpecificAttr" )) { |
3716 | const Record *R = Attr->getValueAsDef(FieldName: "Target" ); |
3717 | std::vector<StringRef> Arches = R->getValueAsListOfStrings(FieldName: "Arches" ); |
3718 | GenerateTargetSpecificAttrChecks(R, Arches, Test, FnName: nullptr); |
3719 | } else if (!Attr->getValueAsListOfDefs(FieldName: "TargetSpecificSpellings" ).empty()) { |
3720 | // Add target checks if this spelling is target-specific. |
3721 | for (const auto &TargetSpelling : |
3722 | Attr->getValueAsListOfDefs(FieldName: "TargetSpecificSpellings" )) { |
3723 | // Find spelling that matches current scope and name. |
3724 | for (const auto &Spelling : GetFlattenedSpellings(Attr: *TargetSpelling)) { |
3725 | if (Scope == Spelling.nameSpace() && Name == Spelling.name()) { |
3726 | const Record *Target = TargetSpelling->getValueAsDef(FieldName: "Target" ); |
3727 | std::vector<StringRef> Arches = |
3728 | Target->getValueAsListOfStrings(FieldName: "Arches" ); |
3729 | GenerateTargetSpecificAttrChecks(R: Target, Arches, Test, |
3730 | /*FnName=*/nullptr); |
3731 | break; |
3732 | } |
3733 | } |
3734 | } |
3735 | } |
3736 | |
3737 | std::string TestStr = |
3738 | !Test.empty() ? '(' + Test + " ? " + itostr(X: Version) + " : 0" + ')' |
3739 | : '(' + itostr(X: Version) + ')'; |
3740 | |
3741 | if (Scope.empty() || Scope == Spelling.nameSpace()) { |
3742 | if (TestStringMap.contains(Key: Spelling.name()) && |
3743 | TestStringMap[Spelling.name()] != TestStr) |
3744 | TestStringMap[Spelling.name()] += " || " + TestStr; |
3745 | else |
3746 | TestStringMap[Spelling.name()] = TestStr; |
3747 | } |
3748 | } |
3749 | |
3750 | // Create the actual string switch statement after all the attributes have |
3751 | // been parsed. |
3752 | for (auto &Entry : TestStringMap) { |
3753 | OS << " .Case(\"" << Entry.getKey() << "\", " << Entry.getValue() |
3754 | << ")\n" ; |
3755 | } |
3756 | |
3757 | OS << " .Default(0);\n" ; |
3758 | } |
3759 | |
3760 | namespace clang { |
3761 | |
3762 | // Emits list of regular keyword attributes with info about their arguments. |
3763 | void EmitClangRegularKeywordAttributeInfo(const RecordKeeper &Records, |
3764 | raw_ostream &OS) { |
3765 | emitSourceFileHeader( |
3766 | Desc: "A list of regular keyword attributes generated from the attribute" |
3767 | " definitions" , |
3768 | OS); |
3769 | // Assume for now that the same token is not used in multiple regular |
3770 | // keyword attributes. |
3771 | for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Attr" )) |
3772 | for (const auto &S : GetFlattenedSpellings(Attr: *R)) { |
3773 | if (!isRegularKeywordAttribute(S)) |
3774 | continue; |
3775 | std::vector<const Record *> Args = R->getValueAsListOfDefs(FieldName: "Args" ); |
3776 | bool HasArgs = any_of( |
3777 | Range&: Args, P: [](const Record *Arg) { return !Arg->getValueAsBit(FieldName: "Fake" ); }); |
3778 | |
3779 | OS << "KEYWORD_ATTRIBUTE(" |
3780 | << S.getSpellingRecord().getValueAsString(FieldName: "Name" ) << ", " |
3781 | << (HasArgs ? "true" : "false" ) << ", )\n" ; |
3782 | } |
3783 | OS << "#undef KEYWORD_ATTRIBUTE\n" ; |
3784 | } |
3785 | |
3786 | void EmitCXX11AttributeInfo(const RecordKeeper &Records, raw_ostream &OS) { |
3787 | OS << "#if defined(CXX11_ATTR_ARGS_INFO)\n" ; |
3788 | for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
3789 | for (const FlattenedSpelling &SI : GetFlattenedSpellings(Attr: *R)) { |
3790 | if (SI.variety() == "CXX11" && SI.nameSpace().empty()) { |
3791 | unsigned RequiredArgs = 0; |
3792 | unsigned OptionalArgs = 0; |
3793 | for (const auto *Arg : R->getValueAsListOfDefs(FieldName: "Args" )) { |
3794 | if (Arg->getValueAsBit(FieldName: "Fake" )) |
3795 | continue; |
3796 | |
3797 | if (Arg->getValueAsBit(FieldName: "Optional" )) |
3798 | OptionalArgs++; |
3799 | else |
3800 | RequiredArgs++; |
3801 | } |
3802 | OS << ".Case(\"" << SI.getSpellingRecord().getValueAsString(FieldName: "Name" ) |
3803 | << "\"," |
3804 | << "AttributeCommonInfo::AttrArgsInfo::" |
3805 | << (RequiredArgs ? "Required" |
3806 | : OptionalArgs ? "Optional" |
3807 | : "None" ) |
3808 | << ")" |
3809 | << "\n" ; |
3810 | } |
3811 | } |
3812 | } |
3813 | OS << "#endif // CXX11_ATTR_ARGS_INFO\n" ; |
3814 | } |
3815 | |
3816 | // Emits the list of spellings for attributes. |
3817 | void EmitClangAttrHasAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { |
3818 | emitSourceFileHeader(Desc: "Code to implement the __has_attribute logic" , OS, |
3819 | Record: Records); |
3820 | |
3821 | // Separate all of the attributes out into four group: generic, C++11, GNU, |
3822 | // and declspecs. Then generate a big switch statement for each of them. |
3823 | using PairTy = std::pair<const Record *, FlattenedSpelling>; |
3824 | std::vector<PairTy> Declspec, Microsoft, GNU, Pragma, HLSLAnnotation; |
3825 | std::map<StringRef, std::vector<PairTy>> CXX, C23; |
3826 | |
3827 | // Walk over the list of all attributes, and split them out based on the |
3828 | // spelling variety. |
3829 | for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
3830 | for (const FlattenedSpelling &SI : GetFlattenedSpellings(Attr: *R)) { |
3831 | StringRef Variety = SI.variety(); |
3832 | if (Variety == "GNU" ) |
3833 | GNU.emplace_back(args&: R, args: SI); |
3834 | else if (Variety == "Declspec" ) |
3835 | Declspec.emplace_back(args&: R, args: SI); |
3836 | else if (Variety == "Microsoft" ) |
3837 | Microsoft.emplace_back(args&: R, args: SI); |
3838 | else if (Variety == "CXX11" ) |
3839 | CXX[SI.nameSpace()].emplace_back(args&: R, args: SI); |
3840 | else if (Variety == "C23" ) |
3841 | C23[SI.nameSpace()].emplace_back(args&: R, args: SI); |
3842 | else if (Variety == "Pragma" ) |
3843 | Pragma.emplace_back(args&: R, args: SI); |
3844 | else if (Variety == "HLSLAnnotation" ) |
3845 | HLSLAnnotation.emplace_back(args&: R, args: SI); |
3846 | } |
3847 | } |
3848 | |
3849 | OS << "const llvm::Triple &T = Target.getTriple();\n" ; |
3850 | OS << "switch (Syntax) {\n" ; |
3851 | OS << "case AttributeCommonInfo::Syntax::AS_GNU:\n" ; |
3852 | OS << " return llvm::StringSwitch<int>(Name)\n" ; |
3853 | GenerateHasAttrSpellingStringSwitch(Attrs: GNU, OS, Variety: "GNU" ); |
3854 | OS << "case AttributeCommonInfo::Syntax::AS_Declspec:\n" ; |
3855 | OS << " return llvm::StringSwitch<int>(Name)\n" ; |
3856 | GenerateHasAttrSpellingStringSwitch(Attrs: Declspec, OS, Variety: "Declspec" ); |
3857 | OS << "case AttributeCommonInfo::Syntax::AS_Microsoft:\n" ; |
3858 | OS << " return llvm::StringSwitch<int>(Name)\n" ; |
3859 | GenerateHasAttrSpellingStringSwitch(Attrs: Microsoft, OS, Variety: "Microsoft" ); |
3860 | OS << "case AttributeCommonInfo::Syntax::AS_Pragma:\n" ; |
3861 | OS << " return llvm::StringSwitch<int>(Name)\n" ; |
3862 | GenerateHasAttrSpellingStringSwitch(Attrs: Pragma, OS, Variety: "Pragma" ); |
3863 | OS << "case AttributeCommonInfo::Syntax::AS_HLSLAnnotation:\n" ; |
3864 | OS << " return llvm::StringSwitch<int>(Name)\n" ; |
3865 | GenerateHasAttrSpellingStringSwitch(Attrs: HLSLAnnotation, OS, Variety: "HLSLAnnotation" ); |
3866 | auto fn = [&OS](StringRef Spelling, |
3867 | const std::map<StringRef, std::vector<PairTy>> &Map) { |
3868 | OS << "case AttributeCommonInfo::Syntax::AS_" << Spelling << ": {\n" ; |
3869 | // C++11-style attributes are further split out based on the Scope. |
3870 | ListSeparator LS(" else " ); |
3871 | for (const auto &[Scope, List] : Map) { |
3872 | OS << LS; |
3873 | OS << "if (ScopeName == \"" << Scope << "\") {\n" ; |
3874 | OS << " return llvm::StringSwitch<int>(Name)\n" ; |
3875 | GenerateHasAttrSpellingStringSwitch(Attrs: List, OS, Variety: Spelling, Scope); |
3876 | OS << "}" ; |
3877 | } |
3878 | OS << "\n} break;\n" ; |
3879 | }; |
3880 | fn("CXX11" , CXX); |
3881 | fn("C23" , C23); |
3882 | OS << "case AttributeCommonInfo::Syntax::AS_Keyword:\n" ; |
3883 | OS << "case AttributeCommonInfo::Syntax::AS_ContextSensitiveKeyword:\n" ; |
3884 | OS << " llvm_unreachable(\"hasAttribute not supported for keyword\");\n" ; |
3885 | OS << " return 0;\n" ; |
3886 | OS << "case AttributeCommonInfo::Syntax::AS_Implicit:\n" ; |
3887 | OS << " llvm_unreachable (\"hasAttribute not supported for " |
3888 | "AS_Implicit\");\n" ; |
3889 | OS << " return 0;\n" ; |
3890 | |
3891 | OS << "}\n" ; |
3892 | } |
3893 | |
3894 | void EmitClangAttrSpellingListIndex(const RecordKeeper &Records, |
3895 | raw_ostream &OS) { |
3896 | emitSourceFileHeader(Desc: "Code to translate different attribute spellings into " |
3897 | "internal identifiers" , |
3898 | OS, Record: Records); |
3899 | |
3900 | OS << " switch (getParsedKind()) {\n" ; |
3901 | OS << " case IgnoredAttribute:\n" ; |
3902 | OS << " case UnknownAttribute:\n" ; |
3903 | OS << " case NoSemaHandlerAttribute:\n" ; |
3904 | OS << " llvm_unreachable(\"Ignored/unknown shouldn't get here\");\n" ; |
3905 | |
3906 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
3907 | for (const auto &I : Attrs) { |
3908 | const Record &R = *I.second; |
3909 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: R); |
3910 | OS << " case AT_" << I.first << ": {\n" ; |
3911 | |
3912 | // If there are none or one spelling to check, resort to the default |
3913 | // behavior of returning index as 0. |
3914 | if (Spellings.size() <= 1) { |
3915 | OS << " return 0;\n" |
3916 | << " break;\n" |
3917 | << " }\n" ; |
3918 | continue; |
3919 | } |
3920 | |
3921 | std::vector<StringRef> Names; |
3922 | llvm::transform(Range&: Spellings, d_first: std::back_inserter(x&: Names), |
3923 | F: [](const FlattenedSpelling &FS) { return FS.name(); }); |
3924 | llvm::sort(C&: Names); |
3925 | Names.erase(first: llvm::unique(R&: Names), last: Names.end()); |
3926 | |
3927 | for (const auto &[Idx, FS] : enumerate(First&: Spellings)) { |
3928 | OS << " if (" ; |
3929 | if (Names.size() > 1) { |
3930 | SmallVector<StringRef, 6> SameLenNames; |
3931 | StringRef FSName = FS.name(); |
3932 | llvm::copy_if( |
3933 | Range&: Names, Out: std::back_inserter(x&: SameLenNames), |
3934 | P: [&](StringRef N) { return N.size() == FSName.size(); }); |
3935 | |
3936 | if (SameLenNames.size() == 1) { |
3937 | OS << "Name.size() == " << FS.name().size() << " && " ; |
3938 | } else { |
3939 | // FIXME: We currently fall back to comparing entire strings if there |
3940 | // are 2 or more spelling names with the same length. This can be |
3941 | // optimized to check only for the the first differing character |
3942 | // between them instead. |
3943 | OS << "Name == \"" << FS.name() << "\"" |
3944 | << " && " ; |
3945 | } |
3946 | } |
3947 | |
3948 | OS << "getSyntax() == AttributeCommonInfo::AS_" << FS.variety() |
3949 | << " && ComputedScope == " ; |
3950 | if (FS.nameSpace() == "" ) |
3951 | OS << "AttributeCommonInfo::Scope::NONE" ; |
3952 | else |
3953 | OS << "AttributeCommonInfo::Scope::" + FS.nameSpace().upper(); |
3954 | |
3955 | OS << ")\n" |
3956 | << " return " << Idx << ";\n" ; |
3957 | } |
3958 | |
3959 | OS << " break;\n" |
3960 | << " }\n" ; |
3961 | } |
3962 | |
3963 | OS << " }\n" |
3964 | << " return 0;\n" ; |
3965 | } |
3966 | |
3967 | // Emits code used by RecursiveASTVisitor to visit attributes |
3968 | void EmitClangAttrASTVisitor(const RecordKeeper &Records, raw_ostream &OS) { |
3969 | emitSourceFileHeader(Desc: "Used by RecursiveASTVisitor to visit attributes." , OS, |
3970 | Record: Records); |
3971 | // Write method declarations for Traverse* methods. |
3972 | // We emit this here because we only generate methods for attributes that |
3973 | // are declared as ASTNodes. |
3974 | OS << "#ifdef ATTR_VISITOR_DECLS_ONLY\n\n" ; |
3975 | ArrayRef<const Record *> Attrs = Records.getAllDerivedDefinitions(ClassName: "Attr" ); |
3976 | for (const auto *Attr : Attrs) { |
3977 | const Record &R = *Attr; |
3978 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
3979 | continue; |
3980 | OS << " bool Traverse" |
3981 | << R.getName() << "Attr(" << R.getName() << "Attr *A);\n" ; |
3982 | OS << " bool Visit" |
3983 | << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n" |
3984 | << " return true; \n" |
3985 | << " }\n" ; |
3986 | } |
3987 | OS << "\n#else // ATTR_VISITOR_DECLS_ONLY\n\n" ; |
3988 | |
3989 | // Write individual Traverse* methods for each attribute class. |
3990 | for (const auto *Attr : Attrs) { |
3991 | const Record &R = *Attr; |
3992 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
3993 | continue; |
3994 | |
3995 | OS << "template <typename Derived>\n" |
3996 | << "bool VISITORCLASS<Derived>::Traverse" |
3997 | << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n" |
3998 | << " if (!getDerived().VisitAttr(A))\n" |
3999 | << " return false;\n" |
4000 | << " if (!getDerived().Visit" << R.getName() << "Attr(A))\n" |
4001 | << " return false;\n" ; |
4002 | |
4003 | for (const auto *Arg : R.getValueAsListOfDefs(FieldName: "Args" )) |
4004 | createArgument(Arg: *Arg, Attr: R.getName())->writeASTVisitorTraversal(OS); |
4005 | |
4006 | if (Attr->getValueAsBit(FieldName: "AcceptsExprPack" )) |
4007 | VariadicExprArgument("DelayedArgs" , R.getName()) |
4008 | .writeASTVisitorTraversal(OS); |
4009 | |
4010 | OS << " return true;\n" ; |
4011 | OS << "}\n\n" ; |
4012 | } |
4013 | |
4014 | // Write generic Traverse routine |
4015 | OS << "template <typename Derived>\n" |
4016 | << "bool VISITORCLASS<Derived>::TraverseAttr(Attr *A) {\n" |
4017 | << " if (!A)\n" |
4018 | << " return true;\n" |
4019 | << "\n" |
4020 | << " switch (A->getKind()) {\n" ; |
4021 | |
4022 | for (const auto *Attr : Attrs) { |
4023 | const Record &R = *Attr; |
4024 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
4025 | continue; |
4026 | |
4027 | OS << " case attr::" << R.getName() << ":\n" |
4028 | << " return getDerived().Traverse" << R.getName() << "Attr(" |
4029 | << "cast<" << R.getName() << "Attr>(A));\n" ; |
4030 | } |
4031 | OS << " }\n" ; // end switch |
4032 | OS << " llvm_unreachable(\"bad attribute kind\");\n" ; |
4033 | OS << "}\n" ; // end function |
4034 | OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n" ; |
4035 | } |
4036 | |
4037 | static void |
4038 | EmitClangAttrTemplateInstantiateHelper(ArrayRef<const Record *> Attrs, |
4039 | raw_ostream &OS, bool AppliesToDecl) { |
4040 | |
4041 | OS << " switch (At->getKind()) {\n" ; |
4042 | for (const auto *Attr : Attrs) { |
4043 | const Record &R = *Attr; |
4044 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
4045 | continue; |
4046 | OS << " case attr::" << R.getName() << ": {\n" ; |
4047 | bool ShouldClone = R.getValueAsBit(FieldName: "Clone" ) && |
4048 | (!AppliesToDecl || |
4049 | R.getValueAsBit(FieldName: "MeaningfulToClassTemplateDefinition" )); |
4050 | |
4051 | if (!ShouldClone) { |
4052 | OS << " return nullptr;\n" ; |
4053 | OS << " }\n" ; |
4054 | continue; |
4055 | } |
4056 | |
4057 | OS << " const auto *A = cast<" |
4058 | << R.getName() << "Attr>(At);\n" ; |
4059 | bool TDependent = R.getValueAsBit(FieldName: "TemplateDependent" ); |
4060 | |
4061 | if (!TDependent) { |
4062 | OS << " return A->clone(C);\n" ; |
4063 | OS << " }\n" ; |
4064 | continue; |
4065 | } |
4066 | |
4067 | std::vector<const Record *> ArgRecords = R.getValueAsListOfDefs(FieldName: "Args" ); |
4068 | std::vector<std::unique_ptr<Argument>> Args; |
4069 | Args.reserve(n: ArgRecords.size()); |
4070 | |
4071 | for (const auto *ArgRecord : ArgRecords) |
4072 | Args.emplace_back(args: createArgument(Arg: *ArgRecord, Attr: R.getName())); |
4073 | |
4074 | for (auto const &ai : Args) |
4075 | ai->writeTemplateInstantiation(OS); |
4076 | |
4077 | OS << " return new (C) " << R.getName() << "Attr(C, *A" ; |
4078 | for (auto const &ai : Args) { |
4079 | OS << ", " ; |
4080 | ai->writeTemplateInstantiationArgs(OS); |
4081 | } |
4082 | OS << ");\n" |
4083 | << " }\n" ; |
4084 | } |
4085 | OS << " } // end switch\n" |
4086 | << " llvm_unreachable(\"Unknown attribute!\");\n" |
4087 | << " return nullptr;\n" ; |
4088 | } |
4089 | |
4090 | // Emits code to instantiate dependent attributes on templates. |
4091 | void EmitClangAttrTemplateInstantiate(const RecordKeeper &Records, |
4092 | raw_ostream &OS) { |
4093 | emitSourceFileHeader(Desc: "Template instantiation code for attributes" , OS, |
4094 | Record: Records); |
4095 | |
4096 | ArrayRef<const Record *> Attrs = Records.getAllDerivedDefinitions(ClassName: "Attr" ); |
4097 | |
4098 | OS << "namespace clang {\n" |
4099 | << "namespace sema {\n\n" |
4100 | << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " |
4101 | << "Sema &S,\n" |
4102 | << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n" ; |
4103 | EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false); |
4104 | OS << "}\n\n" |
4105 | << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n" |
4106 | << " ASTContext &C, Sema &S,\n" |
4107 | << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n" ; |
4108 | EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true); |
4109 | OS << "}\n\n" |
4110 | << "} // end namespace sema\n" |
4111 | << "} // end namespace clang\n" ; |
4112 | } |
4113 | |
4114 | // Emits the list of parsed attributes. |
4115 | void EmitClangAttrParsedAttrList(const RecordKeeper &Records, raw_ostream &OS) { |
4116 | emitSourceFileHeader(Desc: "List of all attributes that Clang recognizes" , OS, |
4117 | Record: Records); |
4118 | |
4119 | OS << "#ifndef PARSED_ATTR\n" ; |
4120 | OS << "#define PARSED_ATTR(NAME) NAME\n" ; |
4121 | OS << "#endif\n\n" ; |
4122 | |
4123 | ParsedAttrMap Names = getParsedAttrList(Records); |
4124 | for (const auto &I : Names) { |
4125 | OS << "PARSED_ATTR(" << I.first << ")\n" ; |
4126 | } |
4127 | } |
4128 | |
4129 | void EmitAttributeSpellingList(const RecordKeeper &Records, raw_ostream &OS) { |
4130 | emitSourceFileHeader(Desc: "List of attribute names" , OS, Record: Records); |
4131 | |
4132 | std::set<StringRef> AttrSpellingList; |
4133 | std::set<StringRef> AttrScopeSpellingList; |
4134 | |
4135 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
4136 | for (const auto &S : GetFlattenedSpellings(Attr: *A)) { |
4137 | AttrSpellingList.insert(x: S.name()); |
4138 | if (S.nameSpace().size()) |
4139 | AttrScopeSpellingList.insert(x: S.nameSpace()); |
4140 | } |
4141 | } |
4142 | |
4143 | OS << "#ifndef ATTR_NAME" << "\n" ; |
4144 | OS << "#define ATTR_NAME(NAME) NAME" << "\n" ; |
4145 | OS << "#endif" << "\n" << "\n" ; |
4146 | for (const auto &AttrName : AttrSpellingList) { |
4147 | OS << "ATTR_NAME(\"" << AttrName << "\")\n" ; |
4148 | } |
4149 | OS << "\n" ; |
4150 | OS << "#undef ATTR_NAME" << "\n" ; |
4151 | OS << "\n" ; |
4152 | |
4153 | OS << "#ifndef ATTR_SCOPE_NAME" << "\n" ; |
4154 | OS << "#define ATTR_SCOPE_NAME(SCOPE_NAME) SCOPE_NAME" << "\n" ; |
4155 | OS << "#endif" << "\n" << "\n" ; |
4156 | for (const auto &AttrScopeName : AttrScopeSpellingList) { |
4157 | OS << "ATTR_SCOPE_NAME(\"" << AttrScopeName << "\")\n" ; |
4158 | } |
4159 | OS << "\n" ; |
4160 | OS << "#undef ATTR_SCOPE_NAME" << "\n" ; |
4161 | OS << "\n" ; |
4162 | } |
4163 | |
4164 | static bool isArgVariadic(const Record &R, StringRef AttrName) { |
4165 | return createArgument(Arg: R, Attr: AttrName)->isVariadic(); |
4166 | } |
4167 | |
4168 | static void emitArgInfo(const Record &R, raw_ostream &OS) { |
4169 | // This function will count the number of arguments specified for the |
4170 | // attribute and emit the number of required arguments followed by the |
4171 | // number of optional arguments. |
4172 | unsigned ArgCount = 0, OptCount = 0, ArgMemberCount = 0; |
4173 | bool HasVariadic = false; |
4174 | for (const auto *Arg : R.getValueAsListOfDefs(FieldName: "Args" )) { |
4175 | // If the arg is fake, it's the user's job to supply it: general parsing |
4176 | // logic shouldn't need to know anything about it. |
4177 | if (Arg->getValueAsBit(FieldName: "Fake" )) |
4178 | continue; |
4179 | Arg->getValueAsBit(FieldName: "Optional" ) ? ++OptCount : ++ArgCount; |
4180 | ++ArgMemberCount; |
4181 | if (!HasVariadic && isArgVariadic(R: *Arg, AttrName: R.getName())) |
4182 | HasVariadic = true; |
4183 | } |
4184 | |
4185 | // If there is a variadic argument, we will set the optional argument count |
4186 | // to its largest value. Since it's currently a 4-bit number, we set it to 15. |
4187 | OS << " /*NumArgs=*/" << ArgCount << ",\n" ; |
4188 | OS << " /*OptArgs=*/" << (HasVariadic ? 15 : OptCount) << ",\n" ; |
4189 | OS << " /*NumArgMembers=*/" << ArgMemberCount << ",\n" ; |
4190 | } |
4191 | |
4192 | static std::string GetDiagnosticSpelling(const Record &R) { |
4193 | StringRef Ret = R.getValueAsString(FieldName: "DiagSpelling" ); |
4194 | if (!Ret.empty()) |
4195 | return Ret.str(); |
4196 | |
4197 | // If we couldn't find the DiagSpelling in this object, we can check to see |
4198 | // if the object is one that has a base, and if it is, loop up to the Base |
4199 | // member recursively. |
4200 | if (auto Base = R.getValueAsOptionalDef(BaseFieldName)) |
4201 | return GetDiagnosticSpelling(R: *Base); |
4202 | |
4203 | return "" ; |
4204 | } |
4205 | |
4206 | static std::string CalculateDiagnostic(const Record &S) { |
4207 | // If the SubjectList object has a custom diagnostic associated with it, |
4208 | // return that directly. |
4209 | const StringRef CustomDiag = S.getValueAsString(FieldName: "CustomDiag" ); |
4210 | if (!CustomDiag.empty()) |
4211 | return ("\"" + Twine(CustomDiag) + "\"" ).str(); |
4212 | |
4213 | std::vector<std::string> DiagList; |
4214 | for (const auto *Subject : S.getValueAsListOfDefs(FieldName: "Subjects" )) { |
4215 | const Record &R = *Subject; |
4216 | // Get the diagnostic text from the Decl or Stmt node given. |
4217 | std::string V = GetDiagnosticSpelling(R); |
4218 | if (V.empty()) { |
4219 | PrintError(ErrorLoc: R.getLoc(), |
4220 | Msg: "Could not determine diagnostic spelling for the node: " + |
4221 | R.getName() + "; please add one to DeclNodes.td" ); |
4222 | } else { |
4223 | // The node may contain a list of elements itself, so split the elements |
4224 | // by a comma, and trim any whitespace. |
4225 | SmallVector<StringRef, 2> Frags; |
4226 | SplitString(Source: V, OutFragments&: Frags, Delimiters: "," ); |
4227 | for (auto Str : Frags) { |
4228 | DiagList.push_back(x: Str.trim().str()); |
4229 | } |
4230 | } |
4231 | } |
4232 | |
4233 | if (DiagList.empty()) { |
4234 | PrintFatalError(ErrorLoc: S.getLoc(), |
4235 | Msg: "Could not deduce diagnostic argument for Attr subjects" ); |
4236 | return "" ; |
4237 | } |
4238 | |
4239 | // FIXME: this is not particularly good for localization purposes and ideally |
4240 | // should be part of the diagnostics engine itself with some sort of list |
4241 | // specifier. |
4242 | |
4243 | // A single member of the list can be returned directly. |
4244 | if (DiagList.size() == 1) |
4245 | return '"' + DiagList.front() + '"'; |
4246 | |
4247 | if (DiagList.size() == 2) |
4248 | return '"' + DiagList[0] + " and " + DiagList[1] + '"'; |
4249 | |
4250 | // If there are more than two in the list, we serialize the first N - 1 |
4251 | // elements with a comma. This leaves the string in the state: foo, bar, |
4252 | // baz (but misses quux). We can then add ", and " for the last element |
4253 | // manually. |
4254 | std::string Diag = join(Begin: DiagList.begin(), End: DiagList.end() - 1, Separator: ", " ); |
4255 | return '"' + Diag + ", and " + *(DiagList.end() - 1) + '"'; |
4256 | } |
4257 | |
4258 | static std::string GetSubjectWithSuffix(const Record *R) { |
4259 | const std::string B = R->getName().str(); |
4260 | if (B == "DeclBase" ) |
4261 | return "Decl" ; |
4262 | return B + "Decl" ; |
4263 | } |
4264 | |
4265 | static std::string functionNameForCustomAppertainsTo(const Record &Subject) { |
4266 | return "is" + Subject.getName().str(); |
4267 | } |
4268 | |
4269 | static void GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) { |
4270 | std::string FnName = functionNameForCustomAppertainsTo(Subject); |
4271 | |
4272 | // If this code has already been generated, we don't need to do anything. |
4273 | static std::set<std::string> CustomSubjectSet; |
4274 | auto I = CustomSubjectSet.find(x: FnName); |
4275 | if (I != CustomSubjectSet.end()) |
4276 | return; |
4277 | |
4278 | // This only works with non-root Decls. |
4279 | const Record *Base = Subject.getValueAsDef(BaseFieldName); |
4280 | |
4281 | // Not currently support custom subjects within custom subjects. |
4282 | if (Base->isSubClassOf(Name: "SubsetSubject" )) { |
4283 | PrintFatalError(ErrorLoc: Subject.getLoc(), |
4284 | Msg: "SubsetSubjects within SubsetSubjects is not supported" ); |
4285 | return; |
4286 | } |
4287 | |
4288 | OS << "static bool " << FnName << "(const Decl *D) {\n" ; |
4289 | OS << " if (const auto *S = dyn_cast<" ; |
4290 | OS << GetSubjectWithSuffix(R: Base); |
4291 | OS << ">(D))\n" ; |
4292 | OS << " return " << Subject.getValueAsString(FieldName: "CheckCode" ) << ";\n" ; |
4293 | OS << " return false;\n" ; |
4294 | OS << "}\n\n" ; |
4295 | |
4296 | CustomSubjectSet.insert(x: FnName); |
4297 | } |
4298 | |
4299 | static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { |
4300 | // If the attribute does not contain a Subjects definition, then use the |
4301 | // default appertainsTo logic. |
4302 | if (Attr.isValueUnset(FieldName: "Subjects" )) |
4303 | return; |
4304 | |
4305 | const Record *SubjectObj = Attr.getValueAsDef(FieldName: "Subjects" ); |
4306 | std::vector<const Record *> Subjects = |
4307 | SubjectObj->getValueAsListOfDefs(FieldName: "Subjects" ); |
4308 | |
4309 | // If the list of subjects is empty, it is assumed that the attribute |
4310 | // appertains to everything. |
4311 | if (Subjects.empty()) |
4312 | return; |
4313 | |
4314 | bool Warn = SubjectObj->getValueAsDef(FieldName: "Diag" )->getValueAsBit(FieldName: "Warn" ); |
4315 | |
4316 | // Split the subjects into declaration subjects and statement subjects. |
4317 | // FIXME: subset subjects are added to the declaration list until there are |
4318 | // enough statement attributes with custom subject needs to warrant |
4319 | // the implementation effort. |
4320 | std::vector<const Record *> DeclSubjects, StmtSubjects; |
4321 | copy_if(Range&: Subjects, Out: std::back_inserter(x&: DeclSubjects), P: [](const Record *R) { |
4322 | return R->isSubClassOf(Name: "SubsetSubject" ) || !R->isSubClassOf(Name: "StmtNode" ); |
4323 | }); |
4324 | copy_if(Range&: Subjects, Out: std::back_inserter(x&: StmtSubjects), |
4325 | P: [](const Record *R) { return R->isSubClassOf(Name: "StmtNode" ); }); |
4326 | |
4327 | // We should have sorted all of the subjects into two lists. |
4328 | // FIXME: this assertion will be wrong if we ever add type attribute subjects. |
4329 | assert(DeclSubjects.size() + StmtSubjects.size() == Subjects.size()); |
4330 | |
4331 | if (DeclSubjects.empty()) { |
4332 | // If there are no decl subjects but there are stmt subjects, diagnose |
4333 | // trying to apply a statement attribute to a declaration. |
4334 | if (!StmtSubjects.empty()) { |
4335 | OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, " ; |
4336 | OS << "const Decl *D) const override {\n" ; |
4337 | OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n" ; |
4338 | OS << " << AL << AL.isRegularKeywordAttribute() << " |
4339 | "D->getLocation();\n" ; |
4340 | OS << " return false;\n" ; |
4341 | OS << "}\n\n" ; |
4342 | } |
4343 | } else { |
4344 | // Otherwise, generate an appertainsTo check specific to this attribute |
4345 | // which checks all of the given subjects against the Decl passed in. |
4346 | OS << "bool diagAppertainsToDecl(Sema &S, " ; |
4347 | OS << "const ParsedAttr &Attr, const Decl *D) const override {\n" ; |
4348 | OS << " if (" ; |
4349 | for (auto I = DeclSubjects.begin(), E = DeclSubjects.end(); I != E; ++I) { |
4350 | // If the subject has custom code associated with it, use the generated |
4351 | // function for it. The function cannot be inlined into this check (yet) |
4352 | // because it requires the subject to be of a specific type, and were that |
4353 | // information inlined here, it would not support an attribute with |
4354 | // multiple custom subjects. |
4355 | if ((*I)->isSubClassOf(Name: "SubsetSubject" )) |
4356 | OS << "!" << functionNameForCustomAppertainsTo(Subject: **I) << "(D)" ; |
4357 | else |
4358 | OS << "!isa<" << GetSubjectWithSuffix(R: *I) << ">(D)" ; |
4359 | |
4360 | if (I + 1 != E) |
4361 | OS << " && " ; |
4362 | } |
4363 | OS << ") {\n" ; |
4364 | OS << " S.Diag(Attr.getLoc(), diag::" ; |
4365 | OS << (Warn ? "warn_attribute_wrong_decl_type_str" |
4366 | : "err_attribute_wrong_decl_type_str" ); |
4367 | OS << ")\n" ; |
4368 | OS << " << Attr << Attr.isRegularKeywordAttribute() << " ; |
4369 | OS << CalculateDiagnostic(S: *SubjectObj) << ";\n" ; |
4370 | OS << " return false;\n" ; |
4371 | OS << " }\n" ; |
4372 | OS << " return true;\n" ; |
4373 | OS << "}\n\n" ; |
4374 | } |
4375 | |
4376 | if (StmtSubjects.empty()) { |
4377 | // If there are no stmt subjects but there are decl subjects, diagnose |
4378 | // trying to apply a declaration attribute to a statement. |
4379 | if (!DeclSubjects.empty()) { |
4380 | OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, " ; |
4381 | OS << "const Stmt *St) const override {\n" ; |
4382 | OS << " S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n" ; |
4383 | OS << " << AL << AL.isRegularKeywordAttribute() << " |
4384 | "St->getBeginLoc();\n" ; |
4385 | OS << " return false;\n" ; |
4386 | OS << "}\n\n" ; |
4387 | } |
4388 | } else { |
4389 | // Now, do the same for statements. |
4390 | OS << "bool diagAppertainsToStmt(Sema &S, " ; |
4391 | OS << "const ParsedAttr &Attr, const Stmt *St) const override {\n" ; |
4392 | OS << " if (" ; |
4393 | for (auto I = StmtSubjects.begin(), E = StmtSubjects.end(); I != E; ++I) { |
4394 | OS << "!isa<" << (*I)->getName() << ">(St)" ; |
4395 | if (I + 1 != E) |
4396 | OS << " && " ; |
4397 | } |
4398 | OS << ") {\n" ; |
4399 | OS << " S.Diag(Attr.getLoc(), diag::" ; |
4400 | OS << (Warn ? "warn_attribute_wrong_decl_type_str" |
4401 | : "err_attribute_wrong_decl_type_str" ); |
4402 | OS << ")\n" ; |
4403 | OS << " << Attr << Attr.isRegularKeywordAttribute() << " ; |
4404 | OS << CalculateDiagnostic(S: *SubjectObj) << ";\n" ; |
4405 | OS << " return false;\n" ; |
4406 | OS << " }\n" ; |
4407 | OS << " return true;\n" ; |
4408 | OS << "}\n\n" ; |
4409 | } |
4410 | } |
4411 | |
4412 | // Generates the mutual exclusion checks. The checks for parsed attributes are |
4413 | // written into OS and the checks for merging declaration attributes are |
4414 | // written into MergeOS. |
4415 | static void GenerateMutualExclusionsChecks(const Record &Attr, |
4416 | const RecordKeeper &Records, |
4417 | raw_ostream &OS, |
4418 | raw_ostream &MergeDeclOS, |
4419 | raw_ostream &MergeStmtOS) { |
4420 | // We don't do any of this magic for type attributes yet. |
4421 | if (Attr.isSubClassOf(Name: "TypeAttr" )) |
4422 | return; |
4423 | |
4424 | // This means the attribute is either a statement attribute, a decl |
4425 | // attribute, or both; find out which. |
4426 | bool CurAttrIsStmtAttr = Attr.isSubClassOf(Name: "StmtAttr" ) || |
4427 | Attr.isSubClassOf(Name: "DeclOrStmtAttr" ) || |
4428 | Attr.isSubClassOf(Name: "InheritableParamOrStmtAttr" ); |
4429 | bool CurAttrIsDeclAttr = !CurAttrIsStmtAttr || |
4430 | Attr.isSubClassOf(Name: "DeclOrStmtAttr" ) || |
4431 | Attr.isSubClassOf(Name: "InheritableParamOrStmtAttr" ); |
4432 | |
4433 | std::vector<std::string> DeclAttrs, StmtAttrs; |
4434 | |
4435 | // Find all of the definitions that inherit from MutualExclusions and include |
4436 | // the given attribute in the list of exclusions to generate the |
4437 | // diagMutualExclusion() check. |
4438 | for (const Record *Exclusion : |
4439 | Records.getAllDerivedDefinitions(ClassName: "MutualExclusions" )) { |
4440 | std::vector<const Record *> MutuallyExclusiveAttrs = |
4441 | Exclusion->getValueAsListOfDefs(FieldName: "Exclusions" ); |
4442 | auto IsCurAttr = [Attr](const Record *R) { |
4443 | return R->getName() == Attr.getName(); |
4444 | }; |
4445 | if (any_of(Range&: MutuallyExclusiveAttrs, P: IsCurAttr)) { |
4446 | // This list of exclusions includes the attribute we're looking for, so |
4447 | // add the exclusive attributes to the proper list for checking. |
4448 | for (const Record *AttrToExclude : MutuallyExclusiveAttrs) { |
4449 | if (IsCurAttr(AttrToExclude)) |
4450 | continue; |
4451 | |
4452 | if (CurAttrIsStmtAttr) |
4453 | StmtAttrs.push_back(x: (AttrToExclude->getName() + "Attr" ).str()); |
4454 | if (CurAttrIsDeclAttr) |
4455 | DeclAttrs.push_back(x: (AttrToExclude->getName() + "Attr" ).str()); |
4456 | } |
4457 | } |
4458 | } |
4459 | |
4460 | // If there are any decl or stmt attributes, silence -Woverloaded-virtual |
4461 | // warnings for them both. |
4462 | if (!DeclAttrs.empty() || !StmtAttrs.empty()) |
4463 | OS << " using ParsedAttrInfo::diagMutualExclusion;\n\n" ; |
4464 | |
4465 | // If we discovered any decl or stmt attributes to test for, generate the |
4466 | // predicates for them now. |
4467 | if (!DeclAttrs.empty()) { |
4468 | // Generate the ParsedAttrInfo subclass logic for declarations. |
4469 | OS << " bool diagMutualExclusion(Sema &S, const ParsedAttr &AL, " |
4470 | << "const Decl *D) const override {\n" ; |
4471 | for (const std::string &A : DeclAttrs) { |
4472 | OS << " if (const auto *A = D->getAttr<" << A << ">()) {\n" ; |
4473 | OS << " S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)" |
4474 | << " << AL << A << (AL.isRegularKeywordAttribute() ||" |
4475 | << " A->isRegularKeywordAttribute());\n" ; |
4476 | OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);" ; |
4477 | OS << " \nreturn false;\n" ; |
4478 | OS << " }\n" ; |
4479 | } |
4480 | OS << " return true;\n" ; |
4481 | OS << " }\n\n" ; |
4482 | |
4483 | // Also generate the declaration attribute merging logic if the current |
4484 | // attribute is one that can be inheritted on a declaration. It is assumed |
4485 | // this code will be executed in the context of a function with parameters: |
4486 | // Sema &S, Decl *D, Attr *A and that returns a bool (false on diagnostic, |
4487 | // true on success). |
4488 | if (Attr.isSubClassOf(Name: "InheritableAttr" )) { |
4489 | MergeDeclOS << " if (const auto *Second = dyn_cast<" |
4490 | << (Attr.getName() + "Attr" ).str() << ">(A)) {\n" ; |
4491 | for (const std::string &A : DeclAttrs) { |
4492 | MergeDeclOS << " if (const auto *First = D->getAttr<" << A |
4493 | << ">()) {\n" ; |
4494 | MergeDeclOS << " S.Diag(First->getLocation(), " |
4495 | << "diag::err_attributes_are_not_compatible) << First << " |
4496 | << "Second << (First->isRegularKeywordAttribute() || " |
4497 | << "Second->isRegularKeywordAttribute());\n" ; |
4498 | MergeDeclOS << " S.Diag(Second->getLocation(), " |
4499 | << "diag::note_conflicting_attribute);\n" ; |
4500 | MergeDeclOS << " return false;\n" ; |
4501 | MergeDeclOS << " }\n" ; |
4502 | } |
4503 | MergeDeclOS << " return true;\n" ; |
4504 | MergeDeclOS << " }\n" ; |
4505 | } |
4506 | } |
4507 | |
4508 | // Statement attributes are a bit different from declarations. With |
4509 | // declarations, each attribute is added to the declaration as it is |
4510 | // processed, and so you can look on the Decl * itself to see if there is a |
4511 | // conflicting attribute. Statement attributes are processed as a group |
4512 | // because AttributedStmt needs to tail-allocate all of the attribute nodes |
4513 | // at once. This means we cannot check whether the statement already contains |
4514 | // an attribute to check for the conflict. Instead, we need to check whether |
4515 | // the given list of semantic attributes contain any conflicts. It is assumed |
4516 | // this code will be executed in the context of a function with parameters: |
4517 | // Sema &S, const SmallVectorImpl<const Attr *> &C. The code will be within a |
4518 | // loop which loops over the container C with a loop variable named A to |
4519 | // represent the current attribute to check for conflicts. |
4520 | // |
4521 | // FIXME: it would be nice not to walk over the list of potential attributes |
4522 | // to apply to the statement more than once, but statements typically don't |
4523 | // have long lists of attributes on them, so re-walking the list should not |
4524 | // be an expensive operation. |
4525 | if (!StmtAttrs.empty()) { |
4526 | MergeStmtOS << " if (const auto *Second = dyn_cast<" |
4527 | << (Attr.getName() + "Attr" ).str() << ">(A)) {\n" ; |
4528 | MergeStmtOS << " auto Iter = llvm::find_if(C, [](const Attr *Check) " |
4529 | << "{ return isa<" ; |
4530 | interleave( |
4531 | c: StmtAttrs, each_fn: [&](StringRef Name) { MergeStmtOS << Name; }, |
4532 | between_fn: [&] { MergeStmtOS << ", " ; }); |
4533 | MergeStmtOS << ">(Check); });\n" ; |
4534 | MergeStmtOS << " if (Iter != C.end()) {\n" ; |
4535 | MergeStmtOS << " S.Diag((*Iter)->getLocation(), " |
4536 | << "diag::err_attributes_are_not_compatible) << *Iter << " |
4537 | << "Second << ((*Iter)->isRegularKeywordAttribute() || " |
4538 | << "Second->isRegularKeywordAttribute());\n" ; |
4539 | MergeStmtOS << " S.Diag(Second->getLocation(), " |
4540 | << "diag::note_conflicting_attribute);\n" ; |
4541 | MergeStmtOS << " return false;\n" ; |
4542 | MergeStmtOS << " }\n" ; |
4543 | MergeStmtOS << " }\n" ; |
4544 | } |
4545 | } |
4546 | |
4547 | static void |
4548 | emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport, |
4549 | raw_ostream &OS) { |
4550 | OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, " |
4551 | << AttributeSubjectMatchRule::EnumName << " rule) {\n" ; |
4552 | OS << " switch (rule) {\n" ; |
4553 | for (const auto &Rule : PragmaAttributeSupport.Rules) { |
4554 | if (Rule.isAbstractRule()) { |
4555 | OS << " case " << Rule.getEnumValue() << ":\n" ; |
4556 | OS << " assert(false && \"Abstract matcher rule isn't allowed\");\n" ; |
4557 | OS << " return false;\n" ; |
4558 | continue; |
4559 | } |
4560 | std::vector<const Record *> Subjects = Rule.getSubjects(); |
4561 | assert(!Subjects.empty() && "Missing subjects" ); |
4562 | OS << " case " << Rule.getEnumValue() << ":\n" ; |
4563 | OS << " return " ; |
4564 | for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) { |
4565 | // If the subject has custom code associated with it, use the function |
4566 | // that was generated for GenerateAppertainsTo to check if the declaration |
4567 | // is valid. |
4568 | if ((*I)->isSubClassOf(Name: "SubsetSubject" )) |
4569 | OS << functionNameForCustomAppertainsTo(Subject: **I) << "(D)" ; |
4570 | else |
4571 | OS << "isa<" << GetSubjectWithSuffix(R: *I) << ">(D)" ; |
4572 | |
4573 | if (I + 1 != E) |
4574 | OS << " || " ; |
4575 | } |
4576 | OS << ";\n" ; |
4577 | } |
4578 | OS << " }\n" ; |
4579 | OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n" ; |
4580 | OS << "}\n\n" ; |
4581 | } |
4582 | |
4583 | static void GenerateLangOptRequirements(const Record &R, |
4584 | raw_ostream &OS) { |
4585 | // If the attribute has an empty or unset list of language requirements, |
4586 | // use the default handler. |
4587 | std::vector<const Record *> LangOpts = R.getValueAsListOfDefs(FieldName: "LangOpts" ); |
4588 | if (LangOpts.empty()) |
4589 | return; |
4590 | |
4591 | OS << "bool acceptsLangOpts(const LangOptions &LangOpts) const override {\n" ; |
4592 | OS << " return " << GenerateTestExpression(LangOpts) << ";\n" ; |
4593 | OS << "}\n\n" ; |
4594 | } |
4595 | |
4596 | static void GenerateTargetRequirements(const Record &Attr, |
4597 | const ParsedAttrMap &Dupes, |
4598 | raw_ostream &OS) { |
4599 | // If the attribute is not a target specific attribute, use the default |
4600 | // target handler. |
4601 | if (!Attr.isSubClassOf(Name: "TargetSpecificAttr" )) |
4602 | return; |
4603 | |
4604 | // Get the list of architectures to be tested for. |
4605 | const Record *R = Attr.getValueAsDef(FieldName: "Target" ); |
4606 | std::vector<StringRef> Arches = R->getValueAsListOfStrings(FieldName: "Arches" ); |
4607 | |
4608 | // If there are other attributes which share the same parsed attribute kind, |
4609 | // such as target-specific attributes with a shared spelling, collapse the |
4610 | // duplicate architectures. This is required because a shared target-specific |
4611 | // attribute has only one ParsedAttr::Kind enumeration value, but it |
4612 | // applies to multiple target architectures. In order for the attribute to be |
4613 | // considered valid, all of its architectures need to be included. |
4614 | if (!Attr.isValueUnset(FieldName: "ParseKind" )) { |
4615 | const StringRef APK = Attr.getValueAsString(FieldName: "ParseKind" ); |
4616 | for (const auto &I : Dupes) { |
4617 | if (I.first == APK) { |
4618 | std::vector<StringRef> DA = |
4619 | I.second->getValueAsDef(FieldName: "Target" )->getValueAsListOfStrings( |
4620 | FieldName: "Arches" ); |
4621 | llvm::append_range(C&: Arches, R&: DA); |
4622 | } |
4623 | } |
4624 | } |
4625 | |
4626 | std::string FnName = "isTarget" ; |
4627 | std::string Test; |
4628 | bool UsesT = GenerateTargetSpecificAttrChecks(R, Arches, Test, FnName: &FnName); |
4629 | |
4630 | OS << "bool existsInTarget(const TargetInfo &Target) const override {\n" ; |
4631 | if (UsesT) |
4632 | OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n" ; |
4633 | OS << " return " << Test << ";\n" ; |
4634 | OS << "}\n\n" ; |
4635 | } |
4636 | |
4637 | static void |
4638 | GenerateSpellingTargetRequirements(const Record &Attr, |
4639 | ArrayRef<const Record *> TargetSpellings, |
4640 | raw_ostream &OS) { |
4641 | // If there are no target specific spellings, use the default target handler. |
4642 | if (TargetSpellings.empty()) |
4643 | return; |
4644 | |
4645 | std::string Test; |
4646 | bool UsesT = false; |
4647 | const std::vector<FlattenedSpelling> SpellingList = |
4648 | GetFlattenedSpellings(Attr); |
4649 | for (unsigned TargetIndex = 0; TargetIndex < TargetSpellings.size(); |
4650 | ++TargetIndex) { |
4651 | const auto &TargetSpelling = TargetSpellings[TargetIndex]; |
4652 | std::vector<FlattenedSpelling> Spellings = |
4653 | GetFlattenedSpellings(Attr: *TargetSpelling); |
4654 | |
4655 | Test += "((SpellingListIndex == " ; |
4656 | for (unsigned Index = 0; Index < Spellings.size(); ++Index) { |
4657 | Test += itostr(X: getSpellingListIndex(SpellingList, Spelling: Spellings[Index])); |
4658 | if (Index != Spellings.size() - 1) |
4659 | Test += " ||\n SpellingListIndex == " ; |
4660 | else |
4661 | Test += ") && " ; |
4662 | } |
4663 | |
4664 | const Record *Target = TargetSpelling->getValueAsDef(FieldName: "Target" ); |
4665 | std::vector<StringRef> Arches = Target->getValueAsListOfStrings(FieldName: "Arches" ); |
4666 | std::string FnName = "isTargetSpelling" ; |
4667 | UsesT |= GenerateTargetSpecificAttrChecks(R: Target, Arches, Test, FnName: &FnName); |
4668 | Test += ")" ; |
4669 | if (TargetIndex != TargetSpellings.size() - 1) |
4670 | Test += " || " ; |
4671 | } |
4672 | |
4673 | OS << "bool spellingExistsInTarget(const TargetInfo &Target,\n" ; |
4674 | OS << " const unsigned SpellingListIndex) const " |
4675 | "override {\n" ; |
4676 | if (UsesT) |
4677 | OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n" ; |
4678 | OS << " return " << Test << ";\n" , OS << "}\n\n" ; |
4679 | } |
4680 | |
4681 | static void GenerateSpellingIndexToSemanticSpelling(const Record &Attr, |
4682 | raw_ostream &OS) { |
4683 | // If the attribute does not have a semantic form, we can bail out early. |
4684 | if (!Attr.getValueAsBit(FieldName: "ASTNode" )) |
4685 | return; |
4686 | |
4687 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); |
4688 | |
4689 | // If there are zero or one spellings, or all of the spellings share the same |
4690 | // name, we can also bail out early. |
4691 | if (Spellings.size() <= 1 || SpellingNamesAreCommon(Spellings)) |
4692 | return; |
4693 | |
4694 | // Generate the enumeration we will use for the mapping. |
4695 | SemanticSpellingMap SemanticToSyntacticMap; |
4696 | std::string Enum = CreateSemanticSpellings(Spellings, Map&: SemanticToSyntacticMap); |
4697 | |
4698 | OS << "unsigned spellingIndexToSemanticSpelling(" ; |
4699 | OS << "const ParsedAttr &Attr) const override {\n" ; |
4700 | OS << Enum; |
4701 | OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n" ; |
4702 | WriteSemanticSpellingSwitch(VarName: "Idx" , Map: SemanticToSyntacticMap, OS); |
4703 | OS << "}\n\n" ; |
4704 | } |
4705 | |
4706 | static void GenerateHandleDeclAttribute(const Record &Attr, raw_ostream &OS) { |
4707 | // Only generate if Attr can be handled simply. |
4708 | if (!Attr.getValueAsBit(FieldName: "SimpleHandler" )) |
4709 | return; |
4710 | |
4711 | // Generate a function which just converts from ParsedAttr to the Attr type. |
4712 | OS << "AttrHandling handleDeclAttribute(Sema &S, Decl *D," ; |
4713 | OS << "const ParsedAttr &Attr) const override {\n" ; |
4714 | OS << " D->addAttr(::new (S.Context) " << Attr.getName(); |
4715 | OS << "Attr(S.Context, Attr));\n" ; |
4716 | OS << " return AttributeApplied;\n" ; |
4717 | OS << "}\n\n" ; |
4718 | } |
4719 | |
4720 | static bool isParamExpr(const Record *Arg) { |
4721 | return !Arg->getDirectSuperClasses().empty() && |
4722 | StringSwitch<bool>( |
4723 | Arg->getDirectSuperClasses().back().first->getName()) |
4724 | .Case(S: "ExprArgument" , Value: true) |
4725 | .Case(S: "VariadicExprArgument" , Value: true) |
4726 | .Default(Value: false); |
4727 | } |
4728 | |
4729 | static void GenerateIsParamExpr(const Record &Attr, raw_ostream &OS) { |
4730 | OS << "bool isParamExpr(size_t N) const override {\n" ; |
4731 | OS << " return " ; |
4732 | auto Args = Attr.getValueAsListOfDefs(FieldName: "Args" ); |
4733 | for (size_t I = 0; I < Args.size(); ++I) |
4734 | if (isParamExpr(Arg: Args[I])) |
4735 | OS << "(N == " << I << ") || " ; |
4736 | OS << "false;\n" ; |
4737 | OS << "}\n\n" ; |
4738 | } |
4739 | |
4740 | static void GenerateHandleAttrWithDelayedArgs(const RecordKeeper &Records, |
4741 | raw_ostream &OS) { |
4742 | OS << "static void handleAttrWithDelayedArgs(Sema &S, Decl *D, " ; |
4743 | OS << "const ParsedAttr &Attr) {\n" ; |
4744 | OS << " SmallVector<Expr *, 4> ArgExprs;\n" ; |
4745 | OS << " ArgExprs.reserve(Attr.getNumArgs());\n" ; |
4746 | OS << " for (unsigned I = 0; I < Attr.getNumArgs(); ++I) {\n" ; |
4747 | OS << " assert(!Attr.isArgIdent(I));\n" ; |
4748 | OS << " ArgExprs.push_back(Attr.getArgAsExpr(I));\n" ; |
4749 | OS << " }\n" ; |
4750 | OS << " clang::Attr *CreatedAttr = nullptr;\n" ; |
4751 | OS << " switch (Attr.getKind()) {\n" ; |
4752 | OS << " default:\n" ; |
4753 | OS << " llvm_unreachable(\"Attribute cannot hold delayed arguments.\");\n" ; |
4754 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
4755 | for (const auto &I : Attrs) { |
4756 | const Record &R = *I.second; |
4757 | if (!R.getValueAsBit(FieldName: "AcceptsExprPack" )) |
4758 | continue; |
4759 | OS << " case ParsedAttr::AT_" << I.first << ": {\n" ; |
4760 | OS << " CreatedAttr = " << R.getName() << "Attr::CreateWithDelayedArgs" ; |
4761 | OS << "(S.Context, ArgExprs.data(), ArgExprs.size(), Attr);\n" ; |
4762 | OS << " break;\n" ; |
4763 | OS << " }\n" ; |
4764 | } |
4765 | OS << " }\n" ; |
4766 | OS << " D->addAttr(CreatedAttr);\n" ; |
4767 | OS << "}\n\n" ; |
4768 | } |
4769 | |
4770 | static bool IsKnownToGCC(const Record &Attr) { |
4771 | // Look at the spellings for this subject; if there are any spellings which |
4772 | // claim to be known to GCC, the attribute is known to GCC. |
4773 | return any_of(Range: GetFlattenedSpellings(Attr), |
4774 | P: [](const FlattenedSpelling &S) { return S.knownToGCC(); }); |
4775 | } |
4776 | |
4777 | /// Emits the parsed attribute helpers |
4778 | void EmitClangAttrParsedAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { |
4779 | emitSourceFileHeader(Desc: "Parsed attribute helpers" , OS, Record: Records); |
4780 | |
4781 | OS << "#if !defined(WANT_DECL_MERGE_LOGIC) && " |
4782 | << "!defined(WANT_STMT_MERGE_LOGIC)\n" ; |
4783 | PragmaClangAttributeSupport &PragmaAttributeSupport = |
4784 | getPragmaAttributeSupport(Records); |
4785 | |
4786 | // Get the list of parsed attributes, and accept the optional list of |
4787 | // duplicates due to the ParseKind. |
4788 | ParsedAttrMap Dupes; |
4789 | ParsedAttrMap Attrs = getParsedAttrList(Records, Dupes: &Dupes); |
4790 | |
4791 | // Generate all of the custom appertainsTo functions that the attributes |
4792 | // will be using. |
4793 | for (const auto &I : Attrs) { |
4794 | const Record &Attr = *I.second; |
4795 | if (Attr.isValueUnset(FieldName: "Subjects" )) |
4796 | continue; |
4797 | const Record *SubjectObj = Attr.getValueAsDef(FieldName: "Subjects" ); |
4798 | for (const Record *Subject : SubjectObj->getValueAsListOfDefs(FieldName: "Subjects" )) |
4799 | if (Subject->isSubClassOf(Name: "SubsetSubject" )) |
4800 | GenerateCustomAppertainsTo(Subject: *Subject, OS); |
4801 | } |
4802 | |
4803 | // This stream is used to collect all of the declaration attribute merging |
4804 | // logic for performing mutual exclusion checks. This gets emitted at the |
4805 | // end of the file in a helper function of its own. |
4806 | std::string DeclMergeChecks, StmtMergeChecks; |
4807 | raw_string_ostream MergeDeclOS(DeclMergeChecks), MergeStmtOS(StmtMergeChecks); |
4808 | |
4809 | // Generate a ParsedAttrInfo struct for each of the attributes. |
4810 | for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { |
4811 | // TODO: If the attribute's kind appears in the list of duplicates, that is |
4812 | // because it is a target-specific attribute that appears multiple times. |
4813 | // It would be beneficial to test whether the duplicates are "similar |
4814 | // enough" to each other to not cause problems. For instance, check that |
4815 | // the spellings are identical, and custom parsing rules match, etc. |
4816 | |
4817 | // We need to generate struct instances based off ParsedAttrInfo from |
4818 | // ParsedAttr.cpp. |
4819 | const std::string &AttrName = I->first; |
4820 | const Record &Attr = *I->second; |
4821 | auto Spellings = GetFlattenedSpellings(Attr); |
4822 | if (!Spellings.empty()) { |
4823 | OS << "static constexpr ParsedAttrInfo::Spelling " << I->first |
4824 | << "Spellings[] = {\n" ; |
4825 | for (const auto &S : Spellings) { |
4826 | StringRef RawSpelling = S.name(); |
4827 | std::string Spelling; |
4828 | if (!S.nameSpace().empty()) |
4829 | Spelling += S.nameSpace().str() + "::" ; |
4830 | if (S.variety() == "GNU" ) |
4831 | Spelling += NormalizeGNUAttrSpelling(AttrSpelling: RawSpelling); |
4832 | else |
4833 | Spelling += RawSpelling; |
4834 | OS << " {AttributeCommonInfo::AS_" << S.variety(); |
4835 | OS << ", \"" << Spelling << "\"},\n" ; |
4836 | } |
4837 | OS << "};\n" ; |
4838 | } |
4839 | |
4840 | std::vector<std::string> ArgNames; |
4841 | for (const auto *Arg : Attr.getValueAsListOfDefs(FieldName: "Args" )) { |
4842 | bool UnusedUnset; |
4843 | if (Arg->getValueAsBitOrUnset(FieldName: "Fake" , Unset&: UnusedUnset)) |
4844 | continue; |
4845 | ArgNames.push_back(x: Arg->getValueAsString(FieldName: "Name" ).str()); |
4846 | for (const Record *Class : Arg->getSuperClasses()) { |
4847 | if (Class->getName().starts_with(Prefix: "Variadic" )) { |
4848 | ArgNames.back().append(s: "..." ); |
4849 | break; |
4850 | } |
4851 | } |
4852 | } |
4853 | if (!ArgNames.empty()) { |
4854 | OS << "static constexpr const char *" << I->first << "ArgNames[] = {\n" ; |
4855 | for (const auto &N : ArgNames) |
4856 | OS << '"' << N << "\"," ; |
4857 | OS << "};\n" ; |
4858 | } |
4859 | |
4860 | OS << "struct ParsedAttrInfo" << I->first |
4861 | << " final : public ParsedAttrInfo {\n" ; |
4862 | OS << " constexpr ParsedAttrInfo" << I->first << "() : ParsedAttrInfo(\n" ; |
4863 | OS << " /*AttrKind=*/ParsedAttr::AT_" << AttrName << ",\n" ; |
4864 | emitArgInfo(R: Attr, OS); |
4865 | OS << " /*HasCustomParsing=*/" ; |
4866 | OS << Attr.getValueAsBit(FieldName: "HasCustomParsing" ) << ",\n" ; |
4867 | OS << " /*AcceptsExprPack=*/" ; |
4868 | OS << Attr.getValueAsBit(FieldName: "AcceptsExprPack" ) << ",\n" ; |
4869 | OS << " /*IsTargetSpecific=*/" ; |
4870 | OS << Attr.isSubClassOf(Name: "TargetSpecificAttr" ) << ",\n" ; |
4871 | OS << " /*IsType=*/" ; |
4872 | OS << (Attr.isSubClassOf(Name: "TypeAttr" ) || Attr.isSubClassOf(Name: "DeclOrTypeAttr" )) |
4873 | << ",\n" ; |
4874 | OS << " /*IsStmt=*/" ; |
4875 | OS << (Attr.isSubClassOf(Name: "StmtAttr" ) || Attr.isSubClassOf(Name: "DeclOrStmtAttr" )) |
4876 | << ",\n" ; |
4877 | OS << " /*IsKnownToGCC=*/" ; |
4878 | OS << IsKnownToGCC(Attr) << ",\n" ; |
4879 | OS << " /*IsSupportedByPragmaAttribute=*/" ; |
4880 | OS << PragmaAttributeSupport.isAttributedSupported(Attribute: *I->second) << ",\n" ; |
4881 | if (!Spellings.empty()) |
4882 | OS << " /*Spellings=*/" << I->first << "Spellings,\n" ; |
4883 | else |
4884 | OS << " /*Spellings=*/{},\n" ; |
4885 | if (!ArgNames.empty()) |
4886 | OS << " /*ArgNames=*/" << I->first << "ArgNames" ; |
4887 | else |
4888 | OS << " /*ArgNames=*/{}" ; |
4889 | OS << ") {}\n" ; |
4890 | GenerateAppertainsTo(Attr, OS); |
4891 | GenerateMutualExclusionsChecks(Attr, Records, OS, MergeDeclOS, MergeStmtOS); |
4892 | GenerateLangOptRequirements(R: Attr, OS); |
4893 | GenerateTargetRequirements(Attr, Dupes, OS); |
4894 | GenerateSpellingTargetRequirements( |
4895 | Attr, TargetSpellings: Attr.getValueAsListOfDefs(FieldName: "TargetSpecificSpellings" ), OS); |
4896 | GenerateSpellingIndexToSemanticSpelling(Attr, OS); |
4897 | PragmaAttributeSupport.generateStrictConformsTo(Attr: *I->second, OS); |
4898 | GenerateHandleDeclAttribute(Attr, OS); |
4899 | GenerateIsParamExpr(Attr, OS); |
4900 | OS << "static const ParsedAttrInfo" << I->first << " Instance;\n" ; |
4901 | OS << "};\n" ; |
4902 | OS << "const ParsedAttrInfo" << I->first << " ParsedAttrInfo" << I->first |
4903 | << "::Instance;\n" ; |
4904 | } |
4905 | |
4906 | OS << "static const ParsedAttrInfo *AttrInfoMap[] = {\n" ; |
4907 | for (const auto &Attr : Attrs) |
4908 | OS << "&ParsedAttrInfo" << Attr.first << "::Instance,\n" ; |
4909 | OS << "};\n\n" ; |
4910 | |
4911 | // Generate function for handling attributes with delayed arguments |
4912 | GenerateHandleAttrWithDelayedArgs(Records, OS); |
4913 | |
4914 | // Generate the attribute match rules. |
4915 | emitAttributeMatchRules(PragmaAttributeSupport, OS); |
4916 | |
4917 | OS << "#elif defined(WANT_DECL_MERGE_LOGIC)\n\n" ; |
4918 | |
4919 | // Write out the declaration merging check logic. |
4920 | OS << "static bool DiagnoseMutualExclusions(Sema &S, const NamedDecl *D, " |
4921 | << "const Attr *A) {\n" ; |
4922 | OS << DeclMergeChecks; |
4923 | OS << " return true;\n" ; |
4924 | OS << "}\n\n" ; |
4925 | |
4926 | OS << "#elif defined(WANT_STMT_MERGE_LOGIC)\n\n" ; |
4927 | |
4928 | // Write out the statement merging check logic. |
4929 | OS << "static bool DiagnoseMutualExclusions(Sema &S, " |
4930 | << "const SmallVectorImpl<const Attr *> &C) {\n" ; |
4931 | OS << " for (const Attr *A : C) {\n" ; |
4932 | OS << StmtMergeChecks; |
4933 | OS << " }\n" ; |
4934 | OS << " return true;\n" ; |
4935 | OS << "}\n\n" ; |
4936 | |
4937 | OS << "#endif\n" ; |
4938 | } |
4939 | |
4940 | // Emits the kind list of parsed attributes |
4941 | void EmitClangAttrParsedAttrKinds(const RecordKeeper &Records, |
4942 | raw_ostream &OS) { |
4943 | emitSourceFileHeader(Desc: "Attribute name matcher" , OS, Record: Records); |
4944 | |
4945 | std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11, |
4946 | Keywords, Pragma, C23, HLSLAnnotation; |
4947 | std::set<StringRef> Seen; |
4948 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
4949 | const Record &Attr = *A; |
4950 | |
4951 | bool SemaHandler = Attr.getValueAsBit(FieldName: "SemaHandler" ); |
4952 | bool Ignored = Attr.getValueAsBit(FieldName: "Ignored" ); |
4953 | if (SemaHandler || Ignored) { |
4954 | // Attribute spellings can be shared between target-specific attributes, |
4955 | // and can be shared between syntaxes for the same attribute. For |
4956 | // instance, an attribute can be spelled GNU<"interrupt"> for an ARM- |
4957 | // specific attribute, or MSP430-specific attribute. Additionally, an |
4958 | // attribute can be spelled GNU<"dllexport"> and Declspec<"dllexport"> |
4959 | // for the same semantic attribute. Ultimately, we need to map each of |
4960 | // these to a single AttributeCommonInfo::Kind value, but the |
4961 | // StringMatcher class cannot handle duplicate match strings. So we |
4962 | // generate a list of string to match based on the syntax, and emit |
4963 | // multiple string matchers depending on the syntax used. |
4964 | std::string AttrName; |
4965 | if (Attr.isSubClassOf(Name: "TargetSpecificAttr" ) && |
4966 | !Attr.isValueUnset(FieldName: "ParseKind" )) { |
4967 | StringRef ParseKind = Attr.getValueAsString(FieldName: "ParseKind" ); |
4968 | if (!Seen.insert(x: ParseKind).second) |
4969 | continue; |
4970 | AttrName = ParseKind.str(); |
4971 | } else { |
4972 | AttrName = NormalizeAttrName(AttrName: Attr.getName()).str(); |
4973 | } |
4974 | |
4975 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); |
4976 | for (const auto &S : Spellings) { |
4977 | StringRef RawSpelling = S.name(); |
4978 | std::vector<StringMatcher::StringPair> *Matches = nullptr; |
4979 | std::string Spelling; |
4980 | StringRef Variety = S.variety(); |
4981 | if (Variety == "CXX11" ) { |
4982 | Matches = &CXX11; |
4983 | if (!S.nameSpace().empty()) |
4984 | Spelling += S.nameSpace().str() + "::" ; |
4985 | } else if (Variety == "C23" ) { |
4986 | Matches = &C23; |
4987 | if (!S.nameSpace().empty()) |
4988 | Spelling += S.nameSpace().str() + "::" ; |
4989 | } else if (Variety == "GNU" ) { |
4990 | Matches = &GNU; |
4991 | } else if (Variety == "Declspec" ) { |
4992 | Matches = &Declspec; |
4993 | } else if (Variety == "Microsoft" ) { |
4994 | Matches = &Microsoft; |
4995 | } else if (Variety == "Keyword" ) { |
4996 | Matches = &Keywords; |
4997 | } else if (Variety == "Pragma" ) { |
4998 | Matches = &Pragma; |
4999 | } else if (Variety == "HLSLAnnotation" ) { |
5000 | Matches = &HLSLAnnotation; |
5001 | if (RawSpelling.compare(RHS: RawSpelling.lower()) != 0) |
5002 | PrintError(ErrorLoc: S.getSpellingRecord().getLoc(), |
5003 | Msg: "HLSLAnnotation Attribute must be lower case." ); |
5004 | } |
5005 | |
5006 | assert(Matches && "Unsupported spelling variety found" ); |
5007 | |
5008 | if (Variety == "GNU" ) |
5009 | Spelling += NormalizeGNUAttrSpelling(AttrSpelling: RawSpelling); |
5010 | else |
5011 | Spelling += RawSpelling; |
5012 | |
5013 | if (SemaHandler) |
5014 | Matches->push_back(x: StringMatcher::StringPair( |
5015 | Spelling, "return AttributeCommonInfo::AT_" + AttrName + ";" )); |
5016 | else |
5017 | Matches->push_back(x: StringMatcher::StringPair( |
5018 | Spelling, "return AttributeCommonInfo::IgnoredAttribute;" )); |
5019 | } |
5020 | } |
5021 | } |
5022 | |
5023 | OS << "static AttributeCommonInfo::Kind getAttrKind(StringRef Name, " ; |
5024 | OS << "AttributeCommonInfo::Syntax Syntax) {\n" ; |
5025 | OS << " if (AttributeCommonInfo::AS_GNU == Syntax) {\n" ; |
5026 | StringMatcher("Name" , GNU, OS).Emit(); |
5027 | OS << " } else if (AttributeCommonInfo::AS_Declspec == Syntax) {\n" ; |
5028 | StringMatcher("Name" , Declspec, OS).Emit(); |
5029 | OS << " } else if (AttributeCommonInfo::AS_Microsoft == Syntax) {\n" ; |
5030 | StringMatcher("Name" , Microsoft, OS).Emit(); |
5031 | OS << " } else if (AttributeCommonInfo::AS_CXX11 == Syntax) {\n" ; |
5032 | StringMatcher("Name" , CXX11, OS).Emit(); |
5033 | OS << " } else if (AttributeCommonInfo::AS_C23 == Syntax) {\n" ; |
5034 | StringMatcher("Name" , C23, OS).Emit(); |
5035 | OS << " } else if (AttributeCommonInfo::AS_Keyword == Syntax || " ; |
5036 | OS << "AttributeCommonInfo::AS_ContextSensitiveKeyword == Syntax) {\n" ; |
5037 | StringMatcher("Name" , Keywords, OS).Emit(); |
5038 | OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n" ; |
5039 | StringMatcher("Name" , Pragma, OS).Emit(); |
5040 | OS << " } else if (AttributeCommonInfo::AS_HLSLAnnotation == Syntax) {\n" ; |
5041 | StringMatcher("Name" , HLSLAnnotation, OS).Emit(); |
5042 | OS << " }\n" ; |
5043 | OS << " return AttributeCommonInfo::UnknownAttribute;\n" |
5044 | << "}\n" ; |
5045 | } |
5046 | |
5047 | // Emits the code to dump an attribute. |
5048 | void EmitClangAttrTextNodeDump(const RecordKeeper &Records, raw_ostream &OS) { |
5049 | emitSourceFileHeader(Desc: "Attribute text node dumper" , OS, Record: Records); |
5050 | |
5051 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
5052 | const Record &R = *Attr; |
5053 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
5054 | continue; |
5055 | |
5056 | // If the attribute has a semantically-meaningful name (which is determined |
5057 | // by whether there is a Spelling enumeration for it), then write out the |
5058 | // spelling used for the attribute. |
5059 | |
5060 | std::string FunctionContent; |
5061 | raw_string_ostream SS(FunctionContent); |
5062 | |
5063 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: R); |
5064 | if (Spellings.size() > 1 && !SpellingNamesAreCommon(Spellings)) |
5065 | SS << " OS << \" \" << A->getSpelling();\n" ; |
5066 | |
5067 | std::vector<const Record *> Args = R.getValueAsListOfDefs(FieldName: "Args" ); |
5068 | for (const auto *Arg : Args) |
5069 | createArgument(Arg: *Arg, Attr: R.getName())->writeDump(OS&: SS); |
5070 | |
5071 | if (Attr->getValueAsBit(FieldName: "AcceptsExprPack" )) |
5072 | VariadicExprArgument("DelayedArgs" , R.getName()).writeDump(OS); |
5073 | |
5074 | if (SS.tell()) { |
5075 | OS << " void Visit" << R.getName() << "Attr(const " << R.getName() |
5076 | << "Attr *A) {\n" ; |
5077 | if (!Args.empty()) |
5078 | OS << " const auto *SA = cast<" << R.getName() |
5079 | << "Attr>(A); (void)SA;\n" ; |
5080 | OS << FunctionContent; |
5081 | OS << " }\n" ; |
5082 | } |
5083 | } |
5084 | } |
5085 | |
5086 | void EmitClangAttrNodeTraverse(const RecordKeeper &Records, raw_ostream &OS) { |
5087 | emitSourceFileHeader(Desc: "Attribute text node traverser" , OS, Record: Records); |
5088 | |
5089 | for (const auto *Attr : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
5090 | const Record &R = *Attr; |
5091 | if (!R.getValueAsBit(FieldName: "ASTNode" )) |
5092 | continue; |
5093 | |
5094 | std::string FunctionContent; |
5095 | raw_string_ostream SS(FunctionContent); |
5096 | |
5097 | std::vector<const Record *> Args = R.getValueAsListOfDefs(FieldName: "Args" ); |
5098 | for (const auto *Arg : Args) |
5099 | createArgument(Arg: *Arg, Attr: R.getName())->writeDumpChildren(OS&: SS); |
5100 | if (Attr->getValueAsBit(FieldName: "AcceptsExprPack" )) |
5101 | VariadicExprArgument("DelayedArgs" , R.getName()).writeDumpChildren(OS&: SS); |
5102 | if (SS.tell()) { |
5103 | OS << " void Visit" << R.getName() << "Attr(const " << R.getName() |
5104 | << "Attr *A) {\n" ; |
5105 | if (!Args.empty()) |
5106 | OS << " const auto *SA = cast<" << R.getName() |
5107 | << "Attr>(A); (void)SA;\n" ; |
5108 | OS << FunctionContent; |
5109 | OS << " }\n" ; |
5110 | } |
5111 | } |
5112 | } |
5113 | |
5114 | void EmitClangAttrParserStringSwitches(const RecordKeeper &Records, |
5115 | raw_ostream &OS) { |
5116 | generateNameToAttrsMap(Records); |
5117 | emitSourceFileHeader(Desc: "Parser-related llvm::StringSwitch cases" , OS, Record: Records); |
5118 | emitClangAttrArgContextList(Records, OS); |
5119 | emitClangAttrIdentifierArgList(Records, OS); |
5120 | emitClangAttrUnevaluatedStringLiteralList(Records, OS); |
5121 | emitClangAttrVariadicIdentifierArgList(Records, OS); |
5122 | emitClangAttrThisIsaIdentifierArgList(Records, OS); |
5123 | emitClangAttrAcceptsExprPack(Records, OS); |
5124 | emitClangAttrTypeArgList(Records, OS); |
5125 | emitClangAttrLateParsedList(Records, OS); |
5126 | emitClangAttrLateParsedExperimentalList(Records, OS); |
5127 | emitClangAttrStrictIdentifierArgList(Records, OS); |
5128 | } |
5129 | |
5130 | void EmitClangAttrSubjectMatchRulesParserStringSwitches( |
5131 | const RecordKeeper &Records, raw_ostream &OS) { |
5132 | getPragmaAttributeSupport(Records).generateParsingHelpers(OS); |
5133 | } |
5134 | |
5135 | void EmitClangAttrDocTable(const RecordKeeper &Records, raw_ostream &OS) { |
5136 | emitSourceFileHeader(Desc: "Clang attribute documentation" , OS, Record: Records); |
5137 | |
5138 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
5139 | if (!A->getValueAsBit(FieldName: "ASTNode" )) |
5140 | continue; |
5141 | std::vector<const Record *> Docs = A->getValueAsListOfDefs(FieldName: "Documentation" ); |
5142 | assert(!Docs.empty()); |
5143 | // Only look at the first documentation if there are several. |
5144 | // (Currently there's only one such attr, revisit if this becomes common). |
5145 | StringRef Text = |
5146 | Docs.front()->getValueAsOptionalString(FieldName: "Content" ).value_or(u: "" ); |
5147 | OS << "\nstatic const char AttrDoc_" << A->getName() << "[] = " |
5148 | << "R\"reST(" << Text.trim() << ")reST\";\n" ; |
5149 | } |
5150 | } |
5151 | |
5152 | enum class SpellingKind : size_t { |
5153 | GNU, |
5154 | CXX11, |
5155 | C23, |
5156 | Declspec, |
5157 | Microsoft, |
5158 | Keyword, |
5159 | Pragma, |
5160 | HLSLAnnotation, |
5161 | NumSpellingKinds |
5162 | }; |
5163 | static const size_t NumSpellingKinds = (size_t)SpellingKind::NumSpellingKinds; |
5164 | |
5165 | class SpellingList { |
5166 | std::vector<std::string> Spellings[NumSpellingKinds]; |
5167 | |
5168 | public: |
5169 | ArrayRef<std::string> operator[](SpellingKind K) const { |
5170 | return Spellings[(size_t)K]; |
5171 | } |
5172 | |
5173 | void add(const Record &Attr, FlattenedSpelling Spelling) { |
5174 | SpellingKind Kind = |
5175 | StringSwitch<SpellingKind>(Spelling.variety()) |
5176 | .Case(S: "GNU" , Value: SpellingKind::GNU) |
5177 | .Case(S: "CXX11" , Value: SpellingKind::CXX11) |
5178 | .Case(S: "C23" , Value: SpellingKind::C23) |
5179 | .Case(S: "Declspec" , Value: SpellingKind::Declspec) |
5180 | .Case(S: "Microsoft" , Value: SpellingKind::Microsoft) |
5181 | .Case(S: "Keyword" , Value: SpellingKind::Keyword) |
5182 | .Case(S: "Pragma" , Value: SpellingKind::Pragma) |
5183 | .Case(S: "HLSLAnnotation" , Value: SpellingKind::HLSLAnnotation); |
5184 | std::string Name; |
5185 | StringRef NameSpace = Spelling.nameSpace(); |
5186 | if (!NameSpace.empty()) { |
5187 | Name = NameSpace; |
5188 | switch (Kind) { |
5189 | case SpellingKind::CXX11: |
5190 | case SpellingKind::C23: |
5191 | Name += "::" ; |
5192 | break; |
5193 | case SpellingKind::Pragma: |
5194 | Name = " " ; |
5195 | break; |
5196 | default: |
5197 | PrintFatalError(ErrorLoc: Attr.getLoc(), Msg: "Unexpected namespace in spelling" ); |
5198 | } |
5199 | } |
5200 | Name += Spelling.name(); |
5201 | |
5202 | Spellings[(size_t)Kind].push_back(x: Name); |
5203 | } |
5204 | |
5205 | void merge(const SpellingList &Other) { |
5206 | for (size_t Kind = 0; Kind < NumSpellingKinds; ++Kind) { |
5207 | Spellings[Kind].insert(position: Spellings[Kind].end(), |
5208 | first: Other.Spellings[Kind].begin(), |
5209 | last: Other.Spellings[Kind].end()); |
5210 | } |
5211 | } |
5212 | }; |
5213 | |
5214 | class DocumentationData { |
5215 | public: |
5216 | const Record *Documentation; |
5217 | const Record *Attribute; |
5218 | std::string Heading; |
5219 | SpellingList SupportedSpellings; |
5220 | |
5221 | DocumentationData(const Record &Documentation, const Record &Attribute, |
5222 | std::pair<std::string, SpellingList> HeadingAndSpellings) |
5223 | : Documentation(&Documentation), Attribute(&Attribute), |
5224 | Heading(std::move(HeadingAndSpellings.first)), |
5225 | SupportedSpellings(std::move(HeadingAndSpellings.second)) {} |
5226 | }; |
5227 | |
5228 | static void (const Record *DocCategory, |
5229 | raw_ostream &OS) { |
5230 | const StringRef Name = DocCategory->getValueAsString(FieldName: "Name" ); |
5231 | OS << Name << "\n" << std::string(Name.size(), '=') << "\n" ; |
5232 | |
5233 | // If there is content, print that as well. |
5234 | const StringRef ContentStr = DocCategory->getValueAsString(FieldName: "Content" ); |
5235 | // Trim leading and trailing newlines and spaces. |
5236 | OS << ContentStr.trim(); |
5237 | |
5238 | OS << "\n\n" ; |
5239 | } |
5240 | |
5241 | static std::pair<std::string, SpellingList> |
5242 | GetAttributeHeadingAndSpellings(const Record &Documentation, |
5243 | const Record &Attribute, |
5244 | StringRef Cat) { |
5245 | // FIXME: there is no way to have a per-spelling category for the attribute |
5246 | // documentation. This may not be a limiting factor since the spellings |
5247 | // should generally be consistently applied across the category. |
5248 | |
5249 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: Attribute); |
5250 | if (Spellings.empty()) |
5251 | PrintFatalError(ErrorLoc: Attribute.getLoc(), |
5252 | Msg: "Attribute has no supported spellings; cannot be " |
5253 | "documented" ); |
5254 | |
5255 | // Determine the heading to be used for this attribute. |
5256 | std::string Heading = Documentation.getValueAsString(FieldName: "Heading" ).str(); |
5257 | if (Heading.empty()) { |
5258 | // If there's only one spelling, we can simply use that. |
5259 | if (Spellings.size() == 1) |
5260 | Heading = Spellings.begin()->name(); |
5261 | else { |
5262 | std::set<std::string> Uniques; |
5263 | for (const FlattenedSpelling &FS : Spellings) { |
5264 | std::string Spelling = |
5265 | NormalizeNameForSpellingComparison(Name: FS.name()).str(); |
5266 | Uniques.insert(x: Spelling); |
5267 | } |
5268 | // If the semantic map has only one spelling, that is sufficient for our |
5269 | // needs. |
5270 | if (Uniques.size() == 1) |
5271 | Heading = *Uniques.begin(); |
5272 | // If it's in the undocumented category, just construct a header by |
5273 | // concatenating all the spellings. Might not be great, but better than |
5274 | // nothing. |
5275 | else if (Cat == "Undocumented" ) |
5276 | Heading = join(Begin: Uniques.begin(), End: Uniques.end(), Separator: ", " ); |
5277 | } |
5278 | } |
5279 | |
5280 | // If the heading is still empty, it is an error. |
5281 | if (Heading.empty()) |
5282 | PrintFatalError(ErrorLoc: Attribute.getLoc(), |
5283 | Msg: "This attribute requires a heading to be specified" ); |
5284 | |
5285 | SpellingList SupportedSpellings; |
5286 | for (const auto &I : Spellings) |
5287 | SupportedSpellings.add(Attr: Attribute, Spelling: I); |
5288 | |
5289 | return std::make_pair(x: std::move(Heading), y: std::move(SupportedSpellings)); |
5290 | } |
5291 | |
5292 | static void WriteDocumentation(const RecordKeeper &Records, |
5293 | const DocumentationData &Doc, raw_ostream &OS) { |
5294 | if (StringRef Label = Doc.Documentation->getValueAsString(FieldName: "Label" ); |
5295 | !Label.empty()) |
5296 | OS << ".. _" << Label << ":\n\n" ; |
5297 | OS << Doc.Heading << "\n" << std::string(Doc.Heading.length(), '-') << "\n" ; |
5298 | |
5299 | // List what spelling syntaxes the attribute supports. |
5300 | // Note: "#pragma clang attribute" is handled outside the spelling kinds loop |
5301 | // so it must be last. |
5302 | OS << ".. csv-table:: Supported Syntaxes\n" ; |
5303 | OS << " :header: \"GNU\", \"C++11\", \"C23\", \"``__declspec``\"," ; |
5304 | OS << " \"Keyword\", \"``#pragma``\", \"HLSL Annotation\", \"``#pragma " |
5305 | "clang " ; |
5306 | OS << "attribute``\"\n\n \"" ; |
5307 | for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) { |
5308 | SpellingKind K = (SpellingKind)Kind; |
5309 | // TODO: List Microsoft (IDL-style attribute) spellings once we fully |
5310 | // support them. |
5311 | if (K == SpellingKind::Microsoft) |
5312 | continue; |
5313 | |
5314 | bool PrintedAny = false; |
5315 | for (StringRef Spelling : Doc.SupportedSpellings[K]) { |
5316 | if (PrintedAny) |
5317 | OS << " |br| " ; |
5318 | OS << "``" << Spelling << "``" ; |
5319 | PrintedAny = true; |
5320 | } |
5321 | |
5322 | OS << "\",\"" ; |
5323 | } |
5324 | |
5325 | if (getPragmaAttributeSupport(Records).isAttributedSupported( |
5326 | Attribute: *Doc.Attribute)) |
5327 | OS << "Yes" ; |
5328 | OS << "\"\n\n" ; |
5329 | |
5330 | // If the attribute is deprecated, print a message about it, and possibly |
5331 | // provide a replacement attribute. |
5332 | if (!Doc.Documentation->isValueUnset(FieldName: "Deprecated" )) { |
5333 | OS << "This attribute has been deprecated, and may be removed in a future " |
5334 | << "version of Clang." ; |
5335 | const Record &Deprecated = *Doc.Documentation->getValueAsDef(FieldName: "Deprecated" ); |
5336 | const StringRef Replacement = Deprecated.getValueAsString(FieldName: "Replacement" ); |
5337 | if (!Replacement.empty()) |
5338 | OS << " This attribute has been superseded by ``" << Replacement |
5339 | << "``." ; |
5340 | OS << "\n\n" ; |
5341 | } |
5342 | |
5343 | const StringRef ContentStr = Doc.Documentation->getValueAsString(FieldName: "Content" ); |
5344 | // Trim leading and trailing newlines and spaces. |
5345 | OS << ContentStr.trim(); |
5346 | |
5347 | OS << "\n\n\n" ; |
5348 | } |
5349 | |
5350 | void EmitClangAttrDocs(const RecordKeeper &Records, raw_ostream &OS) { |
5351 | // Get the documentation introduction paragraph. |
5352 | const Record *Documentation = Records.getDef(Name: "GlobalDocumentation" ); |
5353 | if (!Documentation) { |
5354 | PrintFatalError(Msg: "The Documentation top-level definition is missing, " |
5355 | "no documentation will be generated." ); |
5356 | return; |
5357 | } |
5358 | |
5359 | OS << Documentation->getValueAsString(FieldName: "Intro" ) << "\n" ; |
5360 | |
5361 | // Gather the Documentation lists from each of the attributes, based on the |
5362 | // category provided. |
5363 | struct CategoryLess { |
5364 | bool operator()(const Record *L, const Record *R) const { |
5365 | return L->getValueAsString(FieldName: "Name" ) < R->getValueAsString(FieldName: "Name" ); |
5366 | } |
5367 | }; |
5368 | |
5369 | std::map<const Record *, std::map<uint32_t, DocumentationData>, CategoryLess> |
5370 | MergedDocs; |
5371 | |
5372 | std::vector<DocumentationData> UndocumentedDocs; |
5373 | const Record *UndocumentedCategory = nullptr; |
5374 | |
5375 | // Collect documentation data, grouping by category and heading. |
5376 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr" )) { |
5377 | const Record &Attr = *A; |
5378 | std::vector<const Record *> Docs = |
5379 | Attr.getValueAsListOfDefs(FieldName: "Documentation" ); |
5380 | |
5381 | for (const auto *D : Docs) { |
5382 | const Record &Doc = *D; |
5383 | const Record *Category = Doc.getValueAsDef(FieldName: "Category" ); |
5384 | // If the category is "InternalOnly", then there cannot be any other |
5385 | // documentation categories (otherwise, the attribute would be |
5386 | // emitted into the docs). |
5387 | StringRef Cat = Category->getValueAsString(FieldName: "Name" ); |
5388 | if (Cat == "InternalOnly" && Docs.size() > 1) |
5389 | PrintFatalError(ErrorLoc: Doc.getLoc(), |
5390 | Msg: "Attribute is \"InternalOnly\", but has multiple " |
5391 | "documentation categories" ); |
5392 | |
5393 | if (Cat == "InternalOnly" ) |
5394 | continue; |
5395 | |
5396 | // Track the Undocumented category Record for later grouping |
5397 | if (Cat == "Undocumented" && !UndocumentedCategory) |
5398 | UndocumentedCategory = Category; |
5399 | |
5400 | // Generate Heading and Spellings. |
5401 | auto HeadingAndSpellings = |
5402 | GetAttributeHeadingAndSpellings(Documentation: Doc, Attribute: Attr, Cat); |
5403 | |
5404 | // Handle Undocumented category separately - no content merging |
5405 | if (Cat == "Undocumented" && UndocumentedCategory) { |
5406 | UndocumentedDocs.push_back( |
5407 | x: DocumentationData(Doc, Attr, std::move(HeadingAndSpellings))); |
5408 | continue; |
5409 | } |
5410 | |
5411 | auto &CategoryDocs = MergedDocs[Category]; |
5412 | |
5413 | std::string key = Doc.getValueAsString(FieldName: "Content" ).str(); |
5414 | uint32_t keyHash = llvm::hash_value(arg: key); |
5415 | |
5416 | // If the content already exists, merge the documentation. |
5417 | auto It = CategoryDocs.find(x: keyHash); |
5418 | if (It != CategoryDocs.end()) { |
5419 | // Merge heading |
5420 | if (It->second.Heading != HeadingAndSpellings.first) |
5421 | It->second.Heading += ", " + HeadingAndSpellings.first; |
5422 | // Merge spellings |
5423 | It->second.SupportedSpellings.merge(Other: HeadingAndSpellings.second); |
5424 | // Merge content |
5425 | It->second.Documentation = &Doc; // Update reference |
5426 | } else { |
5427 | // Create new entry for unique content |
5428 | CategoryDocs.emplace(args&: keyHash, |
5429 | args: DocumentationData(Doc, Attr, HeadingAndSpellings)); |
5430 | } |
5431 | } |
5432 | } |
5433 | |
5434 | std::map<const Record *, std::vector<DocumentationData>, CategoryLess> |
5435 | SplitDocs; |
5436 | |
5437 | for (auto &CategoryPair : MergedDocs) { |
5438 | |
5439 | std::vector<DocumentationData> MD; |
5440 | for (auto &DocPair : CategoryPair.second) |
5441 | MD.push_back(x: std::move(DocPair.second)); |
5442 | |
5443 | SplitDocs.emplace(args: CategoryPair.first, args&: MD); |
5444 | } |
5445 | |
5446 | // Append Undocumented category entries |
5447 | if (!UndocumentedDocs.empty() && UndocumentedCategory) { |
5448 | SplitDocs.emplace(args&: UndocumentedCategory, args&: UndocumentedDocs); |
5449 | } |
5450 | |
5451 | // Having split the attributes out based on what documentation goes where, |
5452 | // we can begin to generate sections of documentation. |
5453 | for (auto &I : SplitDocs) { |
5454 | WriteCategoryHeader(DocCategory: I.first, OS); |
5455 | |
5456 | sort(C&: I.second, |
5457 | Comp: [](const DocumentationData &D1, const DocumentationData &D2) { |
5458 | return D1.Heading < D2.Heading; |
5459 | }); |
5460 | |
5461 | // Walk over each of the attributes in the category and write out their |
5462 | // documentation. |
5463 | for (const auto &Doc : I.second) |
5464 | WriteDocumentation(Records, Doc, OS); |
5465 | } |
5466 | } |
5467 | |
5468 | void EmitTestPragmaAttributeSupportedAttributes(const RecordKeeper &Records, |
5469 | raw_ostream &OS) { |
5470 | PragmaClangAttributeSupport Support = getPragmaAttributeSupport(Records); |
5471 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
5472 | OS << "#pragma clang attribute supports the following attributes:\n" ; |
5473 | for (const auto &I : Attrs) { |
5474 | if (!Support.isAttributedSupported(Attribute: *I.second)) |
5475 | continue; |
5476 | OS << I.first; |
5477 | if (I.second->isValueUnset(FieldName: "Subjects" )) { |
5478 | OS << " ()\n" ; |
5479 | continue; |
5480 | } |
5481 | const Record *SubjectObj = I.second->getValueAsDef(FieldName: "Subjects" ); |
5482 | OS << " (" ; |
5483 | ListSeparator LS; |
5484 | for (const auto &Subject : |
5485 | enumerate(First: SubjectObj->getValueAsListOfDefs(FieldName: "Subjects" ))) { |
5486 | if (!isSupportedPragmaClangAttributeSubject(Subject: *Subject.value())) |
5487 | continue; |
5488 | OS << LS; |
5489 | PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet = |
5490 | Support.SubjectsToRules.find(Val: Subject.value())->getSecond(); |
5491 | if (RuleSet.isRule()) { |
5492 | OS << RuleSet.getRule().getEnumValueName(); |
5493 | continue; |
5494 | } |
5495 | OS << "(" ; |
5496 | for (const auto &Rule : enumerate(First: RuleSet.getAggregateRuleSet())) { |
5497 | if (Rule.index()) |
5498 | OS << ", " ; |
5499 | OS << Rule.value().getEnumValueName(); |
5500 | } |
5501 | OS << ")" ; |
5502 | } |
5503 | OS << ")\n" ; |
5504 | } |
5505 | OS << "End of supported attributes.\n" ; |
5506 | } |
5507 | |
5508 | } // end namespace clang |
5509 | |