[cfe-commits] r140926 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Sema/ test/CXX/basic/basic.types/ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/

Richard Smith richard-llvm at metafoo.co.uk
Fri Sep 30 19:31:29 PDT 2011


Author: rsmith
Date: Fri Sep 30 21:31:28 2011
New Revision: 140926

URL: http://llvm.org/viewvc/llvm-project?rev=140926&view=rev
Log:
constexpr: semantic checking for constexpr functions and constructors. Based in
part on patches by Peter Collingbourne.

We diverge from the C++11 standard in a few areas, mostly related to checking
constexpr function declarations, and not just definitions. See WG21 paper
N3308=11-0078 for details.

Function invocation substitution is not available in this patch; constexpr
functions cannot yet be used from within constant expressions.

Added:
    cfe/trunk/test/CXX/basic/basic.types/p10.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/p8.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Type.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/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Sep 30 21:31:28 2011
@@ -1004,6 +1004,25 @@
     return isTriviallyCopyable() && hasTrivialDefaultConstructor();
   }
 
+  // isLiteral - Whether this class is a literal type.
+  //
+  // C++0x [basic.types]p10
+  //   A class type that has all the following properties:
+  //     -- 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
+  //
+  // We resolve DR1361 by ignoring the second bullet.
+  bool isLiteral() const {
+    return hasTrivialDestructor() &&
+           (isAggregate() || hasConstexprNonCopyMoveConstructor()) &&
+           !hasNonLiteralTypeFieldsOrBases();
+  }
+
   /// \brief If this record is an instantiation of a member class,
   /// retrieves the member class from which it was instantiated.
   ///

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 30 21:31:28 2011
@@ -1193,6 +1193,69 @@
   "definition of initialized static data member %0 cannot be marked constexpr">;
 def err_constexpr_var_requires_const_init : Error<
   "constexpr variable %0 must be initialized by a constant expression">;
+def err_constexpr_redecl_mismatch : Error<
+  "%select{non-constexpr declaration of %0 follows constexpr declaration"
+  "|constexpr declaration of %0 follows non-constexpr declaration}1">;
+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 constructor not allowed in "
+  "%select{class|struct}0 with virtual base %plural{1:class|:classes}1">;
+def note_constexpr_tmpl_virtual_base : Note<"constructor template instantiation is "
+  "not constexpr because %select{class|struct}0 has virtual base "
+  "%plural{1:class|:classes}1">;
+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<
+  "types cannot be defined in a constexpr %select{function|constructor}0">;
+def err_constexpr_vla : Error<
+  "variably-modified type %0 cannot be used in a constexpr "
+  "%select{function|constructor}1">;
+def err_constexpr_var_declaration : Error<
+  "variables cannot be declared in a constexpr %select{function|constructor}0">;
+def err_constexpr_body_no_return : Error<
+  "no return statement in constexpr function">;
+def err_constexpr_body_multiple_return : Error<
+  "multiple return statements in constexpr function">;
+def note_constexpr_body_previous_return : Note<
+  "previous return statement is here">;
+def err_constexpr_function_try_block : Error<
+  "function try block not allowed in constexpr %select{function|constructor}0">;
+def err_constexpr_union_ctor_no_init : Error<
+  "constexpr union constructor does not initialize any member">;
+def err_constexpr_ctor_missing_init : Error<
+  "constexpr constructor must initialize all members">;
+def note_constexpr_ctor_missing_init : Note<
+  "member not initialized by constructor">;
+def err_constexpr_method_non_literal : Error<
+  "non-literal type %0 cannot have constexpr members">;
+def note_non_literal_no_constexpr_ctors : Note<
+  "%0 is not literal because it is not an aggregate and has no constexpr "
+  "constructors other than copy or move constructors">;
+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">;
+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<
+  "%0 is not literal because it has a non-trivial destructor">;
  
 // Objective-C++
 def err_objc_decls_may_only_appear_in_global_scope : Error<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Sep 30 21:31:28 2011
@@ -842,6 +842,9 @@
                                std::pair<SourceLocation,
                                          PartialDiagnostic> Note);
 
+  bool RequireLiteralType(SourceLocation Loc, QualType T,
+                          const PartialDiagnostic &PD,
+                          bool AllowIncompleteType = false);
 
   QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
                              const CXXScopeSpec &SS, QualType T);
@@ -1010,6 +1013,23 @@
                                      bool &Redeclaration,
                                      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);
