[cfe-commits] r150359 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Sema/ test/CXX/basic/basic.types/ test/CXX/class/class.static/class.static.data/ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/ test/CXX/expr/expr.const/ test/CXX/special/class.ctor/ test/SemaCXX/

Richard Smith richard-llvm at metafoo.co.uk
Sun Feb 12 19:54:03 PST 2012


Author: rsmith
Date: Sun Feb 12 21:54:03 2012
New Revision: 150359

URL: http://llvm.org/viewvc/llvm-project?rev=150359&view=rev
Log:
Update constexpr implementation to match CWG's chosen approach for core issues
1358, 1360, 1452 and 1453.
 - Instantiations of constexpr functions are always constexpr. This removes the
   need for separate declaration/definition checking, which is now gone.
 - This makes it possible for a constexpr function to be virtual, if they are
   only dependently virtual. Virtual calls to such functions are not constant
   expressions.
 - Likewise, it's now possible for a literal type to have virtual base classes.
   A constexpr constructor for such a type cannot actually produce a constant
   expression, though, so add a special-case diagnostic for a constructor call
   to such a type rather than trying to evaluate it.
 - Classes with trivial default constructors (for which value initialization can
   produce a fully-initialized value) are considered literal types.
 - Classes with volatile members are not literal types.
 - constexpr constructors can be members of non-literal types. We do not yet use
   static initialization for global objects constructed in this way.

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/basic/basic.types/p10.cpp
    cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
    cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
    cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp
    cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
    cfe/trunk/test/SemaCXX/literal-type.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sun Feb 12 21:54:03 2012
@@ -469,7 +469,8 @@
     bool HasTrivialDestructor : 1;
 
     /// HasNonLiteralTypeFieldsOrBases - True when this class contains at least
-    /// one non-static data member or base class of non literal type.
+    /// one non-static data member or base class of non-literal or volatile
+    /// type.
     bool HasNonLiteralTypeFieldsOrBases : 1;
 
     /// ComputedVisibleConversions - True when visible conversion functions are
@@ -1095,8 +1096,8 @@
   // (C++ [class.dtor]p3)
   bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
 
-  // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal type
-  // non-static data member or base class.
+  // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or
+  // volatile type non-static data member or base class.
   bool hasNonLiteralTypeFieldsOrBases() const {
     return data().HasNonLiteralTypeFieldsOrBases;
   }
@@ -1116,20 +1117,23 @@
 
   // isLiteral - Whether this class is a literal type.
   //
-  // C++0x [basic.types]p10
+  // C++11 [basic.types]p10
   //   A class type that has all the following properties:
-  //     -- a trivial destructor
+  //     -- it has a trivial destructor
   //     -- every constructor call and full-expression in the
   //        brace-or-equal-intializers for non-static data members (if any) is
   //        a constant expression.
   //     -- it is an aggregate type or has at least one constexpr constructor or
   //        constructor template that is not a copy or move constructor, and
-  //     -- all non-static data members and base classes of literal types
+  //     -- all of its non-static data members and base classes are of literal
+  //        types
   //
-  // We resolve DR1361 by ignoring the second bullet.
+  // We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by
+  // treating types with trivial default constructors as literal types.
   bool isLiteral() const {
     return hasTrivialDestructor() &&
-           (isAggregate() || hasConstexprNonCopyMoveConstructor()) &&
+           (isAggregate() || hasConstexprNonCopyMoveConstructor() ||
+            hasTrivialDefaultConstructor()) &&
            !hasNonLiteralTypeFieldsOrBases();
   }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Sun Feb 12 21:54:03 2012
@@ -28,6 +28,11 @@
 def note_constexpr_invalid_function : Note<
   "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
   "be used in a constant expression">;
+def note_constexpr_virtual_call : Note<
+  "cannot evaluate virtual function call in a constant expression">;
+def note_constexpr_virtual_base : Note<
+  "cannot construct object of type %0 with virtual base class "
+  "in a constant expression">;
 def note_constexpr_nonliteral : Note<
   "non-literal type %0 cannot be used in a constant expression">;
 def note_constexpr_non_global : Note<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Feb 12 21:54:03 2012
@@ -1361,6 +1361,8 @@
   "constexpr variable declaration must be a definition">;
 def err_constexpr_static_mem_var_requires_init : Error<
   "declaration of constexpr static data member %0 requires an initializer">;
+def err_constexpr_var_non_literal : Error<
+  "constexpr variable cannot have non-literal type %0">;
 def err_constexpr_var_requires_const_init : Error<
   "constexpr variable %0 must be initialized by a constant expression">;
 def err_constexpr_redecl_mismatch : Error<
@@ -1369,29 +1371,17 @@
 def note_constexpr_redecl_mismatch : Note<
   "previous declaration was %select{not |}0marked constexpr">;
 def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
-def note_constexpr_tmpl_virtual : Note<"function template instantiation is not "
-  "constexpr because it is virtual">;
 def err_constexpr_virtual_base : Error<
   "constexpr %select{member function|constructor}0 not allowed in "
   "%select{class|struct}1 with virtual base %plural{1:class|:classes}2">;
-def note_constexpr_tmpl_virtual_base : Note<
-  "%select{function|constructor}0 template instantiation is "
-  "not constexpr because %select{class|struct}1 has virtual base "
-  "%plural{1:class|:classes}2">;
 def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual "
   "base %plural{1:class|:classes}1 is not a literal type">;
 def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
 def err_constexpr_non_literal_return : Error<
   "constexpr function's return type %0 is not a literal type">;
-def note_constexpr_tmpl_non_literal_return : Note<
-  "function template instantiation is not constexpr because return type %0 is "
-  "not a literal type">;
 def err_constexpr_non_literal_param : Error<
   "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is "
   "not a literal type">;
-def note_constexpr_tmpl_non_literal_param : Note<
-  "%select{function|constructor}1 template instantiation is not constexpr "
-  "because %ordinal0 parameter type %2 is not a literal type">;
 def err_constexpr_body_invalid_stmt : Error<
   "statement not allowed in constexpr %select{function|constructor}0">;
 def err_constexpr_type_definition : Error<
@@ -1426,7 +1416,8 @@
 def note_non_literal_base_class : Note<
   "%0 is not literal because it has base class %1 of non-literal type">;
 def note_non_literal_field : Note<
-  "%0 is not literal because it has data member %1 of non-literal type %2">;
+  "%0 is not literal because it has data member %1 of "
+  "%select{non-literal|volatile}3 type %2">;
 def note_non_literal_user_provided_dtor : Note<
   "%0 is not literal because it has a user-provided destructor">;
 def note_non_literal_nontrivial_dtor : Note<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun Feb 12 21:54:03 2012
@@ -835,8 +835,7 @@
                                          PartialDiagnostic> Note);
 
   bool RequireLiteralType(SourceLocation Loc, QualType T,
-                          const PartialDiagnostic &PD,
-                          bool AllowIncompleteType = false);
+                          const PartialDiagnostic &PD);
 
   QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
                              const CXXScopeSpec &SS, QualType T);
@@ -1004,23 +1003,8 @@
                                      bool &AddToScope);
   bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
 
-  /// \brief The kind of constexpr declaration checking we are performing.
-  ///
-  /// The kind affects which diagnostics (if any) are emitted if the function
-  /// does not satisfy the requirements of a constexpr function declaration.
-  enum CheckConstexprKind {
-    /// \brief Check a constexpr function declaration, and produce errors if it
-    /// does not satisfy the requirements.
-    CCK_Declaration,
-    /// \brief Check a constexpr function template instantiation.
-    CCK_Instantiation,
-    /// \brief Produce notes explaining why an instantiation was not constexpr.
-    CCK_NoteNonConstexprInstantiation
-  };
-  bool CheckConstexprFunctionDecl(const FunctionDecl *FD,
-                                  CheckConstexprKind CCK);
-  bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body,
-                                  bool IsInstantiation);
+  bool CheckConstexprFunctionDecl(const FunctionDecl *FD);
+  bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
 
   void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
   // Returns true if the function declaration is a redeclaration

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Feb 12 21:54:03 2012
@@ -799,8 +799,8 @@
       data().IsStandardLayout = false;
     }
 
-    // Record if this field is the first non-literal field or base.
-    if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
+    // Record if this field is the first non-literal or volatile field or base.
+    if (!T->isLiteralType() || T.isVolatileQualified())
       data().HasNonLiteralTypeFieldsOrBases = true;
 
     if (Field->hasInClassInitializer()) {

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Feb 12 21:54:03 2012
@@ -2033,6 +2033,12 @@
   if (!Info.CheckCallLimit(CallLoc))
     return false;
 
+  const CXXRecordDecl *RD = Definition->getParent();
+  if (RD->getNumVBases()) {
+    Info.Diag(CallLoc, diag::note_constexpr_virtual_base) << RD;
+    return false;
+  }
+
   CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data());
 
   // If it's a delegating constructor, just delegate.
@@ -2044,7 +2050,6 @@
   // For a trivial copy or move constructor, perform an APValue copy. This is
   // essential for unions, where the operations performed by the constructor
   // cannot be represented by ctor-initializers.
-  const CXXRecordDecl *RD = Definition->getParent();
   if (Definition->isDefaulted() &&
       ((Definition->isCopyConstructor() && RD->hasTrivialCopyConstructor()) ||
        (Definition->isMoveConstructor() && RD->hasTrivialMoveConstructor()))) {
@@ -2083,7 +2088,7 @@
       QualType BaseType((*I)->getBaseClass(), 0);
 #ifndef NDEBUG
       // Non-virtual base classes are initialized in the order in the class
-      // definition. We cannot have a virtual base class for a literal type.
+      // definition. We have already checked for virtual base classes.
       assert(!BaseIt->isVirtual() && "virtual base for literal type");
       assert(Info.Ctx.hasSameType(BaseIt->getType(), BaseType) &&
              "base class initializers not in expected order");
@@ -2414,6 +2419,7 @@
     const FunctionDecl *FD = 0;
     LValue *This = 0, ThisVal;
     llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+    bool HasQualifier = false;
 
     // Extract function decl and 'this' pointer from the callee.
     if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
@@ -2424,6 +2430,7 @@
           return false;
         Member = ME->getMemberDecl();
         This = &ThisVal;
+        HasQualifier = ME->hasQualifier();
       } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
         // Indirect bound member calls ('.*' or '->*').
         Member = HandleMemberPointerAccess(Info, BE, ThisVal, false);
@@ -2472,6 +2479,12 @@
     if (This && !This->checkSubobject(Info, E, CSK_This))
       return false;
 
+    // DR1358 allows virtual constexpr functions in some cases. Don't allow
+    // calls to such functions in constant expressions.
+    if (This && !HasQualifier &&
+        isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isVirtual())
+      return Error(E, diag::note_constexpr_virtual_call);
+
     const FunctionDecl *Definition = 0;
     Stmt *Body = FD->getBody(Definition);
     APValue Result;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Feb 12 21:54:03 2012
@@ -3991,8 +3991,15 @@
                                            TemplateParamLists.release());
     }
 
-    if (D.getDeclSpec().isConstexprSpecified())
+    if (D.getDeclSpec().isConstexprSpecified()) {
       NewVD->setConstexpr(true);
+      SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc();
+      if (!NewVD->isInvalidDecl() && !R->isDependentType() &&
+          RequireLiteralType(NewVD->getLocation(), R,
+                             PDiag(diag::err_constexpr_var_non_literal)
+                               << SourceRange(ConstexprLoc)))
+        NewVD->setInvalidDecl();
+    }
   }
 
   // Set the lexical context. If the declarator has a C++ scope specifier, the
@@ -5347,10 +5354,6 @@
             Previous.getResultKind() != LookupResult::FoundOverloaded) &&
            "previous declaration set still overloaded");
 
-    if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() &&
-        !CheckConstexprFunctionDecl(NewFD, CCK_Declaration))
-      NewFD->setInvalidDecl();
-
     NamedDecl *PrincipalDecl = (FunctionTemplate
                                 ? cast<NamedDecl>(FunctionTemplate)
                                 : NewFD);
