From 54ecd9863fac6ec2a66296756af78f29f12f1667 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 20 Feb 2013 19:22:51 +0000 Subject: [PATCH] Process and handle attributes on conditions and for loop variables. Process and diagnose attributes on alias declarations, using directives, and attribute declarations. llvm-svn: 175649 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/include/clang/Parse/Parser.h | 3 +- clang/include/clang/Sema/Sema.h | 4 +++ clang/lib/Parse/ParseDecl.cpp | 5 +++- clang/lib/Parse/ParseDeclCXX.cpp | 37 +++++++++++------------- clang/lib/Parse/ParseExprCXX.cpp | 1 + clang/lib/Parse/ParseStmt.cpp | 3 -- clang/lib/Parse/Parser.cpp | 12 ++++++-- clang/lib/Sema/SemaDeclCXX.cpp | 26 ++++++++++++++++- clang/lib/Sema/SemaType.cpp | 6 +++- clang/test/Parser/cxx0x-attributes.cpp | 22 ++++++++++---- 11 files changed, 86 insertions(+), 35 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b69bfda..3377a68 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1908,6 +1908,8 @@ def warn_attribute_not_on_decl : Warning< "%0 attribute ignored when parsing type">, InGroup; def err_base_specifier_attribute : Error< "%0 attribute cannot be applied to a base specifier">; +def err_attribute_declaration : Error< + "%0 attribute cannot be used in an attribute declaration">; // Availability attribute def warn_availability_unknown_platform : Warning< diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index ff4d46e..c0044cb 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1800,7 +1800,8 @@ public: Declarator::TheContext Context = Declarator::TypeNameContext, AccessSpecifier AS = AS_none, - Decl **OwnedType = 0); + Decl **OwnedType = 0, + ParsedAttributes *Attrs = 0); private: void ParseBlockId(SourceLocation CaretLoc); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9d9014a..4d37c89 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1447,6 +1447,9 @@ public: SourceLocation AsmLoc, SourceLocation RParenLoc); + /// \brief Handle a C++11 attribute-declaration. + void ActOnAttributeDeclaration(AttributeList *AttrList); + /// \brief The parser has processed a module import declaration. /// /// \param AtLoc The location of the '@' symbol, if any. @@ -3429,6 +3432,7 @@ public: MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, + AttributeList *AttrList, TypeResult Type); /// BuildCXXConstructExpr - Creates a complete call to a constructor, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index cb013e7..8bfdffc 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -38,13 +38,16 @@ using namespace clang; TypeResult Parser::ParseTypeName(SourceRange *Range, Declarator::TheContext Context, AccessSpecifier AS, - Decl **OwnedType) { + Decl **OwnedType, + ParsedAttributes *Attrs) { DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context); if (DSC == DSC_normal) DSC = DSC_type_specifier; // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); + if (Attrs) + DS.addAttributes(Attrs->getList()); ParseSpecifierQualifierList(DS, AS, DSC); if (OwnedType) *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 4d428ce..22f5863 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -451,24 +451,21 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Decl **OwnedType) { CXXScopeSpec SS; SourceLocation TypenameLoc; - bool IsTypeName; - ParsedAttributesWithRange attrs(AttrFactory); + bool IsTypeName = false; + ParsedAttributesWithRange Attrs(AttrFactory); // FIXME: Simply skip the attributes and diagnose, don't bother parsing them. - MaybeParseCXX11Attributes(attrs); - ProhibitAttributes(attrs); - attrs.clear(); - attrs.Range = SourceRange(); + MaybeParseCXX11Attributes(Attrs); + ProhibitAttributes(Attrs); + Attrs.clear(); + Attrs.Range = SourceRange(); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { - TypenameLoc = Tok.getLocation(); - ConsumeToken(); + TypenameLoc = ConsumeToken(); IsTypeName = true; } - else - IsTypeName = false; // Parse nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); @@ -495,14 +492,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(Attrs); // Maybe this is an alias-declaration. bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; if (IsAliasDecl) { - // TODO: Attribute support. C++0x attributes may appear before the equals. - // Where can GNU attributes appear? + // TODO: Can GNU attributes appear here? ConsumeToken(); Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? @@ -547,20 +543,21 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? Declarator::AliasTemplateContext : - Declarator::AliasDeclContext, AS, OwnedType); + Declarator::AliasDeclContext, AS, OwnedType, + &Attrs); } else { // C++11 attributes are not allowed on a using-declaration, but GNU ones // are. - ProhibitAttributes(attrs); + ProhibitAttributes(Attrs); // Parse (optional) attributes (most likely GNU strong-using extension). - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(Attrs); } // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - !attrs.empty() ? "attributes list" : + !Attrs.empty() ? "attributes list" : IsAliasDecl ? "alias declaration" : "using declaration", tok::semi); @@ -592,13 +589,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, MultiTemplateParamsArg TemplateParamsArg( TemplateParams ? TemplateParams->data() : 0, TemplateParams ? TemplateParams->size() : 0); - // FIXME: Propagate attributes. return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, - UsingLoc, Name, TypeAlias); + UsingLoc, Name, Attrs.getList(), + TypeAlias); } return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, - Name, attrs.getList(), + Name, Attrs.getList(), IsTypeName, TypenameLoc); } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 613b0be..0a1111e 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1383,6 +1383,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, // type-specifier-seq DeclSpec DS(AttrFactory); + DS.takeAttributesFrom(attrs); ParseSpecifierQualifierList(DS); // declarator diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 4c8bd6f..a77c034 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1385,9 +1385,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); - // In C++0x, "for (T NS:a" might not be a typo for :: bool MightBeForRangeStmt = getLangOpts().CPlusPlus; ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 1a667da..2d8d5b1 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -566,7 +566,6 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { /// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl] /// function-definition /// declaration -/// [C++0x] empty-declaration /// [GNU] asm-definition /// [GNU] __extension__ external-declaration /// [OBJC] objc-class-definition @@ -578,8 +577,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { /// [C++] linkage-specification /// [GNU] asm-definition: /// simple-asm-expr ';' +/// [C++11] empty-declaration +/// [C++11] attribute-declaration /// -/// [C++0x] empty-declaration: +/// [C++11] empty-declaration: /// ';' /// /// [C++0x/GNU] 'extern' 'template' declaration @@ -624,6 +625,13 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, HandlePragmaOpenCLExtension(); return DeclGroupPtrTy(); case tok::semi: + // Either a C++11 empty-declaration or attribute-declaration. + if (attrs.Range.isValid()) { + // FIXME: Add an AST representation for this. + Actions.ActOnAttributeDeclaration(attrs.getList()); + return DeclGroupPtrTy(); + } + ConsumeExtraSemi(OutsideFunction); // TODO: Invoke action for top-level semicolon. return DeclGroupPtrTy(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8b0ccd7..8198856 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6456,7 +6456,9 @@ Decl *Sema::ActOnUsingDirective(Scope *S, Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); } - // FIXME: We ignore attributes for now. + if (UDir) + ProcessDeclAttributeList(S, UDir, AttrList); + return UDir; } @@ -7172,6 +7174,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, MultiTemplateParamsArg TemplateParamLists, SourceLocation UsingLoc, UnqualifiedId &Name, + AttributeList *AttrList, TypeResult Type) { // Skip up to the relevant declaration scope. while (S->getFlags() & Scope::TemplateParamScope) @@ -7218,6 +7221,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (Invalid) NewTD->setInvalidDecl(); + ProcessDeclAttributeList(S, NewTD, AttrList); + CheckTypedefForVariablyModifiedType(S, NewTD); Invalid |= NewTD->isInvalidDecl(); @@ -10080,6 +10085,25 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, return LinkageSpec; } +/// \brief Perform semantic checks on a C++11 attribute-declaration. +void Sema::ActOnAttributeDeclaration(AttributeList *AttrList) { + // FIXME: Build an AST node for an attribute declaration and return it. + + // Since we do not support any attributes which can be used in an attribute + // declaration, just diagnose standard and unknown attributes appropriately. + for (/**/; AttrList; AttrList = AttrList->getNext()) { + if (AttrList->getKind() == AttributeList::IgnoredAttribute || + AttrList->isInvalid()) + continue; + + Diag(AttrList->getLoc(), + AttrList->getKind() == AttributeList::UnknownAttribute + ? diag::warn_unknown_attribute_ignored + : diag::err_attribute_declaration) + << AttrList->getName(); + } +} + /// \brief Perform semantic analysis for the variable declaration that /// occurs within a C++ catch clause, returning the newly-created /// variable. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index dcbaa51..6d2ddd1 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3497,7 +3497,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // Make sure there are no unused decl attributes on the declarator. // We don't want to do this for ObjC parameters because we're going // to apply them to the actual parameter declaration. - if (D.getContext() != Declarator::ObjCParameterContext) + // Likewise, we don't want to do this for alias declarations, because + // we are actually going to build a declaration from this eventually. + if (D.getContext() != Declarator::ObjCParameterContext && + D.getContext() != Declarator::AliasDeclContext && + D.getContext() != Declarator::AliasTemplateContext) checkUnusedDeclAttributes(D); if (getLangOpts().CPlusPlus) { diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp index 013d562..ac847a4 100644 --- a/clang/test/Parser/cxx0x-attributes.cpp +++ b/clang/test/Parser/cxx0x-attributes.cpp @@ -41,6 +41,8 @@ const [[]] int between_attr_2 = 0; // expected-error {{an attribute list cannot int after_attr [[]]; int * [[]] ptr_attr; int & [[]] ref_attr = after_attr; +int & [[unknown]] ref_attr_2 = after_attr; // expected-warning {{unknown attribute 'unknown' ignored}} +int & [[noreturn]] ref_attr_3 = after_attr; // expected-error {{'noreturn' attribute cannot be applied to types}} int && [[]] rref_attr = 0; int array_attr [1] [[]]; alignas(8) int aligned_attr; @@ -112,13 +114,18 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}} [[]] asm(""); // expected-error {{an attribute list cannot appear here}} [[]] using ns::i; // expected-error {{an attribute list cannot appear here}} -[[]] using namespace ns; +[[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}} +[[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions and methods}} [[]] using T = int; // expected-error {{an attribute list cannot appear here}} using T [[]] = int; // ok template using U [[]] = T; using ns::i [[]]; // expected-error {{an attribute list cannot appear here}} using [[]] ns::i; // expected-error {{an attribute list cannot appear here}} +using T [[unknown]] = int; // expected-warning {{unknown attribute 'unknown' ignored}} +using T [[noreturn]] = int; // expected-error {{'noreturn' attribute only applies to functions and methods}} +using V = int; // expected-note {{previous}} +using V [[gnu::vector_size(16)]] = int; // expected-error {{redefinition with different types}} auto trailing() -> [[]] const int; // expected-error {{an attribute list cannot appear here}} auto trailing() -> const [[]] int; // expected-error {{an attribute list cannot appear here}} @@ -220,10 +227,10 @@ void bar () { // Condition tests void baz () { - if ([[]] bool b = true) { - switch ([[]] int n { 42 }) { + if ([[unknown]] bool b = true) { // expected-warning {{unknown attribute 'unknown' ignored}} + switch ([[unknown]] int n { 42 }) { // expected-warning {{unknown attribute 'unknown' ignored}} default: - for ([[]] int n = 0; [[]] char b = n < 5; ++b) { + for ([[unknown]] int n = 0; [[unknown]] char b = n < 5; ++b) { // expected-warning 2{{unknown attribute 'unknown' ignored}} } } } @@ -240,7 +247,7 @@ void baz () { do { } while ([[]] false); // expected-error {{an attribute list cannot appear here}} - for ([[]] int n : { 1, 2, 3 }) { + for ([[unknown]] int n : { 1, 2, 3 }) { // expected-warning {{unknown attribute 'unknown' ignored}} } } @@ -251,7 +258,7 @@ enum class [[]] EvenMoreSecrets {}; namespace arguments { void f[[gnu::format(printf, 1, 2)]](const char*, ...); - void g() [[unknown::foo(currently arguments of attributes from unknown namespace other than 'gnu' namespace are ignored... blah...)]]; // expected-warning {{unknown attribute 'foo' ignored}} + void g() [[unknown::foo(arguments of attributes from unknown namespace other than 'gnu' namespace are ignored... blah...)]]; // expected-warning {{unknown attribute 'foo' ignored}} } // Forbid attributes on decl specifiers. @@ -265,3 +272,6 @@ int [[carries_dependency]] foo(int [[carries_dependency]] x); // expected-error int *[[gnu::unused]] v3; // expected-warning {{attribute 'unused' ignored}} int v4[2][[gnu::unused]]; // expected-warning {{attribute 'unused' ignored}} int v5()[[gnu::unused]]; // expected-warning {{attribute 'unused' ignored}} + +[[attribute_declaration]]; // expected-warning {{unknown attribute 'attribute_declaration' ignored}} +[[noreturn]]; // expected-error {{'noreturn' attribute cannot be used in an attribute declaration}} -- 2.7.4