From: Aaron Ballman Date: Mon, 20 Jan 2014 17:18:35 +0000 (+0000) Subject: Remove some hard-coded specialness for thread-safety attributes from the parser,... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1e6097c61dd8b3fb2b6b9cd34e88bfa29500f814;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@199676 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 5ea3915ccf..28b8ade7a2 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -74,6 +74,12 @@ def HasFunctionProto : SubsetSubject(S) || isa(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; + // A single argument to an attribute class Argument { 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. diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index aa7aca30af..f7aa05eefa 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2066,8 +2066,6 @@ private: ParsedAttributes &attrs, SourceLocation *endLoc); - bool IsThreadSafetyAttribute(StringRef AttrName); - void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 8b5c47aaef..f1ba653433 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -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 diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e8207bc80b..f6435f9eea 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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(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, diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 740e6fb3dd..316448aa83 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -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(); diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 834001c666..6ffc02776e 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -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; +} diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 4e5fd095e7..c1916cba0c 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -2006,6 +2006,7 @@ static std::string CalculateDiagnostic(const Record &S) { uint32_t V = StringSwitch(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 Subjects = Attr.getValueAsDef("Subjects")-> + getValueAsListOfDefs("Subjects"); + for (std::vector::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);