SOURCE ../Basic/Attr.td
TARGET ClangAttrIdentifierArg)
+clang_tablegen(AttrTypeArg.inc -gen-clang-attr-type-arg-list
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrTypeArg)
+
clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
}
}
-/// \brief Determine whether the given attribute has an identifier argument.
-static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
- StringRef Name = II.getName();
+/// \brief Normalizes an attribute name by dropping prefixed and suffixed __.
+static StringRef normalizeAttrName(StringRef Name) {
if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
Name = Name.drop_front(2).drop_back(2);
- return llvm::StringSwitch<bool>(Name)
+ return Name;
+}
+
+/// \brief Determine whether the given attribute has an identifier argument.
+static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrIdentifierArg.inc"
.Default(false);
}
+/// \brief Determine whether the given attribute parses a type argument.
+static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrTypeArg.inc"
+ .Default(false);
+}
+
IdentifierLoc *Parser::ParseIdentifierLoc() {
assert(Tok.is(tok::identifier) && "expected an identifier");
IdentifierLoc *IL = IdentifierLoc::create(Actions.Context,
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
- // __attribute__((vec_type_hint)) and iboutletcollection expect a type arg.
- if (AttrKind == AttributeList::AT_VecTypeHint ||
- AttrKind == AttributeList::AT_IBOutletCollection) {
+ // Some attributes expect solely a type parameter.
+ if (attributeIsTypeArgAttr(*AttrName)) {
ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
.Default(false);
}
+/// \brief Emits the first-argument-is-type property for attributes.
+void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("llvm::StringSwitch code to match attributes with a "
+ "type argument", OS);
+
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record *>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &Attr = **I;
+
+ // Determine whether the first argument is a type.
+ std::vector<Record *> Args = Attr.getValueAsListOfDefs("Args");
+ if (Args.empty())
+ continue;
+
+ if (Args[0]->getSuperClasses().back()->getName() != "TypeArgument")
+ continue;
+
+ // All these spellings take a single type argument.
+ std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
+ std::set<std::string> Emitted;
+ for (std::vector<Record*>::const_iterator I = Spellings.begin(),
+ E = Spellings.end(); I != E; ++I) {
+ if (Emitted.insert((*I)->getValueAsString("Name")).second)
+ OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
+ << "true" << ")\n";
+ }
+ }
+}
+
// Emits the first-argument-is-identifier property for attributes.
void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("llvm::StringSwitch code to match attributes with "
enum ActionType {
GenClangAttrClasses,
GenClangAttrIdentifierArgList,
+ GenClangAttrTypeArgList,
GenClangAttrImpl,
GenClangAttrList,
GenClangAttrPCHRead,
"gen-clang-attr-identifier-arg-list",
"Generate a list of attributes that take an "
"identifier as their first argument"),
+ clEnumValN(GenClangAttrTypeArgList,
+ "gen-clang-attr-type-arg-list",
+ "Generate a list of attributes that take a type as their "
+ "first argument"),
clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
"Generate clang attribute implementations"),
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
case GenClangAttrIdentifierArgList:
EmitClangAttrIdentifierArgList(Records, OS);
break;
+ case GenClangAttrTypeArgList:
+ EmitClangAttrTypeArgList(Records, OS);
+ break;
case GenClangAttrImpl:
EmitClangAttrImpl(Records, OS);
break;
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);