Remove some hard-coded specialness for thread-safety attributes from the parser, and made it more declarative. If an attribute is allowed to appear on a function definition when late parsed, it can now use the FunctionDefinition attribute subject. It's treated as a FunctionDecl for most purposes, except it also gets exposed on the AttributeList so that it can be used while parsing.

llvm-svn: 199676
This commit is contained in:
Aaron Ballman 2014-01-20 17:18:35 +00:00
parent 43ccae1bb4
commit 9a99e0da5a
7 changed files with 54 additions and 49 deletions

View File

@ -74,6 +74,12 @@ def HasFunctionProto : SubsetSubject<DeclBase,
isa<ObjCMethodDecl>(S) ||
isa<BlockDecl>(S)}]>;
// This is a fake Decl node that represents a function definition as well as a
// function declaration. This can be used for attributes which are allowed to
// appear on the definition of a function that's been late parsed. It is
// treated and diagnosed the same as a FunctionDecl.
def FunctionDefinition : DDecl<Function, 1>;
// A single argument to an attribute
class Argument<string name, bit optional> {
string Name = name;
@ -1097,7 +1103,7 @@ def ScopedLockable : InheritableAttr {
def NoThreadSafetyAnalysis : InheritableAttr {
let Spellings = [GNU<"no_thread_safety_analysis">];
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def GuardedBy : InheritableAttr {
@ -1146,7 +1152,7 @@ def ExclusiveLockFunction : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def SharedLockFunction : InheritableAttr {
@ -1155,7 +1161,7 @@ def SharedLockFunction : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def AssertExclusiveLock : InheritableAttr {
@ -1164,7 +1170,7 @@ def AssertExclusiveLock : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def AssertSharedLock : InheritableAttr {
@ -1173,7 +1179,7 @@ def AssertSharedLock : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
// The first argument is an integer or boolean value specifying the return value
@ -1184,7 +1190,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
// The first argument is an integer or boolean value specifying the return value
@ -1195,7 +1201,7 @@ def SharedTrylockFunction : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def UnlockFunction : InheritableAttr {
@ -1204,7 +1210,7 @@ def UnlockFunction : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def LockReturned : InheritableAttr {
@ -1213,7 +1219,7 @@ def LockReturned : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def LocksExcluded : InheritableAttr {
@ -1222,7 +1228,7 @@ def LocksExcluded : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def ExclusiveLocksRequired : InheritableAttr {
@ -1231,7 +1237,7 @@ def ExclusiveLocksRequired : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
def SharedLocksRequired : InheritableAttr {
@ -1240,7 +1246,7 @@ def SharedLocksRequired : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
}
// C/C++ consumed attributes.

View File

@ -2066,8 +2066,6 @@ private:
ParsedAttributes &attrs,
SourceLocation *endLoc);
bool IsThreadSafetyAttribute(StringRef AttrName);
void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,

View File

@ -494,6 +494,7 @@ public:
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
bool diagnoseLangOpts(class Sema &S) const;
bool existsInTarget(llvm::Triple T) const;
bool canAppearOnFunctionDefinition() const;
};
/// A factory, from which one makes pools, from which one creates

View File

@ -1096,13 +1096,6 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) {
// FIXME: Do not warn on C++11 attributes, once we start supporting
// them here.
Diag(Tok, diag::warn_attribute_on_function_definition)
<< &LA.AttrName;
}
ParsedAttributes Attrs(AttrFactory);
SourceLocation endLoc;
@ -1148,9 +1141,14 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
}
for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) {
const AttributeList *AL = Attrs.getList();
if (OnDefinition && AL && !AL->isCXX11Attribute() &&
!AL->canAppearOnFunctionDefinition())
Diag(Tok, diag::warn_attribute_on_function_definition)
<< &LA.AttrName;
for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i)
Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs);
}
if (Tok.getLocation() != OrigLoc) {
// Due to a parsing error, we either went over the cached tokens or
@ -1164,31 +1162,6 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
}
}
/// \brief Wrapper around a case statement checking if AttrName is
/// one of the thread safety attributes
bool Parser::IsThreadSafetyAttribute(StringRef AttrName) {
return llvm::StringSwitch<bool>(AttrName)
.Case("guarded_by", true)
.Case("guarded_var", true)
.Case("pt_guarded_by", true)
.Case("pt_guarded_var", true)
.Case("lockable", true)
.Case("scoped_lockable", true)
.Case("no_thread_safety_analysis", true)
.Case("acquired_after", true)
.Case("acquired_before", true)
.Case("exclusive_lock_function", true)
.Case("shared_lock_function", true)
.Case("exclusive_trylock_function", true)
.Case("shared_trylock_function", true)
.Case("unlock_function", true)
.Case("lock_returned", true)
.Case("locks_excluded", true)
.Case("exclusive_locks_required", true)
.Case("shared_locks_required", true)
.Default(false);
}
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,

View File

@ -1055,7 +1055,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (Tok.isNot(tok::equal)) {
AttributeList *DtorAttrs = D.getAttributes();
while (DtorAttrs) {
if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName()) &&
if (!DtorAttrs->canAppearOnFunctionDefinition() &&
!DtorAttrs->isCXX11Attribute()) {
Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition)
<< DtorAttrs->getName();

View File

@ -150,6 +150,7 @@ struct ParsedAttrInfo {
unsigned HasCustomParsing : 1;
unsigned IsTargetSpecific : 1;
unsigned IsType : 1;
unsigned CanAppearOnFuncDef : 1;
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
const Decl *);
@ -196,3 +197,7 @@ bool AttributeList::isTypeAttr() const {
bool AttributeList::existsInTarget(llvm::Triple T) const {
return getInfo(*this).ExistsInTarget(T);
}
bool AttributeList::canAppearOnFunctionDefinition() const {
return getInfo(*this).CanAppearOnFuncDef;
}

View File

@ -2006,6 +2006,7 @@ static std::string CalculateDiagnostic(const Record &S) {
uint32_t V = StringSwitch<uint32_t>(Name)
.Case("Function", Func)
.Case("FunctionDefinition", Func)
.Case("Var", Var)
.Case("ObjCMethod", ObjCMethod)
.Case("ParmVar", Param)
@ -2081,6 +2082,8 @@ static std::string GetSubjectWithSuffix(const Record *R) {
std::string B = R->getName();
if (B == "DeclBase")
return "Decl";
else if (B == "FunctionDefinition")
return "FunctionDecl";
return B + "Decl";
}
static std::string GenerateCustomAppertainsTo(const Record &Subject,
@ -2311,6 +2314,24 @@ static std::string GenerateTargetRequirements(const Record &Attr,
return FnName;
}
static bool CanAppearOnFuncDef(const Record &Attr) {
// Look at the subjects this function appertains to; if a FunctionDefinition
// appears in the list, then this attribute can appear on a function
// definition.
if (Attr.isValueUnset("Subjects"))
return false;
std::vector<Record *> Subjects = Attr.getValueAsDef("Subjects")->
getValueAsListOfDefs("Subjects");
for (std::vector<Record *>::const_iterator I = Subjects.begin(),
E = Subjects.end(); I != E; ++I) {
const Record &Subject = **I;
if (Subject.getName() == "FunctionDefinition")
return true;
}
return false;
}
/// Emits the parsed attribute helpers
void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Parsed attribute helpers", OS);
@ -2346,6 +2367,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
SS << ", " << I->second->getValueAsBit("HasCustomParsing");
SS << ", " << I->second->isSubClassOf("TargetSpecificAttr");
SS << ", " << I->second->isSubClassOf("TypeAttr");
SS << ", " << CanAppearOnFuncDef(*I->second);
SS << ", " << GenerateAppertainsTo(*I->second, OS);
SS << ", " << GenerateLangOptRequirements(*I->second, OS);
SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS);