[cfe-commits] r147271 - in /cfe/trunk: lib/AST/ExprConstant.cpp lib/AST/Type.cpp test/CXX/expr/expr.const/p2-0x.cpp test/CXX/special/class.ctor/p6-0x.cpp test/CodeGenCXX/value-init.cpp test/SemaCXX/constexpr-printing.cpp test/SemaCXX/constexpr-value-init.cpp test/SemaObjCXX/arc-type-traits.mm

Richard Smith richard-llvm at metafoo.co.uk
Sun Dec 25 12:00:18 PST 2011


Author: rsmith
Date: Sun Dec 25 14:00:17 2011
New Revision: 147271

URL: http://llvm.org/viewvc/llvm-project?rev=147271&view=rev
Log:
constexpr: perform zero-initialization prior to / instead of performing a
constructor call when appropriate. Thanks to Eli for spotting this.

Added:
    cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
    cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp
    cfe/trunk/test/CodeGenCXX/value-init.cpp
    cfe/trunk/test/SemaCXX/constexpr-printing.cpp
    cfe/trunk/test/SemaObjCXX/arc-type-traits.mm

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=147271&r1=147270&r2=147271&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Dec 25 14:00:17 2011
@@ -766,9 +766,25 @@
   return true;
 }
 
+/// Check that this core constant expression is of literal type, and if not,
+/// produce an appropriate diagnostic.
+static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
+  if (!E->isRValue() || E->getType()->isLiteralType())
+    return true;
+
+  // Prvalue constant expressions must be of literal types.
+  if (Info.getLangOpts().CPlusPlus0x)
+    Info.Diag(E->getExprLoc(), diag::note_constexpr_nonliteral)
+      << E->getType();
+  else
+    Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+  return false;
+}
+
 /// Check that this core constant expression value is a valid value for a
 /// constant expression, and if it is, produce the corresponding constant value.
-/// If not, report an appropriate diagnostic.
+/// If not, report an appropriate diagnostic. Does not check that the expression
+/// is of literal type.
 static bool CheckConstantExpression(EvalInfo &Info, const Expr *E,
                                     const CCValue &CCValue, APValue &Value,
                                     CheckConstantExpressionKind CCEK
@@ -1643,17 +1659,23 @@
 /// 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) {
+                                           const CXXConstructorDecl *CD,
+                                           bool IsValueInitialization) {
   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);
+      // Value-initialization does not call a trivial default constructor, so
+      // such a call is a core constant expression whether or not the
+      // constructor is constexpr.
+      if (!IsValueInitialization) {
+        // 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);
     }
@@ -1719,8 +1741,7 @@
 static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This,
                                   ArrayRef<const Expr*> Args,
                                   const CXXConstructorDecl *Definition,
-                                  EvalInfo &Info,
-                                  APValue &Result) {
+                                  EvalInfo &Info, APValue &Result) {
   if (!Info.CheckCallLimit(CallExpr->getExprLoc()))
     return false;
 
@@ -1739,7 +1760,7 @@
 
   // Reserve space for the struct members.
   const CXXRecordDecl *RD = Definition->getParent();
-  if (!RD->isUnion())
+  if (!RD->isUnion() && Result.isUninit())
     Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
                      std::distance(RD->field_begin(), RD->field_end()));
 
@@ -1908,8 +1929,8 @@
   RetTy DerivedSuccess(const CCValue &V, const Expr *E) {
     return static_cast<Derived*>(this)->Success(V, E);
   }
-  RetTy DerivedValueInitialization(const Expr *E) {
-    return static_cast<Derived*>(this)->ValueInitialization(E);
+  RetTy DerivedZeroInitialization(const Expr *E) {
+    return static_cast<Derived*>(this)->ZeroInitialization(E);
   }
 
 protected:
@@ -1931,7 +1952,7 @@
     return Error(E, diag::note_invalid_subexpr_in_const_expr);
   }
 
-  RetTy ValueInitialization(const Expr *E) { return Error(E); }
+  RetTy ZeroInitialization(const Expr *E) { return Error(E); }
 
 public:
   ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
