forked from OSchip/llvm-project
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:
parent
43ccae1bb4
commit
9a99e0da5a
|
@ -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.
|
||||
|
|
|
@ -2066,8 +2066,6 @@ private:
|
|||
ParsedAttributes &attrs,
|
||||
SourceLocation *endLoc);
|
||||
|
||||
bool IsThreadSafetyAttribute(StringRef AttrName);
|
||||
|
||||
void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
|
||||
SourceLocation AttrNameLoc,
|
||||
ParsedAttributes &Attrs,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue