[cfe-commits] r66734 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/class.cpp test/SemaCXX/virtuals.cpp

Douglas Gregor dgregor at apple.com
Wed Mar 11 16:00:04 PDT 2009


Author: dgregor
Date: Wed Mar 11 18:00:04 2009
New Revision: 66734

URL: http://llvm.org/viewvc/llvm-project?rev=66734&view=rev
Log:
Move most of the checking from ActOnCXXMemberDeclarator to other, more general routines. This is a step toward separating the checking logic from Declarators, which in turn is required for template instantiation.

Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/SemaCXX/class.cpp
    cfe/trunk/test/SemaCXX/virtuals.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=66734&r1=66733&r2=66734&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Mar 11 18:00:04 2009
@@ -344,6 +344,19 @@
     return false;
   }
   
+  /// \brief Determines whether this is a static data member.
+  ///
+  /// This will only be true in C++, and applies to, e.g., the
+  /// variable 'x' in:
+  /// \code
+  /// struct S {
+  ///   static int x;
+  /// };
+  /// \endcode
+  bool isStaticDataMember() const {
+    return getDeclContext()->isRecord();
+  }
+
   /// isFileVarDecl - Returns true for file scoped variable declaration.
   bool isFileVarDecl() const {
     if (getKind() != Decl::Var)

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=66734&r1=66733&r2=66734&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Wed Mar 11 18:00:04 2009
@@ -248,6 +248,8 @@
      "'mutable' can only be applied to member variables")
 DIAG(err_virtual_non_function, ERROR,
      "'virtual' can only appear on non-static member functions")
+DIAG(err_virtual_out_of_class, ERROR,
+     "'virtual' can only be specified inside the class definition")
 DIAG(err_static_not_bitfield, ERROR,
      "static member %0 cannot be a bit-field")
 DIAG(err_typedef_not_bitfield, ERROR,
@@ -1229,6 +1231,10 @@
 DIAG(err_base_init_direct_and_virtual, ERROR,
      "base class initializer %0 names both a direct base class and an"
      " inherited virtual base class")
+DIAG(err_in_class_initializer_non_integral_type, ERROR,
+     "in-class initializer has non-integral, non-enumeration type %0")
+DIAG(err_in_class_initializer_non_constant, ERROR,
+     "in-class initializer is not an integral constant expression")
 
 // C++ anonymous unions and GNU anonymous structs/unions
 DIAG(ext_anonymous_union, EXTENSION,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=66734&r1=66733&r2=66734&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 11 18:00:04 2009
@@ -1431,10 +1431,15 @@
     DC = 0;
   }
 
-  // Check that there are no default arguments (C++ only).
-  if (getLangOptions().CPlusPlus)
+  if (getLangOptions().CPlusPlus) {
+    // Check that there are no default arguments (C++ only).
     CheckExtraCXXDefaultArguments(D);
 
+    if (D.getDeclSpec().isVirtualSpecified())
+      Diag(D.getDeclSpec().getVirtualSpecLoc(), 
+           diag::err_virtual_non_function);
+  }
+
   TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator);
   if (!NewTD) return 0;
 
@@ -1580,6 +1585,10 @@
     return 0;
   }
 
+  if (D.getDeclSpec().isVirtualSpecified())
+    Diag(D.getDeclSpec().getVirtualSpecLoc(), 
+         diag::err_virtual_non_function);
+
   bool ThreadSpecified = D.getDeclSpec().isThreadSpecified();
   if (!DC->isRecord() && S->getFnParent() == 0) {
     // C99 6.9p2: The storage-class specifiers auto and register shall not
@@ -1751,9 +1760,10 @@
   }
 
   bool isInline = D.getDeclSpec().isInlineSpecified();
-  // bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+  bool isVirtual = D.getDeclSpec().isVirtualSpecified();
   bool isExplicit = D.getDeclSpec().isExplicitSpecified();
 
+  bool isVirtualOkay = false;
   FunctionDecl *NewFD;
   if (D.getKind() == Declarator::DK_Constructor) {
     // This is a C++ constructor declaration.
@@ -1784,6 +1794,8 @@
 
       if (InvalidDecl)
         NewFD->setInvalidDecl();
+
+      isVirtualOkay = true;
     } else {
       Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
 
@@ -1811,12 +1823,16 @@
         
       if (InvalidDecl)
         NewFD->setInvalidDecl();
+
+      isVirtualOkay = true;
     }
   } else if (DC->isRecord()) {
     // This is a C++ method declaration.
     NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
                                   D.getIdentifierLoc(), Name, R,
                                   (SC == FunctionDecl::Static), isInline);
+
+    isVirtualOkay = (SC != FunctionDecl::Static);
   } else {
     NewFD = FunctionDecl::Create(Context, DC,
                                  D.getIdentifierLoc(),
@@ -1835,6 +1851,34 @@
   // from the semantic context.
   NewFD->setLexicalDeclContext(CurContext);
 
+  // C++ [dcl.fct.spec]p5:
+  //   The virtual specifier shall only be used in declarations of
+  //   nonstatic class member functions that appear within a
+  //   member-specification of a class declaration; see 10.3.
+  //
+  // FIXME: Checking the 'virtual' specifier is not sufficient. A
+  // function is also virtual if it overrides an already virtual
+  // function. This is important to do here because it's part of the
+  // declaration.
+  if (isVirtual && !InvalidDecl) {
+    if (!isVirtualOkay) {
+       Diag(D.getDeclSpec().getVirtualSpecLoc(), 
+           diag::err_virtual_non_function);
+    } else if (!CurContext->isRecord()) {
+      // 'virtual' was specified outside of the class.
+      Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class)
+        << CodeModificationHint::CreateRemoval(
+                             SourceRange(D.getDeclSpec().getVirtualSpecLoc()));
+    } else {
+      // Okay: Add virtual to the method.
+      cast<CXXMethodDecl>(NewFD)->setVirtual();
+      CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
+      CurClass->setAggregate(false);
+      CurClass->setPOD(false);
+      CurClass->setPolymorphic(true);
+    }
+  }
+
   // Handle GNU asm-label extension (encoded as an attribute).
   if (Expr *E = (Expr*) D.getAsmLabel()) {
     // The parser guarantees this is a string.
@@ -2109,9 +2153,38 @@
   if (RealDecl == 0)
     return;
   
+  if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
+    // With declarators parsed the way they are, the parser cannot
+    // distinguish between a normal initializer and a pure-specifier.
+    // Thus this grotesque test.
+    IntegerLiteral *IL;
+    Expr *Init = static_cast<Expr *>(init.get());
+    if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
+        Context.getCanonicalType(IL->getType()) == Context.IntTy) {
+      if (Method->isVirtual())
+        Method->setPure();
+      else {
+        Diag(Method->getLocation(), diag::err_non_virtual_pure)
+          << Method->getDeclName() << Init->getSourceRange();
+        Method->setInvalidDecl();
+      }
+    } else {
+      Diag(Method->getLocation(), diag::err_member_function_initialization)
+        << Method->getDeclName() << Init->getSourceRange();
+      Method->setInvalidDecl();
+    }
+    return;
+  }
+
   VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
   if (!VDecl) {
-    Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
+    if (getLangOptions().CPlusPlus &&
+        RealDecl->getLexicalDeclContext()->isRecord() &&
+        isa<NamedDecl>(RealDecl))
+      Diag(RealDecl->getLocation(), diag::err_member_initialization)
+        << cast<NamedDecl>(RealDecl)->getDeclName();
+    else
+      Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
     RealDecl->setInvalidDecl();
     return;
   }
@@ -2150,6 +2223,52 @@
           CheckForConstantInitializer(Init, DclT);
       }
     }
+  } else if (VDecl->isStaticDataMember() && 
+             VDecl->getLexicalDeclContext()->isRecord()) {
+    // This is an in-class initialization for a static data member, e.g.,
+    //
+    // struct S {
+    //   static const int value = 17;
+    // };
+
+    // Attach the initializer
+    VDecl->setInit(Init);
+
+    // C++ [class.mem]p4:
+    //   A member-declarator can contain a constant-initializer only
+    //   if it declares a static member (9.4) of const integral or
+    //   const enumeration type, see 9.4.2.
+    QualType T = VDecl->getType();
+    if (!T->isDependentType() && 
+        (!Context.getCanonicalType(T).isConstQualified() ||
+         !T->isIntegralType())) {
+      Diag(VDecl->getLocation(), diag::err_member_initialization)
+        << VDecl->getDeclName() << Init->getSourceRange();
+      VDecl->setInvalidDecl();
+    } else {
+      // C++ [class.static.data]p4:
+      //   If a static data member is of const integral or const
+      //   enumeration type, its declaration in the class definition
+      //   can specify a constant-initializer which shall be an
+      //   integral constant expression (5.19).
+      if (!Init->isTypeDependent() &&
+          !Init->getType()->isIntegralType()) {
+        // We have a non-dependent, non-integral or enumeration type.
+        Diag(Init->getSourceRange().getBegin(), 
+             diag::err_in_class_initializer_non_integral_type)
+          << Init->getType() << Init->getSourceRange();
+        VDecl->setInvalidDecl();
+      } else if (!Init->isTypeDependent() && !Init->isValueDependent()) {
+        // Check whether the expression is a constant expression.
+        llvm::APSInt Value;
+        SourceLocation Loc;
+        if (!Init->isIntegerConstantExpr(Value, Context, &Loc)) {
+          Diag(Loc, diag::err_in_class_initializer_non_constant)
+            << Init->getSourceRange();
+          VDecl->setInvalidDecl();
+        }
+      }
+    }
   } else if (VDecl->isFileVarDecl()) {
     if (VDecl->getStorageClass() == VarDecl::Extern)
       Diag(VDecl->getLocation(), diag::warn_extern_init);
@@ -3252,6 +3371,7 @@
 Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD,
                                SourceLocation DeclStart, 
                                Declarator &D, ExprTy *BitfieldWidth) {
+
   return HandleField(S, static_cast<RecordDecl*>(TagD), DeclStart, D,
                      static_cast<Expr*>(BitfieldWidth),
                      AS_public);
@@ -3269,9 +3389,14 @@
  
   QualType T = GetTypeForDeclarator(D, S);
 
-  if (getLangOptions().CPlusPlus)
+  if (getLangOptions().CPlusPlus) {
     CheckExtraCXXDefaultArguments(D);
 
+    if (D.getDeclSpec().isVirtualSpecified())
+      Diag(D.getDeclSpec().getVirtualSpecLoc(), 
+           diag::err_virtual_non_function);
+  }
+
   NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
   if (PrevDecl && !isDeclInScope(PrevDecl, Record, S))
     PrevDecl = 0;

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=66734&r1=66733&r2=66734&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Mar 11 18:00:04 2009
@@ -588,72 +588,8 @@
 
   assert((Name || isInstField) && "No identifier for non-field ?");
 
-  if (DS.isVirtualSpecified()) {
-    if (!isFunc || DS.getStorageClassSpec() == DeclSpec::SCS_static) {
-      Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function);
-      Member->setInvalidDecl();
-    } else {
-      cast<CXXMethodDecl>(Member)->setVirtual();
-      CXXRecordDecl *CurClass = cast<CXXRecordDecl>(CurContext);
-      CurClass->setAggregate(false);
-      CurClass->setPOD(false);
-      CurClass->setPolymorphic(true);
-    }
-  }
-
-  // FIXME: The above definition of virtual is not sufficient. A function is
-  // also virtual if it overrides an already virtual function. This is important
-  // to do here because it decides the validity of a pure specifier.
-
-  if (Init) {
-    // C++ 9.2p4: A member-declarator can contain a constant-initializer only
-    // if it declares a static member of const integral or const enumeration
-    // type.
-    if (VarDecl *CVD = dyn_cast<VarDecl>(Member)) {
-      // ...static member of...
-      CVD->setInit(Init);
-      // ...const integral or const enumeration type.
-      if (Context.getCanonicalType(CVD->getType()).isConstQualified() &&
-          CVD->getType()->isIntegralType()) {
-        // constant-initializer
-        if (CheckForConstantInitializer(Init, CVD->getType()))
-          Member->setInvalidDecl();
-
-      } else {
-        // not const integral.
-        Diag(Loc, diag::err_member_initialization)
-          << Name << Init->getSourceRange();
-        Member->setInvalidDecl();
-      }
-
-    } else {
-      // not static member. perhaps virtual function?
-      if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
-        // With declarators parsed the way they are, the parser cannot
-        // distinguish between a normal initializer and a pure-specifier.
-        // Thus this grotesque test.
-        IntegerLiteral *IL;
-        if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
-            Context.getCanonicalType(IL->getType()) == Context.IntTy) {
-          if (MD->isVirtual())
-            MD->setPure();
-          else {
-            Diag(Loc, diag::err_non_virtual_pure)
-              << Name << Init->getSourceRange();
-            Member->setInvalidDecl();
-          }
-        } else {
-          Diag(Loc, diag::err_member_function_initialization)
-            << Name << Init->getSourceRange();
-          Member->setInvalidDecl();
-        }
-      } else {
-        Diag(Loc, diag::err_member_initialization)
-          << Name << Init->getSourceRange();
-        Member->setInvalidDecl();
-      }
-    }
-  }
+  if (Init)
+    AddInitializerToDecl(Member, ExprArg(*this, Init), false);
 
   if (isInstField) {
     FieldCollector->Add(cast<FieldDecl>(Member));

Modified: cfe/trunk/test/SemaCXX/class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=66734&r1=66733&r2=66734&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/class.cpp (original)
+++ cfe/trunk/test/SemaCXX/class.cpp Wed Mar 11 18:00:04 2009
@@ -35,7 +35,7 @@
   int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
   static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
   static const NestedC ci = 0; // expected-error {{error: 'ci' can only be initialized if it is a static const integral data member}}
-  static const int nci = vs; // expected-error {{error: initializer element is not a compile-time constant}}
+  static const int nci = vs; // expected-error {{in-class initializer is not an integral constant expression}}
   static const int vi = 0;
   static const E evi = 0;
 
@@ -53,7 +53,7 @@
 
   typedef int A;
 
-  virtual int viv; // expected-error {{error: 'virtual' can only appear on non-static member functions}}
+  virtual int viv; // expected-error {{'virtual' can only appear on non-static member functions}}
   virtual static int vsif(); // expected-error {{error: 'virtual' can only appear on non-static member functions}}
   virtual int vif();
 

Modified: cfe/trunk/test/SemaCXX/virtuals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/virtuals.cpp?rev=66734&r1=66733&r2=66734&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/virtuals.cpp (original)
+++ cfe/trunk/test/SemaCXX/virtuals.cpp Wed Mar 11 18:00:04 2009
@@ -8,10 +8,15 @@
   void i() = 1; // expected-error {{initializer on function does not look like a pure-specifier}}
   void j() = 0u; // expected-error {{initializer on function does not look like a pure-specifier}}
 
+
+  void k();
+
 public:
   A(int);
 };
 
+virtual void A::k() { } // expected-error{{'virtual' can only be specified inside the class definition}}
+
 class B : public A {
   // Needs to recognize that overridden function is virtual.
   //void g() = 0;





More information about the cfe-commits mailing list