[cfe-commits] r147128 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ lib/AST/ lib/Sema/ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/ test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/ test/CXX/special/class.copy/ test/CXX/special/class.ctor/ test/SemaCXX/

Richard Smith richard-llvm at metafoo.co.uk
Wed Dec 21 18:22:32 PST 2011


Author: rsmith
Date: Wed Dec 21 20:22:31 2011
New Revision: 147128

URL: http://llvm.org/viewvc/llvm-project?rev=147128&view=rev
Log:
PR11614: Mark defaulted special constructors as constexpr if their implicit
definition would satisfy the constexpr requirements.

Added:
    cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/
    cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
    cfe/trunk/test/CXX/special/class.copy/p13-0x.cpp
    cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.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/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/enum-bitfield.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=147128&r1=147127&r2=147128&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Dec 21 20:22:31 2011
@@ -366,10 +366,34 @@
     bool HasTrivialDefaultConstructor : 1;
 
     /// HasConstexprNonCopyMoveConstructor - True when this class has at least
-    /// one constexpr constructor which is neither the copy nor move
-    /// constructor.
+    /// one user-declared constexpr constructor which is neither the copy nor
+    /// move constructor.
     bool HasConstexprNonCopyMoveConstructor : 1;
 
+    /// DefaultedDefaultConstructorIsConstexpr - True if a defaulted default
+    /// constructor for this class would be constexpr.
+    bool DefaultedDefaultConstructorIsConstexpr : 1;
+
+    /// DefaultedCopyConstructorIsConstexpr - True if a defaulted copy
+    /// constructor for this class would be constexpr.
+    bool DefaultedCopyConstructorIsConstexpr : 1;
+
+    /// DefaultedMoveConstructorIsConstexpr - True if a defaulted move
+    /// constructor for this class would be constexpr.
+    bool DefaultedMoveConstructorIsConstexpr : 1;
+
+    /// HasConstexprDefaultConstructor - True if this class has a constexpr
+    /// default constructor (either user-declared or implicitly declared).
+    bool HasConstexprDefaultConstructor : 1;
+
+    /// HasConstexprCopyConstructor - True if this class has a constexpr copy
+    /// constructor (either user-declared or implicitly declared).
+    bool HasConstexprCopyConstructor : 1;
+
+    /// HasConstexprMoveConstructor - True if this class has a constexpr move
+    /// constructor (either user-declared or implicitly declared).
+    bool HasConstexprMoveConstructor : 1;
+
     /// HasTrivialCopyConstructor - True when this class has a trivial copy
     /// constructor.
     ///
@@ -946,19 +970,62 @@
   /// mutable field.
   bool hasMutableFields() const { return data().HasMutableFields; }
 
-  // hasTrivialDefaultConstructor - Whether this class has a trivial default
-  // constructor
-  // (C++0x [class.ctor]p5)
+  /// hasTrivialDefaultConstructor - Whether this class has a trivial default
+  /// constructor (C++11 [class.ctor]p5).
   bool hasTrivialDefaultConstructor() const {
     return data().HasTrivialDefaultConstructor &&
            (!data().UserDeclaredConstructor ||
              data().DeclaredDefaultConstructor);
   }
 
-  // hasConstexprNonCopyMoveConstructor - Whether this class has at least one
-  // constexpr constructor other than the copy or move constructors.
+  /// hasConstexprNonCopyMoveConstructor - Whether this class has at least one
+  /// constexpr constructor other than the copy or move constructors.
   bool hasConstexprNonCopyMoveConstructor() const {
-    return data().HasConstexprNonCopyMoveConstructor;
+    return data().HasConstexprNonCopyMoveConstructor ||
+           (!hasUserDeclaredConstructor() &&
+            defaultedDefaultConstructorIsConstexpr());
+  }
+
+  /// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default
+  /// constructor for this class would be constexpr.
+  bool defaultedDefaultConstructorIsConstexpr() const {
+    return data().DefaultedDefaultConstructorIsConstexpr;
+  }
+
+  /// defaultedCopyConstructorIsConstexpr - Whether a defaulted copy
+  /// constructor for this class would be constexpr.
+  bool defaultedCopyConstructorIsConstexpr() const {
+    return data().DefaultedCopyConstructorIsConstexpr;
+  }
+
+  /// defaultedMoveConstructorIsConstexpr - Whether a defaulted move
+  /// constructor for this class would be constexpr.
+  bool defaultedMoveConstructorIsConstexpr() const {
+    return data().DefaultedMoveConstructorIsConstexpr;
+  }
+
+  /// hasConstexprDefaultConstructor - Whether this class has a constexpr
+  /// default constructor.
+  bool hasConstexprDefaultConstructor() const {
+    return data().HasConstexprDefaultConstructor ||
+           (!data().UserDeclaredConstructor &&
+            data().DefaultedDefaultConstructorIsConstexpr && isLiteral());
+  }
+
+  /// hasConstexprCopyConstructor - Whether this class has a constexpr copy
+  /// constructor.
+  bool hasConstexprCopyConstructor() const {
+    return data().HasConstexprCopyConstructor ||
+           (!data().DeclaredCopyConstructor &&
+            data().DefaultedCopyConstructorIsConstexpr && isLiteral());
+  }
+
+  /// hasConstexprMoveConstructor - Whether this class has a constexpr move
+  /// constructor.
+  bool hasConstexprMoveConstructor() const {
+    return data().HasConstexprMoveConstructor ||
+           (needsImplicitMoveConstructor() &&
+            data().DefaultedMoveConstructorIsConstexpr && isLiteral());
   }
 
   // hasTrivialCopyConstructor - Whether this class has a trivial copy

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=147128&r1=147127&r2=147128&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Dec 21 20:22:31 2011
@@ -4685,6 +4685,9 @@
   "copy constructor|move constructor|copy assignment operator|move assignment "
   "operator|destructor}0 does not match the "
   "calculated one">;
+def err_incorrect_defaulted_constexpr : Error<
+  "defaulted definition of %select{default constructor|copy constructor|"
+  "move constructor}0 is not constexpr">;
 def err_out_of_line_default_deletes : Error<
   "defaulting this %select{default constructor|copy constructor|move "
   "constructor|copy assignment operator|move assignment operator|destructor}0 "

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=147128&r1=147127&r2=147128&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Dec 21 20:22:31 2011
@@ -38,7 +38,12 @@
     Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
     HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
     HasMutableFields(false), HasTrivialDefaultConstructor(true),
-    HasConstexprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
+    HasConstexprNonCopyMoveConstructor(false),
+    DefaultedDefaultConstructorIsConstexpr(true),
+    DefaultedCopyConstructorIsConstexpr(true),
+    DefaultedMoveConstructorIsConstexpr(true),
+    HasConstexprDefaultConstructor(false), HasConstexprCopyConstructor(false),
+    HasConstexprMoveConstructor(false), HasTrivialCopyConstructor(true),
     HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
     HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
     HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
@@ -190,6 +195,13 @@
       //   A standard-layout class is a class that: [...]
       //    -- has [...] no virtual base classes
       data().IsStandardLayout = false;
+
+      // C++11 [dcl.constexpr]p4:
+      //   In the definition of a constexpr constructor [...]
+      //    -- the class shall not have any virtual base classes
+      data().DefaultedDefaultConstructorIsConstexpr = false;
+      data().DefaultedCopyConstructorIsConstexpr = false;
+      data().DefaultedMoveConstructorIsConstexpr = false;
     } else {
       // C++ [class.ctor]p5:
       //   A default constructor is trivial [...] if:
@@ -221,6 +233,32 @@
         data().HasTrivialCopyAssignment = false;
       if (!BaseClassDecl->hasTrivialMoveAssignment())
         data().HasTrivialMoveAssignment = false;
+
+      // C++11 [class.ctor]p6:
+      //   If that user-written default cosntructor would satisfy the
+      //   requirements of a constexpr constructor, the implicitly-defined
+      //   default constructor is constexpr.
+      if (!BaseClassDecl->hasConstexprDefaultConstructor())
+        data().DefaultedDefaultConstructorIsConstexpr = false;
+
+      // C++11 [class.copy]p13:
+      //   If the implicitly-defined constructor would satisfy the requirements
+      //   of a constexpr constructor, the implicitly-defined constructor is
+      //   constexpr.
+      // C++11 [dcl.constexpr]p4:
+      //    -- every constructor involved in initializing [...] base class
+      //       sub-objects shall be a constexpr constructor
+      if (!BaseClassDecl->hasConstexprCopyConstructor())
+        data().DefaultedCopyConstructorIsConstexpr = false;
+      if (BaseClassDecl->hasDeclaredMoveConstructor() ||
+          BaseClassDecl->needsImplicitMoveConstructor())
+        // FIXME: If the implicit move constructor generated for the base class
+        // would be ill-formed, the implicit move constructor generated for the
+        // derived class calls the base class' copy constructor.
+        data().DefaultedMoveConstructorIsConstexpr &=
+          !BaseClassDecl->hasConstexprMoveConstructor();
+      else if (!BaseClassDecl->hasConstexprCopyConstructor())
+        data().DefaultedMoveConstructorIsConstexpr = false;
     }
     
     // C++ [class.ctor]p3:
@@ -471,13 +509,21 @@
     // If this is a special member function, note that it was added and then
     // return early.
     if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
-      if (Constructor->isDefaultConstructor())
+      if (Constructor->isDefaultConstructor()) {
         data().DeclaredDefaultConstructor = true;
-      else if (Constructor->isCopyConstructor())
+        if (Constructor->isConstexpr()) {
+          data().HasConstexprDefaultConstructor = true;
+          data().HasConstexprNonCopyMoveConstructor = true;
+        }
+      } else if (Constructor->isCopyConstructor()) {
         data().DeclaredCopyConstructor = true;
-      else if (Constructor->isMoveConstructor())
+        if (Constructor->isConstexpr())
+          data().HasConstexprCopyConstructor = true;
+      } else if (Constructor->isMoveConstructor()) {
         data().DeclaredMoveConstructor = true;
-      else
+        if (Constructor->isConstexpr())
+          data().HasConstexprMoveConstructor = true;
+      } else
         goto NotASpecialMember;
       return;
     } else if (isa<CXXDestructorDecl>(D)) {
@@ -507,14 +553,18 @@
     // to all functions.
     bool UserProvided = Constructor->isUserProvided();
 
-    // C++0x [class.ctor]p5:
-    //   A default constructor is trivial if it is not user-provided [...]
     if (Constructor->isDefaultConstructor()) {
       data().DeclaredDefaultConstructor = true;
       if (UserProvided) {
+        // C++0x [class.ctor]p5:
+        //   A default constructor is trivial if it is not user-provided [...]
         data().HasTrivialDefaultConstructor = false;
         data().UserProvidedDefaultConstructor = true;
       }
+      if (Constructor->isConstexpr()) {
+        data().HasConstexprDefaultConstructor = true;
+        data().HasConstexprNonCopyMoveConstructor = true;
+      }
     }
 
     // Note when we have a user-declared copy or move constructor, which will
@@ -529,6 +579,9 @@
         //   user-provided [...]
         if (UserProvided)
           data().HasTrivialCopyConstructor = false;
+
+        if (Constructor->isConstexpr())
+          data().HasConstexprCopyConstructor = true;
       } else if (Constructor->isMoveConstructor()) {
         data().UserDeclaredMoveConstructor = true;
         data().DeclaredMoveConstructor = true;
@@ -538,6 +591,9 @@
         //   user-provided [...]
         if (UserProvided)
           data().HasTrivialMoveConstructor = false;
+
+        if (Constructor->isConstexpr())
+          data().HasConstexprMoveConstructor = true;
       }
     }
     if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
@@ -578,8 +634,18 @@
     // C++11 [class.dtor]p5: 
     //   A destructor is trivial if it is not user-provided and if
     //    -- the destructor is not virtual.
-    if (DD->isUserProvided() || DD->isVirtual())
+    if (DD->isUserProvided() || DD->isVirtual()) {
       data().HasTrivialDestructor = false;
+      // C++11 [dcl.constexpr]p1:
+      //   The constexpr specifier shall be applied only to [...] the
+      //   declaration of a static data member of a literal type.
+      // C++11 [basic.types]p10:
+      //   A type is a literal type if it is [...] a class type that [...] has
+      //   a trivial destructor.
+      data().DefaultedDefaultConstructorIsConstexpr = false;
+      data().DefaultedCopyConstructorIsConstexpr = false;
+      data().DefaultedMoveConstructorIsConstexpr = false;
+    }
     
     return;
   }