@@ -2108,20 +2129,20 @@
   RetTy VisitInitListExpr(const InitListExpr *E) {
     if (Info.getLangOpts().CPlusPlus0x) {
       if (E->getNumInits() == 0)
-        return DerivedValueInitialization(E);
+        return DerivedZeroInitialization(E);
       if (E->getNumInits() == 1)
         return StmtVisitorTy::Visit(E->getInit(0));
     }
     return Error(E);
   }
   RetTy VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
-    return DerivedValueInitialization(E);
+    return DerivedZeroInitialization(E);
   }
   RetTy VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
-    return DerivedValueInitialization(E);
+    return DerivedZeroInitialization(E);
   }
   RetTy VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
-    return DerivedValueInitialization(E);
+    return DerivedZeroInitialization(E);
   }
 
   /// A member expression where the object is a prvalue is itself a prvalue.
@@ -2495,7 +2516,7 @@
     Result.setFrom(V);
     return true;
   }
-  bool ValueInitialization(const Expr *E) {
+  bool ZeroInitialization(const Expr *E) {
     return Success((Expr*)0);
   }
 
@@ -2615,7 +2636,7 @@
     return HandleBaseToDerivedCast(Info, E, Result);
 
   case CK_NullToPointer:
-    return ValueInitialization(E);
+    return ZeroInitialization(E);
 
   case CK_IntegralToPointer: {
     CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
@@ -2688,7 +2709,7 @@
     Result.setFrom(V);
     return true;
   }
-  bool ValueInitialization(const Expr *E) {
+  bool ZeroInitialization(const Expr *E) {
     return Success((const ValueDecl*)0);
   }
 
@@ -2709,7 +2730,7 @@
     return ExprEvaluatorBaseTy::VisitCastExpr(E);
 
   case CK_NullToMemberPointer:
-    return ValueInitialization(E);
+    return ZeroInitialization(E);
 
   case CK_BaseToDerivedMemberPointer: {
     if (!Visit(E->getSubExpr()))
@@ -2770,6 +2791,7 @@
     bool Success(const CCValue &V, const Expr *E) {
       return CheckConstantExpression(Info, E, V, Result);
     }
+    bool ZeroInitialization(const Expr *E);
 
     bool VisitCastExpr(const CastExpr *E);
     bool VisitInitListExpr(const InitListExpr *E);
@@ -2777,6 +2799,75 @@
   };
 }
 
+/// Perform zero-initialization on an object of non-union class type.
+/// C++11 [dcl.init]p5:
+///  To zero-initialize an object or reference of type T means:
+///    [...]
+///    -- if T is a (possibly cv-qualified) non-union class type,
+///       each non-static data member and each base-class subobject is
+///       zero-initialized
+static bool HandleClassZeroInitialization(EvalInfo &Info, const RecordDecl *RD,
+                                          const LValue &This, APValue &Result) {
+  assert(!RD->isUnion() && "Expected non-union class type");
+  const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
+  Result = APValue(APValue::UninitStruct(), CD ? CD->getNumBases() : 0,
+                   std::distance(RD->field_begin(), RD->field_end()));
+
+  const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+  if (CD) {
+    unsigned Index = 0;
+    for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
+           E = CD->bases_end(); I != E; ++I, ++Index) {
+      const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+      LValue Subobject = This;
+      HandleLValueDirectBase(Info, Subobject, CD, Base, &Layout);
+      if (!HandleClassZeroInitialization(Info, Base, Subobject,
+                                         Result.getStructBase(Index)))
+        return false;
+    }
+  }
+
+  for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+       I != E; ++I) {
+    // -- if T is a reference type, no initialization is performed.
+    if ((*I)->getType()->isReferenceType())
+      continue;
+
+    LValue Subobject = This;
+    HandleLValueMember(Info, Subobject, *I, &Layout);
+
+    ImplicitValueInitExpr VIE((*I)->getType());
+    if (!EvaluateConstantExpression(
+          Result.getStructField((*I)->getFieldIndex()), Info, Subobject, &VIE))
+      return false;
+  }
+
+  return true;
+}
+
+bool RecordExprEvaluator::ZeroInitialization(const Expr *E) {
+  const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
+  if (RD->isUnion()) {
+    // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
+    // object's first non-static named data member is zero-initialized
+    RecordDecl::field_iterator I = RD->field_begin();
+    if (I == RD->field_end()) {
+      Result = APValue((const FieldDecl*)0);
+      return true;
+    }
+
+    LValue Subobject = This;
+    HandleLValueMember(Info, Subobject, *I);
+    Result = APValue(*I);
+    ImplicitValueInitExpr VIE((*I)->getType());
+    return EvaluateConstantExpression(Result.getUnionValue(), Info,
+                                      Subobject, &VIE);
+  }
+
+  return HandleClassZeroInitialization(Info, RD, This, Result);
+}
+
 bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
   switch (E->getCastKind()) {
   default:
@@ -2860,7 +2951,11 @@
 
 bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
   const CXXConstructorDecl *FD = E->getConstructor();
-  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) {
+  bool ZeroInit = E->requiresZeroInitialization();
+  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
+    if (ZeroInit)
+      return ZeroInitialization(E);
+
     const CXXRecordDecl *RD = FD->getParent();
     if (RD->isUnion())
       Result = APValue((FieldDecl*)0);
@@ -2877,11 +2972,14 @@
     return false;
 
   // FIXME: Elide the copy/move construction wherever we can.
-  if (E->isElidable())
+  if (E->isElidable() && !ZeroInit)
     if (const MaterializeTemporaryExpr *ME
           = dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))
       return Visit(ME->GetTemporaryExpr());
 
