[cfe-commits] r146365 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/ExprConstant.cpp lib/Sema/SemaExpr.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Mon Dec 12 01:28:41 PST 2011
Author: rsmith
Date: Mon Dec 12 03:28:41 2011
New Revision: 146365
URL: http://llvm.org/viewvc/llvm-project?rev=146365&view=rev
Log:
Prepare constant expression infrastructure for the generation of richer
diagnostics. No functionality change.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=146365&r1=146364&r2=146365&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon Dec 12 03:28:41 2011
@@ -429,19 +429,16 @@
/// 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;
+ /// 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), DiagExpr(0) {}
+ EvalStatus() : HasSideEffects(false), Diag(0) {}
// hasSideEffects - Return true if the evaluated expression has
// side effects.
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=146365&r1=146364&r2=146365&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Dec 12 03:28:41 2011
@@ -248,8 +248,24 @@
~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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
}
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 @@
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=146365&r1=146364&r2=146365&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Dec 12 03:28:41 2011
@@ -9190,6 +9190,8 @@
}
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 @@
}
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();
More information about the cfe-commits
mailing list