]> granicus.if.org Git - clang/commitdiff
[Sema] Semantic analysis for empty-declaration and attribute-declaration.
authorMichael Han <fragmentshaders@gmail.com>
Fri, 22 Feb 2013 17:15:32 +0000 (17:15 +0000)
committerMichael Han <fragmentshaders@gmail.com>
Fri, 22 Feb 2013 17:15:32 +0000 (17:15 +0000)
Introduce a new AST Decl node "EmptyDecl" to model empty-declaration. Have attributes from attribute-declaration appertain
to the EmptyDecl node by creating the AST representations of these attributes and attach them to the EmptyDecl node so these
attributes can be sema checked just as attributes attached to "normal" declarations.

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

19 files changed:
include/clang/AST/Decl.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/DeclNodes.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/Decl.cpp
lib/AST/DeclBase.cpp
lib/AST/DeclPrinter.cpp
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Serialization/ASTCommon.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Parser/cxx0x-attributes.cpp
test/SemaCXX/cxx11-ast-print.cpp
tools/libclang/RecursiveASTVisitor.h

index 010563fdd954c96b9139cf50048181dc47634a67..42e6ae0657d19af5023b5c00ed8c5094a4f97eec 100644 (file)
@@ -3297,7 +3297,21 @@ public:
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == Import; }
 };
-  
+
+/// \brief Represents an empty-declaration.
+class EmptyDecl : public Decl {
+  virtual void anchor();
+  EmptyDecl(DeclContext *DC, SourceLocation L)
+    : Decl(Empty, DC, L) { }
+
+public:
+  static EmptyDecl *Create(ASTContext &C, DeclContext *DC,
+                           SourceLocation L);
+  static EmptyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+  static bool classofKind(Kind K) { return K == Empty; }
+};
 
 /// Insertion operator for diagnostics.  This allows sending NamedDecl's
 /// into a diagnostic with <<.
index faec5ebe09c7fa2ba2099962f9d0ab5374c3bb66..4b5e19e73322782173fbcef789aebb0c6ff6d2bb 100644 (file)
@@ -1257,6 +1257,8 @@ DEF_TRAVERSE_DECL(BlockDecl, {
     return true;
   })
 
+DEF_TRAVERSE_DECL(EmptyDecl, { })
+
 DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
     TRY_TO(TraverseStmt(D->getAsmString()));
   })
index 6f2bb35725191c7d39dd1ccf538521576ae876ee..ac7ad6fc6a7921c29d2c193a98788f19b9aa7ef4 100644 (file)
@@ -74,4 +74,5 @@ def StaticAssert : Decl;
 def Block : Decl, DeclContext;
 def ClassScopeFunctionSpecialization : Decl;
 def Import : Decl;
+def Empty : Decl;
 
index e87cdd7673e943e5d1bf4f192e31f6a64822f12b..13e52e0c6c1fb6ff503c5fb6a8ad7c36d0bfe4e5 100644 (file)
@@ -1916,8 +1916,6 @@ 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 7101286a7b0d1a4bae6fe9ecba2708d1e37afd93..669cf9e814ae9cd7c09e0fc01964d4ebeba38151 100644 (file)
@@ -1447,8 +1447,10 @@ public:
                               SourceLocation AsmLoc,
                               SourceLocation RParenLoc);
 
-  /// \brief Handle a C++11 attribute-declaration.
-  void ActOnAttributeDeclaration(AttributeList *AttrList);
+  /// \brief Handle a C++11 empty-declaration and attribute-declaration.
+  Decl *ActOnEmptyDeclaration(Scope *S,
+                              AttributeList *AttrList,
+                              SourceLocation SemiLoc);
 
   /// \brief The parser has processed a module import declaration.
   ///
index a672c7e149e737ae12fac34e86fce01b055cfd3d..93c5c073d5398b086a07fb1eaf0ff2f7554a08d3 100644 (file)
@@ -1031,7 +1031,9 @@ namespace clang {
       /// function specialization. (Microsoft extension).
       DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
       /// \brief An ImportDecl recording a module import.
-      DECL_IMPORT
+      DECL_IMPORT,
+      /// \brief An EmptyDecl record.
+      DECL_EMPTY
     };
 
     /// \brief Record codes for each kind of statement or expression.
