зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
bf3cc73db9
Коммит
5120188238
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче