Index: include/clang/Parse/CMakeLists.txt =================================================================== --- include/clang/Parse/CMakeLists.txt +++ include/clang/Parse/CMakeLists.txt @@ -1,4 +0,0 @@ -clang_tablegen(AttrParserStringSwitches.inc -gen-clang-attr-parser-string-switches - -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ - SOURCE ../Basic/Attr.td - TARGET ClangAttrParserStringSwitches) Index: include/clang/Sema/AttributeList.h =================================================================== --- include/clang/Sema/AttributeList.h +++ include/clang/Sema/AttributeList.h @@ -104,10 +104,21 @@ unsigned IsStmt : 1; /// True if this attribute has any spellings that are known to gcc unsigned IsKnownToGCC : 1; + /// True if the arguments to this attribute should be parsed in an unevaluated + /// context + unsigned IsUnevaluatedArgContext : 1; + // True if the first argument to the attribute is an identifier + unsigned IsIdentifierArg : 1; + // True if the first argument to the attribute is a type argument + unsigned IsTypeArg : 1; + /// True if this attribute has arguments that require late parsing + unsigned IsLateParsed : 1; ParsedAttrInfo() : AttrKind(0), Syntax(0), NumArgs(0), OptArgs(0), HasCustomParsing(0), - IsTargetSpecific(0), IsType(0), IsStmt(0), IsKnownToGCC(0) { } + IsTargetSpecific(0), IsType(0), IsStmt(0), IsKnownToGCC(0), + IsUnevaluatedArgContext(0), IsIdentifierArg(0), IsTypeArg(0), + IsLateParsed(0) { } virtual ~ParsedAttrInfo() {} Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -71,16 +71,6 @@ return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } -/// isAttributeLateParsed - Return true if the attribute has arguments that -/// require late parsing. -static bool isAttributeLateParsed(const IdentifierInfo &II) { -#define CLANG_ATTR_LATE_PARSED_LIST - return llvm::StringSwitch(II.getName()) -#include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); -#undef CLANG_ATTR_LATE_PARSED_LIST -} - /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: @@ -161,7 +151,9 @@ } // Handle "parameterized" attributes - if (!LateAttrs || !isAttributeLateParsed(*AttrName)) { + std::unique_ptr Info = + AttributeList::getInfo(AttrName, nullptr, AttributeList::AS_GNU); + if (!LateAttrs || !Info->IsLateParsed) { ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr, SourceLocation(), AttributeList::AS_GNU, D); continue; @@ -207,34 +199,6 @@ return Name; } -/// \brief Determine whether the given attribute has an identifier argument. -static bool attributeHasIdentifierArg(const IdentifierInfo &II) { -#define CLANG_ATTR_IDENTIFIER_ARG_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) -#include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); -#undef CLANG_ATTR_IDENTIFIER_ARG_LIST -} - -/// \brief Determine whether the given attribute parses a type argument. -static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { -#define CLANG_ATTR_TYPE_ARG_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) -#include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); -#undef CLANG_ATTR_TYPE_ARG_LIST -} - -/// \brief Determine whether the given attribute requires parsing its arguments -/// in an unevaluated context or not. -static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) { -#define CLANG_ATTR_ARG_CONTEXT_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) -#include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); -#undef CLANG_ATTR_ARG_CONTEXT_LIST -} - IdentifierLoc *Parser::ParseIdentifierLoc() { assert(Tok.is(tok::identifier) && "expected an identifier"); IdentifierLoc *IL = IdentifierLoc::create(Actions.Context, @@ -286,7 +250,7 @@ ArgsVector ArgExprs; if (Tok.is(tok::identifier)) { // If this attribute wants an 'identifier' argument, make it so. - bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName); + bool IsIdentifierArg = Info->IsIdentifierArg; AttributeList::Kind AttrKind = AttributeList::Kind(Info->AttrKind); // If we don't know how to parse this attribute, but this is the only @@ -308,7 +272,7 @@ // Parse the non-empty comma-separated list of expressions. do { - bool Uneval = attributeParsedArgsUnevaluated(*AttrName); + bool Uneval = Info->IsUnevaluatedArgContext; EnterExpressionEvaluationContext Unevaluated( Actions, Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated, /*LambdaContextDecl=*/nullptr, @@ -371,7 +335,7 @@ ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Syntax); return; - } else if (attributeIsTypeArgAttr(*AttrName)) { + } else if (Info->IsTypeArg) { ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Syntax); return; Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -1502,80 +1502,12 @@ OS << " }\n"; } -// Emits the LateParsed property for attributes. -static void emitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - - for (const auto *Attr : Attrs) { - bool LateParsed = Attr->getValueAsBit("LateParsed"); - - if (LateParsed) { - std::vector Spellings = GetFlattenedSpellings(*Attr); - - // FIXME: Handle non-GNU attributes - for (const auto &I : Spellings) { - if (I.variety() != "GNU") - continue; - OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n"; - } - } - } - OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n"; -} - -template -static void forEachUniqueSpelling(const Record &Attr, Fn &&F) { - std::vector Spellings = GetFlattenedSpellings(Attr); - SmallDenseSet Seen; - for (const FlattenedSpelling &S : Spellings) { - if (Seen.insert(S.name()).second) - F(S); - } -} - -/// \brief Emits the first-argument-is-type property for attributes. -static void emitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) { - OS << "#if defined(CLANG_ATTR_TYPE_ARG_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - - for (const auto *Attr : Attrs) { - // Determine whether the first argument is a type. - std::vector Args = Attr->getValueAsListOfDefs("Args"); - if (Args.empty()) - continue; - - if (Args[0]->getSuperClasses().back().first->getName() != "TypeArgument") - continue; - - // All these spellings take a single type argument. - forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; - }); - } - OS << "#endif // CLANG_ATTR_TYPE_ARG_LIST\n\n"; -} - -/// \brief Emits the parse-arguments-in-unevaluated-context property for -/// attributes. -static void emitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS) { - OS << "#if defined(CLANG_ATTR_ARG_CONTEXT_LIST)\n"; - ParsedAttrMap Attrs = getParsedAttrList(Records); - for (const auto &I : Attrs) { - const Record &Attr = *I.second; - - if (!Attr.getValueAsBit("ParseArgumentsAsUnevaluated")) - continue; - - // All these spellings take are parsed unevaluated. - forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; - }); - } - OS << "#endif // CLANG_ATTR_ARG_CONTEXT_LIST\n\n"; -} - -static bool isIdentifierArgument(Record *Arg) { +// Is the first arg of Attr an identifier argument? +static bool isIdentifierArgument(const Record &Attr) { + std::vector ArgRecords = Attr.getValueAsListOfDefs("Args"); + if (ArgRecords.empty()) + return false; + const Record *Arg = ArgRecords[0]; return !Arg->getSuperClasses().empty() && llvm::StringSwitch(Arg->getSuperClasses().back().first->getName()) .Case("IdentifierArgument", true) @@ -1584,23 +1516,14 @@ .Default(false); } -// Emits the first-argument-is-identifier property for attributes. -static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) { - OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - - for (const auto *Attr : Attrs) { - // Determine whether the first argument is an identifier. - std::vector Args = Attr->getValueAsListOfDefs("Args"); - if (Args.empty() || !isIdentifierArgument(Args[0])) - continue; - - // All these spellings take an identifier argument. - forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; - }); - } - OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n"; +// Is the first arg of Attr a type argument? +static bool isTypeArgument(const Record &Attr) { + std::vector ArgRecords = Attr.getValueAsListOfDefs("Args"); + if (ArgRecords.empty()) + return false; + const Record *Arg = ArgRecords[0]; + return !Arg->getSuperClasses().empty() && + ArgRecords[0]->getSuperClasses().back().first->getName() == "TypeArgument"; } namespace clang { @@ -2904,6 +2827,14 @@ OS << Attr.isSubClassOf("StmtAttr") << ";\n"; OS << " IsKnownToGCC = "; OS << IsKnownToGCC(Attr) << ";\n"; + OS << " IsUnevaluatedArgContext = "; + OS << Attr.getValueAsBit("ParseArgumentsAsUnevaluated") << ";\n"; + OS << " IsIdentifierArg = "; + OS << isIdentifierArgument(Attr) << ";\n"; + OS << " IsTypeArg = "; + OS << isTypeArgument(Attr) << ";\n"; + OS << " IsLateParsed = "; + OS << Attr.getValueAsBit("LateParsed") << ";\n"; OS << " }\n"; GenerateAppertainsTo(Attr, OS); GenerateLangOptRequirements(Attr, OS); @@ -2952,15 +2883,6 @@ OS << " }\n"; } -void EmitClangAttrParserStringSwitches(RecordKeeper &Records, - raw_ostream &OS) { - emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS); - emitClangAttrArgContextList(Records, OS); - emitClangAttrIdentifierArgList(Records, OS); - emitClangAttrTypeArgList(Records, OS); - emitClangAttrLateParsedList(Records, OS); -} - class DocumentationData { public: const Record *Documentation; Index: utils/TableGen/TableGen.cpp =================================================================== --- utils/TableGen/TableGen.cpp +++ utils/TableGen/TableGen.cpp @@ -24,7 +24,6 @@ enum ActionType { GenClangAttrClasses, - GenClangAttrParserStringSwitches, GenClangAttrImpl, GenClangAttrList, GenClangAttrPCHRead, @@ -62,9 +61,6 @@ cl::values( clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes", "Generate clang attribute clases"), - clEnumValN(GenClangAttrParserStringSwitches, - "gen-clang-attr-parser-string-switches", - "Generate all parser-related attribute string switches"), clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl", "Generate clang attribute implementations"), clEnumValN(GenClangAttrList, "gen-clang-attr-list", @@ -146,9 +142,6 @@ case GenClangAttrClasses: EmitClangAttrClass(Records, OS); break; - case GenClangAttrParserStringSwitches: - EmitClangAttrParserStringSwitches(Records, OS); - break; case GenClangAttrImpl: EmitClangAttrImpl(Records, OS); break; Index: utils/TableGen/TableGenBackends.h =================================================================== --- utils/TableGen/TableGenBackends.h +++ utils/TableGen/TableGenBackends.h @@ -32,7 +32,6 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, const std::string &N, const std::string &S); -void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);