+  if (ZeroInit && !ZeroInitialization(E))
+    return false;
+
   llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
   return HandleConstructorCall(E, This, Args,
                                cast<CXXConstructorDecl>(Definition), Info,
@@ -2891,7 +2989,6 @@
 static bool EvaluateRecord(const Expr *E, const LValue &This,
                            APValue &Result, EvalInfo &Info) {
   assert(E->isRValue() && E->getType()->isRecordType() &&
-         E->getType()->isLiteralType() &&
          "can't evaluate expression as a record rvalue");
   return RecordExprEvaluator(Info, This, Result).Visit(E);
 }
@@ -2941,14 +3038,6 @@
 /// Evaluate an expression of record type as a temporary.
 static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {
   assert(E->isRValue() && E->getType()->isRecordType());
-  if (!E->getType()->isLiteralType()) {
-    if (Info.getLangOpts().CPlusPlus0x)
-      Info.Diag(E->getExprLoc(), diag::note_constexpr_nonliteral)
-        << E->getType();
-    else
-      Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
-    return false;
-  }
   return TemporaryExprEvaluator(Info, Result).Visit(E);
 }
 
@@ -2976,7 +3065,7 @@
       Result = V;
       return true;
     }
-    bool ValueInitialization(const Expr *E);
+    bool ZeroInitialization(const Expr *E);
 
     bool VisitUnaryReal(const UnaryOperator *E)
       { return Visit(E->getSubExpr()); }
@@ -3128,7 +3217,7 @@
 }
 
 bool
-VectorExprEvaluator::ValueInitialization(const Expr *E) {
+VectorExprEvaluator::ZeroInitialization(const Expr *E) {
   const VectorType *VT = E->getType()->getAs<VectorType>();
   QualType EltTy = VT->getElementType();
   APValue ZeroElement;
@@ -3144,7 +3233,7 @@
 
 bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
   VisitIgnoredValue(E->getSubExpr());
-  return ValueInitialization(E);
+  return ZeroInitialization(E);
 }
 
 //===----------------------------------------------------------------------===//
@@ -3167,7 +3256,7 @@
       return true;
     }
 
