diff options
author | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2012-06-18 16:13:52 +0000 |
---|---|---|
committer | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2012-06-18 16:13:52 +0000 |
commit | 93f95f2a2cbb6bb3d17bfb5fc74ce1cccea751b6 (patch) | |
tree | 8240d49bcf20127ffff2af2652d8e4f29b147588 | |
parent | adc6cbf5b502f1b58078455ab4fca66c7daac239 (diff) |
Handle C++11 attribute namespaces automatically.
Now, as long as the 'Namespaces' variable is correct inside Attr.td, the
generated code will correctly admit a C++11 attribute only when it has the
appropriate namespace(s).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158661 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/Attr.td | 7 | ||||
-rw-r--r-- | include/clang/Sema/AttributeList.h | 53 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 27 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/AttributeList.cpp | 18 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAttr.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 3 | ||||
-rw-r--r-- | test/SemaCXX/switch-implicit-fallthrough-per-method.cpp | 12 | ||||
-rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 26 |
9 files changed, 102 insertions, 55 deletions
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index fd97102341..38d5dcb6a6 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -320,8 +320,9 @@ def ExtVectorType : Attr { } def FallThrough : Attr { - let Spellings = ["clang___fallthrough"]; - let Subjects = [CaseStmt, DefaultStmt]; + let Namespaces = ["clang"]; + let Spellings = ["fallthrough"]; + let Subjects = [NullStmt]; } def FastCall : InheritableAttr { @@ -850,4 +851,4 @@ def MultipleInheritance : InheritableAttr { def VirtualInheritance : InheritableAttr { let Spellings = ["__virtual_inheritance"]; -}
\ No newline at end of file +} diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index ef6cf1c09e..9b7a196c36 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -52,6 +52,13 @@ struct AvailabilityChange { /// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used. /// class AttributeList { // TODO: This should really be called ParsedAttribute +public: + /// The style used to specify an attribute. + enum Syntax { + AS_GNU, + AS_CXX11, + AS_Declspec + }; private: IdentifierInfo *AttrName; IdentifierInfo *ScopeName; @@ -64,11 +71,8 @@ private: /// The expressions themselves are stored after the object. unsigned NumArgs : 16; - /// True if Microsoft style: declspec(foo). - unsigned DeclspecAttribute : 1; - - /// True if C++0x-style: [[foo]]. - unsigned CXX0XAttribute : 1; + /// Corresponds to the Syntax enum. + unsigned SyntaxUsed : 2; /// True if already diagnosed as invalid. mutable unsigned Invalid : 1; @@ -123,15 +127,14 @@ private: IdentifierInfo *scopeName, SourceLocation scopeLoc, IdentifierInfo *parmName, SourceLocation parmLoc, Expr **args, unsigned numArgs, - bool declspec, bool cxx0x) + Syntax syntaxUsed) : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), - NumArgs(numArgs), - DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false), + NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), NextInPosition(0), NextInPool(0) { if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*)); - AttrKind = getKind(getName(), getScopeName()); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } AttributeList(IdentifierInfo *attrName, SourceRange attrRange, @@ -142,17 +145,17 @@ private: const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *messageExpr, - bool declspec, bool cxx0x) + Syntax syntaxUsed) : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), - NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), + NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), UnavailableLoc(unavailable), MessageExpr(messageExpr), NextInPosition(0), NextInPool(0) { new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated); new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted); - AttrKind = getKind(getName(), getScopeName()); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } friend class AttributePool; @@ -178,8 +181,8 @@ public: IdentifierInfo *getParameterName() const { return ParmName; } SourceLocation getParameterLoc() const { return ParmLoc; } - bool isDeclspecAttribute() const { return DeclspecAttribute; } - bool isCXX0XAttribute() const { return CXX0XAttribute; } + bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } + bool isCXX0XAttribute() const { return SyntaxUsed == AS_CXX11; } bool isInvalid() const { return Invalid; } void setInvalid(bool b = true) const { Invalid = b; } @@ -188,7 +191,8 @@ public: void setUsedAsTypeAttr() { UsedAsTypeAttr = true; } Kind getKind() const { return Kind(AttrKind); } - static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope); + static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope, + Syntax SyntaxUsed); AttributeList *getNext() const { return NextInPosition; } void setNext(AttributeList *N) { NextInPosition = N; } @@ -372,14 +376,13 @@ public: IdentifierInfo *scopeName, SourceLocation scopeLoc, IdentifierInfo *parmName, SourceLocation parmLoc, Expr **args, unsigned numArgs, - bool declspec = false, bool cxx0x = false) { + AttributeList::Syntax syntax) { void *memory = allocate(sizeof(AttributeList) + numArgs * sizeof(Expr*)); return add(new (memory) AttributeList(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, - args, numArgs, - declspec, cxx0x)); + args, numArgs, syntax)); } AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, @@ -390,14 +393,13 @@ public: const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, - bool declspec = false, bool cxx0x = false) { + AttributeList::Syntax syntax) { void *memory = allocate(AttributeFactory::AvailabilityAllocSize); return add(new (memory) AttributeList(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, introduced, deprecated, obsoleted, - unavailable, MessageExpr, - declspec, cxx0x)); + unavailable, MessageExpr, syntax)); } AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, @@ -499,10 +501,10 @@ public: IdentifierInfo *scopeName, SourceLocation scopeLoc, IdentifierInfo *parmName, SourceLocation parmLoc, Expr **args, unsigned numArgs, - bool declspec = false, bool cxx0x = false) { + AttributeList::Syntax syntax) { AttributeList *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, - args, numArgs, declspec, cxx0x); + args, numArgs, syntax); add(attr); return attr; } @@ -515,12 +517,11 @@ public: const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, - bool declspec = false, bool cxx0x = false) { + AttributeList::Syntax syntax) { AttributeList *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, introduced, deprecated, obsoleted, unavailable, - MessageExpr, - declspec, cxx0x); + MessageExpr, syntax); add(attr); return attr; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index ee394f885b..2e95a317fd 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -159,7 +159,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } else { attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0); + 0, SourceLocation(), 0, 0, AttributeList::AS_GNU); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -275,7 +275,8 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { AttributeList *attr = Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, - ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); + ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(), + AttributeList::AS_GNU); if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection) Diag(Tok, diag::err_iboutletcollection_builtintype); } @@ -319,13 +320,14 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { if (!ArgExpr.isInvalid()) { Expr *ExprList = ArgExpr.take(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), &ExprList, 1, true); + SourceLocation(), &ExprList, 1, + AttributeList::AS_Declspec); } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); } else { attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, true); + 0, SourceLocation(), 0, 0, AttributeList::AS_Declspec); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -344,7 +346,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true); + SourceLocation(), 0, 0, AttributeList::AS_Declspec); } } @@ -354,7 +356,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true); + SourceLocation(), 0, 0, AttributeList::AS_Declspec); } } @@ -364,7 +366,7 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"), AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, false); + SourceLocation(), 0, 0, AttributeList::AS_GNU); } } @@ -700,7 +702,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Changes[Deprecated], Changes[Obsoleted], UnavailableLoc, MessageExpr.take(), - false, false); + AttributeList::AS_GNU); } @@ -905,7 +907,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, // Match the ')'. if (ArgExprsOk && !T.consumeClose()) { Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - ArgExprs.take(), ArgExprs.size()); + ArgExprs.take(), ArgExprs.size(), AttributeList::AS_GNU); } if (EndLoc) *EndLoc = T.getCloseLocation(); @@ -1874,7 +1876,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, ExprVector ArgExprs(Actions); ArgExprs.push_back(ArgExpr.release()); Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, - 0, T.getOpenLocation(), ArgExprs.take(), 1, false, true); + 0, T.getOpenLocation(), ArgExprs.take(), 1, + AttributeList::AS_CXX11); } /// ParseDeclarationSpecifiers @@ -2255,8 +2258,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID); IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); + // FIXME: This does not work correctly if it is set to be a declspec + // attribute, and a GNU attribute is simply incorrect. DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0); + SourceLocation(), 0, 0, AttributeList::AS_GNU); continue; } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 88aa3982fb..b9062927c6 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -907,7 +907,7 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, false); + SourceLocation(), 0, 0, AttributeList::AS_GNU); } } @@ -2899,12 +2899,13 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } bool AttrParsed = false; - switch (AttributeList::getKind(AttrName, ScopeName)) { + switch (AttributeList::getKind(AttrName, ScopeName, + AttributeList::AS_CXX11)) { // No arguments case AttributeList::AT_carries_dependency: // FIXME: implement generic support of attributes with C++11 syntax // see Parse/ParseDecl.cpp: ParseGNUAttributes - case AttributeList::AT_clang___fallthrough: + case AttributeList::AT_fallthrough: case AttributeList::AT_noreturn: { if (Tok.is(tok::l_paren)) { Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) @@ -2916,7 +2917,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), ScopeName, ScopeLoc, 0, - SourceLocation(), 0, 0, false, true); + SourceLocation(), 0, 0, AttributeList::AS_CXX11); AttrParsed = true; break; } diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 8e7029350a..93f8c5d359 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -95,13 +95,15 @@ AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, SourceLocation TokLoc, int Arg) { Expr *IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg), C.IntTy, TokLoc); - return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1, 0); + return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1, + AttributeList::AS_GNU); } #include "clang/Sema/AttrParsedAttrKinds.inc" AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name, - const IdentifierInfo *ScopeName) { + const IdentifierInfo *ScopeName, + Syntax SyntaxUsed) { StringRef AttrName = Name->getName(); // Normalize the attribute name, __foo__ becomes foo. @@ -109,10 +111,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name, AttrName.size() >= 4) AttrName = AttrName.substr(2, AttrName.size() - 4); - // FIXME: implement attribute namespacing correctly. SmallString<64> Buf; if (ScopeName) - AttrName = ((Buf += ScopeName->getName()) += "___") += AttrName; - - return ::getAttrKind(AttrName); + Buf += ScopeName->getName(); + // Ensure that in the case of C++11 attributes, we look for '::foo' if it is + // unscoped. + if (ScopeName || SyntaxUsed == AS_CXX11) + Buf += "::"; + Buf += AttrName; + + return ::getAttrKind(Buf); } diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index 912d7c6482..60b2d1e3ff 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -48,7 +48,7 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range) { switch (A.getKind()) { - case AttributeList::AT_clang___fallthrough: + case AttributeList::AT_fallthrough: return handleFallThroughAttr(S, St, A, Range); default: // if we're here, then we parsed an attribute, but didn't recognize it as a diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 2ad5bcbf4d..0bdf75b3ae 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2728,8 +2728,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(), /*scope*/ 0, SourceLocation(), &S.Context.Idents.get(attrStr), SourceLocation(), - /*args*/ 0, 0, - /*declspec*/ false, /*C++0x*/ false); + /*args*/ 0, 0, AttributeList::AS_GNU); spliceAttrIntoList(*attr, chunk.getAttrListRef()); // TODO: mark whether we did this inference? diff --git a/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp b/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp index 9f9f5924a0..7c52e5138b 100644 --- a/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp +++ b/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp @@ -37,3 +37,15 @@ int fallthrough2(int n) { } return n; } + +void unscoped(int n) { + switch (n % 2) { + case 0: + // FIXME: This should be typo-corrected, probably. + [[fallthrough]]; + case 2: // expected-warning{{unannotated fall-through}} expected-note{{clang::fallthrough}} expected-note{{break;}} + [[clang::fallthrough]]; + case 1: + break; + } +} diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index abca58d578..7e1eaf8541 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringMatcher.h" @@ -1128,6 +1129,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { if (SemaHandler || Ignored) { std::vector<StringRef> Spellings = getValueAsListOfStrings(Attr, "Spellings"); + std::vector<StringRef> Namespaces = + getValueAsListOfStrings(Attr, "Namespaces"); for (std::vector<StringRef>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { @@ -1136,16 +1139,35 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { : Spellings.front()); StringRef Spelling = NormalizeAttrSpelling(*I); + for (std::vector<StringRef>::const_iterator NI = Namespaces.begin(), + NE = Namespaces.end(); NI != NE; ++NI) { + SmallString<64> Buf; + Buf += *NI; + Buf += "::"; + Buf += Spelling; + + if (SemaHandler) + Matches.push_back( + StringMatcher::StringPair( + Buf.str(), + "return AttributeList::AT_" + AttrName.str() + ";")); + else + Matches.push_back( + StringMatcher::StringPair( + Buf.str(), + "return AttributeList::IgnoredAttribute;")); + } + if (SemaHandler) Matches.push_back( StringMatcher::StringPair( Spelling, - std::string("return AttributeList::AT_")+AttrName.str() + ";")); + "return AttributeList::AT_" + AttrName.str() + ";")); else Matches.push_back( StringMatcher::StringPair( Spelling, - std::string("return AttributeList::IgnoredAttribute;"))); + "return AttributeList::IgnoredAttribute;")); } } } |