+
   void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
   void CheckFunctionDeclaration(Scope *S,
                                 FunctionDecl *NewFD, LookupResult &Previous,

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Fri Sep 30 21:31:28 2011
@@ -1134,29 +1134,19 @@
     return true;
   //    -- a class type that has all of the following properties:
   if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+    //    -- a trivial destructor,
+    //    -- every constructor call and full-expression in the
+    //       brace-or-equal-initializers 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
+    //
+    // We resolve DR1361 by ignoring the second bullet.
     if (const CXXRecordDecl *ClassDecl =
-        dyn_cast<CXXRecordDecl>(RT->getDecl())) {
-      //    -- a trivial destructor,
-      if (!ClassDecl->hasTrivialDestructor())
-        return false;
-
-      //    -- every constructor call and full-expression in the
-      //       brace-or-equal-initializers for non-static data members (if any)
-      //       is a constant expression,
-      // We deliberately do not implement this restriction. It isn't necessary
-      // and doesn't make any sense.
-
-      //    -- it is an aggregate type or has at least one constexpr
-      //       constructor or constructor template that is not a copy or move
-      //       constructor, and
-      if (!ClassDecl->isAggregate() &&
-          !ClassDecl->hasConstexprNonCopyMoveConstructor())
-        return false;
-
-      //    -- all non-static data members and base classes of literal types
-      if (ClassDecl->hasNonLiteralTypeFieldsOrBases())
-        return false;
-    }
+        dyn_cast<CXXRecordDecl>(RT->getDecl()))
+      return ClassDecl->isLiteral();
 
     return true;
   }

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Sep 30 21:31:28 2011
@@ -4770,15 +4770,11 @@
       // are implicitly inline.
       NewFD->setImplicitlyInline();
 
-      // FIXME: If this is a redeclaration, check the original declaration was
-      // marked constepr.
-
       // C++0x [dcl.constexpr]p3: functions declared constexpr are required to
       // be either constructors or to return a literal type. Therefore,
       // destructors cannot be declared constexpr.
       if (isa<CXXDestructorDecl>(NewFD))
-        Diag(D.getDeclSpec().getConstexprSpecLoc(),
-             diag::err_constexpr_dtor);
+        Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
     }
 
     // If __module_private__ was specified, mark the function accordingly.
@@ -5050,6 +5046,10 @@
             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);
@@ -6963,6 +6963,10 @@
       ActivePolicy = &WP;
     }
 
+    if (FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+        !CheckConstexprFunctionBody(FD, Body))
+      FD->setInvalidDecl();
+
     assert(ExprTemporaries.empty() && "Leftover temporaries in function");
     assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
   }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Sep 30 21:31:28 2011
@@ -502,6 +502,20 @@
     }
   }
 
+  // C++0x [dcl.constexpr]p1: If any declaration of a function or function
+  // template has a constexpr specifier then all its declarations shall
+  // contain the constexpr specifier. [Note: An explicit specialization can
+  // differ from the template declaration with respect to the constexpr
+  // specifier. -- end note]
+  //
+  // FIXME: Don't reject changes in constexpr in explicit specializations.
+  if (New->isConstexpr() != Old->isConstexpr()) {
+    Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+      << New << New->isConstexpr();
+    Diag(Old->getLocation(), diag::note_previous_declaration);
+    Invalid = true;
+  }
+
   if (CheckEquivalentExceptionSpec(Old, New))
     Invalid = true;
 
@@ -602,6 +616,359 @@
   }
 }
 
+// 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) {
+  unsigned ArgIndex = 0;
+  const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
+  for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(),
+       e = FT->arg_type_end(); i != e; ++i, ++ArgIndex) {
+    const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
+    SourceLocation ParamLoc = PD->getLocation();
+    if (!(*i)->isDependentType() &&
+        SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ?
+                            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;
+      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++0x [dcl.constexpr]p3,4, as amended by N3308.
+//
+// \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");
+
+  if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(NewFD)) {
+    // C++0x [dcl.constexpr]p4:
+    //  In the definition of a constexpr constructor, each of the parameter
+    //  types shall be a literal type.
+    if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+      return false;
+
+    //  In addition, either its function-body shall be = delete or = default or
+    //  it shall satisfy the following constraints:
+    //  - the class shall not have any virtual base classes;
+    const CXXRecordDecl *RD = CD->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)
+          << 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;
+    }
+  } else {
+    // C++0x [dcl.constexpr]p3:
+    //  The definition of a constexpr function shall satisfy the following
+    //  constraints:
+    // - 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);
+      }
+      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;
+      return false;
+    }
+
+    // - each of its parameter types shall be a literal type;
+    if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+      return false;
+  }
+
+  return true;
+}
+
+/// Check the given declaration statement is legal within a constexpr function
+/// body. C++0x [dcl.constexpr]p3,p4.
+///
+/// \return true if the body is OK, false if we have diagnosed a problem.
+static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
+                                   DeclStmt *DS) {
+  // C++0x [dcl.constexpr]p3 and p4:
+  //  The definition of a constexpr function(p3) or constructor(p4) [...] shall
+  //  contain only
+  for (DeclStmt::decl_iterator DclIt = DS->decl_begin(),
+         DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
+    switch ((*DclIt)->getKind()) {
+    case Decl::StaticAssert:
+    case Decl::Using:
+    case Decl::UsingShadow:
+    case Decl::UsingDirective:
+    case Decl::UnresolvedUsingTypename:
+      //   - static_assert-declarations
+      //   - using-declarations,
+      //   - using-directives,
+      continue;
+
+    case Decl::Typedef:
+    case Decl::TypeAlias: {
+      //   - typedef declarations and alias-declarations that do not define
+      //     classes or enumerations,
+      TypedefNameDecl *TN = cast<TypedefNameDecl>(*DclIt);
+      if (TN->getUnderlyingType()->isVariablyModifiedType()) {
+        // Don't allow variably-modified types in constexpr functions.
+        TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
+        SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
+          << TL.getSourceRange() << TL.getType()
+          << isa<CXXConstructorDecl>(Dcl);
+        return false;
+      }
+      continue;
+    }
+
+    case Decl::Enum:
+    case Decl::CXXRecord:
+      // As an extension, we allow the declaration (but not the definition) of
+      // classes and enumerations in all declarations, not just in typedef and
+      // alias declarations.
+      if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) {
+        SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition)
+          << isa<CXXConstructorDecl>(Dcl);
+        return false;
+      }
+      continue;
+
+    case Decl::Var:
+      SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration)
+        << isa<CXXConstructorDecl>(Dcl);
+      return false;
+
+    default:
+      SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+        << isa<CXXConstructorDecl>(Dcl);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/// Check that the given field is initialized within a constexpr constructor.
+///
+/// \param Dcl The constexpr constructor being checked.
+/// \param Field The field being checked. This may be a member of an anonymous
+///        struct or union nested within the class being checked.
+/// \param Inits All declarations, including anonymous struct/union members and
+///        indirect members, for which any initialization was provided.
+/// \param Diagnosed Set to true if an error is produced.
+static void CheckConstexprCtorInitializer(Sema &SemaRef,
+                                          const FunctionDecl *Dcl,
+                                          FieldDecl *Field,
+                                          llvm::SmallSet<Decl*, 16> &Inits,
+                                          bool &Diagnosed) {
+  if (!Inits.count(Field)) {
+    if (!Diagnosed) {
+      SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
+      Diagnosed = true;
+    }
+    SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init);
+  } else if (Field->isAnonymousStructOrUnion()) {
+    const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
+    for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+         I != E; ++I)
+      // If an anonymous union contains an anonymous struct of which any member
+      // is initialized, all members must be initialized.
+      if (!RD->isUnion() || Inits.count(*I))
+        CheckConstexprCtorInitializer(SemaRef, Dcl, *I, Inits, Diagnosed);
+  }
+}
+
+/// Check the body for the given constexpr function declaration only contains
+/// 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) {
+  if (isa<CXXTryStmt>(Body)) {
+    // C++0x [dcl.constexpr]p3:
+    //  The definition of a constexpr function shall satisfy the following
+    //  constraints: [...]
+    // - its function-body shall be = delete, = default, or a
+    //   compound-statement
+    //
+    // C++0x [dcl.constexpr]p4:
+    //  In the definition of a constexpr constructor, [...]
+    // - its function-body shall not be a function-try-block;
+    Diag(Body->getLocStart(), diag::err_constexpr_function_try_block)
+      << isa<CXXConstructorDecl>(Dcl);
+    return false;
+  }
+
+  // - its function-body shall be [...] a compound-statement that contains only
+  CompoundStmt *CompBody = cast<CompoundStmt>(Body);
+
+  llvm::SmallVector<SourceLocation, 4> ReturnStmts;
+  for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(),
+         BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) {
+    switch ((*BodyIt)->getStmtClass()) {
+    case Stmt::NullStmtClass:
+      //   - null statements,
+      continue;
+
+    case Stmt::DeclStmtClass:
+      //   - static_assert-declarations
+      //   - using-declarations,
+      //   - using-directives,
+      //   - typedef declarations and alias-declarations that do not define
+      //     classes or enumerations,
+      if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt)))
+        return false;
+      continue;
+
+    case Stmt::ReturnStmtClass:
+      //   - and exactly one return statement;
+      if (isa<CXXConstructorDecl>(Dcl))
+        break;
+
+      ReturnStmts.push_back((*BodyIt)->getLocStart());
+      // FIXME
+      // - every constructor call and implicit conversion used in initializing
+      //   the return value shall be one of those allowed in a constant
+      //   expression.
+      // Deal with this as part of a general check that the function can produce
+      // a constant expression (for [dcl.constexpr]p5).
+      continue;
+
+    default:
+      break;
+    }
+
+    Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+      << isa<CXXConstructorDecl>(Dcl);
+    return false;
+  }
+
+  if (const CXXConstructorDecl *Constructor
+        = dyn_cast<CXXConstructorDecl>(Dcl)) {
+    const CXXRecordDecl *RD = Constructor->getParent();
+    // - every non-static data member and base class sub-object shall be
+    //   initialized;
+    if (RD->isUnion()) {
+      // DR1359: Exactly one member of a union shall be initialized.
+      if (Constructor->getNumCtorInitializers() == 0) {
+        Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
+        return false;
+      }
+    } else if (!Constructor->isDelegatingConstructor()) {
+      assert(RD->getNumVBases() == 0 && "constexpr ctor with virtual bases");
+
+      // Skip detailed checking if we have enough initializers, and we would
+      // allow at most one initializer per member.
+      bool AnyAnonStructUnionMembers = false;
+      unsigned Fields = 0;
+      for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+           E = RD->field_end(); I != E; ++I, ++Fields) {
+        if ((*I)->isAnonymousStructOrUnion()) {
+          AnyAnonStructUnionMembers = true;
+          break;
+        }
+      }
+      if (AnyAnonStructUnionMembers ||
+          Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) {
+        // Check initialization of non-static data members. Base classes are
+        // always initialized so do not need to be checked. Dependent bases
+        // might not have initializers in the member initializer list.
+        llvm::SmallSet<Decl*, 16> Inits;
+        for (CXXConstructorDecl::init_const_iterator
+               I = Constructor->init_begin(), E = Constructor->init_end();
+             I != E; ++I) {
+          if (FieldDecl *FD = (*I)->getMember())
+            Inits.insert(FD);
+          else if (IndirectFieldDecl *ID = (*I)->getIndirectMember())
+            Inits.insert(ID->chain_begin(), ID->chain_end());
+        }
+
+        bool Diagnosed = false;
+        for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+             E = RD->field_end(); I != E; ++I)
+          CheckConstexprCtorInitializer(*this, Dcl, *I, Inits, Diagnosed);
+        if (Diagnosed)
+          return false;
+      }
+    }
+
+    // FIXME
+    // - every constructor involved in initializing non-static data members
+    //   and base class sub-objects shall be a constexpr constructor;
+    // - every assignment-expression that is an initializer-clause appearing
+    //   directly or indirectly within a brace-or-equal-initializer for
+    //   a non-static data member that is not named by a mem-initializer-id
+    //   shall be a constant expression; and
+    // - every implicit conversion used in converting a constructor argument
+    //   to the corresponding parameter type and converting
+    //   a full-expression to the corresponding member type shall be one of
+    //   those allowed in a constant expression.
+    // Deal with these as part of a general check that the function can produce
+    // a constant expression (for [dcl.constexpr]p5).
+  } else {
+    if (ReturnStmts.empty()) {
+      Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return);
+      return false;
+    }
+    if (ReturnStmts.size() > 1) {
+      Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return);
+      for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
+        Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
+      return false;
+    }
+  }
+
+  return true;
+}
+
 /// isCurrentClassName - Determine whether the identifier II is the
 /// name of the class type currently being defined. In the case of
 /// nested classes, this will only return true if II is the name of