@@ -6223,8 +6226,8 @@
     if (DclT->isDependentType()) {
 
     // Allow any 'static constexpr' members, whether or not they are of literal
-    // type. We separately check that the initializer is a constant expression,
-    // which implicitly requires the member to be of literal type.
+    // type. We separately check that every constexpr variable is of literal
+    // type.
     } else if (VDecl->isConstexpr()) {
 
     // Require constness.
@@ -7350,8 +7353,9 @@
       ActivePolicy = &WP;
     }
 
-    if (FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
-        !CheckConstexprFunctionBody(FD, Body, IsInstantiation))
+    if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+        (!CheckConstexprFunctionDecl(FD) ||
+         !CheckConstexprFunctionBody(FD, Body)))
       FD->setInvalidDecl();
 
     assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Feb 12 21:54:03 2012
@@ -632,9 +632,9 @@
 
 // CheckConstexprParameterTypes - Check whether a function's parameter types
 // are all literal types. If so, return true. If not, produce a suitable
-// diagnostic depending on @p CCK and return false.
-static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD,
-                                         Sema::CheckConstexprKind CCK) {
+// diagnostic and return false.
+static bool CheckConstexprParameterTypes(Sema &SemaRef,
+                                         const FunctionDecl *FD) {
   unsigned ArgIndex = 0;
   const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
   for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(),
@@ -642,63 +642,37 @@
     const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
     SourceLocation ParamLoc = PD->getLocation();
     if (!(*i)->isDependentType() &&
-        SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ?
+        SemaRef.RequireLiteralType(ParamLoc, *i,
                             SemaRef.PDiag(diag::err_constexpr_non_literal_param)
                                      << ArgIndex+1 << PD->getSourceRange()
-                                     << isa<CXXConstructorDecl>(FD) :
-                                   SemaRef.PDiag(),
-                                   /*AllowIncompleteType*/ true)) {
-      if (CCK == Sema::CCK_NoteNonConstexprInstantiation)
-        SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param)
-          << ArgIndex+1 << PD->getSourceRange()
-          << isa<CXXConstructorDecl>(FD) << *i;
+                                     << isa<CXXConstructorDecl>(FD)))
       return false;
-    }
   }
   return true;
 }
 
 // CheckConstexprFunctionDecl - Check whether a function declaration satisfies
-// the requirements of a constexpr function declaration or a constexpr
-// constructor declaration. Return true if it does, false if not.
-//
-// This implements C++11 [dcl.constexpr]p3,4, as amended by N3308.
+// the requirements of a constexpr function definition or a constexpr
+// constructor definition. If so, return true. If not, produce appropriate
+// diagnostics and return false.
 //
-// \param CCK Specifies whether to produce diagnostics if the function does not
-// satisfy the requirements.
-bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD,
-                                      CheckConstexprKind CCK) {
-  assert((CCK != CCK_NoteNonConstexprInstantiation ||
-          (NewFD->getTemplateInstantiationPattern() &&
-           NewFD->getTemplateInstantiationPattern()->isConstexpr())) &&
-         "only constexpr templates can be instantiated non-constexpr");
-
+// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
+bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
   const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
   if (MD && MD->isInstance()) {
-    // C++11 [dcl.constexpr]p4: In the definition of a constexpr constructor...
-    //  In addition, either its function-body shall be = delete or = default or
-    //  it shall satisfy the following constraints:
+    // C++11 [dcl.constexpr]p4:
+    //  The definition of a constexpr constructor shall satisfy the following
+    //  constraints:
     //  - the class shall not have any virtual base classes;
-    //
-    // We apply this to constexpr member functions too: the class cannot be a
-    // literal type, so the members are not permitted to be constexpr.
     const CXXRecordDecl *RD = MD->getParent();
     if (RD->getNumVBases()) {
-      // Note, this is still illegal if the body is = default, since the
-      // implicit body does not satisfy the requirements of a constexpr
-      // constructor. We also reject cases where the body is = delete, as
-      // required by N3308.
-      if (CCK != CCK_Instantiation) {
-        Diag(NewFD->getLocation(),
-             CCK == CCK_Declaration ? diag::err_constexpr_virtual_base
-                                    : diag::note_constexpr_tmpl_virtual_base)
-          << isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
-          << RD->getNumVBases();
-        for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
-               E = RD->vbases_end(); I != E; ++I)
-          Diag(I->getSourceRange().getBegin(),
-               diag::note_constexpr_virtual_base_here) << I->getSourceRange();
-      }
+      Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
+        << isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
+        << RD->getNumVBases();
+      for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+             E = RD->vbases_end(); I != E; ++I)
+        Diag(I->getSourceRange().getBegin(),
+             diag::note_constexpr_virtual_base_here) << I->getSourceRange();
       return false;
     }
   }
@@ -710,39 +684,29 @@
     // - it shall not be virtual;
     const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
     if (Method && Method->isVirtual()) {
-      if (CCK != CCK_Instantiation) {
-        Diag(NewFD->getLocation(),
-             CCK == CCK_Declaration ? diag::err_constexpr_virtual
-                                    : diag::note_constexpr_tmpl_virtual);
-
-        // If it's not obvious why this function is virtual, find an overridden
-        // function which uses the 'virtual' keyword.
-        const CXXMethodDecl *WrittenVirtual = Method;
-        while (!WrittenVirtual->isVirtualAsWritten())
-          WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
-        if (WrittenVirtual != Method)
-          Diag(WrittenVirtual->getLocation(),
-               diag::note_overridden_virtual_function);
-      }
+      Diag(NewFD->getLocation(), diag::err_constexpr_virtual);
+
+      // If it's not obvious why this function is virtual, find an overridden
+      // function which uses the 'virtual' keyword.
+      const CXXMethodDecl *WrittenVirtual = Method;
+      while (!WrittenVirtual->isVirtualAsWritten())
+        WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
+      if (WrittenVirtual != Method)
+        Diag(WrittenVirtual->getLocation(),
+             diag::note_overridden_virtual_function);
       return false;
     }
 
     // - its return type shall be a literal type;
     QualType RT = NewFD->getResultType();
     if (!RT->isDependentType() &&
-        RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ?
-                           PDiag(diag::err_constexpr_non_literal_return) :
-                           PDiag(),
-                           /*AllowIncompleteType*/ true)) {
-      if (CCK == CCK_NoteNonConstexprInstantiation)
-        Diag(NewFD->getLocation(),
-             diag::note_constexpr_tmpl_non_literal_return) << RT;
+        RequireLiteralType(NewFD->getLocation(), RT,
+                           PDiag(diag::err_constexpr_non_literal_return)))
       return false;
-    }
   }
 
   // - each of its parameter types shall be a literal type;
-  if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+  if (!CheckConstexprParameterTypes(*this, NewFD))
     return false;
 
   return true;
@@ -854,8 +818,7 @@
 /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
 ///
 /// \return true if the body is OK, false if we have diagnosed a problem.
-bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body,
-                                      bool IsInstantiation) {
+bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
   if (isa<CXXTryStmt>(Body)) {
     // C++11 [dcl.constexpr]p3:
     //  The definition of a constexpr function shall satisfy the following
@@ -1005,7 +968,7 @@
   //   - every constructor involved in initializing non-static data members and
   //     base class sub-objects shall be a constexpr constructor.
   llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
-  if (!IsInstantiation && !Expr::isPotentialConstantExpr(Dcl, Diags)) {
+  if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
     Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr)
       << isa<CXXConstructorDecl>(Dcl);
     for (size_t I = 0, N = Diags.size(); I != N; ++I)
@@ -3755,9 +3718,6 @@
   // const. [...] The class of which that function is a member shall be
   // a literal type.
   //
-  // It's fine to diagnose constructors here too: such constructors cannot
-  // produce a constant expression, so are ill-formed (no diagnostic required).
-  //
   // If the class has virtual bases, any constexpr members will already have
   // been diagnosed by the checks performed on the member declaration, so
   // suppress this (less useful) diagnostic.
@@ -3766,16 +3726,14 @@
     for (CXXRecordDecl::method_iterator M = Record->method_begin(),
                                      MEnd = Record->method_end();
          M != MEnd; ++M) {
-      if (M->isConstexpr() && M->isInstance()) {
+      if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
         switch (Record->getTemplateSpecializationKind()) {
         case TSK_ImplicitInstantiation:
         case TSK_ExplicitInstantiationDeclaration:
         case TSK_ExplicitInstantiationDefinition:
           // If a template instantiates to a non-literal type, but its members
           // instantiate to constexpr functions, the template is technically
-          // ill-formed, but we allow it for sanity. Such members are treated as
-          // non-constexpr.
-          (*M)->setConstexpr(false);
+          // ill-formed, but we allow it for sanity.
           continue;
 
         case TSK_Undeclared:

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sun Feb 12 21:54:03 2012
@@ -1034,7 +1034,7 @@
                            D->getLocation(), D->getDeclName(), T, TInfo,
                            D->getStorageClass(), D->getStorageClassAsWritten(),
                            D->isInlineSpecified(), D->hasWrittenPrototype(),
-                           /*isConstexpr*/ false);
+                           D->isConstexpr());
 
   if (QualifierLoc)
     Function->setQualifierInfo(QualifierLoc);
@@ -1379,7 +1379,7 @@
                                         StartLoc, NameInfo, T, TInfo,
                                         Constructor->isExplicit(),
                                         Constructor->isInlineSpecified(),
-                                        false, /*isConstexpr*/ false);
+                                        false, Constructor->isConstexpr());
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
                                        StartLoc, NameInfo, T, TInfo,
@@ -1390,7 +1390,7 @@
                                        StartLoc, NameInfo, T, TInfo,
                                        Conversion->isInlineSpecified(),
                                        Conversion->isExplicit(),
-                                       /*isConstexpr*/ false,
+                                       Conversion->isConstexpr(),
                                        Conversion->getLocEnd());
   } else {
     Method = CXXMethodDecl::Create(SemaRef.Context, Record,
@@ -1398,7 +1398,7 @@
                                    D->isStatic(),
                                    D->getStorageClassAsWritten(),
                                    D->isInlineSpecified(),
-                                   /*isConstexpr*/ false, D->getLocEnd());
+                                   D->isConstexpr(), D->getLocEnd());
   }
 
   if (QualifierLoc)
@@ -2305,13 +2305,6 @@
                                                  EPI));
   }
 
-  // C++0x [dcl.constexpr]p6: If the instantiated template specialization of
-  // a constexpr function template satisfies the requirements for a constexpr
-  // function, then it is a constexpr function.
-  if (Tmpl->isConstexpr() &&
-      SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation))
-    New->setConstexpr(true);
-
   const FunctionDecl* Definition = Tmpl;
 
   // Get the definition. Leaves the variable unchanged if undefined.

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sun Feb 12 21:54:03 2012
@@ -4243,19 +4243,14 @@
 /// @param PD The partial diagnostic that will be printed out if T is not a
 /// literal type.
 ///
-/// @param AllowIncompleteType If true, an incomplete type will be considered
-/// acceptable.
-///
 /// @returns @c true if @p T is not a literal type and a diagnostic was emitted,
 /// @c false otherwise.
 bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
-                              const PartialDiagnostic &PD,
-                              bool AllowIncompleteType) {
+                              const PartialDiagnostic &PD) {
   assert(!T->isDependentType() && "type should not be dependent");
 
-  bool Incomplete = RequireCompleteType(Loc, T, 0);
-  if (T->isLiteralType() ||
-      (AllowIncompleteType && Incomplete && !T->isVoidType()))
+  RequireCompleteType(Loc, T, 0);
+  if (T->isLiteralType())
     return false;
 
   if (PD.getDiagID() == 0)
@@ -4273,8 +4268,9 @@
   const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
 
   // If the class has virtual base classes, then it's not an aggregate, and
-  // cannot have any constexpr constructors, so is non-literal. This is better
-  // to diagnose than the resulting absence of constexpr constructors.
+  // cannot have any constexpr constructors or a trivial default constructor,
+  // so is non-literal. This is better to diagnose than the resulting absence
+  // of constexpr constructors.
   if (RD->getNumVBases()) {
     Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
       << RD->isStruct() << RD->getNumVBases();
@@ -4282,29 +4278,9 @@
            E = RD->vbases_end(); I != E; ++I)
       Diag(I->getSourceRange().getBegin(),
            diag::note_constexpr_virtual_base_here) << I->getSourceRange();
-  } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) {
+  } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor() &&
+             !RD->hasTrivialDefaultConstructor()) {
     Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD;
-
-    switch (RD->getTemplateSpecializationKind()) {
-    case TSK_Undeclared:
-    case TSK_ExplicitSpecialization:
-      break;
-
-    case TSK_ImplicitInstantiation:
-    case TSK_ExplicitInstantiationDeclaration:
-    case TSK_ExplicitInstantiationDefinition:
-      // If the base template had constexpr constructors which were
-      // instantiated as non-constexpr constructors, explain why.
-      for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
-           E = RD->ctor_end(); I != E; ++I) {
-        if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor())
-          continue;
-
-        FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction();
-        if (Base && Base->isConstexpr())
-          CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation);
-      }
-    }
   } else if (RD->hasNonLiteralTypeFieldsOrBases()) {
     for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
          E = RD->bases_end(); I != E; ++I) {
@@ -4317,9 +4293,11 @@
     }
     for (CXXRecordDecl::field_iterator I = RD->field_begin(),
          E = RD->field_end(); I != E; ++I) {
-      if (!(*I)->getType()->isLiteralType()) {
+      if (!(*I)->getType()->isLiteralType() ||
+          (*I)->getType().isVolatileQualified()) {
         Diag((*I)->getLocation(), diag::note_non_literal_field)
-          << RD << (*I) << (*I)->getType();
+          << RD << (*I) << (*I)->getType()
+          << (*I)->getType().isVolatileQualified();
         return true;
       }
     }

Modified: cfe/trunk/test/CXX/basic/basic.types/p10.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.types/p10.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.types/p10.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.types/p10.cpp Sun Feb 12 21:54:03 2012
@@ -5,22 +5,23 @@
 // A type is a literal type if it is:
 
 // - a scalar type
-constexpr int f1(double);
+constexpr int f1(double) { return 0; }
 
 // - a reference type
 struct S { S(); };
-constexpr int f2(S &);
+constexpr int f2(S &) { return 0; }
 
 // - a class type that has all of the following properties:
 
 //  - it has a trivial destructor
 struct UserProvDtor {
-  constexpr UserProvDtor(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
+  constexpr int f(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
   ~UserProvDtor(); // expected-note {{has a user-provided destructor}}
 };
 
 struct NonTrivDtor {
-  constexpr NonTrivDtor(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
+  constexpr NonTrivDtor();
+  constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
   virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
 };
 struct NonTrivDtorBase {
@@ -30,16 +31,16 @@
 struct DerivedFromNonTrivDtor : T { // expected-note {{'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not literal because it has base class 'NonTrivDtorBase' of non-literal type}}
   constexpr DerivedFromNonTrivDtor();
 };
-constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
+constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>) { return 0; } // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
 struct TrivDtor {
   constexpr TrivDtor();
 };
-constexpr int f(TrivDtor);
+constexpr int f(TrivDtor) { return 0; }
 struct TrivDefaultedDtor {
   constexpr TrivDefaultedDtor();
   ~TrivDefaultedDtor() = default;
 };
-constexpr int f(TrivDefaultedDtor);
+constexpr int f(TrivDefaultedDtor) { return 0; }
 
 //  - it is an aggregate type or has at least one constexpr constructor or
 //    constexpr constructor template that is not a copy or move constructor
@@ -52,36 +53,41 @@
   template<typename T> constexpr CtorTemplate(T);
 };
 struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}}
-  constexpr CopyCtorOnly(CopyCtorOnly&); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
+  constexpr CopyCtorOnly(CopyCtorOnly&);
+  constexpr int f(); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
 };
 struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}}
-  constexpr MoveCtorOnly(MoveCtorOnly&&); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
+  constexpr MoveCtorOnly(MoveCtorOnly&&);
+  constexpr int f(); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
 };
 template<typename T>
-struct CtorArg { // expected-note {{no constexpr constructors other than copy or move constructors}}
-  constexpr CtorArg(T); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}}
+struct CtorArg {
+  constexpr CtorArg(T);
 };
-constexpr int f(CtorArg<int>);
-constexpr int f(CtorArg<NonLiteral>); // expected-error {{not a literal type}}
+constexpr int f(CtorArg<int>) { return 0; } // ok
+constexpr int f(CtorArg<NonLiteral>) { return 0; } // ok, ctor is still constexpr
 // We have a special-case diagnostic for classes with virtual base classes.
 struct VBase {};
 struct HasVBase : virtual VBase {}; // expected-note 2{{virtual base class declared here}}
 struct Derived : HasVBase {
-  constexpr Derived(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
+  constexpr Derived() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
 };
 template<typename T> struct DerivedFromVBase : T { // expected-note {{struct with virtual base class is not a literal type}}
   constexpr DerivedFromVBase();
 };
-constexpr int f(DerivedFromVBase<HasVBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase<HasVBase>' is not a literal type}}
+constexpr int f(DerivedFromVBase<HasVBase>) {} // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase<HasVBase>' is not a literal type}}
+template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {}
+constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // expected-error {{constant expression}} expected-note {{cannot construct object of type 'DerivedFromVBase<HasVBase>' with virtual base class in a constant expression}}
 
 //  - it has all non-static data members and base classes of literal types
 struct NonLitMember {
   S s; // expected-note {{has data member 's' of non-literal type 'S'}}
 };
-constexpr int f(NonLitMember); // expected-error {{1st parameter type 'NonLitMember' is not a literal type}}
+constexpr int f(NonLitMember) {} // expected-error {{1st parameter type 'NonLitMember' is not a literal type}}
 struct NonLitBase :
   S { // expected-note {{base class 'S' of non-literal type}}
-  constexpr NonLitBase(); // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
+  constexpr NonLitBase();
+  constexpr int f() { return 0; } // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
 };
 struct LitMemBase : Agg {
   Agg agg;
@@ -91,8 +97,8 @@
   T t; // expected-note {{'MemberType<NonLiteral>' is not literal because it has data member 't' of non-literal type 'NonLiteral'}}
   constexpr MemberType();
 };
-constexpr int f(MemberType<int>);
-constexpr int f(MemberType<NonLiteral>); // expected-error {{not a literal type}}
+constexpr int f(MemberType<int>) { return 0; }
+constexpr int f(MemberType<NonLiteral>) { return 0; } // expected-error {{not a literal type}}
 
 // - an array of literal type
 struct ArrGood {
@@ -101,9 +107,9 @@
   TrivDtor td[3];
   TrivDefaultedDtor tdd[3];
 };
-constexpr int f(ArrGood);
+constexpr int f(ArrGood) { return 0; }
 
 struct ArrBad {
   S s[3]; // expected-note {{data member 's' of non-literal type 'S [3]'}}
 };
-constexpr int f(ArrBad); // expected-error {{1st parameter type 'ArrBad' is not a literal type}}
+constexpr int f(ArrBad) { return 0; } // expected-error {{1st parameter type 'ArrBad' is not a literal type}}

Modified: cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp (original)
+++ cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp Sun Feb 12 21:54:03 2012
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
-struct NonLit {
+struct NonLit { // expected-note {{no constexpr constructors}}
   NonLit();
 };
 
@@ -29,15 +29,14 @@
 struct U {
   static constexpr int a = 0;
   static constexpr int b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}}
-  // FIXME: It'd be nice to error on this at template definition time.
-  static constexpr NonLit h = NonLit(); // expected-error 2{{must be initialized by a constant expression}} expected-note 2{{non-literal type}}
+  static constexpr NonLit h = NonLit(); // expected-error {{cannot have non-literal type 'const NonLit'}}
   static constexpr T c = T(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type}}
   static const T d;
 };
 
 template<typename T> constexpr T U<T>::d = T(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type 'const NonLit'}}
 