@@ -746,7 +812,7 @@
       CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
       if (FieldRec->getDefinition()) {
         // C++0x [class.ctor]p5:
-        //   A defulat constructor is trivial [...] if:
+        //   A default constructor is trivial [...] if:
         //    -- for all the non-static data members of its class that are of
         //       class type (or array thereof), each such class has a trivial
         //       default constructor.
@@ -818,7 +884,41 @@
         // Keep track of the presence of mutable fields.
         if (FieldRec->hasMutableFields())
           data().HasMutableFields = true;
+
+        // C++11 [class.copy]p13:
+        //   If the implicitly-defined constructor would satisfy the
+        //   requirements of a constexpr constructor, the implicitly-defined
+        //   constructor is constexpr.
+        // C++11 [dcl.constexpr]p4:
+        //    -- every constructor involved in initializing non-static data
+        //       members [...] shall be a constexpr constructor
+        if (!Field->hasInClassInitializer() &&
+            !FieldRec->hasConstexprDefaultConstructor())
+          // The standard requires any in-class initializer to be a constant
+          // expression. We consider this to be a defect.
+          data().DefaultedDefaultConstructorIsConstexpr = false;
+
+        if (!FieldRec->hasConstexprCopyConstructor())
+          data().DefaultedCopyConstructorIsConstexpr = false;
+
+        if (FieldRec->hasDeclaredMoveConstructor() ||
+            FieldRec->needsImplicitMoveConstructor())
+          // FIXME: If the implicit move constructor generated for the member's
+          // class would be ill-formed, the implicit move constructor generated
+          // for this class calls the member's copy constructor.
+          data().DefaultedMoveConstructorIsConstexpr &=
+            FieldRec->hasConstexprMoveConstructor();
+        else if (!FieldRec->hasConstexprCopyConstructor())
+          data().DefaultedMoveConstructorIsConstexpr = false;
       }
+    } else {
+      // Base element type of field is a non-class type.
+      if (!T->isLiteralType()) {
+        data().DefaultedDefaultConstructorIsConstexpr = false;
+        data().DefaultedCopyConstructorIsConstexpr = false;
+        data().DefaultedMoveConstructorIsConstexpr = false;
+      } else if (!Field->hasInClassInitializer())
+        data().DefaultedDefaultConstructorIsConstexpr = false;
     }
 
     // C++0x [class]p7:

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=147128&r1=147127&r2=147128&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Dec 21 20:22:31 2011
@@ -1591,6 +1591,29 @@
   }
 }
 
+/// CheckTrivialDefaultConstructor - Check whether a constructor is a trivial
+/// default constructor. If so, we'll fold it whether or not it's marked as
+/// constexpr. If it is marked as constexpr, we will never implicitly define it,
+/// so we need special handling.
+static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
+                                    const CXXConstructorDecl *CD) {
+  if (!CD->isTrivial() || !CD->isDefaultConstructor())
+    return false;
+
+  if (!CD->isConstexpr()) {
+    if (Info.getLangOpts().CPlusPlus0x) {
+      // FIXME: If DiagDecl is an implicitly-declared special member function,
+      // we should be much more explicit about why it's not constexpr.
+      Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
+        << /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
+      Info.Note(CD->getLocation(), diag::note_declared_at);
+    } else {
+      Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+    }
+  }
+  return true;
+}
+
 /// CheckConstexprFunction - Check that a function can be called in a constant
 /// expression.
 static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
@@ -2790,6 +2813,16 @@
 
 bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
   const CXXConstructorDecl *FD = E->getConstructor();
+  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) {
+    const CXXRecordDecl *RD = FD->getParent();
+    if (RD->isUnion())
+      Result = APValue((FieldDecl*)0);
+    else
+      Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
+                       std::distance(RD->field_begin(), RD->field_end()));
+    return true;
+  }
+
   const FunctionDecl *Definition = 0;
   FD->getBody(Definition);
 
@@ -3144,6 +3177,18 @@
     return true;
 
   const CXXConstructorDecl *FD = E->getConstructor();
