[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