Removing a bit of custom parsing functionality used by the thread safety analysis APIs. Now using tablegen to determine whether an attribute's arguments should be parsed in an unevaluated context instead of relying on a separate, hard-coded list of attributes.

llvm-svn: 198883
This commit is contained in:
Aaron Ballman 2014-01-09 19:39:35 +00:00
parent a78f365b40
commit 15b27b97b7
9 changed files with 80 additions and 60 deletions

View File

@ -168,6 +168,9 @@ class Attr {
// content. Eg) It parses 3 args, but semantically takes 4 args. Opts out of
// common attribute error checking.
bit HasCustomParsing = 0;
// Set to true if all of the attribute's arguments should be parsed in an
// unevaluated context.
bit ParseArgumentsAsUnevaluated = 0;
// Lists language options, one of which is required to be true for the
// attribute to be applicable. If empty, no language options are required.
list<LangOpt> LangOpts = [];
@ -1008,6 +1011,7 @@ def GuardedBy : InheritableAttr {
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Field, SharedVar], WarnDiag,
"ExpectedFieldOrGlobalVar">;
}
@ -1017,6 +1021,7 @@ def PtGuardedBy : InheritableAttr {
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Field, SharedVar], WarnDiag,
"ExpectedFieldOrGlobalVar">;
}
@ -1026,6 +1031,7 @@ def AcquiredAfter : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Field, SharedVar], WarnDiag,
"ExpectedFieldOrGlobalVar">;
}
@ -1035,6 +1041,7 @@ def AcquiredBefore : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Field, SharedVar], WarnDiag,
"ExpectedFieldOrGlobalVar">;
}
@ -1044,6 +1051,7 @@ def ExclusiveLockFunction : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1052,6 +1060,7 @@ def SharedLockFunction : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1060,6 +1069,7 @@ def AssertExclusiveLock : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1068,6 +1078,7 @@ def AssertSharedLock : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1078,6 +1089,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1088,6 +1100,7 @@ def SharedTrylockFunction : InheritableAttr {
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1096,6 +1109,7 @@ def UnlockFunction : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1104,6 +1118,7 @@ def LockReturned : InheritableAttr {
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1112,6 +1127,7 @@ def LocksExcluded : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1120,6 +1136,7 @@ def ExclusiveLocksRequired : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
@ -1128,6 +1145,7 @@ def SharedLocksRequired : InheritableAttr {
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}

View File

@ -12,3 +12,8 @@ clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrLateParsed)
clang_tablegen(AttrArgContext.inc -gen-clang-attr-arg-context-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrArgContext)

View File

@ -1,6 +1,6 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
BUILT_SOURCES = AttrIdentifierArg.inc AttrLateParsed.inc AttrTypeArg.inc
BUILT_SOURCES = AttrIdentifierArg.inc AttrLateParsed.inc AttrTypeArg.inc AttrArgContext.inc
TABLEGEN_INC_FILES_COMMON = 1
@ -23,3 +23,9 @@ $(ObjDir)/AttrLateParsed.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(Echo) "Building Clang attribute late-parsed table with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-attr-late-parsed-list -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
$(ObjDir)/AttrArgContext.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang attribute argument context table with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-attr-arg-context-list -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<

View File

@ -2058,10 +2058,6 @@ private:
SourceLocation *endLoc);
bool IsThreadSafetyAttribute(StringRef AttrName);
void ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
SourceLocation *EndLoc);
void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,

View File