+
+  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) {
+    const CXXRecordDecl *RD = FD->getParent();
+    if (RD->isUnion())
+      Result.getArrayFiller() = APValue((FieldDecl*)0);
+    else
+      Result.getArrayFiller() =
+          APValue(APValue::UninitStruct(), RD->getNumBases(),
+                  std::distance(RD->field_begin(), RD->field_end()));
+    return true;
+  }
+
   const FunctionDecl *Definition = 0;
   FD->getBody(Definition);
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=147128&r1=147127&r2=147128&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Dec 21 20:22:31 2011
@@ -3756,6 +3756,18 @@
                           *ExceptionType = Context.getFunctionType(
                          Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
 
+  // C++11 [dcl.fct.def.default]p2:
+  //   An explicitly-defaulted function may be declared constexpr only if it
+  //   would have been implicitly declared as constexpr,
+  if (CD->isConstexpr()) {
+    if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) {
+      Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+        << CXXDefaultConstructor;
+      HadError = true;
+    }
+  }
+  //   and may have an explicit exception-specification only if it is compatible
+  //   with the exception-specification on the implicit declaration.
   if (CtorType->hasExceptionSpec()) {
     if (CheckEquivalentExceptionSpec(
           PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3765,11 +3777,20 @@
           CtorType, CD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
-    // We set the declaration to have the computed exception spec here.
-    // We know there are no parameters.
+  }
+
+  //   If a function is explicitly defaulted on its first declaration,
+  if (First) {
+    //  -- it is implicitly considered to be constexpr if the implicit
+    //     definition would be,
+    CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr());
+
+    //  -- it is implicitly considered to have the same
+    //     exception-specification as if it had been implicitly declared
+    //
+    // FIXME: a compatible, but different, explicit exception specification
+    // will be silently overridden. We should issue a warning if this happens.
     EPI.ExtInfo = CtorType->getExtInfo();
-    CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
   }
 
   if (HadError) {
@@ -3823,6 +3844,18 @@
     HadError = true;
   }
 
+  // C++11 [dcl.fct.def.default]p2:
+  //   An explicitly-defaulted function may be declared constexpr only if it
+  //   would have been implicitly declared as constexpr,
+  if (CD->isConstexpr()) {
+    if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) {
+      Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+        << CXXCopyConstructor;
+      HadError = true;
+    }
+  }
+  //   and may have an explicit exception-specification only if it is compatible
+  //   with the exception-specification on the implicit declaration.
   if (CtorType->hasExceptionSpec()) {
     if (CheckEquivalentExceptionSpec(
           PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3832,10 +3865,23 @@
           CtorType, CD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
-    // We set the declaration to have the computed exception spec here.
-    // We duplicate the one parameter type.
+  }
+
+  //   If a function is explicitly defaulted on its first declaration,
+  if (First) {
+    //  -- it is implicitly considered to be constexpr if the implicit
+    //     definition would be,
+    CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr());
+
+    //  -- it is implicitly considered to have the same
+    //     exception-specification as if it had been implicitly declared, and
+    //
+    // FIXME: a compatible, but different, explicit exception specification
+    // will be silently overridden. We should issue a warning if this happens.
     EPI.ExtInfo = CtorType->getExtInfo();
+
+    //  -- [...] it shall have the same parameter type as if it had been
+    //     implicitly declared.
     CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
   }
 
@@ -3917,7 +3963,8 @@
           OperType, MD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
+  }
+  if (First) {
     // We set the declaration to have the computed exception spec here.
     // We duplicate the one parameter type.
     EPI.RefQualifier = OperType->getRefQualifier();
@@ -3974,6 +4021,18 @@
     HadError = true;
   }
 
+  // C++11 [dcl.fct.def.default]p2:
+  //   An explicitly-defaulted function may be declared constexpr only if it
+  //   would have been implicitly declared as constexpr,
+  if (CD->isConstexpr()) {
+    if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) {
+      Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+        << CXXMoveConstructor;
+      HadError = true;
+    }
+  }
+  //   and may have an explicit exception-specification only if it is compatible
+  //   with the exception-specification on the implicit declaration.
   if (CtorType->hasExceptionSpec()) {
     if (CheckEquivalentExceptionSpec(
           PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3983,10 +4042,23 @@
           CtorType, CD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
-    // We set the declaration to have the computed exception spec here.
-    // We duplicate the one parameter type.
+  }
+
+  //   If a function is explicitly defaulted on its first declaration,
+  if (First) {
+    //  -- it is implicitly considered to be constexpr if the implicit
+    //     definition would be,
+    CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr());
+
+    //  -- it is implicitly considered to have the same
+    //     exception-specification as if it had been implicitly declared, and
+    //
+    // FIXME: a compatible, but different, explicit exception specification
+    // will be silently overridden. We should issue a warning if this happens.
     EPI.ExtInfo = CtorType->getExtInfo();
+
+    //  -- [...] it shall have the same parameter type as if it had been
+    //     implicitly declared.
     CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
   }
 
@@ -4066,7 +4138,8 @@
           OperType, MD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
+  }
+  if (First) {
     // We set the declaration to have the computed exception spec here.
     // We duplicate the one parameter type.
     EPI.RefQualifier = OperType->getRefQualifier();
@@ -4113,7 +4186,8 @@
       DD->setInvalidDecl();
       return;
     }
