diff options
| author | Abramo Bagnara <abramo.bagnara@bugseng.com> | 2014-05-22 19:20:46 +0000 |
|---|---|---|
| committer | Abramo Bagnara <abramo.bagnara@bugseng.com> | 2014-05-22 19:20:46 +0000 |
| commit | 847c660ad5aea36a45eec10247116531f539efcb (patch) | |
| tree | ebd3fe08a47188a94de2b551f347aacddca7596f /clang/lib | |
| parent | 328b52e88a1d7244f8beecf3101f6dc794e1be4f (diff) | |
| download | bcm5719-llvm-847c660ad5aea36a45eec10247116531f539efcb.tar.gz bcm5719-llvm-847c660ad5aea36a45eec10247116531f539efcb.zip | |
Improved location for non-constant initializers diagnostics.
llvm-svn: 209466
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 51 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 20 |
2 files changed, 45 insertions, 26 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index aea2f432ad5..7e1b2d94360 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -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 { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 88f099f96d2..a3dd2e7462c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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); } |

