ClangAttrEmitter.cpp revision 703d412d192397b6fa17c5d99a4c1389aa2be2f3
1//===- ClangAttrEmitter.cpp - Generate Clang attribute handling =-*- C++ -*--=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// These tablegen backends emit Clang attribute processing code 11// 12//===----------------------------------------------------------------------===// 13 14#include "ClangAttrEmitter.h" 15#include "llvm/ADT/StringSwitch.h" 16#include "llvm/TableGen/Record.h" 17#include "llvm/TableGen/StringMatcher.h" 18#include <algorithm> 19#include <cctype> 20#include <set> 21 22using namespace llvm; 23 24static const std::vector<StringRef> 25getValueAsListOfStrings(Record &R, StringRef FieldName) { 26 ListInit *List = R.getValueAsListInit(FieldName); 27 assert (List && "Got a null ListInit"); 28 29 std::vector<StringRef> Strings; 30 Strings.reserve(List->getSize()); 31 32 for (ListInit::const_iterator i = List->begin(), e = List->end(); 33 i != e; 34 ++i) { 35 assert(*i && "Got a null element in a ListInit"); 36 if (StringInit *S = dynamic_cast<StringInit *>(*i)) 37 Strings.push_back(S->getValue()); 38 else 39 assert(false && "Got a non-string, non-code element in a ListInit"); 40 } 41 42 return Strings; 43} 44 45static std::string ReadPCHRecord(StringRef type) { 46 return StringSwitch<std::string>(type) 47 .EndsWith("Decl *", "GetLocalDeclAs<" 48 + std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])") 49 .Case("QualType", "getLocalType(F, Record[Idx++])") 50 .Case("Expr *", "ReadSubExpr()") 51 .Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)") 52 .Case("SourceLocation", "ReadSourceLocation(F, Record, Idx)") 53 .Default("Record[Idx++]"); 54} 55 56// Assumes that the way to get the value is SA->getname() 57static std::string WritePCHRecord(StringRef type, StringRef name) { 58 return StringSwitch<std::string>(type) 59 .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + 60 ", Record);\n") 61 .Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n") 62 .Case("Expr *", "AddStmt(" + std::string(name) + ");\n") 63 .Case("IdentifierInfo *", 64 "AddIdentifierRef(" + std::string(name) + ", Record);\n") 65 .Case("SourceLocation", 66 "AddSourceLocation(" + std::string(name) + ", Record);\n") 67 .Default("Record.push_back(" + std::string(name) + ");\n"); 68} 69 70// Normalize attribute name by removing leading and trailing 71// underscores. For example, __foo, foo__, __foo__ would 72// become foo. 73static StringRef NormalizeAttrName(StringRef AttrName) { 74 if (AttrName.startswith("__")) 75 AttrName = AttrName.substr(2, AttrName.size()); 76 77 if (AttrName.endswith("__")) 78 AttrName = AttrName.substr(0, AttrName.size() - 2); 79 80 return AttrName; 81} 82 83// Normalize attribute spelling only if the spelling has both leading 84// and trailing underscores. For example, __ms_struct__ will be 85// normalized to "ms_struct"; __cdecl will remain intact. 86static StringRef NormalizeAttrSpelling(StringRef AttrSpelling) { 87 if (AttrSpelling.startswith("__") && AttrSpelling.endswith("__")) { 88 AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4); 89 } 90 91 return AttrSpelling; 92} 93 94namespace { 95 class Argument { 96 std::string lowerName, upperName; 97 StringRef attrName; 98 99 public: 100 Argument(Record &Arg, StringRef Attr) 101 : lowerName(Arg.getValueAsString("Name")), upperName(lowerName), 102 attrName(Attr) { 103 if (!lowerName.empty()) { 104 lowerName[0] = std::tolower(lowerName[0]); 105 upperName[0] = std::toupper(upperName[0]); 106 } 107 } 108 virtual ~Argument() {} 109 110 StringRef getLowerName() const { return lowerName; } 111 StringRef getUpperName() const { return upperName; } 112 StringRef getAttrName() const { return attrName; } 113 114 // These functions print the argument contents formatted in different ways. 115 virtual void writeAccessors(raw_ostream &OS) const = 0; 116 virtual void writeAccessorDefinitions(raw_ostream &OS) const {} 117 virtual void writeCloneArgs(raw_ostream &OS) const = 0; 118 virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0; 119 virtual void writeTemplateInstantiation(raw_ostream &OS) const {} 120 virtual void writeCtorBody(raw_ostream &OS) const {} 121 virtual void writeCtorInitializers(raw_ostream &OS) const = 0; 122 virtual void writeCtorParameters(raw_ostream &OS) const = 0; 123 virtual void writeDeclarations(raw_ostream &OS) const = 0; 124 virtual void writePCHReadArgs(raw_ostream &OS) const = 0; 125 virtual void writePCHReadDecls(raw_ostream &OS) const = 0; 126 virtual void writePCHWrite(raw_ostream &OS) const = 0; 127 virtual void writeValue(raw_ostream &OS) const = 0; 128 }; 129 130 class SimpleArgument : public Argument { 131 std::string type; 132 133 public: 134 SimpleArgument(Record &Arg, StringRef Attr, std::string T) 135 : Argument(Arg, Attr), type(T) 136 {} 137 138 std::string getType() const { return type; } 139 140 void writeAccessors(raw_ostream &OS) const { 141 OS << " " << type << " get" << getUpperName() << "() const {\n"; 142 OS << " return " << getLowerName() << ";\n"; 143 OS << " }"; 144 } 145 void writeCloneArgs(raw_ostream &OS) const { 146 OS << getLowerName(); 147 } 148 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 149 OS << "A->get" << getUpperName() << "()"; 150 } 151 void writeCtorInitializers(raw_ostream &OS) const { 152 OS << getLowerName() << "(" << getUpperName() << ")"; 153 } 154 void writeCtorParameters(raw_ostream &OS) const { 155 OS << type << " " << getUpperName(); 156 } 157 void writeDeclarations(raw_ostream &OS) const { 158 OS << type << " " << getLowerName() << ";"; 159 } 160 void writePCHReadDecls(raw_ostream &OS) const { 161 std::string read = ReadPCHRecord(type); 162 OS << " " << type << " " << getLowerName() << " = " << read << ";\n"; 163 } 164 void writePCHReadArgs(raw_ostream &OS) const { 165 OS << getLowerName(); 166 } 167 void writePCHWrite(raw_ostream &OS) const { 168 OS << " " << WritePCHRecord(type, "SA->get" + 169 std::string(getUpperName()) + "()"); 170 } 171 void writeValue(raw_ostream &OS) const { 172 if (type == "FunctionDecl *") { 173 OS << "\" << get" << getUpperName() << "()->getNameInfo().getAsString() << \""; 174 } else if (type == "IdentifierInfo *") { 175 OS << "\" << get" << getUpperName() << "()->getName() << \""; 176 } else if (type == "QualType") { 177 OS << "\" << get" << getUpperName() << "().getAsString() << \""; 178 } else if (type == "SourceLocation") { 179 OS << "\" << get" << getUpperName() << "().getRawEncoding() << \""; 180 } else { 181 OS << "\" << get" << getUpperName() << "() << \""; 182 } 183 } 184 }; 185 186 class StringArgument : public Argument { 187 public: 188 StringArgument(Record &Arg, StringRef Attr) 189 : Argument(Arg, Attr) 190 {} 191 192 void writeAccessors(raw_ostream &OS) const { 193 OS << " llvm::StringRef get" << getUpperName() << "() const {\n"; 194 OS << " return llvm::StringRef(" << getLowerName() << ", " 195 << getLowerName() << "Length);\n"; 196 OS << " }\n"; 197 OS << " unsigned get" << getUpperName() << "Length() const {\n"; 198 OS << " return " << getLowerName() << "Length;\n"; 199 OS << " }\n"; 200 OS << " void set" << getUpperName() 201 << "(ASTContext &C, llvm::StringRef S) {\n"; 202 OS << " " << getLowerName() << "Length = S.size();\n"; 203 OS << " this->" << getLowerName() << " = new (C, 1) char [" 204 << getLowerName() << "Length];\n"; 205 OS << " std::memcpy(this->" << getLowerName() << ", S.data(), " 206 << getLowerName() << "Length);\n"; 207 OS << " }"; 208 } 209 void writeCloneArgs(raw_ostream &OS) const { 210 OS << "get" << getUpperName() << "()"; 211 } 212 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 213 OS << "A->get" << getUpperName() << "()"; 214 } 215 void writeCtorBody(raw_ostream &OS) const { 216 OS << " std::memcpy(" << getLowerName() << ", " << getUpperName() 217 << ".data(), " << getLowerName() << "Length);"; 218 } 219 void writeCtorInitializers(raw_ostream &OS) const { 220 OS << getLowerName() << "Length(" << getUpperName() << ".size())," 221 << getLowerName() << "(new (Ctx, 1) char[" << getLowerName() 222 << "Length])"; 223 } 224 void writeCtorParameters(raw_ostream &OS) const { 225 OS << "llvm::StringRef " << getUpperName(); 226 } 227 void writeDeclarations(raw_ostream &OS) const { 228 OS << "unsigned " << getLowerName() << "Length;\n"; 229 OS << "char *" << getLowerName() << ";"; 230 } 231 void writePCHReadDecls(raw_ostream &OS) const { 232 OS << " std::string " << getLowerName() 233 << "= ReadString(Record, Idx);\n"; 234 } 235 void writePCHReadArgs(raw_ostream &OS) const { 236 OS << getLowerName(); 237 } 238 void writePCHWrite(raw_ostream &OS) const { 239 OS << " AddString(SA->get" << getUpperName() << "(), Record);\n"; 240 } 241 void writeValue(raw_ostream &OS) const { 242 OS << "\\\"\" << get" << getUpperName() << "() << \"\\\""; 243 } 244 }; 245 246 class AlignedArgument : public Argument { 247 public: 248 AlignedArgument(Record &Arg, StringRef Attr) 249 : Argument(Arg, Attr) 250 {} 251 252 void writeAccessors(raw_ostream &OS) const { 253 OS << " bool is" << getUpperName() << "Dependent() const;\n"; 254 255 OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n"; 256 257 OS << " bool is" << getUpperName() << "Expr() const {\n"; 258 OS << " return is" << getLowerName() << "Expr;\n"; 259 OS << " }\n"; 260 261 OS << " Expr *get" << getUpperName() << "Expr() const {\n"; 262 OS << " assert(is" << getLowerName() << "Expr);\n"; 263 OS << " return " << getLowerName() << "Expr;\n"; 264 OS << " }\n"; 265 266 OS << " TypeSourceInfo *get" << getUpperName() << "Type() const {\n"; 267 OS << " assert(!is" << getLowerName() << "Expr);\n"; 268 OS << " return " << getLowerName() << "Type;\n"; 269 OS << " }"; 270 } 271 void writeAccessorDefinitions(raw_ostream &OS) const { 272 OS << "bool " << getAttrName() << "Attr::is" << getUpperName() 273 << "Dependent() const {\n"; 274 OS << " if (is" << getLowerName() << "Expr)\n"; 275 OS << " return " << getLowerName() << "Expr && (" << getLowerName() 276 << "Expr->isValueDependent() || " << getLowerName() 277 << "Expr->isTypeDependent());\n"; 278 OS << " else\n"; 279 OS << " return " << getLowerName() 280 << "Type->getType()->isDependentType();\n"; 281 OS << "}\n"; 282 283 // FIXME: Do not do the calculation here 284 // FIXME: Handle types correctly 285 // A null pointer means maximum alignment 286 // FIXME: Load the platform-specific maximum alignment, rather than 287 // 16, the x86 max. 288 OS << "unsigned " << getAttrName() << "Attr::get" << getUpperName() 289 << "(ASTContext &Ctx) const {\n"; 290 OS << " assert(!is" << getUpperName() << "Dependent());\n"; 291 OS << " if (is" << getLowerName() << "Expr)\n"; 292 OS << " return (" << getLowerName() << "Expr ? " << getLowerName() 293 << "Expr->EvaluateKnownConstInt(Ctx).getZExtValue() : 16)" 294 << "* Ctx.getCharWidth();\n"; 295 OS << " else\n"; 296 OS << " return 0; // FIXME\n"; 297 OS << "}\n"; 298 } 299 void writeCloneArgs(raw_ostream &OS) const { 300 OS << "is" << getLowerName() << "Expr, is" << getLowerName() 301 << "Expr ? static_cast<void*>(" << getLowerName() 302 << "Expr) : " << getLowerName() 303 << "Type"; 304 } 305 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 306 // FIXME: move the definition in Sema::InstantiateAttrs to here. 307 // In the meantime, aligned attributes are cloned. 308 } 309 void writeCtorBody(raw_ostream &OS) const { 310 OS << " if (is" << getLowerName() << "Expr)\n"; 311 OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>(" 312 << getUpperName() << ");\n"; 313 OS << " else\n"; 314 OS << " " << getLowerName() 315 << "Type = reinterpret_cast<TypeSourceInfo *>(" << getUpperName() 316 << ");"; 317 } 318 void writeCtorInitializers(raw_ostream &OS) const { 319 OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)"; 320 } 321 void writeCtorParameters(raw_ostream &OS) const { 322 OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName(); 323 } 324 void writeDeclarations(raw_ostream &OS) const { 325 OS << "bool is" << getLowerName() << "Expr;\n"; 326 OS << "union {\n"; 327 OS << "Expr *" << getLowerName() << "Expr;\n"; 328 OS << "TypeSourceInfo *" << getLowerName() << "Type;\n"; 329 OS << "};"; 330 } 331 void writePCHReadArgs(raw_ostream &OS) const { 332 OS << "is" << getLowerName() << "Expr, " << getLowerName() << "Ptr"; 333 } 334 void writePCHReadDecls(raw_ostream &OS) const { 335 OS << " bool is" << getLowerName() << "Expr = Record[Idx++];\n"; 336 OS << " void *" << getLowerName() << "Ptr;\n"; 337 OS << " if (is" << getLowerName() << "Expr)\n"; 338 OS << " " << getLowerName() << "Ptr = ReadExpr(F);\n"; 339 OS << " else\n"; 340 OS << " " << getLowerName() 341 << "Ptr = GetTypeSourceInfo(F, Record, Idx);\n"; 342 } 343 void writePCHWrite(raw_ostream &OS) const { 344 OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n"; 345 OS << " if (SA->is" << getUpperName() << "Expr())\n"; 346 OS << " AddStmt(SA->get" << getUpperName() << "Expr());\n"; 347 OS << " else\n"; 348 OS << " AddTypeSourceInfo(SA->get" << getUpperName() 349 << "Type(), Record);\n"; 350 } 351 void writeValue(raw_ostream &OS) const { 352 OS << "\" << get" << getUpperName() << "(Ctx) << \""; 353 } 354 }; 355 356 class VariadicArgument : public Argument { 357 std::string type; 358 359 public: 360 VariadicArgument(Record &Arg, StringRef Attr, std::string T) 361 : Argument(Arg, Attr), type(T) 362 {} 363 364 std::string getType() const { return type; } 365 366 void writeAccessors(raw_ostream &OS) const { 367 OS << " typedef " << type << "* " << getLowerName() << "_iterator;\n"; 368 OS << " " << getLowerName() << "_iterator " << getLowerName() 369 << "_begin() const {\n"; 370 OS << " return " << getLowerName() << ";\n"; 371 OS << " }\n"; 372 OS << " " << getLowerName() << "_iterator " << getLowerName() 373 << "_end() const {\n"; 374 OS << " return " << getLowerName() << " + " << getLowerName() 375 << "Size;\n"; 376 OS << " }\n"; 377 OS << " unsigned " << getLowerName() << "_size() const {\n" 378 << " return " << getLowerName() << "Size;\n"; 379 OS << " }"; 380 } 381 void writeCloneArgs(raw_ostream &OS) const { 382 OS << getLowerName() << ", " << getLowerName() << "Size"; 383 } 384 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 385 // This isn't elegant, but we have to go through public methods... 386 OS << "A->" << getLowerName() << "_begin(), " 387 << "A->" << getLowerName() << "_size()"; 388 } 389 void writeCtorBody(raw_ostream &OS) const { 390 // FIXME: memcpy is not safe on non-trivial types. 391 OS << " std::memcpy(" << getLowerName() << ", " << getUpperName() 392 << ", " << getLowerName() << "Size * sizeof(" << getType() << "));\n"; 393 } 394 void writeCtorInitializers(raw_ostream &OS) const { 395 OS << getLowerName() << "Size(" << getUpperName() << "Size), " 396 << getLowerName() << "(new (Ctx, 16) " << getType() << "[" 397 << getLowerName() << "Size])"; 398 } 399 void writeCtorParameters(raw_ostream &OS) const { 400 OS << getType() << " *" << getUpperName() << ", unsigned " 401 << getUpperName() << "Size"; 402 } 403 void writeDeclarations(raw_ostream &OS) const { 404 OS << " unsigned " << getLowerName() << "Size;\n"; 405 OS << " " << getType() << " *" << getLowerName() << ";"; 406 } 407 void writePCHReadDecls(raw_ostream &OS) const { 408 OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n"; 409 OS << " llvm::SmallVector<" << type << ", 4> " << getLowerName() 410 << ";\n"; 411 OS << " " << getLowerName() << ".reserve(" << getLowerName() 412 << "Size);\n"; 413 OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n"; 414 415 std::string read = ReadPCHRecord(type); 416 OS << " " << getLowerName() << ".push_back(" << read << ");\n"; 417 } 418 void writePCHReadArgs(raw_ostream &OS) const { 419 OS << getLowerName() << ".data(), " << getLowerName() << "Size"; 420 } 421 void writePCHWrite(raw_ostream &OS) const{ 422 OS << " Record.push_back(SA->" << getLowerName() << "_size());\n"; 423 OS << " for (" << getAttrName() << "Attr::" << getLowerName() 424 << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->" 425 << getLowerName() << "_end(); i != e; ++i)\n"; 426 OS << " " << WritePCHRecord(type, "(*i)"); 427 } 428 void writeValue(raw_ostream &OS) const { 429 OS << "\";\n"; 430 OS << " bool isFirst = true;\n" 431 << " for (" << getAttrName() << "Attr::" << getLowerName() 432 << "_iterator i = " << getLowerName() << "_begin(), e = " 433 << getLowerName() << "_end(); i != e; ++i) {\n" 434 << " if (isFirst) isFirst = false;\n" 435 << " else OS << \", \";\n" 436 << " OS << *i;\n" 437 << " }\n"; 438 OS << " OS << \""; 439 } 440 }; 441 442 class EnumArgument : public Argument { 443 std::string type; 444 std::vector<StringRef> values, enums; 445 public: 446 EnumArgument(Record &Arg, StringRef Attr) 447 : Argument(Arg, Attr), type(Arg.getValueAsString("Type")), 448 values(getValueAsListOfStrings(Arg, "Values")), 449 enums(getValueAsListOfStrings(Arg, "Enums")) 450 {} 451 452 void writeAccessors(raw_ostream &OS) const { 453 OS << " " << type << " get" << getUpperName() << "() const {\n"; 454 OS << " return " << getLowerName() << ";\n"; 455 OS << " }"; 456 } 457 void writeCloneArgs(raw_ostream &OS) const { 458 OS << getLowerName(); 459 } 460 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 461 OS << "A->get" << getUpperName() << "()"; 462 } 463 void writeCtorInitializers(raw_ostream &OS) const { 464 OS << getLowerName() << "(" << getUpperName() << ")"; 465 } 466 void writeCtorParameters(raw_ostream &OS) const { 467 OS << type << " " << getUpperName(); 468 } 469 void writeDeclarations(raw_ostream &OS) const { 470 // Calculate the various enum values 471 std::vector<StringRef> uniques(enums); 472 std::sort(uniques.begin(), uniques.end()); 473 uniques.erase(std::unique(uniques.begin(), uniques.end()), 474 uniques.end()); 475 // FIXME: Emit a proper error 476 assert(!uniques.empty()); 477 478 std::vector<StringRef>::iterator i = uniques.begin(), 479 e = uniques.end(); 480 // The last one needs to not have a comma. 481 --e; 482 483 OS << "public:\n"; 484 OS << " enum " << type << " {\n"; 485 for (; i != e; ++i) 486 OS << " " << *i << ",\n"; 487 OS << " " << *e << "\n"; 488 OS << " };\n"; 489 OS << "private:\n"; 490 OS << " " << type << " " << getLowerName() << ";"; 491 } 492 void writePCHReadDecls(raw_ostream &OS) const { 493 OS << " " << getAttrName() << "Attr::" << type << " " << getLowerName() 494 << "(static_cast<" << getAttrName() << "Attr::" << type 495 << ">(Record[Idx++]));\n"; 496 } 497 void writePCHReadArgs(raw_ostream &OS) const { 498 OS << getLowerName(); 499 } 500 void writePCHWrite(raw_ostream &OS) const { 501 OS << "Record.push_back(SA->get" << getUpperName() << "());\n"; 502 } 503 void writeValue(raw_ostream &OS) const { 504 OS << "\" << get" << getUpperName() << "() << \""; 505 } 506 }; 507 508 class VersionArgument : public Argument { 509 public: 510 VersionArgument(Record &Arg, StringRef Attr) 511 : Argument(Arg, Attr) 512 {} 513 514 void writeAccessors(raw_ostream &OS) const { 515 OS << " VersionTuple get" << getUpperName() << "() const {\n"; 516 OS << " return " << getLowerName() << ";\n"; 517 OS << " }\n"; 518 OS << " void set" << getUpperName() 519 << "(ASTContext &C, VersionTuple V) {\n"; 520 OS << " " << getLowerName() << " = V;\n"; 521 OS << " }"; 522 } 523 void writeCloneArgs(raw_ostream &OS) const { 524 OS << "get" << getUpperName() << "()"; 525 } 526 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 527 OS << "A->get" << getUpperName() << "()"; 528 } 529 void writeCtorBody(raw_ostream &OS) const { 530 } 531 void writeCtorInitializers(raw_ostream &OS) const { 532 OS << getLowerName() << "(" << getUpperName() << ")"; 533 } 534 void writeCtorParameters(raw_ostream &OS) const { 535 OS << "VersionTuple " << getUpperName(); 536 } 537 void writeDeclarations(raw_ostream &OS) const { 538 OS << "VersionTuple " << getLowerName() << ";\n"; 539 } 540 void writePCHReadDecls(raw_ostream &OS) const { 541 OS << " VersionTuple " << getLowerName() 542 << "= ReadVersionTuple(Record, Idx);\n"; 543 } 544 void writePCHReadArgs(raw_ostream &OS) const { 545 OS << getLowerName(); 546 } 547 void writePCHWrite(raw_ostream &OS) const { 548 OS << " AddVersionTuple(SA->get" << getUpperName() << "(), Record);\n"; 549 } 550 void writeValue(raw_ostream &OS) const { 551 OS << getLowerName() << "=\" << get" << getUpperName() << "() << \""; 552 } 553 }; 554 555 class ExprArgument : public SimpleArgument { 556 public: 557 ExprArgument(Record &Arg, StringRef Attr) 558 : SimpleArgument(Arg, Attr, "Expr *") 559 {} 560 561 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 562 OS << "tempInst" << getUpperName(); 563 } 564 565 void writeTemplateInstantiation(raw_ostream &OS) const { 566 OS << " " << getType() << " tempInst" << getUpperName() << ";\n"; 567 OS << " {\n"; 568 OS << " EnterExpressionEvaluationContext " 569 << "Unevaluated(S, Sema::Unevaluated);\n"; 570 OS << " ExprResult " << "Result = S.SubstExpr(" 571 << "A->get" << getUpperName() << "(), TemplateArgs);\n"; 572 OS << " tempInst" << getUpperName() << " = " 573 << "Result.takeAs<Expr>();\n"; 574 OS << " }\n"; 575 } 576 }; 577 578 class VariadicExprArgument : public VariadicArgument { 579 public: 580 VariadicExprArgument(Record &Arg, StringRef Attr) 581 : VariadicArgument(Arg, Attr, "Expr *") 582 {} 583 584 void writeTemplateInstantiationArgs(raw_ostream &OS) const { 585 OS << "tempInst" << getUpperName() << ", " 586 << "A->" << getLowerName() << "_size()"; 587 } 588 589 void writeTemplateInstantiation(raw_ostream &OS) const { 590 OS << " " << getType() << " *tempInst" << getUpperName() 591 << " = new (C, 16) " << getType() 592 << "[A->" << getLowerName() << "_size()];\n"; 593 OS << " {\n"; 594 OS << " EnterExpressionEvaluationContext " 595 << "Unevaluated(S, Sema::Unevaluated);\n"; 596 OS << " " << getType() << " *TI = tempInst" << getUpperName() 597 << ";\n"; 598 OS << " " << getType() << " *I = A->" << getLowerName() 599 << "_begin();\n"; 600 OS << " " << getType() << " *E = A->" << getLowerName() 601 << "_end();\n"; 602 OS << " for (; I != E; ++I, ++TI) {\n"; 603 OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n"; 604 OS << " *TI = Result.takeAs<Expr>();\n"; 605 OS << " }\n"; 606 OS << " }\n"; 607 } 608 }; 609} 610 611static Argument *createArgument(Record &Arg, StringRef Attr, 612 Record *Search = 0) { 613 if (!Search) 614 Search = &Arg; 615 616 Argument *Ptr = 0; 617 llvm::StringRef ArgName = Search->getName(); 618 619 if (ArgName == "AlignedArgument") Ptr = new AlignedArgument(Arg, Attr); 620 else if (ArgName == "EnumArgument") Ptr = new EnumArgument(Arg, Attr); 621 else if (ArgName == "ExprArgument") Ptr = new ExprArgument(Arg, Attr); 622 else if (ArgName == "FunctionArgument") 623 Ptr = new SimpleArgument(Arg, Attr, "FunctionDecl *"); 624 else if (ArgName == "IdentifierArgument") 625 Ptr = new SimpleArgument(Arg, Attr, "IdentifierInfo *"); 626 else if (ArgName == "BoolArgument") Ptr = new SimpleArgument(Arg, Attr, 627 "bool"); 628 else if (ArgName == "IntArgument") Ptr = new SimpleArgument(Arg, Attr, "int"); 629 else if (ArgName == "StringArgument") Ptr = new StringArgument(Arg, Attr); 630 else if (ArgName == "TypeArgument") 631 Ptr = new SimpleArgument(Arg, Attr, "QualType"); 632 else if (ArgName == "UnsignedArgument") 633 Ptr = new SimpleArgument(Arg, Attr, "unsigned"); 634 else if (ArgName == "SourceLocArgument") 635 Ptr = new SimpleArgument(Arg, Attr, "SourceLocation"); 636 else if (ArgName == "VariadicUnsignedArgument") 637 Ptr = new VariadicArgument(Arg, Attr, "unsigned"); 638 else if (ArgName == "VariadicExprArgument") 639 Ptr = new VariadicExprArgument(Arg, Attr); 640 else if (ArgName == "VersionArgument") 641 Ptr = new VersionArgument(Arg, Attr); 642 643 if (!Ptr) { 644 std::vector<Record*> Bases = Search->getSuperClasses(); 645 for (std::vector<Record*>::iterator i = Bases.begin(), e = Bases.end(); 646 i != e; ++i) { 647 Ptr = createArgument(Arg, Attr, *i); 648 if (Ptr) 649 break; 650 } 651 } 652 return Ptr; 653} 654 655static void writeAvailabilityValue(raw_ostream &OS) { 656 OS << "\" << getPlatform()->getName();\n" 657 << " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n" 658 << " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n" 659 << " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n" 660 << " if (getUnavailable()) OS << \", unavailable\";\n" 661 << " OS << \""; 662} 663 664void ClangAttrClassEmitter::run(raw_ostream &OS) { 665 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 666 OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n"; 667 OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n"; 668 669 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 670 671 for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); 672 i != e; ++i) { 673 Record &R = **i; 674 675 if (!R.getValueAsBit("ASTNode")) 676 continue; 677 678 const std::string &SuperName = R.getSuperClasses().back()->getName(); 679 680 OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n"; 681 682 std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); 683 std::vector<Argument*> Args; 684 std::vector<Argument*>::iterator ai, ae; 685 Args.reserve(ArgRecords.size()); 686 687 for (std::vector<Record*>::iterator ri = ArgRecords.begin(), 688 re = ArgRecords.end(); 689 ri != re; ++ri) { 690 Record &ArgRecord = **ri; 691 Argument *Arg = createArgument(ArgRecord, R.getName()); 692 assert(Arg); 693 Args.push_back(Arg); 694 695 Arg->writeDeclarations(OS); 696 OS << "\n\n"; 697 } 698 699 ae = Args.end(); 700 701 OS << "\n public:\n"; 702 OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; 703 704 for (ai = Args.begin(); ai != ae; ++ai) { 705 OS << " , "; 706 (*ai)->writeCtorParameters(OS); 707 OS << "\n"; 708 } 709 710 OS << " )\n"; 711 OS << " : " << SuperName << "(attr::" << R.getName() << ", R)\n"; 712 713 for (ai = Args.begin(); ai != ae; ++ai) { 714 OS << " , "; 715 (*ai)->writeCtorInitializers(OS); 716 OS << "\n"; 717 } 718 719 OS << " {\n"; 720 721 for (ai = Args.begin(); ai != ae; ++ai) { 722 (*ai)->writeCtorBody(OS); 723 OS << "\n"; 724 } 725 OS << " }\n\n"; 726 727 OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n"; 728 OS << " virtual void printPretty(llvm::raw_ostream &OS, ASTContext &Ctx) const;\n"; 729 730 for (ai = Args.begin(); ai != ae; ++ai) { 731 (*ai)->writeAccessors(OS); 732 OS << "\n\n"; 733 } 734 735 OS << R.getValueAsString("AdditionalMembers"); 736 OS << "\n\n"; 737 738 OS << " static bool classof(const Attr *A) { return A->getKind() == " 739 << "attr::" << R.getName() << "; }\n"; 740 OS << " static bool classof(const " << R.getName() 741 << "Attr *) { return true; }\n"; 742 743 bool LateParsed = R.getValueAsBit("LateParsed"); 744 OS << " virtual bool isLateParsed() const { return " 745 << LateParsed << "; }\n"; 746 747 OS << "};\n\n"; 748 } 749 750 OS << "#endif\n"; 751} 752 753void ClangAttrImplEmitter::run(raw_ostream &OS) { 754 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 755 756 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 757 std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ri, re; 758 std::vector<Argument*>::iterator ai, ae; 759 760 for (; i != e; ++i) { 761 Record &R = **i; 762 763 if (!R.getValueAsBit("ASTNode")) 764 continue; 765 766 std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); 767 std::vector<StringRef> Spellings = getValueAsListOfStrings(R, "Spellings"); 768 std::vector<Argument*> Args; 769 for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri) 770 Args.push_back(createArgument(**ri, R.getName())); 771 772 for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai) 773 (*ai)->writeAccessorDefinitions(OS); 774 775 OS << R.getName() << "Attr *" << R.getName() 776 << "Attr::clone(ASTContext &C) const {\n"; 777 OS << " return new (C) " << R.getName() << "Attr(getLocation(), C"; 778 for (ai = Args.begin(); ai != ae; ++ai) { 779 OS << ", "; 780 (*ai)->writeCloneArgs(OS); 781 } 782 OS << ");\n}\n\n"; 783 784 OS << "void " << R.getName() << "Attr::printPretty(" 785 << "llvm::raw_ostream &OS, ASTContext &Ctx) const {\n"; 786 if (Spellings.begin() != Spellings.end()) { 787 OS << " OS << \" __attribute__((" << *Spellings.begin(); 788 if (Args.size()) OS << "("; 789 if (*Spellings.begin()=="availability") { 790 writeAvailabilityValue(OS); 791 } else { 792 for (ai = Args.begin(); ai != ae; ++ai) { 793 if (ai!=Args.begin()) OS <<", "; 794 (*ai)->writeValue(OS); 795 } 796 } 797 if (Args.size()) OS << ")"; 798 OS << "))\";\n"; 799 } 800 OS << "}\n\n"; 801 } 802} 803 804static void EmitAttrList(raw_ostream &OS, StringRef Class, 805 const std::vector<Record*> &AttrList) { 806 std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end(); 807 808 if (i != e) { 809 // Move the end iterator back to emit the last attribute. 810 for(--e; i != e; ++i) { 811 if (!(*i)->getValueAsBit("ASTNode")) 812 continue; 813 814 OS << Class << "(" << (*i)->getName() << ")\n"; 815 } 816 817 OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n"; 818 } 819} 820 821void ClangAttrListEmitter::run(raw_ostream &OS) { 822 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 823 824 OS << "#ifndef LAST_ATTR\n"; 825 OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n"; 826 OS << "#endif\n\n"; 827 828 OS << "#ifndef INHERITABLE_ATTR\n"; 829 OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n"; 830 OS << "#endif\n\n"; 831 832 OS << "#ifndef LAST_INHERITABLE_ATTR\n"; 833 OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; 834 OS << "#endif\n\n"; 835 836 OS << "#ifndef INHERITABLE_PARAM_ATTR\n"; 837 OS << "#define INHERITABLE_PARAM_ATTR(NAME) ATTR(NAME)\n"; 838 OS << "#endif\n\n"; 839 840 OS << "#ifndef LAST_INHERITABLE_PARAM_ATTR\n"; 841 OS << "#define LAST_INHERITABLE_PARAM_ATTR(NAME)" 842 " INHERITABLE_PARAM_ATTR(NAME)\n"; 843 OS << "#endif\n\n"; 844 845 Record *InhClass = Records.getClass("InheritableAttr"); 846 Record *InhParamClass = Records.getClass("InheritableParamAttr"); 847 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), 848 NonInhAttrs, InhAttrs, InhParamAttrs; 849 for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); 850 i != e; ++i) { 851 if (!(*i)->getValueAsBit("ASTNode")) 852 continue; 853 854 if ((*i)->isSubClassOf(InhParamClass)) 855 InhParamAttrs.push_back(*i); 856 else if ((*i)->isSubClassOf(InhClass)) 857 InhAttrs.push_back(*i); 858 else 859 NonInhAttrs.push_back(*i); 860 } 861 862 EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs); 863 EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs); 864 EmitAttrList(OS, "ATTR", NonInhAttrs); 865 866 OS << "#undef LAST_ATTR\n"; 867 OS << "#undef INHERITABLE_ATTR\n"; 868 OS << "#undef LAST_INHERITABLE_ATTR\n"; 869 OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n"; 870 OS << "#undef ATTR\n"; 871} 872 873void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { 874 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 875 876 Record *InhClass = Records.getClass("InheritableAttr"); 877 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), 878 ArgRecords; 879 std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; 880 std::vector<Argument*> Args; 881 std::vector<Argument*>::iterator ri, re; 882 883 OS << " switch (Kind) {\n"; 884 OS << " default:\n"; 885 OS << " assert(0 && \"Unknown attribute!\");\n"; 886 OS << " break;\n"; 887 for (; i != e; ++i) { 888 Record &R = **i; 889 if (!R.getValueAsBit("ASTNode")) 890 continue; 891 892 OS << " case attr::" << R.getName() << ": {\n"; 893 if (R.isSubClassOf(InhClass)) 894 OS << " bool isInherited = Record[Idx++];\n"; 895 ArgRecords = R.getValueAsListOfDefs("Args"); 896 Args.clear(); 897 for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) { 898 Argument *A = createArgument(**ai, R.getName()); 899 Args.push_back(A); 900 A->writePCHReadDecls(OS); 901 } 902 OS << " New = new (Context) " << R.getName() << "Attr(Range, Context"; 903 for (ri = Args.begin(), re = Args.end(); ri != re; ++ri) { 904 OS << ", "; 905 (*ri)->writePCHReadArgs(OS); 906 } 907 OS << ");\n"; 908 if (R.isSubClassOf(InhClass)) 909 OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n"; 910 OS << " break;\n"; 911 OS << " }\n"; 912 } 913 OS << " }\n"; 914} 915 916void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) { 917 Record *InhClass = Records.getClass("InheritableAttr"); 918 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; 919 std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; 920 921 OS << " switch (A->getKind()) {\n"; 922 OS << " default:\n"; 923 OS << " llvm_unreachable(\"Unknown attribute kind!\");\n"; 924 OS << " break;\n"; 925 for (; i != e; ++i) { 926 Record &R = **i; 927 if (!R.getValueAsBit("ASTNode")) 928 continue; 929 OS << " case attr::" << R.getName() << ": {\n"; 930 Args = R.getValueAsListOfDefs("Args"); 931 if (R.isSubClassOf(InhClass) || !Args.empty()) 932 OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName() 933 << "Attr>(A);\n"; 934 if (R.isSubClassOf(InhClass)) 935 OS << " Record.push_back(SA->isInherited());\n"; 936 for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai) 937 createArgument(**ai, R.getName())->writePCHWrite(OS); 938 OS << " break;\n"; 939 OS << " }\n"; 940 } 941 OS << " }\n"; 942} 943 944void ClangAttrSpellingListEmitter::run(raw_ostream &OS) { 945 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 946 947 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 948 949 for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { 950 Record &Attr = **I; 951 952 std::vector<StringRef> Spellings = getValueAsListOfStrings(Attr, "Spellings"); 953 954 for (std::vector<StringRef>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { 955 StringRef Spelling = *I; 956 OS << ".Case(\"" << Spelling << "\", true)\n"; 957 } 958 } 959 960} 961 962void ClangAttrLateParsedListEmitter::run(raw_ostream &OS) { 963 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 964 965 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 966 967 for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); 968 I != E; ++I) { 969 Record &Attr = **I; 970 971 bool LateParsed = Attr.getValueAsBit("LateParsed"); 972 973 if (LateParsed) { 974 std::vector<StringRef> Spellings = 975 getValueAsListOfStrings(Attr, "Spellings"); 976 977 for (std::vector<StringRef>::const_iterator I = Spellings.begin(), 978 E = Spellings.end(); I != E; ++I) { 979 OS << ".Case(\"" << (*I) << "\", " << LateParsed << ")\n"; 980 } 981 } 982 } 983} 984 985 986void ClangAttrTemplateInstantiateEmitter::run(raw_ostream &OS) { 987 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 988 989 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 990 991 OS << "namespace clang {\n" 992 << "namespace sema {\n\n" 993 << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " 994 << "Sema &S,\n" 995 << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n" 996 << " switch (At->getKind()) {\n" 997 << " default:\n" 998 << " break;\n"; 999 1000 for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); 1001 I != E; ++I) { 1002 Record &R = **I; 1003 if (!R.getValueAsBit("ASTNode")) 1004 continue; 1005 1006 OS << " case attr::" << R.getName() << ": {\n"; 1007 OS << " const " << R.getName() << "Attr *A = cast<" 1008 << R.getName() << "Attr>(At);\n"; 1009 bool TDependent = R.getValueAsBit("TemplateDependent"); 1010 1011 if (!TDependent) { 1012 OS << " return A->clone(C);\n"; 1013 OS << " }\n"; 1014 continue; 1015 } 1016 1017 std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); 1018 std::vector<Argument*> Args; 1019 std::vector<Argument*>::iterator ai, ae; 1020 Args.reserve(ArgRecords.size()); 1021 1022 for (std::vector<Record*>::iterator ri = ArgRecords.begin(), 1023 re = ArgRecords.end(); 1024 ri != re; ++ri) { 1025 Record &ArgRecord = **ri; 1026 Argument *Arg = createArgument(ArgRecord, R.getName()); 1027 assert(Arg); 1028 Args.push_back(Arg); 1029 } 1030 ae = Args.end(); 1031 1032 for (ai = Args.begin(); ai != ae; ++ai) { 1033 (*ai)->writeTemplateInstantiation(OS); 1034 } 1035 OS << " return new (C) " << R.getName() << "Attr(A->getLocation(), C"; 1036 for (ai = Args.begin(); ai != ae; ++ai) { 1037 OS << ", "; 1038 (*ai)->writeTemplateInstantiationArgs(OS); 1039 } 1040 OS << ");\n }\n"; 1041 } 1042 OS << " } // end switch\n" 1043 << " llvm_unreachable(\"Unknown attribute!\");\n" 1044 << " return 0;\n" 1045 << "}\n\n" 1046 << "} // end namespace sema\n" 1047 << "} // end namespace clang\n"; 1048} 1049 1050void ClangAttrParsedAttrListEmitter::run(raw_ostream &OS) { 1051 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 1052 1053 OS << "#ifndef PARSED_ATTR\n"; 1054 OS << "#define PARSED_ATTR(NAME) NAME\n"; 1055 OS << "#endif\n\n"; 1056 1057 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 1058 std::set<StringRef> ProcessedAttrs; 1059 1060 for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); 1061 I != E; ++I) { 1062 Record &Attr = **I; 1063 1064 bool SemaHandler = Attr.getValueAsBit("SemaHandler"); 1065 bool DistinctSpellings = Attr.getValueAsBit("DistinctSpellings"); 1066 1067 if (SemaHandler) { 1068 std::vector<StringRef> Spellings = 1069 getValueAsListOfStrings(Attr, "Spellings"); 1070 1071 for (std::vector<StringRef>::const_iterator I = Spellings.begin(), 1072 E = Spellings.end(); I != E; ++I) { 1073 StringRef AttrName = *I; 1074 1075 AttrName = NormalizeAttrName(AttrName); 1076 // skip if a normalized version has been processed. 1077 if (ProcessedAttrs.find(AttrName) != ProcessedAttrs.end()) 1078 continue; 1079 else 1080 ProcessedAttrs.insert(AttrName); 1081 1082 OS << "PARSED_ATTR(" << AttrName << ")\n"; 1083 1084 if (!DistinctSpellings) 1085 break; 1086 } 1087 } 1088 } 1089} 1090 1091void ClangAttrParsedAttrKindsEmitter::run(raw_ostream &OS) { 1092 OS << "// This file is generated by TableGen. Do not edit.\n\n"; 1093 OS << "\n"; 1094 1095 std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); 1096 1097 std::vector<StringMatcher::StringPair> Matches; 1098 for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); 1099 I != E; ++I) { 1100 Record &Attr = **I; 1101 1102 bool SemaHandler = Attr.getValueAsBit("SemaHandler"); 1103 bool Ignored = Attr.getValueAsBit("Ignored"); 1104 bool DistinctSpellings = Attr.getValueAsBit("DistinctSpellings"); 1105 if (SemaHandler || Ignored) { 1106 std::vector<StringRef> Spellings = 1107 getValueAsListOfStrings(Attr, "Spellings"); 1108 1109 for (std::vector<StringRef>::const_iterator I = Spellings.begin(), 1110 E = Spellings.end(); I != E; ++I) { 1111 StringRef AttrName = NormalizeAttrName(DistinctSpellings 1112 ? *I 1113 : Spellings.front()); 1114 StringRef Spelling = NormalizeAttrSpelling(*I); 1115 1116 if (SemaHandler) 1117 Matches.push_back( 1118 StringMatcher::StringPair( 1119 Spelling, 1120 std::string("return AttributeList::AT_")+AttrName.str() + ";")); 1121 else 1122 Matches.push_back( 1123 StringMatcher::StringPair( 1124 Spelling, 1125 std::string("return AttributeList::IgnoredAttribute;"))); 1126 } 1127 } 1128 } 1129 1130 OS << "static AttributeList::Kind getAttrKind(StringRef Name) {\n"; 1131 StringMatcher("Name", Matches, OS).Emit(); 1132 OS << "return AttributeList::UnknownAttribute;\n" 1133 << "}\n"; 1134} 1135 1136 1137