-U<int> u1; // expected-note {{here}}
+U<int> u1;
 U<NonLit> u2; // expected-note {{here}}
 
 static_assert(U<int>::a == 0, "");

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp Sun Feb 12 21:54:03 2012
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
-struct notlit {
+struct notlit { // expected-note {{not literal because}}
   notlit() {}
 };
 struct notlit2 {
@@ -20,7 +20,7 @@
 // not a definition of an object
 constexpr extern int i2; // expected-error {{constexpr variable declaration must be a definition}}
 // not a literal type
-constexpr notlit nl1; // expected-error {{constexpr variable 'nl1' must be initialized by a constant expression}} expected-note {{non-literal type 'const notlit' cannot be used in a constant expression}}
+constexpr notlit nl1; // expected-error {{constexpr variable cannot have non-literal type 'const notlit'}}
 // function parameters
 void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}
 // non-static member
@@ -77,11 +77,11 @@
 // explicit specialization can differ in constepxr
 // FIXME: When checking the explicit specialization, we implicitly instantiate
 // the primary template then claim a constexpr mismatch.
-template <> notlit ft(notlit nl) { return nl; }
+template <> notlit ft(notlit nl) { return nl; } // unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
 template <> char ft(char c) { return c; } // desired-note {{previous}} unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
 template <> constexpr char ft(char nl); // desired-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
 template <> constexpr int gt(int nl) { return nl; } // unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
-template <> notlit S::f() const { return notlit(); }
+template <> notlit S::f() const { return notlit(); } // unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
 template <> constexpr int S::g() { return 0; } // desired-note {{previous}} unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
 template <> int S::g() const; // desired-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
 // specializations can drop the 'constexpr' but not the implied 'const'.

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp Sun Feb 12 21:54:03 2012
@@ -8,7 +8,7 @@
   typedef double D;
 }
 
-struct NonLiteral { // expected-note 4{{no constexpr constructors}}
+struct NonLiteral { // expected-note 2{{no constexpr constructors}}
   NonLiteral() {}
   NonLiteral(int) {}
 };
@@ -24,31 +24,28 @@
   int ImplicitlyVirtual() const;
 };
 
-// Note, the wording applies constraints to the definition of constexpr
-// functions, but we intentionally apply all that we can to the declaration
-// instead. See DR1360.
-
 // The definition of a constexpr function shall satisfy the following
 // constraints:
 struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}}
-  constexpr T(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
+  constexpr T();
+  constexpr int f(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
 
   //  - it shall not be virtual;
-  virtual constexpr int ExplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
+  virtual constexpr int ExplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
 
-  constexpr int ImplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
+  constexpr int ImplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
 
   //  - its return type shall be a literal type;
-  constexpr NonLiteral NonLiteralReturn(); // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
-  constexpr void VoidReturn(); // expected-error {{constexpr function's return type 'void' is not a literal type}}
+  constexpr NonLiteral NonLiteralReturn() { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
+  constexpr void VoidReturn() { return; } // expected-error {{constexpr function's return type 'void' is not a literal type}}
   constexpr ~T(); // expected-error {{destructor cannot be marked constexpr}}
   typedef NonLiteral F();
-  constexpr F NonLiteralReturn2; // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
+  constexpr F NonLiteralReturn2; // ok until definition
 
   //  - each of its parameter types shall be a literal type;
-  constexpr int NonLiteralParam(NonLiteral); // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
+  constexpr int NonLiteralParam(NonLiteral) { return 0; } // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
   typedef int G(NonLiteral);
-  constexpr G NonLiteralParam2; // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
+  constexpr G NonLiteralParam2; // ok until definition
 
   //  - its function-body shall be = delete, = default,
   constexpr int Deleted() = delete;
@@ -65,7 +62,7 @@
 };
 
 struct V : virtual U { // expected-note {{here}}
-  constexpr int F(); // expected-error {{constexpr member function not allowed in struct with virtual base class}}
+  constexpr int F() { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}}
 };
 
 //  or a compound-statememt that contains only

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp Sun Feb 12 21:54:03 2012
@@ -18,16 +18,12 @@
   operator int() const { return 0; }
 };
 