index 0dbb0d30aa237fe661c9656acf0b5351e025b0e7..d2a9f84cd4fab3d99c06502facf6283cf441a4df 100644 (file)
@@ -3343,6 +3343,17 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
   return new (Mem) FileScopeAsmDecl(0, 0, SourceLocation(), SourceLocation());
 }
 
+void EmptyDecl::anchor() {}
+
+EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+  return new (C) EmptyDecl(DC, L);
+}
+
+EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+  void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EmptyDecl));
+  return new (Mem) EmptyDecl(0, SourceLocation());
+}
+
 //===----------------------------------------------------------------------===//
 // ImportDecl Implementation
 //===----------------------------------------------------------------------===//
index f675436fc5f25d0fdb4b1f98871d186c037287f0..cdf150595c3d993daa96bbfc6b3b58d182f54d81 100644 (file)
@@ -558,6 +558,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
     case ObjCCategory:
     case ObjCCategoryImpl:
     case Import:
+    case Empty:
       // Never looked up by name.
       return 0;
   }
index dce4f9af2589888bb7512e6194f019aed26a61b1..2be0b6c80461fd9cf6cfe69ccd86b7805602adb8 100644 (file)
@@ -51,6 +51,7 @@ namespace {
     void VisitEnumDecl(EnumDecl *D);
     void VisitRecordDecl(RecordDecl *D);
     void VisitEnumConstantDecl(EnumConstantDecl *D);
+    void VisitEmptyDecl(EmptyDecl *D);
     void VisitFunctionDecl(FunctionDecl *D);
     void VisitFriendDecl(FriendDecl *D);
     void VisitFieldDecl(FieldDecl *D);
@@ -723,6 +724,11 @@ void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
   Out << *D->getAliasedNamespace();
 }
 
+void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) {
+  prettyPrintAttributes(D);
+  Out << ";\n";
+}
+
 void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
     Out << "__module_private__ ";
index a4d673b8c3235ad609b55fac39fc5a9ae258567b..9c523149bdfa2560bf4e23e518eea3b8b0187526 100644 (file)
@@ -83,6 +83,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
   case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
   case Decl::Label:        // __label__ x;
   case Decl::Import:
+  case Decl::Empty:
     // None of these decls require codegen support.
     return;
 
index 60ec3232031e7d0807edc5d13f4c0494c78984da..6442f04070dc0d6486c7e8c5c3c45fc7e1b6f8e7 100644 (file)
@@ -2742,6 +2742,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
   case Decl::TypeAliasTemplate:
   case Decl::NamespaceAlias:
   case Decl::Block:
+  case Decl::Empty:
     break;
   case Decl::CXXConstructor:
     // Skip function templates
index d9772755bd2e0dd105e863a324e9af8c7a3ed346..24849edd63bb6ec4963ebf46fcd9b6cfd47b8e52 100644 (file)
@@ -626,15 +626,11 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
     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();
-    }
-
+    SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
+                                               attrs.getList(),
+                                               Tok.getLocation());
     ConsumeExtraSemi(OutsideFunction);
-    // TODO: Invoke action for top-level semicolon.
-    return DeclGroupPtrTy();
+    break;
   case tok::r_brace:
     Diag(Tok, diag::err_extraneous_closing_brace);
     ConsumeBrace();
index 8198856547c69835a5522706642434432a830b35..ce526a9ed3901ac43d4337822a94a6a1e821bf00 100644 (file)
@@ -10085,23 +10085,17 @@ 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();
-  }
+Decl *Sema::ActOnEmptyDeclaration(Scope *S,
+                                  AttributeList *AttrList,
+                                  SourceLocation SemiLoc) {
+  Decl *ED = EmptyDecl::Create(Context, CurContext, SemiLoc);
+  // Attribute declarations appertain to empty declaration so we handle
+  // them here.
+  if (AttrList)
+    ProcessDeclAttributeList(S, ED, AttrList);
+
+  CurContext->addDecl(ED);
+  return ED;
 }
 
 /// \brief Perform semantic analysis for the variable declaration that