@@ -3226,6 +3593,47 @@
     }
   }
 
+  // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
+  // function that is not a constructor declares that member function to be
+  // 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.
+  if (LangOpts.CPlusPlus0x && !Record->isDependentType() &&
+      !Record->isLiteral() && !Record->getNumVBases()) {
+    for (CXXRecordDecl::method_iterator M = Record->method_begin(),
+                                     MEnd = Record->method_end();
+         M != MEnd; ++M) {
+      if ((*M)->isConstexpr()) {
+        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);
+          continue;
+
+        case TSK_Undeclared:
+        case TSK_ExplicitSpecialization:
+          RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record),
+                             PDiag(diag::err_constexpr_method_non_literal));
+          break;
+        }
+
+        // Only produce one error per class.
+        break;
+      }
+    }
+  }
+
   // Declare inherited constructors. We do this eagerly here because:
   // - The standard requires an eager diagnostic for conflicting inherited
   //   constructors from different classes.

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Sep 30 21:31:28 2011
@@ -1067,15 +1067,12 @@
                                          TemplateArgs);
   }
 
-  bool isConstexpr = D->isConstexpr();
-  // FIXME: check whether the instantiation produces a constexpr function.
-
   FunctionDecl *Function =
       FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
                            D->getLocation(), D->getDeclName(), T, TInfo,
                            D->getStorageClass(), D->getStorageClassAsWritten(),
                            D->isInlineSpecified(), D->hasWrittenPrototype(),
-                           isConstexpr);
+                           /*isConstexpr*/ false);
 
   if (QualifierLoc)
     Function->setQualifierInfo(QualifierLoc);
@@ -1388,9 +1385,6 @@
     if (!DC) return 0;
   }
 
-  bool isConstexpr = D->isConstexpr();
-  // FIXME: check whether the instantiation produces a constexpr function.
-
   // Build the instantiated method declaration.
   CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
   CXXMethodDecl *Method = 0;
