aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2011-12-30 21:15:51 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2011-12-30 21:15:51 +0000
commit51201882382fb40c9456a06c7f93d6ddd4a57712 (patch)
tree2b485b2651f5385cda9709b77582bf4320e3569f /lib/AST/ExprConstant.cpp
parentbf3cc73db94f2fbeb57929887bd05d5a0e077f0c (diff)
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
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp220
1 files changed, 172 insertions, 48 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index ba5b1f4bb6..3579e75d94 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -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) {
- // 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);
}
@@ -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;
}