-// Note, the wording applies constraints to the definition of constexpr
-// constructors, but we intentionally apply all that we can to the declaration
-// instead. See DR1360.
-
 // In the definition of a constexpr constructor, each of the parameter types
 // shall be a literal type.
 struct S {
-  constexpr S(int, N::C);
-  constexpr S(int, NonLiteral, N::C); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
-  constexpr S(int, NonLiteral = 42); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
+  constexpr S(int, N::C) {}
+  constexpr S(int, NonLiteral, N::C) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
+  constexpr S(int, NonLiteral = 42) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
 
   // In addition, either its function-body shall be = delete or = default
   constexpr S() = default;
@@ -38,14 +34,14 @@
 
 // - the class shall not have any virtual base classes;
 struct T : virtual S { // expected-note {{here}}
-  constexpr T(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
+  constexpr T() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
 };
 namespace IndirectVBase {
   struct A {};
   struct B : virtual A {}; // expected-note {{here}}
   class C : public B {
   public:
-    constexpr C(); // expected-error {{constexpr constructor not allowed in class with virtual base class}}
+    constexpr C() {} // expected-error {{constexpr constructor not allowed in class with virtual base class}}
   };
 }
 

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp Sun Feb 12 21:54:03 2012
@@ -10,7 +10,7 @@
 
 struct NonLiteral {
   NonLiteral() {}
-  NonLiteral(int) {}
+  NonLiteral(int) {} // expected-note 2{{here}}
   operator int() const { return 0; }
 };
 struct Literal {
@@ -19,7 +19,7 @@
 };
 
 struct S {
-  virtual int ImplicitlyVirtual();
+  virtual int ImplicitlyVirtual() const;
 };
 struct T {};
 
@@ -27,48 +27,42 @@
   constexpr int ImplicitlyVirtual() { return 0; }
 };
 
-// FIXME: Can't test this until we have function invocation substitution
-#if 0
-constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // desired-error {{not a constant expression}}
+constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}}
 constexpr int b = ImplicitVirtualFromDependentBase<T>().ImplicitlyVirtual(); // ok
-#endif
+constexpr int c = ImplicitVirtualFromDependentBase<S>().ImplicitVirtualFromDependentBase<S>::ImplicitlyVirtual();
 
 template<typename R> struct ConstexprMember {
   constexpr R F() { return 0; }
 };
-// FIXME: Can't test this until we have function invocation substitution
-#if 0
-constexpr int c = ConstexprMember<int>().F(); // ok
-constexpr int d = ConstexprMember<NonLiteral>().F(); // desired-error {{not a constant expression}}
-#endif
-
-template<typename ...P> struct ConstexprCtor { // expected-note 2{{no constexpr constructors}}
-  constexpr ConstexprCtor(P...); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}} \
-                                    expected-note {{constructor template instantiation is not constexpr because 2nd parameter type 'NonLiteral' is not a literal type}}
-};
-constexpr ConstexprCtor<> f1(); // ok
-constexpr ConstexprCtor<int> f2(); // ok
-constexpr ConstexprCtor<NonLiteral> f3(); // expected-error {{not a literal type}}
-constexpr ConstexprCtor<int, NonLiteral> f4(); // expected-error {{not a literal type}}
+constexpr int d = ConstexprMember<int>().F(); // ok
+constexpr int e = ConstexprMember<NonLiteral>().F(); // expected-error {{constant expression}}
+
+template<typename ...P> struct ConstexprCtor {
+  constexpr ConstexprCtor(P...) {}
+};
+constexpr ConstexprCtor<> f1() { return {}; } // ok
+constexpr ConstexprCtor<int> f2() { return 0; } // ok
+constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
+constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
 
 struct VirtBase : virtual S {}; // expected-note {{here}}
 
 namespace TemplateVBase {
   template<typename T> struct T1 : virtual Literal { // expected-note {{here}}
-    constexpr T1(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
+    constexpr T1() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
   };
 
-  template<typename T> struct T2 : virtual T { // expected-note {{struct with virtual base class is not a literal type}} expected-note {{here}}
+  template<typename T> struct T2 : virtual T {
     // FIXME: This is ill-formed (no diagnostic required).
     // We should diagnose it now rather than waiting until instantiation.
-    constexpr T2(); // desired-error {{constexpr constructor not allowed in class with virtual base classes}}
+    constexpr T2() {}
   };
-  constexpr T2<Literal> g2(); // expected-error {{not a literal type}}
+  constexpr T2<Literal> g2() { return {}; }
 
   template<typename T> class T3 : public T { // expected-note {{class with virtual base class is not a literal type}}
   public:
     constexpr T3() {}
   };
-  constexpr T3<Literal> g3(); // ok
-  constexpr T3<VirtBase> g4(); // expected-error {{not a literal type}}
+  constexpr T3<Literal> g3() { return {}; } // ok
+  constexpr T3<VirtBase> g4() { return {}; } // expected-error {{not a literal type}}
 }

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp Sun Feb 12 21:54:03 2012
@@ -18,15 +18,15 @@
 // A variable declaration which uses the constexpr specifier shall have an
 // initializer and shall be initialized by a constant expression.
 constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}}
-constexpr struct C { C(); } ni2; // expected-error {{constexpr variable 'ni2' must be initialized by a constant expression}} expected-note {{non-literal type 'const struct C' cannot be used in a constant expression}}
+constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}}
 constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}}
 
 constexpr int nc1 = i; // expected-error {{constexpr variable 'nc1' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
-constexpr C nc2 = C(); // expected-error {{constexpr variable 'nc2' must be initialized by a constant expression}} expected-note {{non-literal type}}
+constexpr C nc2 = C(); // expected-error {{cannot have non-literal type 'const C'}}
 int &f(); // expected-note {{declared here}}
 constexpr int &nc3 = f(); // expected-error {{constexpr variable 'nc3' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}}
 constexpr int nc4(i); // expected-error {{constexpr variable 'nc4' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
-constexpr C nc5((C())); // expected-error {{constexpr variable 'nc5' must be initialized by a constant expression}} expected-note {{non-literal type 'const C'}}
+constexpr C nc5((C())); // expected-error {{cannot have non-literal type 'const C'}}
 int &f(); // expected-note {{here}}
 constexpr int &nc6(f()); // expected-error {{constexpr variable 'nc6' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f'}}
 

Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Sun Feb 12 21:54:03 2012
@@ -288,7 +288,7 @@
   //   non-volatile const object with a preceding initialization, initialized
   //   with a constant expression  [Note: a string literal (2.14.5 [lex.string])
   //   corresponds to an array of such objects. -end note], or
