Improved location for non-constant initializers diagnostics.
llvm-svn: 209466
This commit is contained in:
parent
328b52e88a
commit
847c660ad5
|
@ -520,7 +520,10 @@ public:
|
|||
|
||||
/// isConstantInitializer - Returns true if this expression can be emitted to
|
||||
/// IR as a constant, and thus can be used as a constant initializer in C.
|
||||
bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const;
|
||||
/// If this expression is not constant and Culprit is non-null,
|
||||
/// it is used to store the address of first non constant expr.
|
||||
bool isConstantInitializer(ASTContext &Ctx, bool ForRef,
|
||||
const Expr **Culprit = nullptr) const;
|
||||
|
||||
/// EvalStatus is a struct with detailed info about an evaluation in progress.
|
||||
struct EvalStatus {
|
||||
|
|
|
@ -2669,7 +2669,8 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
||||
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
|
||||
const Expr **Culprit) const {
|
||||
// This function is attempting whether an expression is an initializer
|
||||
// which can be evaluated at compile-time. It very closely parallels
|
||||
// ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
|
||||
|
@ -2681,7 +2682,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
|||
|
||||
if (IsForRef) {
|
||||
EvalResult Result;
|
||||
return EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects;
|
||||
if (EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects)
|
||||
return true;
|
||||
if (Culprit)
|
||||
*Culprit = this;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (getStmtClass()) {
|
||||
|
@ -2700,7 +2705,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
|||
|
||||
// Trivial copy constructor
|
||||
assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument");
|
||||
return CE->getArg(0)->isConstantInitializer(Ctx, false);
|
||||
return CE->getArg(0)->isConstantInitializer(Ctx, false, Culprit);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -2710,14 +2715,14 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
|||
// "struct x {int x;} x = (struct x) {};".
|
||||
// FIXME: This accepts other cases it shouldn't!
|
||||
const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
|
||||
return Exp->isConstantInitializer(Ctx, false);
|
||||
return Exp->isConstantInitializer(Ctx, false, Culprit);
|
||||
}
|
||||
case InitListExprClass: {
|
||||
const InitListExpr *ILE = cast<InitListExpr>(this);
|
||||
if (ILE->getType()->isArrayType()) {
|
||||
unsigned numInits = ILE->getNumInits();
|
||||
for (unsigned i = 0; i < numInits; i++) {
|
||||
if (!ILE->getInit(i)->isConstantInitializer(Ctx, false))
|
||||
if (!ILE->getInit(i)->isConstantInitializer(Ctx, false, Culprit))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -2741,11 +2746,14 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
|||
if (Field->isBitField()) {
|
||||
// Bitfields have to evaluate to an integer.
|
||||
llvm::APSInt ResultTmp;
|
||||
if (!Elt->EvaluateAsInt(ResultTmp, Ctx))
|
||||
if (!Elt->EvaluateAsInt(ResultTmp, Ctx)) {
|
||||
if (Culprit)
|
||||
*Culprit = Elt;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
bool RefType = Field->getType()->isReferenceType();
|
||||
if (!Elt->isConstantInitializer(Ctx, RefType))
|
||||
if (!Elt->isConstantInitializer(Ctx, RefType, Culprit))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2759,19 +2767,22 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
|||
return true;
|
||||
case ParenExprClass:
|
||||
return cast<ParenExpr>(this)->getSubExpr()
|
||||
->isConstantInitializer(Ctx, IsForRef);
|
||||
->isConstantInitializer(Ctx, IsForRef, Culprit);
|
||||
case GenericSelectionExprClass:
|
||||
return cast<GenericSelectionExpr>(this)->getResultExpr()
|
||||
->isConstantInitializer(Ctx, IsForRef);
|
||||
->isConstantInitializer(Ctx, IsForRef, Culprit);
|
||||
case ChooseExprClass:
|
||||
if (cast<ChooseExpr>(this)->isConditionDependent())
|
||||
if (cast<ChooseExpr>(this)->isConditionDependent()) {
|
||||
if (Culprit)
|
||||
*Culprit = this;
|
||||
return false;
|
||||
}
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr()
|
||||
->isConstantInitializer(Ctx, IsForRef);
|
||||
->isConstantInitializer(Ctx, IsForRef, Culprit);
|
||||
case UnaryOperatorClass: {
|
||||
const UnaryOperator* Exp = cast<UnaryOperator>(this);
|
||||
if (Exp->getOpcode() == UO_Extension)
|
||||
return Exp->getSubExpr()->isConstantInitializer(Ctx, false);
|
||||
return Exp->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
|
||||
break;
|
||||
}
|
||||
case CXXFunctionalCastExprClass:
|
||||
|
@ -2791,25 +2802,29 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
|||
CE->getCastKind() == CK_ConstructorConversion ||
|
||||
CE->getCastKind() == CK_NonAtomicToAtomic ||
|
||||
CE->getCastKind() == CK_AtomicToNonAtomic)
|
||||
return CE->getSubExpr()->isConstantInitializer(Ctx, false);
|
||||
return CE->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
|
||||
|
||||
break;
|
||||
}
|
||||
case MaterializeTemporaryExprClass:
|
||||
return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
|
||||
->isConstantInitializer(Ctx, false);
|
||||
->isConstantInitializer(Ctx, false, Culprit);
|
||||
|
||||
case SubstNonTypeTemplateParmExprClass:
|
||||
return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
|
||||
->isConstantInitializer(Ctx, false);
|
||||
->isConstantInitializer(Ctx, false, Culprit);
|
||||
case CXXDefaultArgExprClass:
|
||||
return cast<CXXDefaultArgExpr>(this)->getExpr()
|
||||
->isConstantInitializer(Ctx, false);
|
||||
->isConstantInitializer(Ctx, false, Culprit);
|
||||
case CXXDefaultInitExprClass:
|
||||
return cast<CXXDefaultInitExpr>(this)->getExpr()
|
||||
->isConstantInitializer(Ctx, false);
|
||||
->isConstantInitializer(Ctx, false, Culprit);
|
||||
}
|
||||
return isEvaluatable(Ctx);
|
||||
if (isEvaluatable(Ctx))
|
||||
return true;
|
||||
if (Culprit)
|
||||
*Culprit = this;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Expr::HasSideEffects(const ASTContext &Ctx) const {
|
||||
|
|
|
@ -7931,10 +7931,11 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
|
|||
// "may accept other forms of constant expressions" exception.
|
||||
// (We never end up here for C++, so the constant expression
|
||||
// rules there don't matter.)
|
||||
if (Init->isConstantInitializer(Context, false))
|
||||
const Expr *Culprit;
|
||||
if (Init->isConstantInitializer(Context, false, &Culprit))
|
||||
return false;
|
||||
Diag(Init->getExprLoc(), diag::err_init_element_not_constant)
|
||||
<< Init->getSourceRange();
|
||||
Diag(Culprit->getExprLoc(), diag::err_init_element_not_constant)
|
||||
<< Culprit->getSourceRange();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -8415,6 +8416,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
// static storage duration shall be constant expressions or string literals.
|
||||
// C++ does not have this restriction.
|
||||
if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) {
|
||||
const Expr *Culprit;
|
||||
if (VDecl->getStorageClass() == SC_Static)
|
||||
CheckForConstantInitializer(Init, DclT);
|
||||
// C89 is stricter than C99 for non-static aggregate types.
|
||||
|
@ -8423,10 +8425,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
// constant expressions.
|
||||
else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
|
||||
isa<InitListExpr>(Init) &&
|
||||
!Init->isConstantInitializer(Context, false))
|
||||
Diag(Init->getExprLoc(),
|
||||
!Init->isConstantInitializer(Context, false, &Culprit))
|
||||
Diag(Culprit->getExprLoc(),
|
||||
diag::ext_aggregate_init_not_constant)
|
||||
<< Init->getSourceRange();
|
||||
<< Culprit->getSourceRange();
|
||||
}
|
||||
} else if (VDecl->isStaticDataMember() &&
|
||||
VDecl->getLexicalDeclContext()->isRecord()) {
|
||||
|
@ -8897,6 +8899,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
|||
}
|
||||
|
||||
if (var->getTLSKind() == VarDecl::TLS_Static) {
|
||||
const Expr *Culprit;
|
||||
if (var->getType().isDestructedType()) {
|
||||
// GNU C++98 edits for __thread, [basic.start.term]p3:
|
||||
// The type of an object with thread storage duration shall not
|
||||
|
@ -8906,12 +8909,13 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
|||
Diag(var->getLocation(), diag::note_use_thread_local);
|
||||
} else if (getLangOpts().CPlusPlus && var->hasInit() &&
|
||||
!var->getInit()->isConstantInitializer(
|
||||
Context, var->getType()->isReferenceType())) {
|
||||
Context, var->getType()->isReferenceType(), &Culprit)) {
|
||||
// GNU C++98 edits for __thread, [basic.start.init]p4:
|
||||
// An object of thread storage duration shall not require dynamic
|
||||
// initialization.
|
||||
// FIXME: Need strict checking here.
|
||||
Diag(var->getLocation(), diag::err_thread_dynamic_init);
|
||||
Diag(Culprit->getExprLoc(), diag::err_thread_dynamic_init)
|
||||
<< Culprit->getSourceRange();
|
||||
if (getLangOpts().CPlusPlus11)
|
||||
Diag(var->getLocation(), diag::note_use_thread_local);
|
||||
}
|
||||
|
|
|
@ -282,7 +282,12 @@ int a5[] = (int5){1, 2, 3, 4, 5}; // expected-warning{{initialization of an arra
|
|||
int a6[5] = (int[]){1, 2, 3}; // expected-error{{cannot initialize array of type 'int [5]' with array of type 'int [3]'}}
|
||||
|
||||
int nonconst_value();
|
||||
int a7[5] = (int[5]){ 1, 2, 3, 4, nonconst_value() }; // expected-error{{initializer element is not a compile-time constant}}
|
||||
int a7[5] = (int[5]){ 1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
nonconst_value() // expected-error{{initializer element is not a compile-time constant}}
|
||||
};
|
||||
|
||||
// <rdar://problem/10636946>
|
||||
__attribute__((weak)) const unsigned int test10_bound = 10;
|
||||
|
|
Loading…
Reference in New Issue