-    bool ValueInitialization(const Expr *E) {
+    bool ZeroInitialization(const Expr *E) {
       const ConstantArrayType *CAT =
           Info.Ctx.getAsConstantArrayType(E->getType());
       if (!CAT)
@@ -3177,7 +3266,7 @@
                        CAT->getSize().getZExtValue());
       if (!Result.hasArrayFiller()) return true;
 
-      // Value-initialize all elements.
+      // Zero-initialize all elements.
       LValue Subobject = This;
       Subobject.Designator.addIndex(0);
       ImplicitValueInitExpr VIE(CAT->getElementType());
@@ -3192,8 +3281,7 @@
 
 static bool EvaluateArray(const Expr *E, const LValue &This,
                           APValue &Result, EvalInfo &Info) {
-  assert(E->isRValue() && E->getType()->isArrayType() &&
-         E->getType()->isLiteralType() && "not a literal array rvalue");
+  assert(E->isRValue() && E->getType()->isArrayType() && "not an array rvalue");
   return ArrayExprEvaluator(Info, This, Result).Visit(E);
 }
 
@@ -3263,7 +3351,16 @@
 
   const CXXConstructorDecl *FD = E->getConstructor();
 
-  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) {
+  bool ZeroInit = E->requiresZeroInitialization();
+  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
+    if (ZeroInit) {
+      LValue Subobject = This;
+      Subobject.Designator.addIndex(0);
+      ImplicitValueInitExpr VIE(CAT->getElementType());
+      return EvaluateConstantExpression(Result.getArrayFiller(), Info,
+                                        Subobject, &VIE);
+    }
+
     const CXXRecordDecl *RD = FD->getParent();
     if (RD->isUnion())
       Result.getArrayFiller() = APValue((FieldDecl*)0);
@@ -3286,6 +3383,14 @@
   //   S s[10];
   LValue Subobject = This;
   Subobject.Designator.addIndex(0);
+
+  if (ZeroInit) {
+    ImplicitValueInitExpr VIE(CAT->getElementType());
+    if (!EvaluateConstantExpression(Result.getArrayFiller(), Info, Subobject,
+                                    &VIE))
+      return false;
+  }
+
   llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
   return HandleConstructorCall(E, Subobject, Args,
                                cast<CXXConstructorDecl>(Definition),
@@ -3349,7 +3454,7 @@
     return Success(V.getInt(), E);
   }
 
-  bool ValueInitialization(const Expr *E) { return Success(0, E); }
+  bool ZeroInitialization(const Expr *E) { return Success(0, E); }
 
   //===--------------------------------------------------------------------===//
   //                            Visitor Methods
@@ -3392,7 +3497,7 @@
 
   // Note, GNU defines __null as an integer, not a pointer.
   bool VisitGNUNullExpr(const GNUNullExpr *E) {
-    return ValueInitialization(E);
+    return ZeroInitialization(E);
   }
 
   bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
@@ -4384,7 +4489,7 @@
     return true;
   }
 
-  bool ValueInitialization(const Expr *E) {
+  bool ZeroInitialization(const Expr *E) {
     Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
     return true;
   }
@@ -4399,8 +4504,7 @@
   bool VisitUnaryReal(const UnaryOperator *E);
   bool VisitUnaryImag(const UnaryOperator *E);
 
-  // FIXME: Missing: array subscript of vector, member of vector,
-  //                 ImplicitValueInitExpr
+  // FIXME: Missing: array subscript of vector, member of vector
 };
 } // end anonymous namespace
 
@@ -5007,13 +5111,13 @@
       return false;
     P.moveInto(Result);
     return true;
-  } else if (E->getType()->isArrayType() && E->getType()->isLiteralType()) {
+  } else if (E->getType()->isArrayType()) {
     LValue LV;
     LV.set(E, Info.CurrentCall);
     if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info))
       return false;
     Result = Info.CurrentCall->Temporaries[E];
-  } else if (E->getType()->isRecordType() && E->getType()->isLiteralType()) {
+  } else if (E->getType()->isRecordType()) {
     LValue LV;
     LV.set(E, Info.CurrentCall);
     if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info))
