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 Header) 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 Header) 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 Header) { |
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 | else |
3745 | TestStringMap[Spelling.name()] = TestStr; |
3746 | } |
3747 | } |
3748 | |
3749 | // Create the actual string switch statement after all the attributes have |
3750 | // been parsed. |
3751 | for (auto &Entry : TestStringMap) { |
3752 | OS << " .Case(\""<< Entry.getKey() << "\", "<< Entry.getValue() |
3753 | << ")\n"; |
3754 | } |
3755 | |
3756 | OS << " .Default(0);\n"; |
3757 | } |
3758 | |
3759 | namespace clang { |
3760 | |
3761 | // Emits list of regular keyword attributes with info about their arguments. |
3762 | void EmitClangRegularKeywordAttributeInfo(const RecordKeeper &Records, |
3763 | raw_ostream &OS) { |
3764 | emitSourceFileHeader( |
3765 | Desc: "A list of regular keyword attributes generated from the attribute" |
3766 | " definitions", |
3767 | OS); |
3768 | // Assume for now that the same token is not used in multiple regular |
3769 | // keyword attributes. |
3770 | for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Attr")) |
3771 | for (const auto &S : GetFlattenedSpellings(Attr: *R)) { |
3772 | if (!isRegularKeywordAttribute(S)) |
3773 | continue; |
3774 | std::vector<const Record *> Args = R->getValueAsListOfDefs(FieldName: "Args"); |
3775 | bool HasArgs = any_of( |
3776 | Range&: Args, P: [](const Record *Arg) { return !Arg->getValueAsBit(FieldName: "Fake"); }); |
3777 | |
3778 | OS << "KEYWORD_ATTRIBUTE(" |
3779 | << S.getSpellingRecord().getValueAsString(FieldName: "Name") << ", " |
3780 | << (HasArgs ? "true": "false") << ", )\n"; |
3781 | } |
3782 | OS << "#undef KEYWORD_ATTRIBUTE\n"; |
3783 | } |
3784 | |
3785 | void EmitCXX11AttributeInfo(const RecordKeeper &Records, raw_ostream &OS) { |
3786 | OS << "#if defined(CXX11_ATTR_ARGS_INFO)\n"; |
3787 | for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Attr")) { |
3788 | for (const FlattenedSpelling &SI : GetFlattenedSpellings(Attr: *R)) { |
3789 | if (SI.variety() == "CXX11"&& SI.nameSpace().empty()) { |
3790 | unsigned RequiredArgs = 0; |
3791 | unsigned OptionalArgs = 0; |
3792 | for (const auto *Arg : R->getValueAsListOfDefs(FieldName: "Args")) { |
3793 | if (Arg->getValueAsBit(FieldName: "Fake")) |
3794 | continue; |
3795 | |
3796 | if (Arg->getValueAsBit(FieldName: "Optional")) |
3797 | OptionalArgs++; |
3798 | else |
3799 | RequiredArgs++; |
3800 | } |
3801 | OS << ".Case(\""<< SI.getSpellingRecord().getValueAsString(FieldName: "Name") |
3802 | << "\"," |
3803 | << "AttributeCommonInfo::AttrArgsInfo::" |
3804 | << (RequiredArgs ? "Required" |
3805 | : OptionalArgs ? "Optional" |
3806 | : "None") |
3807 | << ")" |
3808 | << "\n"; |
3809 | } |
3810 | } |
3811 | } |
3812 | OS << "#endif // CXX11_ATTR_ARGS_INFO\n"; |
3813 | } |
3814 | |
3815 | // Emits the list of spellings for attributes. |
3816 | void EmitClangAttrHasAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { |
3817 | emitSourceFileHeader(Desc: "Code to implement the __has_attribute logic", OS, |
3818 | Record: Records); |
3819 | |
3820 | // Separate all of the attributes out into four group: generic, C++11, GNU, |
3821 | // and declspecs. Then generate a big switch statement for each of them. |
3822 | using PairTy = std::pair<const Record *, FlattenedSpelling>; |
3823 | std::vector<PairTy> Declspec, Microsoft, GNU, Pragma, HLSLAnnotation; |
3824 | std::map<StringRef, std::vector<PairTy>> CXX, C23; |
3825 | |
3826 | // Walk over the list of all attributes, and split them out based on the |
3827 | // spelling variety. |
3828 | for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Attr")) { |
3829 | for (const FlattenedSpelling &SI : GetFlattenedSpellings(Attr: *R)) { |
3830 | StringRef Variety = SI.variety(); |
3831 | if (Variety == "GNU") |
3832 | GNU.emplace_back(args&: R, args: SI); |
3833 | else if (Variety == "Declspec") |
3834 | Declspec.emplace_back(args&: R, args: SI); |
3835 | else if (Variety == "Microsoft") |
3836 | Microsoft.emplace_back(args&: R, args: SI); |
3837 | else if (Variety == "CXX11") |
3838 | CXX[SI.nameSpace()].emplace_back(args&: R, args: SI); |
3839 | else if (Variety == "C23") |
3840 | C23[SI.nameSpace()].emplace_back(args&: R, args: SI); |
3841 | else if (Variety == "Pragma") |
3842 | Pragma.emplace_back(args&: R, args: SI); |
3843 | else if (Variety == "HLSLAnnotation") |
3844 | HLSLAnnotation.emplace_back(args&: R, args: SI); |
3845 | } |
3846 | } |
3847 | |
3848 | OS << "const llvm::Triple &T = Target.getTriple();\n"; |
3849 | OS << "switch (Syntax) {\n"; |
3850 | OS << "case AttributeCommonInfo::Syntax::AS_GNU:\n"; |
3851 | OS << " return llvm::StringSwitch<int>(Name)\n"; |
3852 | GenerateHasAttrSpellingStringSwitch(Attrs: GNU, OS, Variety: "GNU"); |
3853 | OS << "case AttributeCommonInfo::Syntax::AS_Declspec:\n"; |
3854 | OS << " return llvm::StringSwitch<int>(Name)\n"; |
3855 | GenerateHasAttrSpellingStringSwitch(Attrs: Declspec, OS, Variety: "Declspec"); |
3856 | OS << "case AttributeCommonInfo::Syntax::AS_Microsoft:\n"; |
3857 | OS << " return llvm::StringSwitch<int>(Name)\n"; |
3858 | GenerateHasAttrSpellingStringSwitch(Attrs: Microsoft, OS, Variety: "Microsoft"); |
3859 | OS << "case AttributeCommonInfo::Syntax::AS_Pragma:\n"; |
3860 | OS << " return llvm::StringSwitch<int>(Name)\n"; |
3861 | GenerateHasAttrSpellingStringSwitch(Attrs: Pragma, OS, Variety: "Pragma"); |
3862 | OS << "case AttributeCommonInfo::Syntax::AS_HLSLAnnotation:\n"; |
3863 | OS << " return llvm::StringSwitch<int>(Name)\n"; |
3864 | GenerateHasAttrSpellingStringSwitch(Attrs: HLSLAnnotation, OS, Variety: "HLSLAnnotation"); |
3865 | auto fn = [&OS](StringRef Spelling, |
3866 | const std::map<StringRef, std::vector<PairTy>> &Map) { |
3867 | OS << "case AttributeCommonInfo::Syntax::AS_"<< Spelling << ": {\n"; |
3868 | // C++11-style attributes are further split out based on the Scope. |
3869 | ListSeparator LS(" else "); |
3870 | for (const auto &[Scope, List] : Map) { |
3871 | OS << LS; |
3872 | OS << "if (ScopeName == \""<< Scope << "\") {\n"; |
3873 | OS << " return llvm::StringSwitch<int>(Name)\n"; |
3874 | GenerateHasAttrSpellingStringSwitch(Attrs: List, OS, Variety: Spelling, Scope); |
3875 | OS << "}"; |
3876 | } |
3877 | OS << "\n} break;\n"; |
3878 | }; |
3879 | fn("CXX11", CXX); |
3880 | fn("C23", C23); |
3881 | OS << "case AttributeCommonInfo::Syntax::AS_Keyword:\n"; |
3882 | OS << "case AttributeCommonInfo::Syntax::AS_ContextSensitiveKeyword:\n"; |
3883 | OS << " llvm_unreachable(\"hasAttribute not supported for keyword\");\n"; |
3884 | OS << " return 0;\n"; |
3885 | OS << "case AttributeCommonInfo::Syntax::AS_Implicit:\n"; |
3886 | OS << " llvm_unreachable (\"hasAttribute not supported for " |
3887 | "AS_Implicit\");\n"; |
3888 | OS << " return 0;\n"; |
3889 | |
3890 | OS << "}\n"; |
3891 | } |
3892 | |
3893 | void EmitClangAttrSpellingListIndex(const RecordKeeper &Records, |
3894 | raw_ostream &OS) { |
3895 | emitSourceFileHeader(Desc: "Code to translate different attribute spellings into " |
3896 | "internal identifiers", |
3897 | OS, Record: Records); |
3898 | |
3899 | OS << " switch (getParsedKind()) {\n"; |
3900 | OS << " case IgnoredAttribute:\n"; |
3901 | OS << " case UnknownAttribute:\n"; |
3902 | OS << " case NoSemaHandlerAttribute:\n"; |
3903 | OS << " llvm_unreachable(\"Ignored/unknown shouldn't get here\");\n"; |
3904 | |
3905 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
3906 | for (const auto &I : Attrs) { |
3907 | const Record &R = *I.second; |
3908 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr: R); |
3909 | OS << " case AT_"<< I.first << ": {\n"; |
3910 | |
3911 | // If there are none or one spelling to check, resort to the default |
3912 | // behavior of returning index as 0. |
3913 | if (Spellings.size() <= 1) { |
3914 | OS << " return 0;\n" |
3915 | << " break;\n" |
3916 | << " }\n"; |
3917 | continue; |
3918 | } |
3919 | |
3920 | std::vector<StringRef> Names; |
3921 | llvm::transform(Range&: Spellings, d_first: std::back_inserter(x&: Names), |
3922 | F: [](const FlattenedSpelling &FS) { return FS.name(); }); |
3923 | llvm::sort(C&: Names); |
3924 | Names.erase(first: llvm::unique(R&: Names), last: Names.end()); |
3925 | |
3926 | for (const auto &[Idx, FS] : enumerate(First&: Spellings)) { |
3927 | OS << " if ("; |
3928 | if (Names.size() > 1) { |
3929 | SmallVector<StringRef, 6> SameLenNames; |
3930 | StringRef FSName = FS.name(); |
3931 | llvm::copy_if( |
3932 | Range&: Names, Out: std::back_inserter(x&: SameLenNames), |
3933 | P: [&](StringRef N) { return N.size() == FSName.size(); }); |
3934 | |
3935 | if (SameLenNames.size() == 1) { |
3936 | OS << "Name.size() == "<< FS.name().size() << " && "; |
3937 | } else { |
3938 | // FIXME: We currently fall back to comparing entire strings if there |
3939 | // are 2 or more spelling names with the same length. This can be |
3940 | // optimized to check only for the the first differing character |
3941 | // between them instead. |
3942 | OS << "Name == \""<< FS.name() << "\"" |
3943 | << " && "; |
3944 | } |
3945 | } |
3946 | |
3947 | OS << "getSyntax() == AttributeCommonInfo::AS_"<< FS.variety() |
3948 | << " && ComputedScope == "; |
3949 | if (FS.nameSpace() == "") |
3950 | OS << "AttributeCommonInfo::Scope::NONE"; |
3951 | else |
3952 | OS << "AttributeCommonInfo::Scope::"+ FS.nameSpace().upper(); |
3953 | |
3954 | OS << ")\n" |
3955 | << " return "<< Idx << ";\n"; |
3956 | } |
3957 | |
3958 | OS << " break;\n" |
3959 | << " }\n"; |
3960 | } |
3961 | |
3962 | OS << " }\n" |
3963 | << " return 0;\n"; |
3964 | } |
3965 | |
3966 | // Emits code used by RecursiveASTVisitor to visit attributes |
3967 | void EmitClangAttrASTVisitor(const RecordKeeper &Records, raw_ostream &OS) { |
3968 | emitSourceFileHeader(Desc: "Used by RecursiveASTVisitor to visit attributes.", OS, |
3969 | Record: Records); |
3970 | // Write method declarations for Traverse* methods. |
3971 | // We emit this here because we only generate methods for attributes that |
3972 | // are declared as ASTNodes. |
3973 | OS << "#ifdef ATTR_VISITOR_DECLS_ONLY\n\n"; |
3974 | ArrayRef<const Record *> Attrs = Records.getAllDerivedDefinitions(ClassName: "Attr"); |
3975 | for (const auto *Attr : Attrs) { |
3976 | const Record &R = *Attr; |
3977 | if (!R.getValueAsBit(FieldName: "ASTNode")) |
3978 | continue; |
3979 | OS << " bool Traverse" |
3980 | << R.getName() << "Attr("<< R.getName() << "Attr *A);\n"; |
3981 | OS << " bool Visit" |
3982 | << R.getName() << "Attr("<< R.getName() << "Attr *A) {\n" |
3983 | << " return true; \n" |
3984 | << " }\n"; |
3985 | } |
3986 | OS << "\n#else // ATTR_VISITOR_DECLS_ONLY\n\n"; |
3987 | |
3988 | // Write individual Traverse* methods for each attribute class. |
3989 | for (const auto *Attr : Attrs) { |
3990 | const Record &R = *Attr; |
3991 | if (!R.getValueAsBit(FieldName: "ASTNode")) |
3992 | continue; |
3993 | |
3994 | OS << "template <typename Derived>\n" |
3995 | << "bool VISITORCLASS<Derived>::Traverse" |
3996 | << R.getName() << "Attr("<< R.getName() << "Attr *A) {\n" |
3997 | << " if (!getDerived().VisitAttr(A))\n" |
3998 | << " return false;\n" |
3999 | << " if (!getDerived().Visit"<< R.getName() << "Attr(A))\n" |
4000 | << " return false;\n"; |
4001 | |
4002 | for (const auto *Arg : R.getValueAsListOfDefs(FieldName: "Args")) |
4003 | createArgument(Arg: *Arg, Attr: R.getName())->writeASTVisitorTraversal(OS); |
4004 | |
4005 | if (Attr->getValueAsBit(FieldName: "AcceptsExprPack")) |
4006 | VariadicExprArgument("DelayedArgs", R.getName()) |
4007 | .writeASTVisitorTraversal(OS); |
4008 | |
4009 | OS << " return true;\n"; |
4010 | OS << "}\n\n"; |
4011 | } |
4012 | |
4013 | // Write generic Traverse routine |
4014 | OS << "template <typename Derived>\n" |
4015 | << "bool VISITORCLASS<Derived>::TraverseAttr(Attr *A) {\n" |
4016 | << " if (!A)\n" |
4017 | << " return true;\n" |
4018 | << "\n" |
4019 | << " switch (A->getKind()) {\n"; |
4020 | |
4021 | for (const auto *Attr : Attrs) { |
4022 | const Record &R = *Attr; |
4023 | if (!R.getValueAsBit(FieldName: "ASTNode")) |
4024 | continue; |
4025 | |
4026 | OS << " case attr::"<< R.getName() << ":\n" |
4027 | << " return getDerived().Traverse"<< R.getName() << "Attr(" |
4028 | << "cast<"<< R.getName() << "Attr>(A));\n"; |
4029 | } |
4030 | OS << " }\n"; // end switch |
4031 | OS << " llvm_unreachable(\"bad attribute kind\");\n"; |
4032 | OS << "}\n"; // end function |
4033 | OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n"; |
4034 | } |
4035 | |
4036 | static void |
4037 | EmitClangAttrTemplateInstantiateHelper(ArrayRef<const Record *> Attrs, |
4038 | raw_ostream &OS, bool AppliesToDecl) { |
4039 | |
4040 | OS << " switch (At->getKind()) {\n"; |
4041 | for (const auto *Attr : Attrs) { |
4042 | const Record &R = *Attr; |
4043 | if (!R.getValueAsBit(FieldName: "ASTNode")) |
4044 | continue; |
4045 | OS << " case attr::"<< R.getName() << ": {\n"; |
4046 | bool ShouldClone = R.getValueAsBit(FieldName: "Clone") && |
4047 | (!AppliesToDecl || |
4048 | R.getValueAsBit(FieldName: "MeaningfulToClassTemplateDefinition")); |
4049 | |
4050 | if (!ShouldClone) { |
4051 | OS << " return nullptr;\n"; |
4052 | OS << " }\n"; |
4053 | continue; |
4054 | } |
4055 | |
4056 | OS << " const auto *A = cast<" |
4057 | << R.getName() << "Attr>(At);\n"; |
4058 | bool TDependent = R.getValueAsBit(FieldName: "TemplateDependent"); |
4059 | |
4060 | if (!TDependent) { |
4061 | OS << " return A->clone(C);\n"; |
4062 | OS << " }\n"; |
4063 | continue; |
4064 | } |
4065 | |
4066 | std::vector<const Record *> ArgRecords = R.getValueAsListOfDefs(FieldName: "Args"); |
4067 | std::vector<std::unique_ptr<Argument>> Args; |
4068 | Args.reserve(n: ArgRecords.size()); |
4069 | |
4070 | for (const auto *ArgRecord : ArgRecords) |
4071 | Args.emplace_back(args: createArgument(Arg: *ArgRecord, Attr: R.getName())); |
4072 | |
4073 | for (auto const &ai : Args) |
4074 | ai->writeTemplateInstantiation(OS); |
4075 | |
4076 | OS << " return new (C) "<< R.getName() << "Attr(C, *A"; |
4077 | for (auto const &ai : Args) { |
4078 | OS << ", "; |
4079 | ai->writeTemplateInstantiationArgs(OS); |
4080 | } |
4081 | OS << ");\n" |
4082 | << " }\n"; |
4083 | } |
4084 | OS << " } // end switch\n" |
4085 | << " llvm_unreachable(\"Unknown attribute!\");\n" |
4086 | << " return nullptr;\n"; |
4087 | } |
4088 | |
4089 | // Emits code to instantiate dependent attributes on templates. |
4090 | void EmitClangAttrTemplateInstantiate(const RecordKeeper &Records, |
4091 | raw_ostream &OS) { |
4092 | emitSourceFileHeader(Desc: "Template instantiation code for attributes", OS, |
4093 | Record: Records); |
4094 | |
4095 | ArrayRef<const Record *> Attrs = Records.getAllDerivedDefinitions(ClassName: "Attr"); |
4096 | |
4097 | OS << "namespace clang {\n" |
4098 | << "namespace sema {\n\n" |
4099 | << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " |
4100 | << "Sema &S,\n" |
4101 | << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; |
4102 | EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false); |
4103 | OS << "}\n\n" |
4104 | << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n" |
4105 | << " ASTContext &C, Sema &S,\n" |
4106 | << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; |
4107 | EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true); |
4108 | OS << "}\n\n" |
4109 | << "} // end namespace sema\n" |
4110 | << "} // end namespace clang\n"; |
4111 | } |
4112 | |
4113 | // Emits the list of parsed attributes. |
4114 | void EmitClangAttrParsedAttrList(const RecordKeeper &Records, raw_ostream &OS) { |
4115 | emitSourceFileHeader(Desc: "List of all attributes that Clang recognizes", OS, |
4116 | Record: Records); |
4117 | |
4118 | OS << "#ifndef PARSED_ATTR\n"; |
4119 | OS << "#define PARSED_ATTR(NAME) NAME\n"; |
4120 | OS << "#endif\n\n"; |
4121 | |
4122 | ParsedAttrMap Names = getParsedAttrList(Records); |
4123 | for (const auto &I : Names) { |
4124 | OS << "PARSED_ATTR("<< I.first << ")\n"; |
4125 | } |
4126 | } |
4127 | |
4128 | void EmitAttributeSpellingList(const RecordKeeper &Records, raw_ostream &OS) { |
4129 | emitSourceFileHeader(Desc: "List of attribute names", OS, Record: Records); |
4130 | |
4131 | std::set<StringRef> AttrSpellingList; |
4132 | std::set<StringRef> AttrScopeSpellingList; |
4133 | |
4134 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr")) { |
4135 | for (const auto &S : GetFlattenedSpellings(Attr: *A)) { |
4136 | AttrSpellingList.insert(x: S.name()); |
4137 | if (S.nameSpace().size()) |
4138 | AttrScopeSpellingList.insert(x: S.nameSpace()); |
4139 | } |
4140 | } |
4141 | |
4142 | OS << "#ifndef ATTR_NAME"<< "\n"; |
4143 | OS << "#define ATTR_NAME(NAME) NAME"<< "\n"; |
4144 | OS << "#endif"<< "\n"<< "\n"; |
4145 | for (const auto &AttrName : AttrSpellingList) { |
4146 | OS << "ATTR_NAME(\""<< AttrName << "\")\n"; |
4147 | } |
4148 | OS << "\n"; |
4149 | OS << "#undef ATTR_NAME"<< "\n"; |
4150 | OS << "\n"; |
4151 | |
4152 | OS << "#ifndef ATTR_SCOPE_NAME"<< "\n"; |
4153 | OS << "#define ATTR_SCOPE_NAME(SCOPE_NAME) SCOPE_NAME"<< "\n"; |
4154 | OS << "#endif"<< "\n"<< "\n"; |
4155 | for (const auto &AttrScopeName : AttrScopeSpellingList) { |
4156 | OS << "ATTR_SCOPE_NAME(\""<< AttrScopeName << "\")\n"; |
4157 | } |
4158 | OS << "\n"; |
4159 | OS << "#undef ATTR_SCOPE_NAME"<< "\n"; |
4160 | OS << "\n"; |
4161 | } |
4162 | |
4163 | static bool isArgVariadic(const Record &R, StringRef AttrName) { |
4164 | return createArgument(Arg: R, Attr: AttrName)->isVariadic(); |
4165 | } |
4166 | |
4167 | static void emitArgInfo(const Record &R, raw_ostream &OS) { |
4168 | // This function will count the number of arguments specified for the |
4169 | // attribute and emit the number of required arguments followed by the |
4170 | // number of optional arguments. |
4171 | unsigned ArgCount = 0, OptCount = 0, ArgMemberCount = 0; |
4172 | bool HasVariadic = false; |
4173 | for (const auto *Arg : R.getValueAsListOfDefs(FieldName: "Args")) { |
4174 | // If the arg is fake, it's the user's job to supply it: general parsing |
4175 | // logic shouldn't need to know anything about it. |
4176 | if (Arg->getValueAsBit(FieldName: "Fake")) |
4177 | continue; |
4178 | Arg->getValueAsBit(FieldName: "Optional") ? ++OptCount : ++ArgCount; |
4179 | ++ArgMemberCount; |
4180 | if (!HasVariadic && isArgVariadic(R: *Arg, AttrName: R.getName())) |
4181 | HasVariadic = true; |
4182 | } |
4183 | |
4184 | // If there is a variadic argument, we will set the optional argument count |
4185 | // to its largest value. Since it's currently a 4-bit number, we set it to 15. |
4186 | OS << " /*NumArgs=*/"<< ArgCount << ",\n"; |
4187 | OS << " /*OptArgs=*/"<< (HasVariadic ? 15 : OptCount) << ",\n"; |
4188 | OS << " /*NumArgMembers=*/"<< ArgMemberCount << ",\n"; |
4189 | } |
4190 | |
4191 | static std::string GetDiagnosticSpelling(const Record &R) { |
4192 | StringRef Ret = R.getValueAsString(FieldName: "DiagSpelling"); |
4193 | if (!Ret.empty()) |
4194 | return Ret.str(); |
4195 | |
4196 | // If we couldn't find the DiagSpelling in this object, we can check to see |
4197 | // if the object is one that has a base, and if it is, loop up to the Base |
4198 | // member recursively. |
4199 | if (auto Base = R.getValueAsOptionalDef(BaseFieldName)) |
4200 | return GetDiagnosticSpelling(R: *Base); |
4201 | |
4202 | return ""; |
4203 | } |
4204 | |
4205 | static std::string CalculateDiagnostic(const Record &S) { |
4206 | // If the SubjectList object has a custom diagnostic associated with it, |
4207 | // return that directly. |
4208 | const StringRef CustomDiag = S.getValueAsString(FieldName: "CustomDiag"); |
4209 | if (!CustomDiag.empty()) |
4210 | return ("\""+ Twine(CustomDiag) + "\"").str(); |
4211 | |
4212 | std::vector<std::string> DiagList; |
4213 | for (const auto *Subject : S.getValueAsListOfDefs(FieldName: "Subjects")) { |
4214 | const Record &R = *Subject; |
4215 | // Get the diagnostic text from the Decl or Stmt node given. |
4216 | std::string V = GetDiagnosticSpelling(R); |
4217 | if (V.empty()) { |
4218 | PrintError(ErrorLoc: R.getLoc(), |
4219 | Msg: "Could not determine diagnostic spelling for the node: "+ |
4220 | R.getName() + "; please add one to DeclNodes.td"); |
4221 | } else { |
4222 | // The node may contain a list of elements itself, so split the elements |
4223 | // by a comma, and trim any whitespace. |
4224 | SmallVector<StringRef, 2> Frags; |
4225 | SplitString(Source: V, OutFragments&: Frags, Delimiters: ","); |
4226 | for (auto Str : Frags) { |
4227 | DiagList.push_back(x: Str.trim().str()); |
4228 | } |
4229 | } |
4230 | } |
4231 | |
4232 | if (DiagList.empty()) { |
4233 | PrintFatalError(ErrorLoc: S.getLoc(), |
4234 | Msg: "Could not deduce diagnostic argument for Attr subjects"); |
4235 | return ""; |
4236 | } |
4237 | |
4238 | // FIXME: this is not particularly good for localization purposes and ideally |
4239 | // should be part of the diagnostics engine itself with some sort of list |
4240 | // specifier. |
4241 | |
4242 | // A single member of the list can be returned directly. |
4243 | if (DiagList.size() == 1) |
4244 | return '"' + DiagList.front() + '"'; |
4245 | |
4246 | if (DiagList.size() == 2) |
4247 | return '"' + DiagList[0] + " and "+ DiagList[1] + '"'; |
4248 | |
4249 | // If there are more than two in the list, we serialize the first N - 1 |
4250 | // elements with a comma. This leaves the string in the state: foo, bar, |
4251 | // baz (but misses quux). We can then add ", and " for the last element |
4252 | // manually. |
4253 | std::string Diag = join(Begin: DiagList.begin(), End: DiagList.end() - 1, Separator: ", "); |
4254 | return '"' + Diag + ", and "+ *(DiagList.end() - 1) + '"'; |
4255 | } |
4256 | |
4257 | static std::string GetSubjectWithSuffix(const Record *R) { |
4258 | const std::string B = R->getName().str(); |
4259 | if (B == "DeclBase") |
4260 | return "Decl"; |
4261 | return B + "Decl"; |
4262 | } |
4263 | |
4264 | static std::string functionNameForCustomAppertainsTo(const Record &Subject) { |
4265 | return "is"+ Subject.getName().str(); |
4266 | } |
4267 | |
4268 | static void GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) { |
4269 | std::string FnName = functionNameForCustomAppertainsTo(Subject); |
4270 | |
4271 | // If this code has already been generated, we don't need to do anything. |
4272 | static std::set<std::string> CustomSubjectSet; |
4273 | auto I = CustomSubjectSet.find(x: FnName); |
4274 | if (I != CustomSubjectSet.end()) |
4275 | return; |
4276 | |
4277 | // This only works with non-root Decls. |
4278 | const Record *Base = Subject.getValueAsDef(BaseFieldName); |
4279 | |
4280 | // Not currently support custom subjects within custom subjects. |
4281 | if (Base->isSubClassOf(Name: "SubsetSubject")) { |
4282 | PrintFatalError(ErrorLoc: Subject.getLoc(), |
4283 | Msg: "SubsetSubjects within SubsetSubjects is not supported"); |
4284 | return; |
4285 | } |
4286 | |
4287 | OS << "static bool "<< FnName << "(const Decl *D) {\n"; |
4288 | OS << " if (const auto *S = dyn_cast<"; |
4289 | OS << GetSubjectWithSuffix(R: Base); |
4290 | OS << ">(D))\n"; |
4291 | OS << " return "<< Subject.getValueAsString(FieldName: "CheckCode") << ";\n"; |
4292 | OS << " return false;\n"; |
4293 | OS << "}\n\n"; |
4294 | |
4295 | CustomSubjectSet.insert(x: FnName); |
4296 | } |
4297 | |
4298 | static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { |
4299 | // If the attribute does not contain a Subjects definition, then use the |
4300 | // default appertainsTo logic. |
4301 | if (Attr.isValueUnset(FieldName: "Subjects")) |
4302 | return; |
4303 | |
4304 | const Record *SubjectObj = Attr.getValueAsDef(FieldName: "Subjects"); |
4305 | std::vector<const Record *> Subjects = |
4306 | SubjectObj->getValueAsListOfDefs(FieldName: "Subjects"); |
4307 | |
4308 | // If the list of subjects is empty, it is assumed that the attribute |
4309 | // appertains to everything. |
4310 | if (Subjects.empty()) |
4311 | return; |
4312 | |
4313 | bool Warn = SubjectObj->getValueAsDef(FieldName: "Diag")->getValueAsBit(FieldName: "Warn"); |
4314 | |
4315 | // Split the subjects into declaration subjects and statement subjects. |
4316 | // FIXME: subset subjects are added to the declaration list until there are |
4317 | // enough statement attributes with custom subject needs to warrant |
4318 | // the implementation effort. |
4319 | std::vector<const Record *> DeclSubjects, StmtSubjects; |
4320 | copy_if(Range&: Subjects, Out: std::back_inserter(x&: DeclSubjects), P: [](const Record *R) { |
4321 | return R->isSubClassOf(Name: "SubsetSubject") || !R->isSubClassOf(Name: "StmtNode"); |
4322 | }); |
4323 | copy_if(Range&: Subjects, Out: std::back_inserter(x&: StmtSubjects), |
4324 | P: [](const Record *R) { return R->isSubClassOf(Name: "StmtNode"); }); |
4325 | |
4326 | // We should have sorted all of the subjects into two lists. |
4327 | // FIXME: this assertion will be wrong if we ever add type attribute subjects. |
4328 | assert(DeclSubjects.size() + StmtSubjects.size() == Subjects.size()); |
4329 | |
4330 | if (DeclSubjects.empty()) { |
4331 | // If there are no decl subjects but there are stmt subjects, diagnose |
4332 | // trying to apply a statement attribute to a declaration. |
4333 | if (!StmtSubjects.empty()) { |
4334 | OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, "; |
4335 | OS << "const Decl *D) const override {\n"; |
4336 | OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n"; |
4337 | OS << " << AL << AL.isRegularKeywordAttribute() << " |
4338 | "D->getLocation();\n"; |
4339 | OS << " return false;\n"; |
4340 | OS << "}\n\n"; |
4341 | } |
4342 | } else { |
4343 | // Otherwise, generate an appertainsTo check specific to this attribute |
4344 | // which checks all of the given subjects against the Decl passed in. |
4345 | OS << "bool diagAppertainsToDecl(Sema &S, "; |
4346 | OS << "const ParsedAttr &Attr, const Decl *D) const override {\n"; |
4347 | OS << " if ("; |
4348 | for (auto I = DeclSubjects.begin(), E = DeclSubjects.end(); I != E; ++I) { |
4349 | // If the subject has custom code associated with it, use the generated |
4350 | // function for it. The function cannot be inlined into this check (yet) |
4351 | // because it requires the subject to be of a specific type, and were that |
4352 | // information inlined here, it would not support an attribute with |
4353 | // multiple custom subjects. |
4354 | if ((*I)->isSubClassOf(Name: "SubsetSubject")) |
4355 | OS << "!"<< functionNameForCustomAppertainsTo(Subject: **I) << "(D)"; |
4356 | else |
4357 | OS << "!isa<"<< GetSubjectWithSuffix(R: *I) << ">(D)"; |
4358 | |
4359 | if (I + 1 != E) |
4360 | OS << " && "; |
4361 | } |
4362 | OS << ") {\n"; |
4363 | OS << " S.Diag(Attr.getLoc(), diag::"; |
4364 | OS << (Warn ? "warn_attribute_wrong_decl_type_str" |
4365 | : "err_attribute_wrong_decl_type_str"); |
4366 | OS << ")\n"; |
4367 | OS << " << Attr << Attr.isRegularKeywordAttribute() << "; |
4368 | OS << CalculateDiagnostic(S: *SubjectObj) << ";\n"; |
4369 | OS << " return false;\n"; |
4370 | OS << " }\n"; |
4371 | OS << " return true;\n"; |
4372 | OS << "}\n\n"; |
4373 | } |
4374 | |
4375 | if (StmtSubjects.empty()) { |
4376 | // If there are no stmt subjects but there are decl subjects, diagnose |
4377 | // trying to apply a declaration attribute to a statement. |
4378 | if (!DeclSubjects.empty()) { |
4379 | OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, "; |
4380 | OS << "const Stmt *St) const override {\n"; |
4381 | OS << " S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n"; |
4382 | OS << " << AL << AL.isRegularKeywordAttribute() << " |
4383 | "St->getBeginLoc();\n"; |
4384 | OS << " return false;\n"; |
4385 | OS << "}\n\n"; |
4386 | } |
4387 | } else { |
4388 | // Now, do the same for statements. |
4389 | OS << "bool diagAppertainsToStmt(Sema &S, "; |
4390 | OS << "const ParsedAttr &Attr, const Stmt *St) const override {\n"; |
4391 | OS << " if ("; |
4392 | for (auto I = StmtSubjects.begin(), E = StmtSubjects.end(); I != E; ++I) { |
4393 | OS << "!isa<"<< (*I)->getName() << ">(St)"; |
4394 | if (I + 1 != E) |
4395 | OS << " && "; |
4396 | } |
4397 | OS << ") {\n"; |
4398 | OS << " S.Diag(Attr.getLoc(), diag::"; |
4399 | OS << (Warn ? "warn_attribute_wrong_decl_type_str" |
4400 | : "err_attribute_wrong_decl_type_str"); |
4401 | OS << ")\n"; |
4402 | OS << " << Attr << Attr.isRegularKeywordAttribute() << "; |
4403 | OS << CalculateDiagnostic(S: *SubjectObj) << ";\n"; |
4404 | OS << " return false;\n"; |
4405 | OS << " }\n"; |
4406 | OS << " return true;\n"; |
4407 | OS << "}\n\n"; |
4408 | } |
4409 | } |
4410 | |
4411 | // Generates the mutual exclusion checks. The checks for parsed attributes are |
4412 | // written into OS and the checks for merging declaration attributes are |
4413 | // written into MergeOS. |
4414 | static void GenerateMutualExclusionsChecks(const Record &Attr, |
4415 | const RecordKeeper &Records, |
4416 | raw_ostream &OS, |
4417 | raw_ostream &MergeDeclOS, |
4418 | raw_ostream &MergeStmtOS) { |
4419 | // We don't do any of this magic for type attributes yet. |
4420 | if (Attr.isSubClassOf(Name: "TypeAttr")) |
4421 | return; |
4422 | |
4423 | // This means the attribute is either a statement attribute, a decl |
4424 | // attribute, or both; find out which. |
4425 | bool CurAttrIsStmtAttr = Attr.isSubClassOf(Name: "StmtAttr") || |
4426 | Attr.isSubClassOf(Name: "DeclOrStmtAttr") || |
4427 | Attr.isSubClassOf(Name: "InheritableParamOrStmtAttr"); |
4428 | bool CurAttrIsDeclAttr = !CurAttrIsStmtAttr || |
4429 | Attr.isSubClassOf(Name: "DeclOrStmtAttr") || |
4430 | Attr.isSubClassOf(Name: "InheritableParamOrStmtAttr"); |
4431 | |
4432 | std::vector<std::string> DeclAttrs, StmtAttrs; |
4433 | |
4434 | // Find all of the definitions that inherit from MutualExclusions and include |
4435 | // the given attribute in the list of exclusions to generate the |
4436 | // diagMutualExclusion() check. |
4437 | for (const Record *Exclusion : |
4438 | Records.getAllDerivedDefinitions(ClassName: "MutualExclusions")) { |
4439 | std::vector<const Record *> MutuallyExclusiveAttrs = |
4440 | Exclusion->getValueAsListOfDefs(FieldName: "Exclusions"); |
4441 | auto IsCurAttr = [Attr](const Record *R) { |
4442 | return R->getName() == Attr.getName(); |
4443 | }; |
4444 | if (any_of(Range&: MutuallyExclusiveAttrs, P: IsCurAttr)) { |
4445 | // This list of exclusions includes the attribute we're looking for, so |
4446 | // add the exclusive attributes to the proper list for checking. |
4447 | for (const Record *AttrToExclude : MutuallyExclusiveAttrs) { |
4448 | if (IsCurAttr(AttrToExclude)) |
4449 | continue; |
4450 | |
4451 | if (CurAttrIsStmtAttr) |
4452 | StmtAttrs.push_back(x: (AttrToExclude->getName() + "Attr").str()); |
4453 | if (CurAttrIsDeclAttr) |
4454 | DeclAttrs.push_back(x: (AttrToExclude->getName() + "Attr").str()); |
4455 | } |
4456 | } |
4457 | } |
4458 | |
4459 | // If there are any decl or stmt attributes, silence -Woverloaded-virtual |
4460 | // warnings for them both. |
4461 | if (!DeclAttrs.empty() || !StmtAttrs.empty()) |
4462 | OS << " using ParsedAttrInfo::diagMutualExclusion;\n\n"; |
4463 | |
4464 | // If we discovered any decl or stmt attributes to test for, generate the |
4465 | // predicates for them now. |
4466 | if (!DeclAttrs.empty()) { |
4467 | // Generate the ParsedAttrInfo subclass logic for declarations. |
4468 | OS << " bool diagMutualExclusion(Sema &S, const ParsedAttr &AL, " |
4469 | << "const Decl *D) const override {\n"; |
4470 | for (const std::string &A : DeclAttrs) { |
4471 | OS << " if (const auto *A = D->getAttr<"<< A << ">()) {\n"; |
4472 | OS << " S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)" |
4473 | << " << AL << A << (AL.isRegularKeywordAttribute() ||" |
4474 | << " A->isRegularKeywordAttribute());\n"; |
4475 | OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);"; |
4476 | OS << " \nreturn false;\n"; |
4477 | OS << " }\n"; |
4478 | } |
4479 | OS << " return true;\n"; |
4480 | OS << " }\n\n"; |
4481 | |
4482 | // Also generate the declaration attribute merging logic if the current |
4483 | // attribute is one that can be inheritted on a declaration. It is assumed |
4484 | // this code will be executed in the context of a function with parameters: |
4485 | // Sema &S, Decl *D, Attr *A and that returns a bool (false on diagnostic, |
4486 | // true on success). |
4487 | if (Attr.isSubClassOf(Name: "InheritableAttr")) { |
4488 | MergeDeclOS << " if (const auto *Second = dyn_cast<" |
4489 | << (Attr.getName() + "Attr").str() << ">(A)) {\n"; |
4490 | for (const std::string &A : DeclAttrs) { |
4491 | MergeDeclOS << " if (const auto *First = D->getAttr<"<< A |
4492 | << ">()) {\n"; |
4493 | MergeDeclOS << " S.Diag(First->getLocation(), " |
4494 | << "diag::err_attributes_are_not_compatible) << First << " |
4495 | << "Second << (First->isRegularKeywordAttribute() || " |
4496 | << "Second->isRegularKeywordAttribute());\n"; |
4497 | MergeDeclOS << " S.Diag(Second->getLocation(), " |
4498 | << "diag::note_conflicting_attribute);\n"; |
4499 | MergeDeclOS << " return false;\n"; |
4500 | MergeDeclOS << " }\n"; |
4501 | } |
4502 | MergeDeclOS << " return true;\n"; |
4503 | MergeDeclOS << " }\n"; |
4504 | } |
4505 | } |
4506 | |
4507 | // Statement attributes are a bit different from declarations. With |
4508 | // declarations, each attribute is added to the declaration as it is |
4509 | // processed, and so you can look on the Decl * itself to see if there is a |
4510 | // conflicting attribute. Statement attributes are processed as a group |
4511 | // because AttributedStmt needs to tail-allocate all of the attribute nodes |
4512 | // at once. This means we cannot check whether the statement already contains |
4513 | // an attribute to check for the conflict. Instead, we need to check whether |
4514 | // the given list of semantic attributes contain any conflicts. It is assumed |
4515 | // this code will be executed in the context of a function with parameters: |
4516 | // Sema &S, const SmallVectorImpl<const Attr *> &C. The code will be within a |
4517 | // loop which loops over the container C with a loop variable named A to |
4518 | // represent the current attribute to check for conflicts. |
4519 | // |
4520 | // FIXME: it would be nice not to walk over the list of potential attributes |
4521 | // to apply to the statement more than once, but statements typically don't |
4522 | // have long lists of attributes on them, so re-walking the list should not |
4523 | // be an expensive operation. |
4524 | if (!StmtAttrs.empty()) { |
4525 | MergeStmtOS << " if (const auto *Second = dyn_cast<" |
4526 | << (Attr.getName() + "Attr").str() << ">(A)) {\n"; |
4527 | MergeStmtOS << " auto Iter = llvm::find_if(C, [](const Attr *Check) " |
4528 | << "{ return isa<"; |
4529 | interleave( |
4530 | c: StmtAttrs, each_fn: [&](StringRef Name) { MergeStmtOS << Name; }, |
4531 | between_fn: [&] { MergeStmtOS << ", "; }); |
4532 | MergeStmtOS << ">(Check); });\n"; |
4533 | MergeStmtOS << " if (Iter != C.end()) {\n"; |
4534 | MergeStmtOS << " S.Diag((*Iter)->getLocation(), " |
4535 | << "diag::err_attributes_are_not_compatible) << *Iter << " |
4536 | << "Second << ((*Iter)->isRegularKeywordAttribute() || " |
4537 | << "Second->isRegularKeywordAttribute());\n"; |
4538 | MergeStmtOS << " S.Diag(Second->getLocation(), " |
4539 | << "diag::note_conflicting_attribute);\n"; |
4540 | MergeStmtOS << " return false;\n"; |
4541 | MergeStmtOS << " }\n"; |
4542 | MergeStmtOS << " }\n"; |
4543 | } |
4544 | } |
4545 | |
4546 | static void |
4547 | emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport, |
4548 | raw_ostream &OS) { |
4549 | OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, " |
4550 | << AttributeSubjectMatchRule::EnumName << " rule) {\n"; |
4551 | OS << " switch (rule) {\n"; |
4552 | for (const auto &Rule : PragmaAttributeSupport.Rules) { |
4553 | if (Rule.isAbstractRule()) { |
4554 | OS << " case "<< Rule.getEnumValue() << ":\n"; |
4555 | OS << " assert(false && \"Abstract matcher rule isn't allowed\");\n"; |
4556 | OS << " return false;\n"; |
4557 | continue; |
4558 | } |
4559 | std::vector<const Record *> Subjects = Rule.getSubjects(); |
4560 | assert(!Subjects.empty() && "Missing subjects"); |
4561 | OS << " case "<< Rule.getEnumValue() << ":\n"; |
4562 | OS << " return "; |
4563 | for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) { |
4564 | // If the subject has custom code associated with it, use the function |
4565 | // that was generated for GenerateAppertainsTo to check if the declaration |
4566 | // is valid. |
4567 | if ((*I)->isSubClassOf(Name: "SubsetSubject")) |
4568 | OS << functionNameForCustomAppertainsTo(Subject: **I) << "(D)"; |
4569 | else |
4570 | OS << "isa<"<< GetSubjectWithSuffix(R: *I) << ">(D)"; |
4571 | |
4572 | if (I + 1 != E) |
4573 | OS << " || "; |
4574 | } |
4575 | OS << ";\n"; |
4576 | } |
4577 | OS << " }\n"; |
4578 | OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n"; |
4579 | OS << "}\n\n"; |
4580 | } |
4581 | |
4582 | static void GenerateLangOptRequirements(const Record &R, |
4583 | raw_ostream &OS) { |
4584 | // If the attribute has an empty or unset list of language requirements, |
4585 | // use the default handler. |
4586 | std::vector<const Record *> LangOpts = R.getValueAsListOfDefs(FieldName: "LangOpts"); |
4587 | if (LangOpts.empty()) |
4588 | return; |
4589 | |
4590 | OS << "bool acceptsLangOpts(const LangOptions &LangOpts) const override {\n"; |
4591 | OS << " return "<< GenerateTestExpression(LangOpts) << ";\n"; |
4592 | OS << "}\n\n"; |
4593 | } |
4594 | |
4595 | static void GenerateTargetRequirements(const Record &Attr, |
4596 | const ParsedAttrMap &Dupes, |
4597 | raw_ostream &OS) { |
4598 | // If the attribute is not a target specific attribute, use the default |
4599 | // target handler. |
4600 | if (!Attr.isSubClassOf(Name: "TargetSpecificAttr")) |
4601 | return; |
4602 | |
4603 | // Get the list of architectures to be tested for. |
4604 | const Record *R = Attr.getValueAsDef(FieldName: "Target"); |
4605 | std::vector<StringRef> Arches = R->getValueAsListOfStrings(FieldName: "Arches"); |
4606 | |
4607 | // If there are other attributes which share the same parsed attribute kind, |
4608 | // such as target-specific attributes with a shared spelling, collapse the |
4609 | // duplicate architectures. This is required because a shared target-specific |
4610 | // attribute has only one ParsedAttr::Kind enumeration value, but it |
4611 | // applies to multiple target architectures. In order for the attribute to be |
4612 | // considered valid, all of its architectures need to be included. |
4613 | if (!Attr.isValueUnset(FieldName: "ParseKind")) { |
4614 | const StringRef APK = Attr.getValueAsString(FieldName: "ParseKind"); |
4615 | for (const auto &I : Dupes) { |
4616 | if (I.first == APK) { |
4617 | std::vector<StringRef> DA = |
4618 | I.second->getValueAsDef(FieldName: "Target")->getValueAsListOfStrings( |
4619 | FieldName: "Arches"); |
4620 | llvm::append_range(C&: Arches, R&: DA); |
4621 | } |
4622 | } |
4623 | } |
4624 | |
4625 | std::string FnName = "isTarget"; |
4626 | std::string Test; |
4627 | bool UsesT = GenerateTargetSpecificAttrChecks(R, Arches, Test, FnName: &FnName); |
4628 | |
4629 | OS << "bool existsInTarget(const TargetInfo &Target) const override {\n"; |
4630 | if (UsesT) |
4631 | OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n"; |
4632 | OS << " return "<< Test << ";\n"; |
4633 | OS << "}\n\n"; |
4634 | } |
4635 | |
4636 | static void |
4637 | GenerateSpellingTargetRequirements(const Record &Attr, |
4638 | ArrayRef<const Record *> TargetSpellings, |
4639 | raw_ostream &OS) { |
4640 | // If there are no target specific spellings, use the default target handler. |
4641 | if (TargetSpellings.empty()) |
4642 | return; |
4643 | |
4644 | std::string Test; |
4645 | bool UsesT = false; |
4646 | const std::vector<FlattenedSpelling> SpellingList = |
4647 | GetFlattenedSpellings(Attr); |
4648 | for (unsigned TargetIndex = 0; TargetIndex < TargetSpellings.size(); |
4649 | ++TargetIndex) { |
4650 | const auto &TargetSpelling = TargetSpellings[TargetIndex]; |
4651 | std::vector<FlattenedSpelling> Spellings = |
4652 | GetFlattenedSpellings(Attr: *TargetSpelling); |
4653 | |
4654 | Test += "((SpellingListIndex == "; |
4655 | for (unsigned Index = 0; Index < Spellings.size(); ++Index) { |
4656 | Test += itostr(X: getSpellingListIndex(SpellingList, Spelling: Spellings[Index])); |
4657 | if (Index != Spellings.size() - 1) |
4658 | Test += " ||\n SpellingListIndex == "; |
4659 | else |
4660 | Test += ") && "; |
4661 | } |
4662 | |
4663 | const Record *Target = TargetSpelling->getValueAsDef(FieldName: "Target"); |
4664 | std::vector<StringRef> Arches = Target->getValueAsListOfStrings(FieldName: "Arches"); |
4665 | std::string FnName = "isTargetSpelling"; |
4666 | UsesT |= GenerateTargetSpecificAttrChecks(R: Target, Arches, Test, FnName: &FnName); |
4667 | Test += ")"; |
4668 | if (TargetIndex != TargetSpellings.size() - 1) |
4669 | Test += " || "; |
4670 | } |
4671 | |
4672 | OS << "bool spellingExistsInTarget(const TargetInfo &Target,\n"; |
4673 | OS << " const unsigned SpellingListIndex) const " |
4674 | "override {\n"; |
4675 | if (UsesT) |
4676 | OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n"; |
4677 | OS << " return "<< Test << ";\n", OS << "}\n\n"; |
4678 | } |
4679 | |
4680 | static void GenerateSpellingIndexToSemanticSpelling(const Record &Attr, |
4681 | raw_ostream &OS) { |
4682 | // If the attribute does not have a semantic form, we can bail out early. |
4683 | if (!Attr.getValueAsBit(FieldName: "ASTNode")) |
4684 | return; |
4685 | |
4686 | std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); |
4687 | |
4688 | // If there are zero or one spellings, or all of the spellings share the same |
4689 | // name, we can also bail out early. |
4690 | if (Spellings.size() <= 1 || SpellingNamesAreCommon(Spellings)) |
4691 | return; |
4692 | |
4693 | // Generate the enumeration we will use for the mapping. |
4694 | SemanticSpellingMap SemanticToSyntacticMap; |
4695 | std::string Enum = CreateSemanticSpellings(Spellings, Map&: SemanticToSyntacticMap); |
4696 | |
4697 | OS << "unsigned spellingIndexToSemanticSpelling("; |
4698 | OS << "const ParsedAttr &Attr) const override {\n"; |
4699 | OS << Enum; |
4700 | OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n"; |
4701 | WriteSemanticSpellingSwitch(VarName: "Idx", Map: SemanticToSyntacticMap, OS); |
4702 | OS << "}\n\n"; |
4703 | } |
4704 | |
4705 | static void GenerateHandleDeclAttribute(const Record &Attr, raw_ostream &OS) { |
4706 | // Only generate if Attr can be handled simply. |
4707 | if (!Attr.getValueAsBit(FieldName: "SimpleHandler")) |
4708 | return; |
4709 | |
4710 | // Generate a function which just converts from ParsedAttr to the Attr type. |
4711 | OS << "AttrHandling handleDeclAttribute(Sema &S, Decl *D,"; |
4712 | OS << "const ParsedAttr &Attr) const override {\n"; |
4713 | OS << " D->addAttr(::new (S.Context) "<< Attr.getName(); |
4714 | OS << "Attr(S.Context, Attr));\n"; |
4715 | OS << " return AttributeApplied;\n"; |
4716 | OS << "}\n\n"; |
4717 | } |
4718 | |
4719 | static bool isParamExpr(const Record *Arg) { |
4720 | return !Arg->getDirectSuperClasses().empty() && |
4721 | StringSwitch<bool>( |
4722 | Arg->getDirectSuperClasses().back().first->getName()) |
4723 | .Case(S: "ExprArgument", Value: true) |
4724 | .Case(S: "VariadicExprArgument", Value: true) |
4725 | .Default(Value: false); |
4726 | } |
4727 | |
4728 | static void GenerateIsParamExpr(const Record &Attr, raw_ostream &OS) { |
4729 | OS << "bool isParamExpr(size_t N) const override {\n"; |
4730 | OS << " return "; |
4731 | auto Args = Attr.getValueAsListOfDefs(FieldName: "Args"); |
4732 | for (size_t I = 0; I < Args.size(); ++I) |
4733 | if (isParamExpr(Arg: Args[I])) |
4734 | OS << "(N == "<< I << ") || "; |
4735 | OS << "false;\n"; |
4736 | OS << "}\n\n"; |
4737 | } |
4738 | |
4739 | static void GenerateHandleAttrWithDelayedArgs(const RecordKeeper &Records, |
4740 | raw_ostream &OS) { |
4741 | OS << "static void handleAttrWithDelayedArgs(Sema &S, Decl *D, "; |
4742 | OS << "const ParsedAttr &Attr) {\n"; |
4743 | OS << " SmallVector<Expr *, 4> ArgExprs;\n"; |
4744 | OS << " ArgExprs.reserve(Attr.getNumArgs());\n"; |
4745 | OS << " for (unsigned I = 0; I < Attr.getNumArgs(); ++I) {\n"; |
4746 | OS << " assert(!Attr.isArgIdent(I));\n"; |
4747 | OS << " ArgExprs.push_back(Attr.getArgAsExpr(I));\n"; |
4748 | OS << " }\n"; |
4749 | OS << " clang::Attr *CreatedAttr = nullptr;\n"; |
4750 | OS << " switch (Attr.getKind()) {\n"; |
4751 | OS << " default:\n"; |
4752 | OS << " llvm_unreachable(\"Attribute cannot hold delayed arguments.\");\n"; |
4753 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
4754 | for (const auto &I : Attrs) { |
4755 | const Record &R = *I.second; |
4756 | if (!R.getValueAsBit(FieldName: "AcceptsExprPack")) |
4757 | continue; |
4758 | OS << " case ParsedAttr::AT_"<< I.first << ": {\n"; |
4759 | OS << " CreatedAttr = "<< R.getName() << "Attr::CreateWithDelayedArgs"; |
4760 | OS << "(S.Context, ArgExprs.data(), ArgExprs.size(), Attr);\n"; |
4761 | OS << " break;\n"; |
4762 | OS << " }\n"; |
4763 | } |
4764 | OS << " }\n"; |
4765 | OS << " D->addAttr(CreatedAttr);\n"; |
4766 | OS << "}\n\n"; |
4767 | } |
4768 | |
4769 | static bool IsKnownToGCC(const Record &Attr) { |
4770 | // Look at the spellings for this subject; if there are any spellings which |
4771 | // claim to be known to GCC, the attribute is known to GCC. |
4772 | return any_of(Range: GetFlattenedSpellings(Attr), |
4773 | P: [](const FlattenedSpelling &S) { return S.knownToGCC(); }); |
4774 | } |
4775 | |
4776 | /// Emits the parsed attribute helpers |
4777 | void EmitClangAttrParsedAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { |
4778 | emitSourceFileHeader(Desc: "Parsed attribute helpers", OS, Record: Records); |
4779 | |
4780 | OS << "#if !defined(WANT_DECL_MERGE_LOGIC) && " |
4781 | << "!defined(WANT_STMT_MERGE_LOGIC)\n"; |
4782 | PragmaClangAttributeSupport &PragmaAttributeSupport = |
4783 | getPragmaAttributeSupport(Records); |
4784 | |
4785 | // Get the list of parsed attributes, and accept the optional list of |
4786 | // duplicates due to the ParseKind. |
4787 | ParsedAttrMap Dupes; |
4788 | ParsedAttrMap Attrs = getParsedAttrList(Records, Dupes: &Dupes); |
4789 | |
4790 | // Generate all of the custom appertainsTo functions that the attributes |
4791 | // will be using. |
4792 | for (const auto &I : Attrs) { |
4793 | const Record &Attr = *I.second; |
4794 | if (Attr.isValueUnset(FieldName: "Subjects")) |
4795 | continue; |
4796 | const Record *SubjectObj = Attr.getValueAsDef(FieldName: "Subjects"); |
4797 | for (const Record *Subject : SubjectObj->getValueAsListOfDefs(FieldName: "Subjects")) |
4798 | if (Subject->isSubClassOf(Name: "SubsetSubject")) |
4799 | GenerateCustomAppertainsTo(Subject: *Subject, OS); |
4800 | } |
4801 | |
4802 | // This stream is used to collect all of the declaration attribute merging |
4803 | // logic for performing mutual exclusion checks. This gets emitted at the |
4804 | // end of the file in a helper function of its own. |
4805 | std::string DeclMergeChecks, StmtMergeChecks; |
4806 | raw_string_ostream MergeDeclOS(DeclMergeChecks), MergeStmtOS(StmtMergeChecks); |
4807 | |
4808 | // Generate a ParsedAttrInfo struct for each of the attributes. |
4809 | for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { |
4810 | // TODO: If the attribute's kind appears in the list of duplicates, that is |
4811 | // because it is a target-specific attribute that appears multiple times. |
4812 | // It would be beneficial to test whether the duplicates are "similar |
4813 | // enough" to each other to not cause problems. For instance, check that |
4814 | // the spellings are identical, and custom parsing rules match, etc. |
4815 | |
4816 | // We need to generate struct instances based off ParsedAttrInfo from |
4817 | // ParsedAttr.cpp. |
4818 | const std::string &AttrName = I->first; |
4819 | const Record &Attr = *I->second; |
4820 | auto Spellings = GetFlattenedSpellings(Attr); |
4821 | if (!Spellings.empty()) { |
4822 | OS << "static constexpr ParsedAttrInfo::Spelling "<< I->first |
4823 | << "Spellings[] = {\n"; |
4824 | for (const auto &S : Spellings) { |
4825 | StringRef RawSpelling = S.name(); |
4826 | std::string Spelling; |
4827 | if (!S.nameSpace().empty()) |
4828 | Spelling += S.nameSpace().str() + "::"; |
4829 | if (S.variety() == "GNU") |
4830 | Spelling += NormalizeGNUAttrSpelling(AttrSpelling: RawSpelling); |
4831 | else |
4832 | Spelling += RawSpelling; |
4833 | OS << " {AttributeCommonInfo::AS_"<< S.variety(); |
4834 | OS << ", \""<< Spelling << "\"},\n"; |
4835 | } |
4836 | OS << "};\n"; |
4837 | } |
4838 | |
4839 | std::vector<std::string> ArgNames; |
4840 | for (const auto *Arg : Attr.getValueAsListOfDefs(FieldName: "Args")) { |
4841 | bool UnusedUnset; |
4842 | if (Arg->getValueAsBitOrUnset(FieldName: "Fake", Unset&: UnusedUnset)) |
4843 | continue; |
4844 | ArgNames.push_back(x: Arg->getValueAsString(FieldName: "Name").str()); |
4845 | for (const Record *Class : Arg->getSuperClasses()) { |
4846 | if (Class->getName().starts_with(Prefix: "Variadic")) { |
4847 | ArgNames.back().append(s: "..."); |
4848 | break; |
4849 | } |
4850 | } |
4851 | } |
4852 | if (!ArgNames.empty()) { |
4853 | OS << "static constexpr const char *"<< I->first << "ArgNames[] = {\n"; |
4854 | for (const auto &N : ArgNames) |
4855 | OS << '"' << N << "\","; |
4856 | OS << "};\n"; |
4857 | } |
4858 | |
4859 | OS << "struct ParsedAttrInfo"<< I->first |
4860 | << " final : public ParsedAttrInfo {\n"; |
4861 | OS << " constexpr ParsedAttrInfo"<< I->first << "() : ParsedAttrInfo(\n"; |
4862 | OS << " /*AttrKind=*/ParsedAttr::AT_"<< AttrName << ",\n"; |
4863 | emitArgInfo(R: Attr, OS); |
4864 | OS << " /*HasCustomParsing=*/"; |
4865 | OS << Attr.getValueAsBit(FieldName: "HasCustomParsing") << ",\n"; |
4866 | OS << " /*AcceptsExprPack=*/"; |
4867 | OS << Attr.getValueAsBit(FieldName: "AcceptsExprPack") << ",\n"; |
4868 | OS << " /*IsTargetSpecific=*/"; |
4869 | OS << Attr.isSubClassOf(Name: "TargetSpecificAttr") << ",\n"; |
4870 | OS << " /*IsType=*/"; |
4871 | OS << (Attr.isSubClassOf(Name: "TypeAttr") || Attr.isSubClassOf(Name: "DeclOrTypeAttr")) |
4872 | << ",\n"; |
4873 | OS << " /*IsStmt=*/"; |
4874 | OS << (Attr.isSubClassOf(Name: "StmtAttr") || Attr.isSubClassOf(Name: "DeclOrStmtAttr")) |
4875 | << ",\n"; |
4876 | OS << " /*IsKnownToGCC=*/"; |
4877 | OS << IsKnownToGCC(Attr) << ",\n"; |
4878 | OS << " /*IsSupportedByPragmaAttribute=*/"; |
4879 | OS << PragmaAttributeSupport.isAttributedSupported(Attribute: *I->second) << ",\n"; |
4880 | if (!Spellings.empty()) |
4881 | OS << " /*Spellings=*/"<< I->first << "Spellings,\n"; |
4882 | else |
4883 | OS << " /*Spellings=*/{},\n"; |
4884 | if (!ArgNames.empty()) |
4885 | OS << " /*ArgNames=*/"<< I->first << "ArgNames"; |
4886 | else |
4887 | OS << " /*ArgNames=*/{}"; |
4888 | OS << ") {}\n"; |
4889 | GenerateAppertainsTo(Attr, OS); |
4890 | GenerateMutualExclusionsChecks(Attr, Records, OS, MergeDeclOS, MergeStmtOS); |
4891 | GenerateLangOptRequirements(R: Attr, OS); |
4892 | GenerateTargetRequirements(Attr, Dupes, OS); |
4893 | GenerateSpellingTargetRequirements( |
4894 | Attr, TargetSpellings: Attr.getValueAsListOfDefs(FieldName: "TargetSpecificSpellings"), OS); |
4895 | GenerateSpellingIndexToSemanticSpelling(Attr, OS); |
4896 | PragmaAttributeSupport.generateStrictConformsTo(Attr: *I->second, OS); |
4897 | GenerateHandleDeclAttribute(Attr, OS); |
4898 | GenerateIsParamExpr(Attr, OS); |
4899 | OS << "static const ParsedAttrInfo"<< I->first << " Instance;\n"; |
4900 | OS << "};\n"; |
4901 | OS << "const ParsedAttrInfo"<< I->first << " ParsedAttrInfo"<< I->first |
4902 | << "::Instance;\n"; |
4903 | } |
4904 | |
4905 | OS << "static const ParsedAttrInfo *AttrInfoMap[] = {\n"; |
4906 | for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { |
4907 | OS << "&ParsedAttrInfo"<< I->first << "::Instance,\n"; |
4908 | } |
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 WriteCategoryHeader(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 (auto I = Spellings.begin(), E = Spellings.end(); |
5264 | I != E; ++I) { |
5265 | std::string Spelling = |
5266 | NormalizeNameForSpellingComparison(Name: I->name()).str(); |
5267 | Uniques.insert(x: Spelling); |
5268 | } |
5269 | // If the semantic map has only one spelling, that is sufficient for our |
5270 | // needs. |
5271 | if (Uniques.size() == 1) |
5272 | Heading = *Uniques.begin(); |
5273 | // If it's in the undocumented category, just construct a header by |
5274 | // concatenating all the spellings. Might not be great, but better than |
5275 | // nothing. |
5276 | else if (Cat == "Undocumented") |
5277 | Heading = join(Begin: Uniques.begin(), End: Uniques.end(), Separator: ", "); |
5278 | } |
5279 | } |
5280 | |
5281 | // If the heading is still empty, it is an error. |
5282 | if (Heading.empty()) |
5283 | PrintFatalError(ErrorLoc: Attribute.getLoc(), |
5284 | Msg: "This attribute requires a heading to be specified"); |
5285 | |
5286 | SpellingList SupportedSpellings; |
5287 | for (const auto &I : Spellings) |
5288 | SupportedSpellings.add(Attr: Attribute, Spelling: I); |
5289 | |
5290 | return std::make_pair(x: std::move(Heading), y: std::move(SupportedSpellings)); |
5291 | } |
5292 | |
5293 | static void WriteDocumentation(const RecordKeeper &Records, |
5294 | const DocumentationData &Doc, raw_ostream &OS) { |
5295 | if (StringRef Label = Doc.Documentation->getValueAsString(FieldName: "Label"); |
5296 | !Label.empty()) |
5297 | OS << ".. _"<< Label << ":\n\n"; |
5298 | OS << Doc.Heading << "\n"<< std::string(Doc.Heading.length(), '-') << "\n"; |
5299 | |
5300 | // List what spelling syntaxes the attribute supports. |
5301 | // Note: "#pragma clang attribute" is handled outside the spelling kinds loop |
5302 | // so it must be last. |
5303 | OS << ".. csv-table:: Supported Syntaxes\n"; |
5304 | OS << " :header: \"GNU\", \"C++11\", \"C23\", \"``__declspec``\","; |
5305 | OS << " \"Keyword\", \"``#pragma``\", \"HLSL Annotation\", \"``#pragma " |
5306 | "clang "; |
5307 | OS << "attribute``\"\n\n \""; |
5308 | for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) { |
5309 | SpellingKind K = (SpellingKind)Kind; |
5310 | // TODO: List Microsoft (IDL-style attribute) spellings once we fully |
5311 | // support them. |
5312 | if (K == SpellingKind::Microsoft) |
5313 | continue; |
5314 | |
5315 | bool PrintedAny = false; |
5316 | for (StringRef Spelling : Doc.SupportedSpellings[K]) { |
5317 | if (PrintedAny) |
5318 | OS << " |br| "; |
5319 | OS << "``"<< Spelling << "``"; |
5320 | PrintedAny = true; |
5321 | } |
5322 | |
5323 | OS << "\",\""; |
5324 | } |
5325 | |
5326 | if (getPragmaAttributeSupport(Records).isAttributedSupported( |
5327 | Attribute: *Doc.Attribute)) |
5328 | OS << "Yes"; |
5329 | OS << "\"\n\n"; |
5330 | |
5331 | // If the attribute is deprecated, print a message about it, and possibly |
5332 | // provide a replacement attribute. |
5333 | if (!Doc.Documentation->isValueUnset(FieldName: "Deprecated")) { |
5334 | OS << "This attribute has been deprecated, and may be removed in a future " |
5335 | << "version of Clang."; |
5336 | const Record &Deprecated = *Doc.Documentation->getValueAsDef(FieldName: "Deprecated"); |
5337 | const StringRef Replacement = Deprecated.getValueAsString(FieldName: "Replacement"); |
5338 | if (!Replacement.empty()) |
5339 | OS << " This attribute has been superseded by ``"<< Replacement |
5340 | << "``."; |
5341 | OS << "\n\n"; |
5342 | } |
5343 | |
5344 | const StringRef ContentStr = Doc.Documentation->getValueAsString(FieldName: "Content"); |
5345 | // Trim leading and trailing newlines and spaces. |
5346 | OS << ContentStr.trim(); |
5347 | |
5348 | OS << "\n\n\n"; |
5349 | } |
5350 | |
5351 | void EmitClangAttrDocs(const RecordKeeper &Records, raw_ostream &OS) { |
5352 | // Get the documentation introduction paragraph. |
5353 | const Record *Documentation = Records.getDef(Name: "GlobalDocumentation"); |
5354 | if (!Documentation) { |
5355 | PrintFatalError(Msg: "The Documentation top-level definition is missing, " |
5356 | "no documentation will be generated."); |
5357 | return; |
5358 | } |
5359 | |
5360 | OS << Documentation->getValueAsString(FieldName: "Intro") << "\n"; |
5361 | |
5362 | // Gather the Documentation lists from each of the attributes, based on the |
5363 | // category provided. |
5364 | struct CategoryLess { |
5365 | bool operator()(const Record *L, const Record *R) const { |
5366 | return L->getValueAsString(FieldName: "Name") < R->getValueAsString(FieldName: "Name"); |
5367 | } |
5368 | }; |
5369 | |
5370 | std::map<const Record *, std::map<uint32_t, DocumentationData>, CategoryLess> |
5371 | MergedDocs; |
5372 | |
5373 | std::vector<DocumentationData> UndocumentedDocs; |
5374 | const Record *UndocumentedCategory = nullptr; |
5375 | |
5376 | // Collect documentation data, grouping by category and heading. |
5377 | for (const auto *A : Records.getAllDerivedDefinitions(ClassName: "Attr")) { |
5378 | const Record &Attr = *A; |
5379 | std::vector<const Record *> Docs = |
5380 | Attr.getValueAsListOfDefs(FieldName: "Documentation"); |
5381 | |
5382 | for (const auto *D : Docs) { |
5383 | const Record &Doc = *D; |
5384 | const Record *Category = Doc.getValueAsDef(FieldName: "Category"); |
5385 | // If the category is "InternalOnly", then there cannot be any other |
5386 | // documentation categories (otherwise, the attribute would be |
5387 | // emitted into the docs). |
5388 | StringRef Cat = Category->getValueAsString(FieldName: "Name"); |
5389 | if (Cat == "InternalOnly"&& Docs.size() > 1) |
5390 | PrintFatalError(ErrorLoc: Doc.getLoc(), |
5391 | Msg: "Attribute is \"InternalOnly\", but has multiple " |
5392 | "documentation categories"); |
5393 | |
5394 | if (Cat == "InternalOnly") |
5395 | continue; |
5396 | |
5397 | // Track the Undocumented category Record for later grouping |
5398 | if (Cat == "Undocumented"&& !UndocumentedCategory) |
5399 | UndocumentedCategory = Category; |
5400 | |
5401 | // Generate Heading and Spellings. |
5402 | auto HeadingAndSpellings = |
5403 | GetAttributeHeadingAndSpellings(Documentation: Doc, Attribute: Attr, Cat); |
5404 | |
5405 | // Handle Undocumented category separately - no content merging |
5406 | if (Cat == "Undocumented"&& UndocumentedCategory) { |
5407 | UndocumentedDocs.push_back( |
5408 | x: DocumentationData(Doc, Attr, std::move(HeadingAndSpellings))); |
5409 | continue; |
5410 | } |
5411 | |
5412 | auto &CategoryDocs = MergedDocs[Category]; |
5413 | |
5414 | std::string key = Doc.getValueAsString(FieldName: "Content").str(); |
5415 | uint32_t keyHash = llvm::hash_value(arg: key); |
5416 | |
5417 | // If the content already exists, merge the documentation. |
5418 | auto It = CategoryDocs.find(x: keyHash); |
5419 | if (It != CategoryDocs.end()) { |
5420 | // Merge heading |
5421 | if (It->second.Heading != HeadingAndSpellings.first) |
5422 | It->second.Heading += ", "+ HeadingAndSpellings.first; |
5423 | // Merge spellings |
5424 | It->second.SupportedSpellings.merge(Other: HeadingAndSpellings.second); |
5425 | // Merge content |
5426 | It->second.Documentation = &Doc; // Update reference |
5427 | } else { |
5428 | // Create new entry for unique content |
5429 | CategoryDocs.emplace(args&: keyHash, |
5430 | args: DocumentationData(Doc, Attr, HeadingAndSpellings)); |
5431 | } |
5432 | } |
5433 | } |
5434 | |
5435 | std::map<const Record *, std::vector<DocumentationData>, CategoryLess> |
5436 | SplitDocs; |
5437 | |
5438 | for (auto &CategoryPair : MergedDocs) { |
5439 | |
5440 | std::vector<DocumentationData> MD; |
5441 | for (auto &DocPair : CategoryPair.second) |
5442 | MD.push_back(x: std::move(DocPair.second)); |
5443 | |
5444 | SplitDocs.emplace(args: CategoryPair.first, args&: MD); |
5445 | } |
5446 | |
5447 | // Append Undocumented category entries |
5448 | if (!UndocumentedDocs.empty() && UndocumentedCategory) { |
5449 | SplitDocs.emplace(args&: UndocumentedCategory, args&: UndocumentedDocs); |
5450 | } |
5451 | |
5452 | // Having split the attributes out based on what documentation goes where, |
5453 | // we can begin to generate sections of documentation. |
5454 | for (auto &I : SplitDocs) { |
5455 | WriteCategoryHeader(DocCategory: I.first, OS); |
5456 | |
5457 | sort(C&: I.second, |
5458 | Comp: [](const DocumentationData &D1, const DocumentationData &D2) { |
5459 | return D1.Heading < D2.Heading; |
5460 | }); |
5461 | |
5462 | // Walk over each of the attributes in the category and write out their |
5463 | // documentation. |
5464 | for (const auto &Doc : I.second) |
5465 | WriteDocumentation(Records, Doc, OS); |
5466 | } |
5467 | } |
5468 | |
5469 | void EmitTestPragmaAttributeSupportedAttributes(const RecordKeeper &Records, |
5470 | raw_ostream &OS) { |
5471 | PragmaClangAttributeSupport Support = getPragmaAttributeSupport(Records); |
5472 | ParsedAttrMap Attrs = getParsedAttrList(Records); |
5473 | OS << "#pragma clang attribute supports the following attributes:\n"; |
5474 | for (const auto &I : Attrs) { |
5475 | if (!Support.isAttributedSupported(Attribute: *I.second)) |
5476 | continue; |
5477 | OS << I.first; |
5478 | if (I.second->isValueUnset(FieldName: "Subjects")) { |
5479 | OS << " ()\n"; |
5480 | continue; |
5481 | } |
5482 | const Record *SubjectObj = I.second->getValueAsDef(FieldName: "Subjects"); |
5483 | OS << " ("; |
5484 | bool PrintComma = false; |
5485 | for (const auto &Subject : |
5486 | enumerate(First: SubjectObj->getValueAsListOfDefs(FieldName: "Subjects"))) { |
5487 | if (!isSupportedPragmaClangAttributeSubject(Subject: *Subject.value())) |
5488 | continue; |
5489 | if (PrintComma) |
5490 | OS << ", "; |
5491 | PrintComma = true; |
5492 | PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet = |
5493 | Support.SubjectsToRules.find(Val: Subject.value())->getSecond(); |
5494 | if (RuleSet.isRule()) { |
5495 | OS << RuleSet.getRule().getEnumValueName(); |
5496 | continue; |
5497 | } |
5498 | OS << "("; |
5499 | for (const auto &Rule : enumerate(First: RuleSet.getAggregateRuleSet())) { |
5500 | if (Rule.index()) |
5501 | OS << ", "; |
5502 | OS << Rule.value().getEnumValueName(); |
5503 | } |
5504 | OS << ")"; |
5505 | } |
5506 | OS << ")\n"; |
5507 | } |
5508 | OS << "End of supported attributes.\n"; |
5509 | } |
5510 | |
5511 | } // end namespace clang |
5512 |
Definitions
- FlattenedSpelling
- FlattenedSpelling
- FlattenedSpelling
- variety
- name
- nameSpace
- knownToGCC
- getSpellingRecord
- FlattenedSpellingInfo
- FlattenedSpellingInfo
- GetFlattenedSpellings
- ReadPCHRecord
- getStorageType
- WritePCHRecord
- NormalizeAttrName
- NormalizeNameForSpellingComparison
- NormalizeGNUAttrSpelling
- getParsedAttrList
- Argument
- Argument
- Argument
- ~Argument
- getLowerName
- getUpperName
- getAttrName
- isOptional
- setOptional
- isFake
- setFake
- writeAccessorDefinitions
- writeASTVisitorTraversal
- writeTemplateInstantiation
- writeCtorBody
- getIsOmitted
- writeDumpChildren
- writeHasChildren
- isEnumArg
- isVariadicEnumArg
- isVariadic
- writeImplicitCtorArgs
- SimpleArgument
- SimpleArgument
- getType
- writeAccessors
- writeCloneArgs
- writeTemplateInstantiationArgs
- writeCtorInitializers
- writeCtorDefaultInitializers
- writeCtorParameters
- writeDeclarations
- writePCHReadDecls
- writePCHReadArgs
- writePCHWrite
- getIsOmitted
- writeValue
- writeDump
- DefaultSimpleArgument
- DefaultSimpleArgument
- writeAccessors
- StringArgument
- StringArgument
- writeAccessors
- writeCloneArgs
- writeTemplateInstantiationArgs
- writeCtorBody
- writeCtorInitializers
- writeCtorDefaultInitializers
- writeCtorParameters
- writeDeclarations
- writePCHReadDecls
- writePCHReadArgs
- writePCHWrite
- writeValue
- writeDump
- AlignedArgument
- AlignedArgument
- writeAccessors
- writeAccessorDefinitions
- writeASTVisitorTraversal
- writeCloneArgs
- writeTemplateInstantiationArgs
- writeCtorBody
- writeCtorInitializers
- writeCtorDefaultInitializers
- writeCtorParameters
- writeImplicitCtorArgs
- writeDeclarations
- writePCHReadArgs
- writePCHReadDecls
- writePCHWrite
- getIsOmitted
- writeValue
- writeDump
- writeDumpChildren
- writeHasChildren
- VariadicArgument
- writeValueImpl
- writeDumpImpl
- VariadicArgument
- VariadicArgument
- getType
- getArgName
- getArgSizeName
- isVariadic
- writeAccessors
- writeSetter
- writeCloneArgs
- writeTemplateInstantiationArgs
- writeASTVisitorTraversal
- writeCtorBody
- writeCtorInitializers
- writeCtorDefaultInitializers
- writeCtorParameters
- writeImplicitCtorArgs
- writeDeclarations
- writePCHReadDecls
- writePCHReadArgs
- writePCHWrite
- writeValue
- writeDump
- VariadicOMPInteropInfoArgument
- VariadicOMPInteropInfoArgument
- writeDump
- writePCHReadDecls
- writePCHWrite
- VariadicParamIdxArgument
- VariadicParamIdxArgument
- writeValueImpl
- writeDumpImpl
- VariadicParamOrParamIdxArgument
- VariadicParamOrParamIdxArgument
- uniqueEnumsInOrder
- EnumArgument
- EnumArgument
- isEnumArg
- writeAccessors
- writeCloneArgs
- writeTemplateInstantiationArgs
- writeCtorInitializers
- writeCtorDefaultInitializers
- writeCtorParameters
- writeDeclarations
- writePCHReadDecls
- writePCHReadArgs
- writePCHWrite
- writeValue
- writeDump
- writeConversion
- VariadicEnumArgument
- writeValueImpl
- VariadicEnumArgument
- isVariadicEnumArg
- writeDeclarations
- writeDump
- writePCHReadDecls
- writePCHWrite
- writeConversion
- VersionArgument
- VersionArgument
- writeAccessors
- writeCloneArgs
- writeTemplateInstantiationArgs
- writeCtorInitializers
- writeCtorDefaultInitializers
- writeCtorParameters
- writeDeclarations
- writePCHReadDecls
- writePCHReadArgs
- writePCHWrite
- writeValue
- writeDump
- ExprArgument
- ExprArgument
- writeASTVisitorTraversal
- writeTemplateInstantiationArgs
- writeTemplateInstantiation
- writeValue
- writeDump
- writeDumpChildren
- writeHasChildren
- VariadicExprArgument
- VariadicExprArgument
- VariadicExprArgument
- writeASTVisitorTraversal
- writeTemplateInstantiationArgs
- writeTemplateInstantiation
- writeDump
- writeDumpChildren
- writeHasChildren
- VariadicIdentifierArgument
- VariadicIdentifierArgument
- VariadicStringArgument
- VariadicStringArgument
- writeCtorBody
- writeValueImpl
- TypeArgument
- TypeArgument
- writeAccessors
- writeASTVisitorTraversal
- writeTemplateInstantiation
- writeTemplateInstantiationArgs
- writePCHWrite
- WrappedAttr
- WrappedAttr
- writePCHReadDecls
- writePCHWrite
- writeDump
- writeDumpChildren
- writeHasChildren
- createArgument
- writeAvailabilityValue
- writeDeprecatedAttrValue
- writeGetSpellingFunction
- writePrettyPrintFunction
- getSpellingListIndex
- writeAttrAccessorDefinition
- SpellingNamesAreCommon
- CreateSemanticSpellings
- WriteSemanticSpellingSwitch
- LateAttrParseKind
- getLateAttrParseKind
- emitClangAttrLateParsedListImpl
- emitClangAttrLateParsedList
- emitClangAttrLateParsedExperimentalList
- hasGNUorCXX11Spelling
- AttributeSubjectMatchRule
- AttributeSubjectMatchRule
- isSubRule
- getSubjects
- getLangOpts
- isAbstractRule
- getName
- isNegatedSubRule
- getSpelling
- getEnumValueName
- getEnumValue
- EnumName
- PragmaClangAttributeSupport
- RuleOrAggregateRuleSet
- RuleOrAggregateRuleSet
- isRule
- getRule
- getAggregateRuleSet
- getRule
- getAggregateRuleSet
- isSupportedPragmaClangAttributeSubject
- doesDeclDeriveFrom
- PragmaClangAttributeSupport
- getPragmaAttributeSupport
- emitMatchRuleList
- isAttributedSupported
- GenerateTestExpression
- generateStrictConformsTo
- generateParsingHelpers
- forEachSpelling
- NameToAttrsMap
- generateNameToAttrsMap
- generateFlattenedSpellingInfo
- nameAppliesToOneAttribute
- emitIfSimpleValue
- emitSingleCondition
- emitStringSwitchCases
- isTypeArgument
- emitClangAttrTypeArgList
- emitClangAttrArgContextList
- isIdentifierArgument
- isVariadicIdentifierArgument
- isVariadicExprArgument
- isStringLiteralArgument
- isVariadicStringLiteralArgument
- emitClangAttrVariadicIdentifierArgList
- emitClangAttrUnevaluatedStringLiteralList
- emitClangAttrIdentifierArgList
- emitClangAttrStrictIdentifierArgList
- keywordThisIsaIdentifierInArgument
- emitClangAttrThisIsaIdentifierArgList
- emitClangAttrAcceptsExprPack
- isRegularKeywordAttribute
- emitFormInitializer
- emitAttributes
- EmitClangAttrClass
- EmitClangAttrImpl
- emitAttrList
- AttrHasPragmaSpelling
- AttrClassDescriptor
- AttrClassDescriptors
- emitDefaultDefine
- AttrClass
- AttrClass
- emitDefaultDefines
- emitUndefs
- emitAttrList
- classifyAttrOnRoot
- emitAttrRange
- classifyAttr
- getFirstAttr
- getLastAttr
- AttrClassHierarchy
- AttrClassHierarchy
- emitDefaultDefines
- emitUndefs
- emitAttrLists
- emitAttrRanges
- classifyAttr
- findClassByRecord
- findSuperClass
- EmitClangAttrList
- EmitClangAttrSubjectMatchRuleList
- EmitClangAttrPCHRead
- EmitClangAttrPCHWrite
- GenerateTargetSpecificAttrCheck
- GenerateTargetSpecificAttrChecks
- GenerateHasAttrSpellingStringSwitch
- EmitClangRegularKeywordAttributeInfo
- EmitCXX11AttributeInfo
- EmitClangAttrHasAttrImpl
- EmitClangAttrSpellingListIndex
- EmitClangAttrASTVisitor
- EmitClangAttrTemplateInstantiateHelper
- EmitClangAttrTemplateInstantiate
- EmitClangAttrParsedAttrList
- EmitAttributeSpellingList
- isArgVariadic
- emitArgInfo
- GetDiagnosticSpelling
- CalculateDiagnostic
- GetSubjectWithSuffix
- functionNameForCustomAppertainsTo
- GenerateCustomAppertainsTo
- GenerateAppertainsTo
- GenerateMutualExclusionsChecks
- emitAttributeMatchRules
- GenerateLangOptRequirements
- GenerateTargetRequirements
- GenerateSpellingTargetRequirements
- GenerateSpellingIndexToSemanticSpelling
- GenerateHandleDeclAttribute
- isParamExpr
- GenerateIsParamExpr
- GenerateHandleAttrWithDelayedArgs
- IsKnownToGCC
- EmitClangAttrParsedAttrImpl
- EmitClangAttrParsedAttrKinds
- EmitClangAttrTextNodeDump
- EmitClangAttrNodeTraverse
- EmitClangAttrParserStringSwitches
- EmitClangAttrSubjectMatchRulesParserStringSwitches
- EmitClangAttrDocTable
- SpellingKind
- NumSpellingKinds
- SpellingList
- operator[]
- add
- merge
- DocumentationData
- DocumentationData
- WriteCategoryHeader
- GetAttributeHeadingAndSpellings
- WriteDocumentation
- EmitClangAttrDocs
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more