Unrevert r147271, reverted in r147361.

Also temporarily remove the assumption from IR gen that we can emit IR for every
constant we can fold, since it isn't currently true in C++11, to fix PR11676.

Original comment from r147271:

constexpr: perform zero-initialization prior to / instead of performing a
constructor call when appropriate. Thanks to Eli for spotting this.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147384 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2011-12-30 21:15:51 +00:00
Родитель bf3cc73db9
Коммит 5120188238
9 изменённых файлов: 236 добавлений и 74 удалений

Просмотреть файл

@ -767,9 +767,25 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
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
@ -1644,17 +1660,23 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
/// 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) {
// 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);
}
@ -1720,8 +1742,7 @@ static bool HandleFunctionCall(const Expr *CallExpr, const FunctionDecl *Callee,
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;
@ -1740,7 +1761,7 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This,
// 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()));
@ -1909,8 +1930,8 @@ private:
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:
@ -1932,7 +1953,7 @@ protected:
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) {}
@ -2109,20 +2130,20 @@ public:
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.
@ -2511,7 +2532,7 @@ public:
Result.setFrom(V);
return true;
}
bool ValueInitialization(const Expr *E) {
bool ZeroInitialization(const Expr *E) {
return Success((Expr*)0);
}
@ -2631,7 +2652,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
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;
@ -2704,7 +2725,7 @@ public:
Result.setFrom(V);
return true;
}
bool ValueInitialization(const Expr *E) {
bool ZeroInitialization(const Expr *E) {
return Success((const ValueDecl*)0);
}
@ -2725,7 +2746,7 @@ bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_NullToMemberPointer:
return ValueInitialization(E);
return ZeroInitialization(E);
case CK_BaseToDerivedMemberPointer: {
if (!Visit(E->getSubExpr()))
@ -2786,6 +2807,7 @@ namespace {
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);
@ -2793,6 +2815,75 @@ namespace {
};
}
/// 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:
@ -2876,7 +2967,11 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
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);
@ -2893,11 +2988,14 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
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,
@ -2907,7 +3005,6 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
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);
}
@ -2957,14 +3054,6 @@ public:
/// 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);
}
@ -2992,7 +3081,7 @@ namespace {
Result = V;
return true;
}
bool ValueInitialization(const Expr *E);
bool ZeroInitialization(const Expr *E);
bool VisitUnaryReal(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
@ -3144,7 +3233,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
bool
VectorExprEvaluator::ValueInitialization(const Expr *E) {
VectorExprEvaluator::ZeroInitialization(const Expr *E) {
const VectorType *VT = E->getType()->getAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
@ -3160,7 +3249,7 @@ VectorExprEvaluator::ValueInitialization(const Expr *E) {
bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
VisitIgnoredValue(E->getSubExpr());
return ValueInitialization(E);
return ZeroInitialization(E);
}
//===----------------------------------------------------------------------===//
@ -3183,7 +3272,7 @@ namespace {
return true;
}
bool ValueInitialization(const Expr *E) {
bool ZeroInitialization(const Expr *E) {
const ConstantArrayType *CAT =
Info.Ctx.getAsConstantArrayType(E->getType());
if (!CAT)
@ -3193,7 +3282,7 @@ namespace {
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());
@ -3208,8 +3297,7 @@ namespace {
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);
}
@ -3279,7 +3367,16 @@ bool ArrayExprEvaluator::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) {
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);
@ -3302,6 +3399,14 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
// 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),
@ -3365,7 +3470,7 @@ public:
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
@ -3408,7 +3513,7 @@ public:
// 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) {
@ -4411,7 +4516,7 @@ public:
return true;
}
bool ValueInitialization(const Expr *E) {
bool ZeroInitialization(const Expr *E) {
Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
return true;
}
@ -4426,8 +4531,7 @@ public:
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
@ -5034,13 +5138,13 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) {
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))
@ -5072,7 +5176,10 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) {
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())
@ -5090,6 +5197,9 @@ static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
/// 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;
@ -5173,9 +5283,23 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
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;
}

Просмотреть файл

@ -1126,10 +1126,6 @@ bool Type::isLiteralType() const {
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

Просмотреть файл

@ -970,7 +970,13 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::Value *Loc =
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
if (!emission.IsConstantAggregate) {
llvm::Constant *constant = 0;
if (emission.IsConstantAggregate) {
assert(!capturedByInit && "constant init contains a capturing block?");
constant = CGM.EmitConstantExpr(D.getInit(), type, this);
}
if (!constant) {
LValue lv = MakeAddrLValue(Loc, type, alignment);
lv.setNonGC(true);
return EmitExprAsInit(Init, &D, lv, capturedByInit);
@ -978,13 +984,8 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
// If this is a simple aggregate initialization, we can optimize it
// in various ways.
assert(!capturedByInit && "constant init contains a capturing block?");
bool isVolatile = type.isVolatileQualified();
llvm::Constant *constant = CGM.EmitConstantExpr(D.getInit(), type, this);
assert(constant != 0 && "Wasn't a simple constant init?");
llvm::Value *SizeVal =
llvm::ConstantInt::get(IntPtrTy,
getContext().getTypeSizeInChars(type).getQuantity());

Просмотреть файл

@ -33,11 +33,11 @@ struct NonConstexpr3 {
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

Просмотреть файл

@ -8,8 +8,16 @@ struct NonConstexpr1 { // expected-note {{here}}
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

Просмотреть файл

@ -134,8 +134,7 @@ namespace zeroinit {
// 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;
}

Просмотреть файл

@ -11,8 +11,11 @@ struct S {
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;

Просмотреть файл

@ -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, "");

Просмотреть файл

@ -53,16 +53,16 @@ TRAIT_IS_TRUE(__has_trivial_destructor, __autoreleasing id);
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);