index 9f1514bdff2e0629f92b7bfe4041e9a21b6a3362..3319cc36412dcbe7f5e1e744f04a8616a9b51563 100644 (file)
@@ -168,6 +168,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
   case Decl::TypeAliasTemplate:
   case Decl::ObjCProtocol:
   case Decl::ObjCInterface:
+  case Decl::Empty:
     return true;
 
   // Never redeclarable.
index f4d03cf7755be2f35ed79389510b8bca97ecf0c0..504c2e6588b8b266ec6511b9e6fbbef422cfb261 100644 (file)
@@ -265,6 +265,7 @@ namespace clang {
     void VisitFriendTemplateDecl(FriendTemplateDecl *D);
     void VisitStaticAssertDecl(StaticAssertDecl *D);
     void VisitBlockDecl(BlockDecl *BD);
+    void VisitEmptyDecl(EmptyDecl *D);
 
     std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
     
@@ -1526,6 +1527,10 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
   D->RParenLoc = ReadSourceLocation(Record, Idx);
 }
 
+void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) {
+  VisitDecl(D);
+}
+
 std::pair<uint64_t, uint64_t>
 ASTDeclReader::VisitDeclContext(DeclContext *DC) {
   uint64_t LexicalOffset = Record[Idx++];
@@ -2129,6 +2134,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
     // locations.
     D = ImportDecl::CreateDeserialized(Context, ID, Record.back());
     break;
+  case DECL_EMPTY:
+    D = EmptyDecl::CreateDeserialized(Context, ID);
+    break;
   }
 
   assert(D && "Unknown declaration reading AST file");
index 3795e21bdf674f4d5501b356ab71bea0063bd9dd..6c63a149c2b692b5f1e8e6e12f6542d80cadfadc 100644 (file)
@@ -102,6 +102,7 @@ namespace clang {
     void VisitFriendTemplateDecl(FriendTemplateDecl *D);
     void VisitStaticAssertDecl(StaticAssertDecl *D);
     void VisitBlockDecl(BlockDecl *D);
+    void VisitEmptyDecl(EmptyDecl *D);
 
     void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
                           uint64_t VisibleOffset);
@@ -780,6 +781,11 @@ void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
   Code = serialization::DECL_FILE_SCOPE_ASM;
 }
 
+void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) {
+  VisitDecl(D);
+  Code = serialization::DECL_EMPTY;
+}
+
 void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
   VisitDecl(D);
   Writer.AddStmt(D->getBody());
index 4e7ac16cc5d51e6d93c9e68f17f1c1a17e58c57a..5e4e388a264520a3a583c903b52b8754fb253434 100644 (file)
@@ -279,4 +279,5 @@ 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}}
+[[noreturn]]; // expected-error {{'noreturn' attribute only applies to functions and methods}}
+[[carries_dependency]]; // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
index 66ff0f064a30c46def4b11c7167c97e0c26d0cc7..8e9480476c12075a1f3dcae6b10dda2c0ae97f1b 100644 (file)
@@ -38,3 +38,5 @@ const char *p8 = 4.9_quux;
 const char *p9 = 0x42e3F_fritz;
 // CHECK: const char *p10 = 3.300e+15_fritz;
 const char *p10 = 3.300e+15_fritz;
+// CHECK: ;
+;
index 35d59d02cde04ecea1e608c599b253c02685b94d..9788c956da029df1e96d72c54d68eb01ac605173 100644 (file)
@@ -1199,6 +1199,8 @@ DEF_TRAVERSE_DECL(BlockDecl, {
     return true;
   })
 
+DEF_TRAVERSE_DECL(EmptyDecl, { })
+
 DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
     TRY_TO(TraverseStmt(D->getAsmString()));
   })