@@ -5045,7 +5149,10 @@
 static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
                                        const LValue &This, const Expr *E,
                                        CheckConstantExpressionKind CCEK) {
-  if (E->isRValue() && E->getType()->isLiteralType()) {
+  if (!CheckLiteralType(Info, E))
+    return false;
+
+  if (E->isRValue()) {
     // Evaluate arrays and record types in-place, so that later initializers can
     // refer to earlier-initialized members of the object.
     if (E->getType()->isArrayType())
@@ -5063,6 +5170,9 @@
 /// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
 /// lvalue-to-rvalue cast if it is an lvalue.
 static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
+  if (!CheckLiteralType(Info, E))
+    return false;
+
   CCValue Value;
   if (!::Evaluate(Value, Info, E))
     return false;
@@ -5142,9 +5252,23 @@
   EvalInfo InitInfo(Ctx, EStatus);
   InitInfo.setEvaluatingDecl(VD, Value);
 
+  if (!CheckLiteralType(InitInfo, this))
+    return false;
+
   LValue LVal;
   LVal.set(VD);
 
+  // C++11 [basic.start.init]p2:
+  //  Variables with static storage duration or thread storage duration shall be
+  //  zero-initialized before any other initialization takes place.
+  // This behavior is not present in C.
+  if (Ctx.getLangOptions().CPlusPlus && !VD->hasLocalStorage() &&
+      !VD->getType()->isReferenceType()) {
+    ImplicitValueInitExpr VIE(VD->getType());
+    if (!EvaluateConstantExpression(Value, InitInfo, LVal, &VIE))
+      return false;
+  }
+
   return EvaluateConstantExpression(Value, InitInfo, LVal, this) &&
          !EStatus.HasSideEffects;
 }

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=147271&r1=147270&r2=147271&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Sun Dec 25 14:00:17 2011
@@ -1126,10 +1126,6 @@
   if (BaseTy->isIncompleteType())
     return false;
 
-  // Objective-C lifetime types are not literal types.
-  if (BaseTy->isObjCRetainableType())
-    return false;
-  
   // C++0x [basic.types]p10:
   //   A type is a literal type if it is:
   //    -- a scalar type; or

Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=147271&r1=147270&r2=147271&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Sun Dec 25 14:00:17 2011
@@ -33,11 +33,11 @@
   int m : NonConstexpr2().n; // expected-error {{constant expression}} expected-note {{undefined constructor 'NonConstexpr2'}}
 };
 struct NonConstexpr4 {
-  NonConstexpr4();
+  NonConstexpr4(); // expected-note {{declared here}}
   int n;
 };
 struct NonConstexpr5 {
-  int n : NonConstexpr4().n; // expected-error {{constant expression}} expected-note {{non-literal type 'NonConstexpr4' cannot be used in a constant expression}}
+  int n : NonConstexpr4().n; // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4' cannot be used in a constant expression}}
 };
 
 // - an invocation of an undefined constexpr function or an undefined

Modified: cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp?rev=147271&r1=147270&r2=147271&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp Sun Dec 25 14:00:17 2011
@@ -8,8 +8,16 @@
 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 NonConstexpr2a : NonConstexpr1 { };
+constexpr NonConstexpr1 nc1 = NonConstexpr1(); // ok, does not call constructor
+constexpr NonConstexpr2 nc2 = NonConstexpr2(); // ok, does not call constructor
+constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr2a'}}
+constexpr int nc2_a = NonConstexpr2().nl.a; // ok
+constexpr int nc2a_a = NonConstexpr2a().a; // ok
+struct Helper {
+  friend constexpr NonConstexpr1::NonConstexpr1(); // expected-error {{follows non-constexpr declaration}}
+  friend constexpr NonConstexpr2::NonConstexpr2(); // expected-error {{follows non-constexpr declaration}}
+};
 
 struct Constexpr1 {};
 constexpr Constexpr1 c1 = Constexpr1(); // ok

Modified: cfe/trunk/test/CodeGenCXX/value-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/value-init.cpp?rev=147271&r1=147270&r2=147271&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/value-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/value-init.cpp Sun Dec 25 14:00:17 2011
@@ -134,8 +134,7 @@
   // CHECK: define i32 @_ZN8zeroinit4testEv()
   int test() {
     // CHECK: call void @llvm.memset.p0i8.i64
-    // CHECK: getelementptr
-    // CHECK: ret i32
+    // CHECK: ret i32 0
     return S().i;
   }
 

Modified: cfe/trunk/test/SemaCXX/constexpr-printing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-printing.cpp?rev=147271&r1=147270&r2=147271&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-printing.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-printing.cpp Sun Dec 25 14:00:17 2011
@@ -11,8 +11,11 @@
 
 constexpr int extract(const S &s) { return s.n; } // expected-note {{read of uninitialized object is not allowed in a constant expression}}
 
-constexpr S s1; // expected-error {{constant expression}} expected-note {{in call to 'S()'}}
-constexpr S s2(10);
+constexpr S s1; // ok
+void f() {
+  constexpr S s1; // expected-error {{constant expression}} expected-note {{in call to 'S()'}}
+  constexpr S s2(10);
+}
 
 typedef __attribute__((vector_size(16))) int vector_int;
 

Added: cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-value-init.cpp?rev=147271&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-value-init.cpp (added)
+++ cfe/trunk/test/SemaCXX/constexpr-value-init.cpp Sun Dec 25 14:00:17 2011
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify
+
+struct A {
+  constexpr A() : a(b + 1), b(a + 1) {} // expected-note {{uninitialized}}
+  int a;
+  int b;
+};
+struct B {
+  A a;
+};
+
+constexpr A a; // ok, zero initialization preceeds static initialization
+void f() {
+  constexpr A a; // expected-error {{constant expression}} expected-note {{in call to 'A()'}}
+}
+
+constexpr B b1; // expected-error {{requires a user-provided default constructor}}
+constexpr B b2 = B(); // ok
+static_assert(b2.a.a == 1, "");
+static_assert(b2.a.b == 2, "");
+
+struct C {
+  int c;
+};
+struct D : C { int d; };
+constexpr C c1; // expected-error {{requires a user-provided default constructor}}
+constexpr C c2 = C(); // ok
+constexpr D d1; // expected-error {{requires a user-provided default constructor}}
+constexpr D d2 = D(); // expected-error {{constant expression}} expected-note {{non-literal type 'const D'}}
+static_assert(D().c == 0, "");
+static_assert(D().d == 0, "");

Modified: cfe/trunk/test/SemaObjCXX/arc-type-traits.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-type-traits.mm?rev=147271&r1=147270&r2=147271&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-type-traits.mm (original)
+++ cfe/trunk/test/SemaObjCXX/arc-type-traits.mm Sun Dec 25 14:00:17 2011
@@ -53,16 +53,16 @@
 TRAIT_IS_TRUE(__has_trivial_destructor, __unsafe_unretained id);
 
 // __is_literal
-TRAIT_IS_FALSE(__is_literal, __strong id);
-TRAIT_IS_FALSE(__is_literal, __weak id);
-TRAIT_IS_FALSE(__is_literal, __autoreleasing id);
-TRAIT_IS_FALSE(__is_literal, __unsafe_unretained id);
+TRAIT_IS_TRUE(__is_literal, __strong id);
+TRAIT_IS_TRUE(__is_literal, __weak id);
+TRAIT_IS_TRUE(__is_literal, __autoreleasing id);
+TRAIT_IS_TRUE(__is_literal, __unsafe_unretained id);
 
 // __is_literal_type
-TRAIT_IS_FALSE(__is_literal_type, __strong id);
-TRAIT_IS_FALSE(__is_literal_type, __weak id);
-TRAIT_IS_FALSE(__is_literal_type, __autoreleasing id);
-TRAIT_IS_FALSE(__is_literal_type, __unsafe_unretained id);
+TRAIT_IS_TRUE(__is_literal_type, __strong id);
+TRAIT_IS_TRUE(__is_literal_type, __weak id);
+TRAIT_IS_TRUE(__is_literal_type, __autoreleasing id);
+TRAIT_IS_TRUE(__is_literal_type, __unsafe_unretained id);
 
 // __is_pod
 TRAIT_IS_FALSE(__is_pod, __strong id);





More information about the cfe-commits mailing list