-  } else if (First) {
+  }
+  if (First) {
     // We set the declaration to have the computed exception spec here.
     // There are no parameters.
     EPI.ExtInfo = DtorType->getExtInfo();
@@ -6792,16 +6866,12 @@
   DeclarationName Name
     = Context.DeclarationNames.getCXXConstructorName(ClassType);
   DeclarationNameInfo NameInfo(Name, ClassLoc);
-  CXXConstructorDecl *DefaultCon
-    = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
-                                 Context.getFunctionType(Context.VoidTy,
-                                                         0, 0, EPI),
-                                 /*TInfo=*/0,
-                                 /*isExplicit=*/false,
-                                 /*isInline=*/true,
-                                 /*isImplicitlyDeclared=*/true,
-                                 // FIXME: apply the rules for definitions here
-                                 /*isConstexpr=*/false);
+  CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo,
+      Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0,
+      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+      /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() &&
+        getLangOptions().CPlusPlus0x);
   DefaultCon->setAccess(AS_public);
   DefaultCon->setDefaulted();
   DefaultCon->setImplicit();
@@ -8476,21 +8546,17 @@
   DeclarationNameInfo NameInfo(Name, ClassLoc);
 
   //   An implicitly-declared copy constructor is an inline public
-  //   member of its class. 
-  CXXConstructorDecl *CopyConstructor
-    = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
-                                 Context.getFunctionType(Context.VoidTy,
-                                                         &ArgType, 1, EPI),
-                                 /*TInfo=*/0,
-                                 /*isExplicit=*/false,
-                                 /*isInline=*/true,
-                                 /*isImplicitlyDeclared=*/true,
-                                 // FIXME: apply the rules for definitions here
-                                 /*isConstexpr=*/false);
+  //   member of its class.
+  CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo,
+      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+      /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() &&
+        getLangOptions().CPlusPlus0x);
   CopyConstructor->setAccess(AS_public);
   CopyConstructor->setDefaulted();
   CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
-  
+
   // Note that we have declared this constructor.
   ++ASTContext::NumImplicitCopyConstructorsDeclared;
   
@@ -8631,21 +8697,17 @@
 
   // C++0x [class.copy]p11:
   //   An implicitly-declared copy/move constructor is an inline public
-  //   member of its class. 
-  CXXConstructorDecl *MoveConstructor
-    = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
-                                 Context.getFunctionType(Context.VoidTy,
-                                                         &ArgType, 1, EPI),
-                                 /*TInfo=*/0,
-                                 /*isExplicit=*/false,
-                                 /*isInline=*/true,
-                                 /*isImplicitlyDeclared=*/true,
-                                 // FIXME: apply the rules for definitions here
-                                 /*isConstexpr=*/false);
+  //   member of its class.
+  CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo,
+      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+      /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() &&
+        getLangOptions().CPlusPlus0x);
   MoveConstructor->setAccess(AS_public);
   MoveConstructor->setDefaulted();
   MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
-  
+
   // Add the parameter to the constructor.
   ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
                                                ClassLoc, ClassLoc,

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=147128&r1=147127&r2=147128&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 Wed Dec 21 20:22:31 2011
@@ -42,13 +42,12 @@
 struct S2 {} constexpr; // expected-error {{struct cannot be marked constexpr}}
 union U2 {} constexpr; // expected-error {{union cannot be marked constexpr}}
 enum E2 {} constexpr; // expected-error {{enum cannot be marked constexpr}}