@ -33,6 +33,7 @@ add_dependencies(clangParse
ClangDiagnosticCommon
ClangDiagnosticParse
ClangStmtNodes
ClangAttrArgContext
)
target_link_libraries(clangParse

View File

@ -207,6 +207,14 @@ static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
.Default(false);
}
/// \brief Determine whether the given attribute requires parsing its arguments
/// in an unevaluated context or not.
static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) {
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrArgContext.inc"
.Default(false);
}
IdentifierLoc *Parser::ParseIdentifierLoc() {
assert(Tok.is(tok::identifier) && "expected an identifier");
IdentifierLoc *IL = IdentifierLoc::create(Actions.Context,
@ -270,13 +278,6 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
return;
}
// Thread safety attributes are parsed in an unevaluated context.
// FIXME: Share the bulk of the parsing code here and just pull out
// the unevaluated context.
if (IsThreadSafetyAttribute(AttrName->getName())) {
ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
// Type safety attributes have their own grammar.
if (AttrKind == AttributeList::AT_TypeTagForDatatype) {
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
@ -291,8 +292,13 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
// Ignore the left paren location for now.
ConsumeParen();
OwningPtr<EnterExpressionEvaluationContext> Unevaluated;
ArgsVector ArgExprs;
if (attributeParsedArgsUnevaluated(*AttrName))
Unevaluated.reset(new EnterExpressionEvaluationContext(Actions,
Sema::Unevaluated));
if (Tok.is(tok::identifier)) {
// If this attribute wants an 'identifier' argument, make it so.
bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName);
@ -1215,54 +1221,6 @@ bool Parser::IsThreadSafetyAttribute(StringRef AttrName) {
.Default(false);
}
/// \brief Parse the contents of thread safety attributes. These
/// should always be parsed as an expression list.
///
/// We need to special case the parsing due to the fact that if the first token
/// of the first argument is an identifier, the main parse loop will store
/// that token as a "parameter" and the rest of
/// the arguments will be added to a list of "arguments". However,
/// subsequent tokens in the first argument are lost. We instead parse each
/// argument as an expression and add all arguments to the list of "arguments".
/// In future, we will take advantage of this special case to also
/// deal with some argument scoping issues here (for example, referring to a
/// function parameter in the attribute on that function).
void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
SourceLocation *EndLoc) {
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ArgsVector ArgExprs;
bool ArgExprsOk = true;
// now parse the list of expressions
while (Tok.isNot(tok::r_paren)) {
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
ArgExprsOk = false;
T.consumeClose();
break;
} else {
ArgExprs.push_back(ArgExpr.release());
}
// Eat the comma, move to the next argument
if (!TryConsumeToken(tok::comma))
break;
}
// Match the ')'.
if (ArgExprsOk && !T.consumeClose()) {
Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, ArgExprs.data(),
ArgExprs.size(), AttributeList::AS_GNU);
}
if (EndLoc)
*EndLoc = T.getCloseLocation();
}
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,

View File

@ -1291,6 +1291,33 @@ void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) {
}
}
/// \brief Emits the parse-arguments-in-unevaluated-context property for
/// attributes.
void EmitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("StringSwitch code to match attributes which require "
"an unevaluated context", OS);
ParsedAttrMap Attrs = getParsedAttrList(Records);
for (ParsedAttrMap::const_iterator I = Attrs.begin(), E = Attrs.end();
I != E; ++I) {
const Record &Attr = *I->second;
if (!Attr.getValueAsBit("ParseArgumentsAsUnevaluated"))
continue;
// All these spellings take are parsed unevaluated.
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 "

View File

@ -25,6 +25,7 @@ using namespace clang;
enum ActionType {
GenClangAttrClasses,
GenClangAttrIdentifierArgList,
GenClangAttrArgContextList,
GenClangAttrTypeArgList,
GenClangAttrImpl,
GenClangAttrList,
@ -66,6 +67,10 @@ cl::opt<ActionType> Action(
"gen-clang-attr-identifier-arg-list",
"Generate a list of attributes that take an "
"identifier as their first argument"),
clEnumValN(GenClangAttrArgContextList,
"gen-clang-attr-arg-context-list",
"Generate a list of attributes that parse their arguments "
"in an unevaluated context"),
clEnumValN(GenClangAttrTypeArgList,
"gen-clang-attr-type-arg-list",
"Generate a list of attributes that take a type as their "
@ -154,6 +159,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrIdentifierArgList:
EmitClangAttrIdentifierArgList(Records, OS);
break;
case GenClangAttrArgContextList:
EmitClangAttrArgContextList(Records, OS);
break;
case GenClangAttrTypeArgList:
EmitClangAttrTypeArgList(Records, OS);
break;

View File

@ -31,6 +31,7 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrArgContextList(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);