]> granicus.if.org Git - clang/commitdiff
Process and handle attributes on conditions and for loop variables. Process and
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 20 Feb 2013 19:22:51 +0000 (19:22 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 20 Feb 2013 19:22:51 +0000 (19:22 +0000)
diagnose attributes on alias declarations, using directives, and attribute
declarations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175649 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaType.cpp
test/Parser/cxx0x-attributes.cpp

index b69bfda24241057602c8a21fe3691daecad5571a..3377a68911d46b819ccb8f28db27f54160d1b40e 100644 (file)
@@ -1908,6 +1908,8 @@ def warn_attribute_not_on_decl : Warning<
   "%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
 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<
index ff4d46e6acfdf253678cc4e5657ad97e7a87b165..c0044cbba0c6497fe28a13003414ffe5ea91694b 100644 (file)
@@ -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);
index 9d9014ab9ca1313f1df950231377b859e094a66b..4d37c89edbdae22f78acc3da75bef1af873bfcbe 100644 (file)
@@ -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,
index cb013e77f139534369524fd73193620cd7c2a21b..8bfdffc8650101c0c4f18d5335e1398b2a45bce2 100644 (file)
@@ -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;
index 4d428ceea1dc28b567f36eab7705a463234a5d06..22f5863e5f6acc4415f64511ad174d5cd7c1b4cd 100644 (file)
@@ -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);
 }
 
index 613b0bec5d98ed822cf34c789bfd6b3405bd4b8d..0a1111e358524534def555ed580f534790d9b4b4 100644 (file)
@@ -1383,6 +1383,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
 
   // type-specifier-seq
   DeclSpec DS(AttrFactory);
+  DS.takeAttributesFrom(attrs);
   ParseSpecifierQualifierList(DS);
 
   // declarator
index 4c8bd6fe56b1ced764eb33b0044e807a29f2ca71..a77c03459fa406a7459e296265c2e24186ad7c1e 100644 (file)
@@ -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);
index 1a667daab71828dcbe51be0335ab8e9bae66ae2a..2d8d5b1322823ce4d12ad6146fdedd73cd50e064 100644 (file)
@@ -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();
index 8b0ccd71460d86721e4212330fba16ac8731f4b8..8198856547c69835a5522706642434432a830b35 100644 (file)
@@ -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.
index dcbaa5143cfd6758169ee2714391d70e108c4ca4..6d2ddd11d3966f1e691de1372713606b3c702644 100644 (file)
@@ -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) {
index 013d562ed603e558fd51680dd0416eade5260bda..ac847a4893edc7b8f7a7a2f124a71404cfde23a3 100644 (file)
@@ -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<typename T> 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}}