-// FIXME: Mark default constructors as 'constexpr' when appropriate.
-constexpr class C3 {} c3 = C3(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
-constexpr struct S3 {} s3 = S3(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
+constexpr class C3 {} c3 = C3();
+constexpr struct S3 {} s3 = S3();
 constexpr union U3 {} u3 = {};
 constexpr enum E3 { V3 } e3 = V3;
-class C4 {} constexpr c4 = C4(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
-struct S4 {} constexpr s4 = S4(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
+class C4 {} constexpr c4 = C4();
+struct S4 {} constexpr s4 = S4();
 union U4 {} constexpr u4 = {};
 enum E4 { V4 } constexpr e4 = V4;
 constexpr int; // expected-error {{constexpr can only be used in variable and function declarations}}

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=147128&r1=147127&r2=147128&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 Wed Dec 21 20:22:31 2011
@@ -30,7 +30,7 @@
 
 // The definition of a constexpr function shall satisfy the following
 // constraints:
-struct T : SS { // expected-note {{base class 'SS' of non-literal type}}
+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}}
 
   //  - it shall not be virtual;

Added: cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp?rev=147128&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp Wed Dec 21 20:22:31 2011
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+// An explicitly-defaulted function may be declared constexpr only if it would
+// have been implicitly declared as constexpr.
+struct S1 {
+  constexpr S1() = default; // expected-error {{defaulted definition of default constructor is not constexpr}}
+  constexpr S1(const S1&) = default;
+  constexpr S1(S1&&) = default;
+  constexpr S1 &operator=(const S1&) = default; // expected-error {{explicitly-defaulted copy assignment operator may not have}}
+  constexpr S1 &operator=(S1&&) = default; // expected-error {{explicitly-defaulted move assignment operator may not have}}
+  constexpr ~S1() = default; // expected-error {{destructor cannot be marked constexpr}}
+  int n;
+};
+struct NoCopyMove {
+  constexpr NoCopyMove() {}
+  NoCopyMove(const NoCopyMove&);
+  NoCopyMove(NoCopyMove&&);
+};
+struct S2 {
+  constexpr S2() = default;
+  constexpr S2(const S2&) = default; // expected-error {{defaulted definition of copy constructor is not constexpr}}
+  constexpr S2(S2&&) = default; // expected-error {{defaulted definition of move constructor is not constexpr}}
+  NoCopyMove ncm;
+};
+
+// If a function is explicitly defaulted on its first declaration
+//   -- it is implicitly considered to be constexpr if the implicit declaration
+//      would be
+struct S3 {
+  S3() = default; // expected-note {{here}}
+  S3(const S3&) = default;
+  S3(S3&&) = default;
+  constexpr S3(int n) : n(n) {}
+  int n;
+};
+constexpr S3 s3a = S3(0);
+constexpr S3 s3b = s3a;
+constexpr S3 s3c = S3(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+
+struct S4 {
+  S4() = default;
+  S4(const S4&) = default; // expected-note {{here}}
+  S4(S4&&) = default; // expected-note {{here}}
+  NoCopyMove ncm;
+};
+constexpr S4 s4a; // ok
+constexpr S4 s4b = S4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+constexpr S4 s4c = s4a; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+
+struct S5 {
+  constexpr S5();
+  int n = 1, m = n + 3;
+};
+constexpr S5::S5() = default;
+static_assert(S5().m == 4, "");

Added: cfe/trunk/test/CXX/special/class.copy/p13-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p13-0x.cpp?rev=147128&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p13-0x.cpp (added)
+++ cfe/trunk/test/CXX/special/class.copy/p13-0x.cpp Wed Dec 21 20:22:31 2011
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+// If the implicitly-defined constructor would satisfy the requirements of a
+// constexpr constructor, the implicitly-defined constructor is constexpr.
+struct Constexpr1 {
+  constexpr Constexpr1() : n(0) {}
+  int n;
+};
+constexpr Constexpr1 c1a = Constexpr1(Constexpr1()); // ok
+constexpr Constexpr1 c1b = Constexpr1(Constexpr1(c1a)); // ok
+
+struct Constexpr2 {
+  Constexpr1 ce1;
+  constexpr Constexpr2() = default;
+  constexpr Constexpr2(const Constexpr2 &o) : ce1(o.ce1) {}
+  // no move constructor
+};
+
+constexpr Constexpr2 c2a = Constexpr2(Constexpr2()); // ok
+constexpr Constexpr2 c2b = Constexpr2(Constexpr2(c2a)); // ok
+
+struct Constexpr3 {
+  Constexpr2 ce2;
+  // all special constructors are constexpr, move ctor calls ce2's copy ctor
+};
+
+constexpr Constexpr3 c3a = Constexpr3(Constexpr3()); // ok
+constexpr Constexpr3 c3b = Constexpr3(Constexpr3(c3a)); // ok
+
+struct NonConstexprCopy {
+  constexpr NonConstexprCopy() = default;
+  NonConstexprCopy(const NonConstexprCopy &);
+  constexpr NonConstexprCopy(NonConstexprCopy &&) = default;
+
+  int n = 42;
+};
+
+NonConstexprCopy::NonConstexprCopy(const NonConstexprCopy &) = default; // expected-note {{here}}
+
+constexpr NonConstexprCopy ncc1 = NonConstexprCopy(NonConstexprCopy()); // ok
+constexpr NonConstexprCopy ncc2 = ncc1; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+
+struct NonConstexprDefault {
+  NonConstexprDefault() = default;
+  constexpr NonConstexprDefault(int n) : n(n) {}
+  int n;
+};
+struct Constexpr4 {
+  NonConstexprDefault ncd;
+};
+
+constexpr NonConstexprDefault ncd = NonConstexprDefault(NonConstexprDefault(1));
+constexpr Constexpr4 c4a = { ncd };
+constexpr Constexpr4 c4b = Constexpr4(c4a);
+constexpr Constexpr4 c4c = Constexpr4(static_cast<Constexpr4&&>(const_cast<Constexpr4&>(c4b)));

Added: 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=147128&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp (added)
+++ cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp Wed Dec 21 20:22:31 2011
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+// Implicitly-defined default constructors are constexpr if the implicit
+// definition would be.
+struct NonConstexpr1 { // expected-note {{here}}
+  int a;
+};
+struct NonConstexpr2 { // expected-note {{here}}
+  NonConstexpr1 nl;
+};
+constexpr NonConstexpr1 nc1 = NonConstexpr1(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr1'}}
+constexpr NonConstexpr2 nc2 = NonConstexpr2(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr2'}}
+
+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 Constexpr2 {
+  int a = 0;
+};
+constexpr Constexpr2 c2 = Constexpr2(); // ok
+
+int n;
+struct Member {
+  Member() : a(n) {}
+  constexpr Member(int&a) : a(a) {}
+  int &a;
+};
+struct NonConstexpr4 { // expected-note {{here}}
+  Member m;
+};
+constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4'}}
+struct Constexpr3 {
+  constexpr Constexpr3() : m(n) {}
+  Member m;
+};
+constexpr Constexpr3 c3 = Constexpr3(); // ok
+struct Constexpr4 {
+  Constexpr3 m;
+};
+constexpr Constexpr4 c4 = Constexpr4(); // ok
+
+
+// This rule breaks some legal C++98 programs!
+struct A {}; // expected-note {{here}}
+struct B {
+  friend A::A(); // expected-error {{non-constexpr declaration of 'A' follows constexpr declaration}}
+};

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=147128&r1=147127&r2=147128&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed Dec 21 20:22:31 2011
@@ -86,7 +86,7 @@
 
   using IntParam0 = IntParam<0>;
   using IntParam0 = IntParam<id(0)>;
-  using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}} expected-error {{not an integral constant expression}}
+  using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}}
 }
 
 namespace CaseStatements {
@@ -517,16 +517,15 @@
 };
 static_assert(D().c.n == 42, "");
 
-struct E { // expected-note {{here}}
+struct E {
   constexpr E() : p(&p) {} // expected-note {{pointer to temporary cannot be used to initialize a member in a constant expression}}
   void *p;
 };
 constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{in call to 'E()'}} expected-note {{temporary created here}}
 // This is a constant expression if we elide the copy constructor call, and
 // is not a constant expression if we don't! But we do, so it is.
-// FIXME: The move constructor is not currently implicitly defined as constexpr.
-constexpr E e2 = E(); // unexpected-error {{constant expression}} unexpected-note {{here}} unexpected-note {{non-constexpr constructor 'E' cannot be used in a constant expression}}
-static_assert(e2.p == &e2.p, ""); // unexpected-error {{constant expression}} unexpected-note {{initializer of 'e2' is not a constant expression}}
+constexpr E e2 = E();
+static_assert(e2.p == &e2.p, "");
 constexpr E e3;
 static_assert(e3.p == &e3.p, "");
 

Modified: cfe/trunk/test/SemaCXX/enum-bitfield.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-bitfield.cpp?rev=147128&r1=147127&r2=147128&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/enum-bitfield.cpp (original)
+++ cfe/trunk/test/SemaCXX/enum-bitfield.cpp Wed Dec 21 20:22:31 2011
@@ -2,7 +2,7 @@
 
 enum E {};
 
-struct Z {}; // expected-note {{here}}
+struct Z {};
 typedef int Integer;
 
 struct X {
@@ -14,5 +14,5 @@
 
 struct Y {
   enum E : int(2);
-  enum E : Z(); // expected-error{{not an integer constant}} expected-note {{non-constexpr constructor 'Z'}}
+  enum E : Z(); // expected-error{{not an integer constant}}
 };





More information about the cfe-commits mailing list