-  volatile const int vi = 1; // expected-note {{here}}
+  volatile const int vi = 1; // expected-note 2{{here}}
   const int ci = 1;
   volatile const int &vrci = ci;
   static_assert(vi, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
@@ -298,18 +298,23 @@
   // - a non-volatile glvalue of literal type that refers to a non-volatile
   //   object defined with constexpr, or that refers to a sub-object of such an
   //   object, or
+  struct V {
+    constexpr V() : v(1) {}
+    volatile int v; // expected-note {{not literal because}}
+  };
+  constexpr V v; // expected-error {{non-literal type}}
   struct S {
-    constexpr S(int=0) : i(1), v(1) {}
-    constexpr S(const S &s) : i(2), v(2) {}
+    constexpr S(int=0) : i(1), v(const_cast<volatile int&>(vi)) {}
+    constexpr S(const S &s) : i(2), v(const_cast<volatile int&>(vi)) {}
     int i;
-    volatile int v; // expected-note {{here}}
+    volatile int &v;
   };
-  constexpr S s;
+  constexpr S s; // ok
   constexpr volatile S vs; // expected-note {{here}}
-  constexpr const volatile S &vrs = s;
+  constexpr const volatile S &vrs = s; // ok
   static_assert(s.i, "");
   static_assert(s.v, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
-  static_assert(const_cast<int&>(s.v), ""); // expected-error {{constant expression}} expected-note {{read of volatile member 'v'}}
+  static_assert(const_cast<int&>(s.v), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vi'}}
   static_assert(vs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
   static_assert(const_cast<int&>(vs.i), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vs'}}
   static_assert(vrs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}

Modified: cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp Sun Feb 12 21:54:03 2012
@@ -11,7 +11,7 @@
 struct NonConstexpr2a : NonConstexpr1 { };
 constexpr NonConstexpr1 nc1 = NonConstexpr1(); // ok, does not call constructor
 constexpr NonConstexpr2 nc2 = NonConstexpr2(); // ok, does not call constructor
-constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr2a'}}
+constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // ok, does not call constructor
 constexpr int nc2_a = NonConstexpr2().nl.a; // ok
 constexpr int nc2a_a = NonConstexpr2a().a; // ok
 struct Helper {
@@ -21,8 +21,8 @@
 
 struct Constexpr1 {};
 constexpr Constexpr1 c1 = Constexpr1(); // ok
-struct NonConstexpr3 : virtual Constexpr1 {};
-constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr3'}}
+struct NonConstexpr3 : virtual Constexpr1 {}; // expected-note {{struct with virtual base}} expected-note {{declared here}}
+constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{non-literal type 'const NonConstexpr3'}}
 
 struct Constexpr2 {
   int a = 0;

Modified: cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-value-init.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-value-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-value-init.cpp Sun Feb 12 21:54:03 2012
@@ -26,6 +26,6 @@
 constexpr C c1; // expected-error {{requires a user-provided default constructor}}
 constexpr C c2 = C(); // ok
 constexpr D d1; // expected-error {{requires a user-provided default constructor}}
-constexpr D d2 = D(); // expected-error {{constant expression}} expected-note {{non-literal type 'const D'}}
+constexpr D d2 = D(); // ok with DR1452
 static_assert(D().c == 0, "");
 static_assert(D().d == 0, "");

Modified: cfe/trunk/test/SemaCXX/literal-type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/literal-type.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/literal-type.cpp (original)
+++ cfe/trunk/test/SemaCXX/literal-type.cpp Sun Feb 12 21:54:03 2012
@@ -23,6 +23,8 @@
 //           a constant expression,
 //        -- it is an aggregate type or has at least one constexpr constructor
 //           or constructor template that is not a copy or move constructor, and
+//           [DR1452 adds class types with trivial default constructors to
+//            this list]
 //        -- it has all non-static data members and base classes of literal
 //           types
 struct Empty {};
@@ -36,25 +38,26 @@
 struct HasDtor { ~HasDtor(); };
 
 class NonAggregate { int x; };
-struct HasNonLiteralBase : NonAggregate {};
+struct NonLiteral { NonLiteral(); };
+struct HasNonLiteralBase : NonLiteral {};
 struct HasNonLiteralMember { HasDtor x; };
 
 static_assert(__is_literal(Empty), "fail");
 static_assert(__is_literal(LiteralType), "fail");
+static_assert(__is_literal(NonAggregate), "fail");
+static_assert(!__is_literal(NonLiteral), "fail");
 static_assert(!__is_literal(HasDtor), "fail");
-static_assert(!__is_literal(NonAggregate), "fail");
 static_assert(!__is_literal(HasNonLiteralBase), "fail");
 static_assert(!__is_literal(HasNonLiteralMember), "fail");
 
-// FIXME: Test constexpr constructors and non-static members with initializers
-// when Clang supports them:
-#if 0
-extern int f();
+// DR1361 removes the brace-or-equal-initializer bullet so that we can allow:
+extern int f(); // expected-note {{here}}
 struct HasNonConstExprMemInit {
-  int x = f();
-  constexpr HasNonConstExprMemInit(int y) {}
+  int x = f(); // expected-note {{non-constexpr function}}
+  constexpr HasNonConstExprMemInit() {} // expected-error {{never produces a constant expression}}
+  constexpr HasNonConstExprMemInit(int y) : x(y) {} // ok
 };
-static_assert(!__is_literal(HasNonConstExprMemInit), "fail");
+static_assert(__is_literal(HasNonConstExprMemInit), "fail");
 
 class HasConstExprCtor {
   int x;
@@ -66,6 +69,9 @@
 public:
   template <typename U> constexpr HasConstExprCtorTemplate(U y) : x(y) {}
 };
+template <typename T> class HasConstExprCtorT {
+  constexpr HasConstExprCtorT(T) {}
+};
 static_assert(__is_literal(HasConstExprCtor), "fail");
-static_assert(__is_literal(HasConstExprCtorTemplate), "fail");
-#endif
+static_assert(__is_literal(HasConstExprCtorTemplate<int>), "fail");
+static_assert(__is_literal(HasConstExprCtorT<NonLiteral>), "fail");





More information about the cfe-commits mailing list