@@ -1403,7 +1397,7 @@
                                         StartLoc, NameInfo, T, TInfo,
                                         Constructor->isExplicit(),
                                         Constructor->isInlineSpecified(),
-                                        false, isConstexpr);
+                                        false, /*isConstexpr*/ false);
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
                                        StartLoc, NameInfo, T, TInfo,
@@ -1414,14 +1408,15 @@
                                        StartLoc, NameInfo, T, TInfo,
                                        Conversion->isInlineSpecified(),
                                        Conversion->isExplicit(),
-                                       isConstexpr, Conversion->getLocEnd());
+                                       /*isConstexpr*/ false,
+                                       Conversion->getLocEnd());
   } else {
     Method = CXXMethodDecl::Create(SemaRef.Context, Record,
                                    StartLoc, NameInfo, T, TInfo,
                                    D->isStatic(),
                                    D->getStorageClassAsWritten(),
                                    D->isInlineSpecified(),
-                                   isConstexpr, D->getLocEnd());
+                                   /*isConstexpr*/ false, D->getLocEnd());
   }
 
   if (QualifierLoc)
@@ -2312,6 +2307,13 @@
                                                  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=140926&r1=140925&r2=140926&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Sep 30 21:31:28 2011
@@ -3992,6 +3992,118 @@
                              std::make_pair(SourceLocation(), PDiag(0)));
 }
 
+/// @brief Ensure that the type T is a literal type.
+///
+/// This routine checks whether the type @p T is a literal type. If @p T is an
+/// incomplete type, an attempt is made to complete it. If @p T is a literal
+/// type, or @p AllowIncompleteType is true and @p T is an incomplete type,
+/// returns false. Otherwise, this routine issues the diagnostic @p PD (giving
+/// it the type @p T), along with notes explaining why the type is not a
+/// literal type, and returns true.
+///
+/// @param Loc  The location in the source that the non-literal type
+/// diagnostic should refer to.
+///
+/// @param T  The type that this routine is examining for literalness.
+///
+/// @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) {
+  assert(!T->isDependentType() && "type should not be dependent");
+
+  bool Incomplete = RequireCompleteType(Loc, T, 0);
+  if (T->isLiteralType() || (AllowIncompleteType && Incomplete))
+    return false;
+
+  if (PD.getDiagID() == 0)
+    return true;
+
+  Diag(Loc, PD) << T;
+
+  if (T->isVariableArrayType())
+    return true;
+
+  const RecordType *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>();
+  if (!RT)
+    return true;
+
+  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.
+  if (RD->getNumVBases()) {
+    Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
+      << 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();
+  } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) {
+    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) {
+      if (!I->getType()->isLiteralType()) {
+        Diag(I->getSourceRange().getBegin(),
+             diag::note_non_literal_base_class)
+          << RD << I->getType() << I->getSourceRange();
+        return true;
+      }
+    }
+    for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+         E = RD->field_end(); I != E; ++I) {
+      if (!(*I)->getType()->isLiteralType()) {
+        Diag((*I)->getLocation(), diag::note_non_literal_field)
+          << RD << (*I) << (*I)->getType();
+        return true;
+      }
+    }
+  } else if (!RD->hasTrivialDestructor()) {
+    // All fields and bases are of literal types, so have trivial destructors.
+    // If this class's destructor is non-trivial it must be user-declared.
+    CXXDestructorDecl *Dtor = RD->getDestructor();
+    assert(Dtor && "class has literal fields and bases but no dtor?");
+    if (!Dtor)
+      return true;
+
+    Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
+         diag::note_non_literal_user_provided_dtor :
+         diag::note_non_literal_nontrivial_dtor) << RD;
+  }
+
+  return true;
+}
+
 /// \brief Retrieve a version of the type 'T' that is elaborated by Keyword
 /// and qualified by the nested-name-specifier contained in SS.
 QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,

