diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-12-12 09:28:41 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-12-12 09:28:41 +0000 |
commit | dd1f29b6d686899bfd033f26e16cb1621e5549e8 (patch) | |
tree | 8d9c131dd87c383779b7f03b114bebd12b193515 | |
parent | 50058ec63f38eabeb94391a61d2e7fb18a062173 (diff) |
Prepare constant expression infrastructure for the generation of richer
diagnostics. No functionality change.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146365 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Expr.h | 23 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 150 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 28 |
3 files changed, 108 insertions, 93 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index eca572a3b2..ce541f63db 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -429,19 +429,16 @@ public: /// For example, (f() && 0) can be folded, but it still has side effects. bool HasSideEffects; - /// Diag - If the expression is unfoldable, then Diag may contain a note - /// diagnostic indicating why it's not foldable. DiagLoc indicates a caret - /// position for the error, and DiagExpr is the expression that caused - /// the error. - /// If the expression is foldable, but not a constant expression, Diag - /// may contain a note diagnostic that describes why it isn't a constant - /// expression. If the expression *is* a constant expression, then Diag - /// will be zero. - unsigned Diag; - const Expr *DiagExpr; - SourceLocation DiagLoc; - - EvalStatus() : HasSideEffects(false), Diag(0), DiagExpr(0) {} + /// Diag - If this is non-null, it will be filled in with a stack of notes + /// indicating why evaluation failed (or why it failed to produce a constant + /// expression). + /// If the expression is unfoldable, the notes will indicate why it's not + /// foldable. If the expression is foldable, but not a constant expression, + /// the notes will describes why it isn't a constant expression. If the + /// expression *is* a constant expression, no notes will be produced. + llvm::SmallVectorImpl<PartialDiagnosticAt> *Diag; + + EvalStatus() : HasSideEffects(false), Diag(0) {} // hasSideEffects - Return true if the evaluated expression has // side effects. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 1ef3605f20..40cac36129 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -248,8 +248,24 @@ namespace { ~CallStackFrame(); }; + /// A partial diagnostic which we might know in advance that we are not going + /// to emit. + class OptionalDiagnostic { + PartialDiagnostic *Diag; + + public: + explicit OptionalDiagnostic(PartialDiagnostic *Diag = 0) : Diag(Diag) {} + + template<typename T> + OptionalDiagnostic &operator<<(const T &v) { + if (Diag) + *Diag << v; + return *this; + } + }; + struct EvalInfo { - const ASTContext &Ctx; + ASTContext &Ctx; /// EvalStatus - Contains information about the evaluation. Expr::EvalStatus &EvalStatus; @@ -279,8 +295,9 @@ namespace { EvalInfo(const ASTContext &C, Expr::EvalStatus &S) - : Ctx(C), EvalStatus(S), CurrentCall(0), CallStackDepth(0), - BottomFrame(*this, 0, 0), EvaluatingDecl(0), EvaluatingDeclValue(0) {} + : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0), + CallStackDepth(0), BottomFrame(*this, 0, 0), EvaluatingDecl(0), + EvaluatingDeclValue(0) {} const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const { MapTy::const_iterator i = OpaqueValues.find(e); @@ -299,25 +316,29 @@ namespace { return CallStackDepth > getLangOpts().ConstexprCallDepth; } - /// Diagnose that the evaluation does not produce a C++11 core constant - /// expression. - void CCEDiag(const Expr *E, SourceLocation Loc, diag::kind Diag) { - // Don't override a previous diagnostic. - if (EvalStatus.Diag == 0) { - EvalStatus.DiagLoc = Loc; - EvalStatus.Diag = Diag; - EvalStatus.DiagExpr = E; - } - } - /// Diagnose that the evaluation cannot be folded. - void Diag(const Expr *E, SourceLocation Loc, diag::kind Diag) { + OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId) { // If we have a prior diagnostic, it will be noting that the expression // isn't a constant expression. This diagnostic is more important. // FIXME: We might want to show both diagnostics to the user. - EvalStatus.DiagLoc = Loc; - EvalStatus.Diag = Diag; - EvalStatus.DiagExpr = E; + if (EvalStatus.Diag) { + EvalStatus.Diag->clear(); + EvalStatus.Diag->reserve(1); + PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator()); + EvalStatus.Diag->push_back(std::make_pair(Loc, PD)); + // FIXME: Add a call stack for constexpr evaluation. + return OptionalDiagnostic(&EvalStatus.Diag->back().second); + } + return OptionalDiagnostic(); + } + + /// Diagnose that the evaluation does not produce a C++11 core constant + /// expression. + OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId) { + // Don't override a previous diagnostic. + if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) + return OptionalDiagnostic(); + return Diag(Loc, DiagId); } }; @@ -567,7 +588,7 @@ template<typename T> static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E, const T &LVal, APValue &Value) { if (!IsGlobalLValue(LVal.getLValueBase())) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -873,7 +894,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, // argument substitution. if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { if (!Frame || !Frame->Arguments) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } Result = Frame->Arguments[PVD->getFunctionScopeIndex()]; @@ -890,13 +911,13 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, // Never evaluate the initializer of a weak variable. We can't be sure that // this is the definition which will be used. if (VD->isWeak()) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } const Expr *Init = VD->getAnyInitializer(); if (!Init || Init->isValueDependent()) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -906,7 +927,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, } if (VD->isEvaluatingValue()) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -929,7 +950,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, // or a failed evaluation of the initializer should be reattempted each time // it is used. VD->setEvaluatedValue(APValue()); - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -963,7 +984,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, CCValue &Obj, QualType ObjType, const SubobjectDesignator &Sub, QualType SubType) { if (Sub.Invalid || Sub.OnePastTheEnd) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } if (Sub.Entries.empty()) @@ -979,7 +1000,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, assert(CAT && "vla in literal type?"); uint64_t Index = Sub.Entries[I].ArrayIndex; if (CAT->getSize().ule(Index)) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } if (O->getArrayInitializedElts() > Index) @@ -994,8 +1015,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) { - Info.Diag(E, E->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } O = &O->getUnionValue(); @@ -1011,7 +1031,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, } if (O->isUninit()) { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } } @@ -1038,8 +1058,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, if (!LVal.Base) { // FIXME: Indirection through a null pointer deserves a specific diagnostic. - Info.Diag(Conv, Conv->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -1057,23 +1076,20 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, // them are not permitted. const VarDecl *VD = dyn_cast<VarDecl>(D); if (!VD || VD->isInvalidDecl()) { - Info.Diag(Conv, Conv->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } QualType VT = VD->getType(); if (!isa<ParmVarDecl>(VD)) { if (!IsConstNonVolatile(VT)) { - Info.Diag(Conv, Conv->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } // FIXME: Allow folding of values of any literal type in all languages. if (!VT->isIntegralOrEnumerationType() && !VT->isRealFloatingType() && !VD->isConstexpr()) { - Info.Diag(Conv, Conv->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } } @@ -1098,16 +1114,14 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, if (const StringLiteral *S = dyn_cast<StringLiteral>(Base)) { const SubobjectDesignator &Designator = LVal.Designator; if (Designator.Invalid || Designator.Entries.size() != 1) { - Info.Diag(Conv, Conv->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } assert(Type->isIntegerType() && "string element not integer type"); uint64_t Index = Designator.Entries[0].ArrayIndex; if (Index > S->getLength()) { - Info.Diag(Conv, Conv->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), @@ -1131,8 +1145,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, if (!Evaluate(RVal, Info, CLE->getInitializer())) return false; } else { - Info.Diag(Conv, Conv->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -1346,8 +1359,7 @@ static bool HandleFunctionCall(const Expr *CallExpr, const LValue *This, EvalInfo &Info, CCValue &Result) { if (Info.atCallLimit()) { // FIXME: Add a specific proper diagnostic for this. - Info.Diag(CallExpr, CallExpr->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(CallExpr->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -1367,8 +1379,7 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This, APValue &Result) { if (Info.atCallLimit()) { // FIXME: Add a specific diagnostic for this. - Info.Diag(CallExpr, CallExpr->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); + Info.Diag(CallExpr->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -1428,7 +1439,7 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This, return false; } else { // FIXME: handle indirect field initializers - Info.Diag((*I)->getInit(), (*I)->getInit()->getExprLoc(), + Info.Diag((*I)->getInit()->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -1564,14 +1575,14 @@ protected: typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy; typedef ExprEvaluatorBase ExprEvaluatorBaseTy; - void CCEDiag(const Expr *E, diag::kind D) { + OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) { Info.CCEDiag(E, E->getExprLoc(), D); } /// Report an evaluation error. This should only be called when an error is /// first discovered. When propagating an error, just return false. bool Error(const Expr *E, diag::kind D) { - Info.Diag(E, E->getExprLoc(), D); + Info.Diag(E->getExprLoc(), D); return false; } bool Error(const Expr *E) { @@ -2974,7 +2985,7 @@ static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) { if (!Val.isInt()) { // FIXME: It would be better to produce the diagnostic for casting // a pointer to an integer. - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } Result = Val.getInt(); @@ -4549,7 +4560,7 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) { if (!EvaluateVoid(E, Info)) return false; } else { - Info.Diag(E, E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); return false; } @@ -5088,14 +5099,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return ICEDiag(2, E->getLocStart()); } -/// Evaluate an expression as a C++11 constant expression. -static bool EvaluateCPlusPlus11ConstantExpression(ASTContext &Ctx, - const Expr *E, - Expr::EvalResult &Result) { - EvalInfo Info(Ctx, Result); - return EvaluateAsRValue(Info, E, Result.Val) && !Result.Diag; -} - /// Evaluate an expression as a C++11 integral constant expression. static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx, const Expr *E, @@ -5107,18 +5110,27 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx, } Expr::EvalResult Result; - if (EvaluateCPlusPlus11ConstantExpression(Ctx, E, Result)) { - assert(Result.Val.isInt() && "pointer cast to int is not an ICE"); - if (Value) *Value = Result.Val.getInt(); - return true; - } else { - if (Loc) *Loc = Result.DiagLoc.isValid() ? Result.DiagLoc : E->getExprLoc(); - return false; + llvm::SmallVector<PartialDiagnosticAt, 8> Diags; + Result.Diag = &Diags; + EvalInfo Info(Ctx, Result); + + bool IsICE = EvaluateAsRValue(Info, E, Result.Val); + if (!Diags.empty()) { + IsICE = false; + if (Loc) *Loc = Diags[0].first; + } else if (!IsICE && Loc) { + *Loc = E->getExprLoc(); } + + if (!IsICE) + return false; + + assert(Result.Val.isInt() && "pointer cast to int is not an ICE"); + if (Value) *Value = Result.Val.getInt(); + return true; } -bool Expr::isIntegerConstantExpr(ASTContext &Ctx, - SourceLocation *Loc) const { +bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { if (Ctx.getLangOptions().CPlusPlus0x) return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f7e67cdf3e..d0aa0a6e7c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9190,6 +9190,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, } bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ + // FIXME: In C++11, this evaluates the expression even if it's not an ICE. + // Don't evaluate it a second time below just to get the diagnostics. llvm::APSInt ICEResult; if (E->isIntegerConstantExpr(ICEResult, Context)) { if (Result) @@ -9198,29 +9200,33 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ } Expr::EvalResult EvalResult; + llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + EvalResult.Diag = &Notes; if (!E->EvaluateAsRValue(EvalResult, Context) || !EvalResult.Val.isInt() || EvalResult.HasSideEffects) { Diag(E->getExprLoc(), diag::err_expr_not_ice) << E->getSourceRange(); - if (EvalResult.Diag) { - // We only show the note if it's not the usual "invalid subexpression" - // or if it's actually in a subexpression. - if (EvalResult.Diag != diag::note_invalid_subexpr_in_const_expr || - E->IgnoreParens() != EvalResult.DiagExpr->IgnoreParens()) - Diag(EvalResult.DiagLoc, EvalResult.Diag); + // We only show the notes if they're not the usual "invalid subexpression" + // or if they are actually in a subexpression. + if (!Notes.empty() && + (Notes.size() != 1 || + Notes[0].second.getDiagID() != diag::note_invalid_subexpr_in_const_expr + || Notes[0].first != E->IgnoreParens()->getExprLoc())) { + for (unsigned I = 0, N = Notes.size(); I != N; ++I) + Diag(Notes[I].first, Notes[I].second); } return true; } - Diag(E->getExprLoc(), diag::ext_expr_not_ice) << - E->getSourceRange(); + Diag(E->getExprLoc(), diag::ext_expr_not_ice) << E->getSourceRange(); - if (EvalResult.Diag && - Diags.getDiagnosticLevel(diag::ext_expr_not_ice, EvalResult.DiagLoc) + if (Notes.size() && + Diags.getDiagnosticLevel(diag::ext_expr_not_ice, E->getExprLoc()) != DiagnosticsEngine::Ignored) - Diag(EvalResult.DiagLoc, EvalResult.Diag); + for (unsigned I = 0, N = Notes.size(); I != N; ++I) + Diag(Notes[I].first, Notes[I].second); if (Result) *Result = EvalResult.Val.getInt(); |