Added: 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=140926&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.types/p10.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.types/p10.cpp Fri Sep 30 21:31:28 2011
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct NonLiteral { NonLiteral(); };
+
+// A type is a literal type if it is:
+
+// - a scalar type
+constexpr int f1(double);
+
+// - a reference type
+struct S { S(); };
+constexpr int f2(S &);
+
+// - 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}}
+  ~UserProvDtor(); // expected-note {{has a user-provided destructor}}
+};
+struct NonTrivDtor {
+  constexpr NonTrivDtor(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
+  virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
+};
+struct NonTrivDtorBase {
+  ~NonTrivDtorBase();
+};
+template<typename T>
+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}}
+struct TrivDtor {
+  constexpr TrivDtor();
+};
+// FIXME: when building DefinitionData we look at 'isUserProvided' before it's set up!
+#if 0
+struct TrivDefaultedDtor {
+  constexpr TrivDefaultedDtor();
+  ~TrivDefaultedDtor() = default;
+};
+#endif
+
+//  - it is an aggregate type or has at least one constexpr constructor or
+//    constexpr constructor template that is not a copy or move constructor
+struct Agg {
+  int a;
+  char *b;
+};
+constexpr int f3(Agg a) { return a.a; }
+struct CtorTemplate {
+  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}}
+};
+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}}
+};
+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}}
+};
+constexpr int f(CtorArg<int>);
+constexpr int f(CtorArg<NonLiteral>); // expected-error {{not a literal type}}
+// 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}}
+};
+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}}
+
+//  - 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}}
+struct NonLitBase :
+  S { // expected-note {{base class 'S' of non-literal type}}
+  constexpr NonLitBase(); // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
+};
+struct LitMemBase : Agg {
+  Agg agg;
+};
+template<typename T>
+struct MemberType {
+  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}}
+
+// - an array of literal type
+struct ArrGood {
+  Agg agg[24];
+  double d[12];
+  TrivDtor td[3];
+};
+constexpr int f(ArrGood);
+
+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}}

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=140926&r1=140925&r2=140926&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 Fri Sep 30 21:31:28 2011
@@ -49,22 +49,41 @@
 enum E4 { V4 } constexpr e4 = V4;
 constexpr int; // expected-error {{constexpr can only be used in variable and function declarations}}
 // redeclaration mismatch
-constexpr int f3(); // n
-int f3(); // x
-int f4(); // n
-constexpr int f4(); // x
+constexpr int f3(); // expected-note {{previous declaration is here}}
+int f3(); // expected-error {{non-constexpr declaration of 'f3' follows constexpr declaration}}
+int f4(); // expected-note {{previous declaration is here}}
+constexpr int f4(); // expected-error {{constexpr declaration of 'f4' follows non-constexpr declaration}}
+template<typename T> constexpr T f5(T);
+template<typename T> constexpr T f5(T); // expected-note {{previous}}
+template<typename T> T f5(T); // expected-error {{non-constexpr declaration of 'f5' follows constexpr declaration}}
+template<typename T> T f6(T); // expected-note {{here}}
+template<typename T> constexpr T f6(T); // expected-error {{constexpr declaration of 'f6' follows non-constexpr declaration}}
 // destructor
 struct ConstexprDtor {
   constexpr ~ConstexprDtor() = default; // expected-error {{destructor cannot be marked constexpr}}
 };
 
 // template stuff
-template <typename T>
-constexpr T ft(T t) { return t; }
+template <typename T> constexpr T ft(T t) { return t; }
+template <typename T> T gt(T t) { return t; }
+struct S {
+  template<typename T> constexpr T f();
+  template<typename T> T g() const;
+};
 
-// specialization can differ in constepxr
-template <>
-notlit ft(notlit nl) { return nl; }
+// 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 <> 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 <> 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'.
+template <> char S::g() { return 0; } // expected-error {{no function template matches}}
+template <> double S::g() const { return 0; } // ok
 
 // FIXME: The initializer is a constant expression.
 constexpr int i3 = ft(1); // unexpected-error {{must be initialized by a constant expression}}

Added: 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=140926&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp Fri Sep 30 21:31:28 2011
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -verify -std=c++0x %s
+
+namespace N {
+  typedef char C;
+}
+
+namespace M {
+  typedef double D;
+}
+
+struct NonLiteral { // expected-note 4{{no constexpr constructors}}
+  NonLiteral() {}
+  NonLiteral(int) {}
+};
+struct Literal {
+  constexpr Literal() {}
+  operator int() const { return 0; }
+};
+
+struct S {
+  virtual int ImplicitlyVirtual() const = 0; // expected-note {{overridden virtual function}}
+};
+struct SS : S { 
+  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 { // expected-note {{base class 'SS' of non-literal type}}
+  constexpr T(); // 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}}
+
+  constexpr int ImplicitlyVirtual(); // 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 ~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}}
+
+  //  - 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}}
+  typedef int G(NonLiteral);
+  constexpr G NonLiteralParam2; // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
+
+  //  - its function-body shall be = delete, = default,
+  constexpr int Deleted() = delete;
+  // It's not possible for the function-body to legally be "= default" here.
+  // Other than constructors, only the copy- and move-assignment operators and
+  // destructor can be defaulted. Destructors can't be constexpr since they
+  // don't have a literal return type. Defaulted assignment operators can't be
+  // constexpr since they can't be const.
+  constexpr T &operator=(const T&) = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
+};
+struct U {
+  constexpr U SelfReturn();
+  constexpr int SelfParam(U);
+};
+
+//  or a compound-statememt that contains only
+constexpr int AllowedStmts() {
+  //  - null statements
+  ;
+
+  //  - static_assert-declarations
+  static_assert(true, "the impossible happened!");
+
+  //  - typedef declarations and alias-declarations that do not define classes
+  //    or enumerations
+  typedef int I;
+  typedef struct S T;
+  using J = int;
+  using K = int[sizeof(I) + sizeof(J)];
+  // Note, the standard requires we reject this.
+  struct U;
+
+  //  - using-declarations
+  using N::C;
+
+  //  - using-directives
+  using namespace N;
+
+  //  - and exactly one return statement
+  return sizeof(K) + sizeof(C) + sizeof(K);
+}
+constexpr int ForStmt() {
+  for (int n = 0; n < 10; ++n) // expected-error {{statement not allowed in constexpr function}}
+    return 0;
+}
+constexpr int VarDecl() {
+  constexpr int a = 0; // expected-error {{variables cannot be declared in a constexpr function}}
+  return 0;
+}
+constexpr int FuncDecl() {
+  constexpr int ForwardDecl(int); // expected-error {{statement not allowed in constexpr function}}
+  return ForwardDecl(42);
+}
+constexpr int ClassDecl1() {
+  typedef struct { } S1; // expected-error {{types cannot be defined in a constexpr function}}
+  return 0;
+}
+constexpr int ClassDecl2() {
+  using S2 = struct { }; // expected-error {{types cannot be defined in a constexpr function}}
+  return 0;
+}
+constexpr int ClassDecl3() {
+  struct S3 { }; // expected-error {{types cannot be defined in a constexpr function}}
+  return 0;
+}
+constexpr int NoReturn() {} // expected-error {{no return statement in constexpr function}}
+constexpr int MultiReturn() {
+  return 0; // expected-note {{return statement}}
+  return 0; // expected-error {{multiple return statements in constexpr function}}
+}
+
+//  - every constructor call and implicit conversion used in initializing the
+//    return value shall be one of those allowed in a constant expression.
+//
+// We implement the proposed resolution of DR1364 and ignore this bullet.

Added: 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=140926&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp Fri Sep 30 21:31:28 2011
@@ -0,0 +1,188 @@
+// RUN: %clang_cc1 -verify -std=c++0x -fcxx-exceptions %s
+
+namespace N {
+  typedef char C;
+}
+
+namespace M {
+  typedef double D;
+}
+
+struct NonLiteral { // expected-note 2{{no constexpr constructors}}
+  NonLiteral() {}
+  NonLiteral(int) {}
+};
+struct Literal {
+  constexpr Literal() {}
+  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}}
+
+  // In addition, either its function-body shall be = delete or = default
+  constexpr S() = default;
+  constexpr S(Literal) = delete;
+};
+
+// or it shall satisfy the following constraints:
+
+// - 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 classes}}
+};
+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 classes}}
+  };
+}
+
+// - its function-body shall not be a function-try-block;
+struct U {
+  constexpr U()
+    try // expected-error {{function try block not allowed in constexpr constructor}}
+    : u() {
+  } catch (...) {
+    throw;
+  }
+  int u;
+};
+
+// - the compound-statememt of its function-body shall contain only
+struct V {
+  constexpr V() {
+    //  - null statements,
+    ;
+
+    //  - static_assert-declarations,
+    static_assert(true, "the impossible happened!");
+
+    //  - typedef declarations and alias-declarations that do not define classes
+    //    or enumerations,
+    typedef int I;
+    typedef struct S T;
+    using J = int;
+    using K = int[sizeof(I) + sizeof(J)];
+    // Note, the standard requires we reject this.
+    struct U;
+
+    //  - using-declarations,
+    using N::C;
+
+    //  - and using-directives;
+    using namespace N;
+  }
+
+  constexpr V(int(&)[1]) {
+    for (int n = 0; n < 10; ++n) // expected-error {{statement not allowed in constexpr constructor}}
+      /**/;
+  }
+  constexpr V(int(&)[2]) {
+    constexpr int a = 0; // expected-error {{variables cannot be declared in a constexpr constructor}}
+  }
+  constexpr V(int(&)[3]) {
+    constexpr int ForwardDecl(int); // expected-error {{statement not allowed in constexpr constructor}}
+  }
+  constexpr V(int(&)[4]) {
+    typedef struct { } S1; // expected-error {{types cannot be defined in a constexpr constructor}}
+  }
+  constexpr V(int(&)[5]) {
+    using S2 = struct { }; // expected-error {{types cannot be defined in a constexpr constructor}}
+  }
+  constexpr V(int(&)[6]) {
+    struct S3 { }; // expected-error {{types cannot be defined in a constexpr constructor}}
+  }
+  constexpr V(int(&)[7]) {
+    return; // expected-error {{statement not allowed in constexpr constructor}}
+  }
+};
+
+// - every non-static data member and base class sub-object shall be initialized
+struct W {
+  int n; // expected-note {{member not initialized by constructor}}
+  constexpr W() {} // expected-error {{constexpr constructor must initialize all members}}
+};
+struct AnonMembers {
+  int a; // expected-note {{member not initialized by constructor}}
+  union { // expected-note 2{{member not initialized by constructor}}
+    char b;
+    struct {
+      double c;
+      long d; // expected-note {{member not initialized by constructor}}
+    };
+    union {
+      char e;
+      void *f;
+    };
+  };
+  struct { // expected-note {{member not initialized by constructor}}
+    long long g;
+    struct {
+      int h; // expected-note {{member not initialized by constructor}}
+      double i; // expected-note {{member not initialized by constructor}}
+    };
+    union { // expected-note 2{{member not initialized by constructor}}
+      char *j;
+      AnonMembers *k;
+    };
+  };
+
+  constexpr AnonMembers(int(&)[1]) : a(), b(), g(), h(), i(), j() {} // ok
+  // missing d, i, j/k union
+  constexpr AnonMembers(int(&)[2]) : a(), c(), g(), h() {} // expected-error {{constexpr constructor must initialize all members}}
+  constexpr AnonMembers(int(&)[3]) : a(), e(), g(), h(), i(), k() {} // ok
+  // missing h, j/k union
+  constexpr AnonMembers(int(&)[4]) : a(), c(), d(), g(), i() {} // expected-error {{constexpr constructor must initialize all members}}
+  // missing b/c/d/e/f union
+  constexpr AnonMembers(int(&)[5]) : a(), g(), h(), i(), k() {} // expected-error {{constexpr constructor must initialize all members}}
+  // missing a, b/c/d/e/f union, g/h/i/j/k struct
+  constexpr AnonMembers(int(&)[6]) {} // expected-error {{constexpr constructor must initialize all members}}
+};
+
+// - every constructor involved in initializing non-static data members and base
+//   class sub-objects shall be a constexpr constructor.
+//
+// FIXME: Implement this as part of the 'must be able to produce a constant
+// expression' rules.
+
+// - every assignment-expression that is an initializer-caluse appearing
+//   directly or indirectly within a brace-or-equal-initializer for a non-static
+//   data member that is not named by a mem-initializer-id shall be a constant
+//   expression; and
+//
+// Note, we deliberately do not implement this bullet, so that we can allow the
+// following example. (See N3308).
+struct X {
+  int a = 0;
+  int b = 2 * a + 1; // ok, not a constant expression.
+
+  constexpr X() {}
+  constexpr X(int c) : a(c) {} // ok, b initialized by 2 * c + 1
+};
+
+//  - every implicit conversion used in converting a constructor argument to the
+//    corresponding parameter type and converting a full-expression to the
+//    corresponding member type shall be one of those allowed in a constant
+//    expression.
+//
+// We implement the proposed resolution of DR1364 and ignore this bullet.
+
+
+namespace StdExample {
+  struct Length {
+    explicit constexpr Length(int i = 0) : val(i) { }
+  private:
+      int val;
+  };
+}

Added: 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=140926&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp Fri Sep 30 21:31:28 2011
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -verify -std=c++0x %s
+
+namespace N {
+  typedef char C;
+}
+
+namespace M {
+  typedef double D;
+}
+
+struct NonLiteral {
+  NonLiteral() {}
+  NonLiteral(int) {}
+  operator int() const { return 0; }
+};
+struct Literal {
+  constexpr Literal() {}
+  operator int() const { return 0; }
+};
+
+struct S {
+  virtual int ImplicitlyVirtual();
+};
+struct T {};
+
+template<typename T> struct ImplicitVirtualFromDependentBase : T {
+  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 b = ImplicitVirtualFromDependentBase<T>().ImplicitlyVirtual(); // ok
+#endif
+
+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}}
+
+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}}
+  };
+
+  template<typename T> struct T2 : virtual T { // expected-note {{struct with virtual base class is not a literal type}} expected-note {{here}}
+    // 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<Literal> g2(); // expected-error {{not a literal type}}
+
+  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}}
+}

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp?rev=140926&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp Fri Sep 30 21:31:28 2011
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct S {
+  constexpr void f();
+  constexpr void g() const;
+};
+
+void f(const S &s) {
+  s.f();
+  s.g();
+}
+
+namespace std_example {
+
+  class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}
+  public:
+    explicit debug_flag(bool);
+    constexpr bool is_on(); // expected-error {{non-literal type 'std_example::debug_flag' cannot have constexpr members}}
+  private:
+    bool flag;
+  };
+
+  constexpr int bar(int x, int y) // expected-note {{here}}
+    { return x + y + x*y; }
+  int bar(int x, int y) // expected-error {{non-constexpr declaration of 'bar' follows constexpr declaration}}
+    { return x * 2 + 3 * y; }
+
+}





More information about the cfe-commits mailing list