[cfe-commits] r149108 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp test/CodeGenCXX/const-init-cxx11.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Thu Jan 26 17:14:48 PST 2012


Author: rsmith
Date: Thu Jan 26 19:14:48 2012
New Revision: 149108

URL: http://llvm.org/viewvc/llvm-project?rev=149108&view=rev
Log:
constexpr: Implement the [dcl.constexpr]p5 check for whether a constexpr
function definition can produce a constant expression. This also provides the
last few checks for [dcl.constexpr]p3 and [dcl.constexpr]p4.

Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
    cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Thu Jan 26 19:14:48 2012
@@ -425,6 +425,14 @@
   bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0,
                            SourceLocation *Loc = 0) const;
 
+  /// isPotentialConstantExpr - Return true if this function's definition
+  /// might be usable in a constant expression in C++11, if it were marked
+  /// constexpr. Return false if the function can never produce a constant
+  /// expression, along with diagnostics describing why not.
+  static bool isPotentialConstantExpr(const FunctionDecl *FD,
+                                      llvm::SmallVectorImpl<
+                                        PartialDiagnosticAt> &Diags);
+
   /// 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;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 26 19:14:48 2012
@@ -1360,6 +1360,9 @@
   "%select{function|constructor}1">;
 def err_constexpr_var_declaration : Error<
   "variables cannot be declared in a constexpr %select{function|constructor}0">;
+def err_constexpr_function_never_constant_expr : Error<
+  "constexpr %select{function|constructor}0 never produces "
+  "a constant expression">;
 def err_constexpr_body_no_return : Error<
   "no return statement in constexpr function">;
 def err_constexpr_body_multiple_return : Error<

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Jan 26 19:14:48 2012
@@ -9,6 +9,28 @@
 //
 // This file implements the Expr constant evaluator.
 //
+// Constant expression evaluation produces four main results:
+//
+//  * A success/failure flag indicating whether constant folding was successful.
+//    This is the 'bool' return value used by most of the code in this file. A
+//    'false' return value indicates that constant folding has failed, and any
+//    appropriate diagnostic has already been produced.
+//
+//  * An evaluated result, valid only if constant folding has not failed.
+//
+//  * A flag indicating if evaluation encountered (unevaluated) side-effects.
+//    These arise in cases such as (sideEffect(), 0) and (sideEffect() || 1),
+//    where it is possible to determine the evaluated result regardless.
+//
+//  * A set of notes indicating why the evaluation was not a constant expression
+//    (under the C++11 rules only, at the moment), or, if folding failed too,
+//    why the expression could not be folded.
+//
+// If we are checking for a potential constant expression, failure to constant
+// fold a potential constant sub-expression will be indicated by a 'false'
+// return value (the expression could not be folded) and no diagnostic (the
+// expression is not necessarily non-constant).
+//
 //===----------------------------------------------------------------------===//
 
 #include "clang/AST/APValue.h"
@@ -346,7 +368,7 @@
     MapTy OpaqueValues;
 
     /// BottomFrame - The frame in which evaluation started. This must be
-    /// initialized last.
+    /// initialized after CurrentCall and CallStackDepth.
     CallStackFrame BottomFrame;
 
     /// EvaluatingDecl - This is the declaration whose initializer is being
@@ -361,11 +383,17 @@
     /// notes attached to it will also be stored, otherwise they will not be.
     bool HasActiveDiagnostic;
 
+    /// CheckingPotentialConstantExpression - Are we checking whether the
+    /// expression is a potential constant expression? If so, some diagnostics
+    /// are suppressed.
+    bool CheckingPotentialConstantExpression;
+
 
     EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
       : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
         CallStackDepth(0), BottomFrame(*this, SourceLocation(), 0, 0, 0),
-        EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false) {}
+        EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
+        CheckingPotentialConstantExpression(false) {}
 
     const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const {
       MapTy::const_iterator i = OpaqueValues.find(e);
@@ -381,6 +409,10 @@
     const LangOptions &getLangOpts() const { return Ctx.getLangOptions(); }
 
     bool CheckCallLimit(SourceLocation Loc) {
+      // Don't perform any constexpr calls (other than the call we're checking)
+      // when checking a potential constant expression.
+      if (CheckingPotentialConstantExpression && CallStackDepth > 1)
+        return false;
       if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
         return true;
       Diag(Loc, diag::note_constexpr_depth_limit_exceeded)
@@ -412,12 +444,15 @@
         unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
         if (Limit)
           CallStackNotes = std::min(CallStackNotes, Limit + 1);
+        if (CheckingPotentialConstantExpression)
+          CallStackNotes = 0;
 
         HasActiveDiagnostic = true;
         EvalStatus.Diag->clear();
         EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
         addDiag(Loc, DiagId);
-        addCallStack(Limit);
+        if (!CheckingPotentialConstantExpression)
+          addCallStack(Limit);
         return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
       }
       HasActiveDiagnostic = false;
@@ -449,6 +484,12 @@
                                 Diags.begin(), Diags.end());
       }
     }
+
+    /// Should we continue evaluation as much as possible after encountering a
+    /// construct which can't be folded?
+    bool keepEvaluatingAfterFailure() {
+      return CheckingPotentialConstantExpression && EvalStatus.Diag->empty();
+    }
   };
 }
 
@@ -827,6 +868,14 @@
   // Block variables at global or local static scope.
   case Expr::BlockExprClass:
     return !cast<BlockExpr>(E)->getBlockDecl()->hasCaptures();
+  case Expr::ImplicitValueInitExprClass:
+    // FIXME:
+    // We can never form an lvalue with an implicit value initialization as its
+    // base through expression evaluation, so these only appear in one case: the
+    // implicit variable declaration we invent when checking whether a constexpr
+    // constructor can produce a constant expression. We must assume that such
+    // an expression might be a global lvalue.
+    return true;
   }
 }
 
@@ -1238,6 +1287,10 @@
   // If this is a parameter to an active constexpr function call, perform
   // argument substitution.
   if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
+    // Assume arguments of a potential constant expression are unknown
+    // constant expressions.
+    if (Info.CheckingPotentialConstantExpression)
+      return false;
     if (!Frame || !Frame->Arguments) {
       Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
       return false;
@@ -1249,7 +1302,10 @@
   // Dig out the initializer, and use the declaration which it's attached to.
   const Expr *Init = VD->getAnyInitializer(VD);
   if (!Init || Init->isValueDependent()) {
-    Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+    // If we're checking a potential constant expression, the variable could be
+    // initialized later.
+    if (!Info.CheckingPotentialConstantExpression)
+      Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
     return false;
   }
 
@@ -1323,6 +1379,9 @@
   }
   if (Sub.Entries.empty())
     return true;
+  if (Info.CheckingPotentialConstantExpression && Obj.isUninit())
+    // This object might be initialized later.
+    return false;
 
   assert(!Obj.isLValue() && "extracting subobject of lvalue");
   const APValue *O = &Obj;
@@ -1383,7 +1442,8 @@
     }
 
     if (O->isUninit()) {
-      Info.Diag(E->getExprLoc(), diag::note_constexpr_read_uninit);
+      if (!Info.CheckingPotentialConstantExpression)
+        Info.Diag(E->getExprLoc(), diag::note_constexpr_read_uninit);
       return false;
     }
   }
@@ -1603,7 +1663,8 @@
                                                   bool IncludeMember = true) {
   assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
 
-  if (!EvaluateObjectArgument(Info, BO->getLHS(), LV))
+  bool EvalObjOK = EvaluateObjectArgument(Info, BO->getLHS(), LV);
+  if (!EvalObjOK && !Info.keepEvaluatingAfterFailure())
     return 0;
 
   MemberPtr MemPtr;
@@ -1615,6 +1676,9 @@
   if (!MemPtr.getDecl())
     return 0;
 
+  if (!EvalObjOK)
+    return 0;
+
   if (MemPtr.isDerivedMember()) {
     // This is a member of some derived class. Truncate LV appropriately.
     // The end of the derived-to-base path for the base object must match the
@@ -1786,6 +1850,12 @@
 static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
                                    const FunctionDecl *Declaration,
                                    const FunctionDecl *Definition) {
+  // Potential constant expressions can contain calls to declared, but not yet
+  // defined, constexpr functions.
+  if (Info.CheckingPotentialConstantExpression && !Definition &&
+      Declaration->isConstexpr())
+    return false;
+
   // Can we evaluate this function call?
   if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
     return true;
@@ -1811,44 +1881,49 @@
 /// EvaluateArgs - Evaluate the arguments to a function call.
 static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
                          EvalInfo &Info) {
+  bool Success = true;
   for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
-       I != E; ++I)
-    if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
-      return false;
-  return true;
+       I != E; ++I) {
+    if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
+      // If we're checking for a potential constant expression, evaluate all
+      // initializers even if some of them fail.
+      if (!Info.keepEvaluatingAfterFailure())
+        return false;
+      Success = false;
+    }
+  }
+  return Success;
 }
 
 /// Evaluate a function call.
-static bool HandleFunctionCall(const Expr *CallExpr, const FunctionDecl *Callee,
-                               const LValue *This,
+static bool HandleFunctionCall(SourceLocation CallLoc,
+                               const FunctionDecl *Callee, const LValue *This,
                                ArrayRef<const Expr*> Args, const Stmt *Body,
                                EvalInfo &Info, APValue &Result) {
-  if (!Info.CheckCallLimit(CallExpr->getExprLoc()))
-    return false;
-
   ArgVector ArgValues(Args.size());
   if (!EvaluateArgs(Args, ArgValues, Info))
     return false;
 
-  CallStackFrame Frame(Info, CallExpr->getExprLoc(), Callee, This,
-                       ArgValues.data());
+  if (!Info.CheckCallLimit(CallLoc))
+    return false;
+
+  CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
   return EvaluateStmt(Result, Info, Body) == ESR_Returned;
 }
 
 /// Evaluate a constructor call.
-static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This,
+static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
                                   ArrayRef<const Expr*> Args,
                                   const CXXConstructorDecl *Definition,
                                   EvalInfo &Info, APValue &Result) {
-  if (!Info.CheckCallLimit(CallExpr->getExprLoc()))
-    return false;
-
   ArgVector ArgValues(Args.size());
   if (!EvaluateArgs(Args, ArgValues, Info))
     return false;
 
-  CallStackFrame Frame(Info, CallExpr->getExprLoc(), Definition,
-                       &This, ArgValues.data());
+  if (!Info.CheckCallLimit(CallLoc))
+    return false;
+
+  CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data());
 
   // If it's a delegating constructor, just delegate.
   if (Definition->isDelegatingConstructor()) {
@@ -1866,9 +1941,14 @@
     LValue RHS;
     RHS.setFrom(ArgValues[0]);
     CCValue Value;
-    return HandleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
-                                          RHS, Value) &&
-           CheckConstantExpression(Info, CallExpr, Value, Result);
+    if (!HandleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
+                                        RHS, Value))
+      return false;
+    assert((Value.isStruct() || Value.isUnion()) &&
+           "trivial copy/move from non-class type?");
+    // Any CCValue of class type must already be a constant expression.
+    Result = Value;
+    return true;
   }
 
   // Reserve space for the struct members.
@@ -1878,12 +1958,17 @@
 
   const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
 
+  bool Success = true;
   unsigned BasesSeen = 0;
 #ifndef NDEBUG
   CXXRecordDecl::base_class_const_iterator BaseIt = RD->bases_begin();
 #endif
   for (CXXConstructorDecl::init_const_iterator I = Definition->init_begin(),
        E = Definition->init_end(); I != E; ++I) {
+    LValue Subobject = This;
+    APValue *Value = &Result;
+
+    // Determine the subobject to initialize.
     if ((*I)->isBaseInitializer()) {
       QualType BaseType((*I)->getBaseClass(), 0);
 #ifndef NDEBUG
@@ -1894,27 +1979,18 @@
              "base class initializers not in expected order");
       ++BaseIt;
 #endif
-      LValue Subobject = This;
       HandleLValueDirectBase(Info, (*I)->getInit(), Subobject, RD,
                              BaseType->getAsCXXRecordDecl(), &Layout);
-      if (!EvaluateConstantExpression(Result.getStructBase(BasesSeen++), Info,
-                                      Subobject, (*I)->getInit()))
-        return false;
+      Value = &Result.getStructBase(BasesSeen++);
     } else if (FieldDecl *FD = (*I)->getMember()) {
-      LValue Subobject = This;
       HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout);
       if (RD->isUnion()) {
         Result = APValue(FD);
-        if (!EvaluateConstantExpression(Result.getUnionValue(), Info, Subobject,
-                                        (*I)->getInit(), CCEK_MemberInit))
-          return false;
-      } else if (!EvaluateConstantExpression(
-                   Result.getStructField(FD->getFieldIndex()),
-                   Info, Subobject, (*I)->getInit(), CCEK_MemberInit))
-        return false;
+        Value = &Result.getUnionValue();
+      } else {
+        Value = &Result.getStructField(FD->getFieldIndex());
+      }
     } else if (IndirectFieldDecl *IFD = (*I)->getIndirectMember()) {
-      LValue Subobject = This;
-      APValue *Value = &Result;
       // Walk the indirect field decl's chain to find the object to initialize,
       // and make sure we've initialized every step along it.
       for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
@@ -1935,21 +2011,28 @@
             *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
                              std::distance(CD->field_begin(), CD->field_end()));
         }
+        HandleLValueMember(Info, (*I)->getInit(), Subobject, FD);
         if (CD->isUnion())
           Value = &Value->getUnionValue();
         else
           Value = &Value->getStructField(FD->getFieldIndex());
-        HandleLValueMember(Info, (*I)->getInit(), Subobject, FD);
       }
-      if (!EvaluateConstantExpression(*Value, Info, Subobject, (*I)->getInit(),
-                                      CCEK_MemberInit))
-        return false;
     } else {
       llvm_unreachable("unknown base initializer kind");
     }
+
+    if (!EvaluateConstantExpression(*Value, Info, Subobject, (*I)->getInit(),
+                                    (*I)->isBaseInitializer()
+                                      ? CCEK_Constant : CCEK_MemberInit)) {
+      // If we're checking for a potential constant expression, evaluate all
+      // initializers even if some of them fail.
+      if (!Info.keepEvaluatingAfterFailure())
+        return false;
+      Success = false;
+    }
   }
 
-  return true;
+  return Success;
 }
 
 namespace {
@@ -2258,7 +2341,8 @@
     APValue Result;
 
     if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) ||
-        !HandleFunctionCall(E, Definition, This, Args, Body, Info, Result))
+        !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body,
+                            Info, Result))
       return false;
 
     return DerivedSuccess(CCValue(Info.Ctx, Result, CCValue::GlobalValue()), E);
@@ -2703,11 +2787,12 @@
   if (IExp->getType()->isPointerType())
     std::swap(PExp, IExp);
 
-  if (!EvaluatePointer(PExp, Result, Info))
+  bool EvalPtrOK = EvaluatePointer(PExp, Result, Info);
+  if (!EvalPtrOK && !Info.keepEvaluatingAfterFailure())
     return false;
 
   llvm::APSInt Offset;
-  if (!EvaluateInteger(IExp, Offset, Info))
+  if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
     return false;
   int64_t AdditionalOffset
     = Offset.isSigned() ? Offset.getSExtValue()
@@ -3076,6 +3161,7 @@
   Result = APValue(APValue::UninitStruct(), 0,
                    std::distance(RD->field_begin(), RD->field_end()));
   unsigned ElementNo = 0;
+  bool Success = true;
   for (RecordDecl::field_iterator Field = RD->field_begin(),
        FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
     // Anonymous bit-fields are not considered members of the class for
@@ -3085,26 +3171,27 @@
 
     LValue Subobject = This;
 
-    if (ElementNo < E->getNumInits()) {
-      HandleLValueMember(Info, E->getInit(ElementNo), Subobject, *Field,
-                         &Layout);
-      if (!EvaluateConstantExpression(
-            Result.getStructField((*Field)->getFieldIndex()),
-            Info, Subobject, E->getInit(ElementNo++)))
-        return false;
-    } else {
-      // Perform an implicit value-initialization for members beyond the end of
-      // the initializer list.
-      HandleLValueMember(Info, E, Subobject, *Field, &Layout);
-      ImplicitValueInitExpr VIE(Field->getType());
-      if (!EvaluateConstantExpression(
-            Result.getStructField((*Field)->getFieldIndex()),
-            Info, Subobject, &VIE))
+    bool HaveInit = ElementNo < E->getNumInits();
+
+    // FIXME: Diagnostics here should point to the end of the initializer
+    // list, not the start.
+    HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E, Subobject,
+                       *Field, &Layout);
+
+    // Perform an implicit value-initialization for members beyond the end of
+    // the initializer list.
+    ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
+
+    if (!EvaluateConstantExpression(
+          Result.getStructField((*Field)->getFieldIndex()),
+          Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) {
+      if (!Info.keepEvaluatingAfterFailure())
         return false;
+      Success = false;
     }
   }
 
-  return true;
+  return Success;
 }
 
 bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
@@ -3143,7 +3230,7 @@
     return false;
 
   llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
-  return HandleConstructorCall(E, This, Args,
+  return HandleConstructorCall(E->getExprLoc(), This, Args,
                                cast<CXXConstructorDecl>(Definition), Info,
                                Result);
 }
@@ -3454,18 +3541,18 @@
     for (uint64_t I = 0; I < NumElements; ++I) {
       CCValue Char;
       if (!HandleLValueToRValueConversion(Info, E->getInit(0),
-                                          CAT->getElementType(), LV, Char))
-        return false;
-      if (!CheckConstantExpression(Info, E->getInit(0), Char,
-                                   Result.getArrayInitializedElt(I)))
-        return false;
-      if (!HandleLValueArrayAdjustment(Info, E->getInit(0), LV,
+                                          CAT->getElementType(), LV, Char) ||
+          !CheckConstantExpression(Info, E->getInit(0), Char,
+                                   Result.getArrayInitializedElt(I)) ||
+          !HandleLValueArrayAdjustment(Info, E->getInit(0), LV,
                                        CAT->getElementType(), 1))
         return false;
     }
     return true;
   }
 
+  bool Success = true;
+
   Result = APValue(APValue::UninitArray(), E->getNumInits(),
                    CAT->getSize().getZExtValue());
   LValue Subobject = This;
@@ -3474,21 +3561,23 @@
   for (InitListExpr::const_iterator I = E->begin(), End = E->end();
        I != End; ++I, ++Index) {
     if (!EvaluateConstantExpression(Result.getArrayInitializedElt(Index),
-                                    Info, Subobject, cast<Expr>(*I)))
-      return false;
-    if (!HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject,
-                                     CAT->getElementType(), 1))
-      return false;
+                                    Info, Subobject, cast<Expr>(*I)) ||
+        !HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject,
+                                     CAT->getElementType(), 1)) {
+      if (!Info.keepEvaluatingAfterFailure())
+        return false;
+      Success = false;
+    }
   }
 
-  if (!Result.hasArrayFiller()) return true;
+  if (!Result.hasArrayFiller()) return Success;
   assert(E->hasArrayFiller() && "no array filler for incomplete init list");
   // FIXME: The Subobject here isn't necessarily right. This rarely matters,
   // but sometimes does:
   //   struct S { constexpr S() : p(&p) {} void *p; };
   //   S s[10] = {};
   return EvaluateConstantExpression(Result.getArrayFiller(), Info,
-                                    Subobject, E->getArrayFiller());
+                                    Subobject, E->getArrayFiller()) && Success;
 }
 
 bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
@@ -3548,7 +3637,7 @@
   }
 
   llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
-  return HandleConstructorCall(E, Subobject, Args,
+  return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
                                cast<CXXConstructorDecl>(Definition),
                                Info, Result.getArrayFiller());
 }
@@ -4072,10 +4161,11 @@
     assert(RHSTy->isAnyComplexType() && "Invalid comparison");
     ComplexValue LHS, RHS;
 
-    if (!EvaluateComplex(E->getLHS(), LHS, Info))
+    bool LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+    if (!LHSOK && !Info.keepEvaluatingAfterFailure())
       return false;
 
-    if (!EvaluateComplex(E->getRHS(), RHS, Info))
+    if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
       return false;
 
     if (LHS.isComplexFloat()) {
@@ -4114,10 +4204,11 @@
       RHSTy->isRealFloatingType()) {
     APFloat RHS(0.0), LHS(0.0);
 
-    if (!EvaluateFloat(E->getRHS(), RHS, Info))
+    bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info);
+    if (!LHSOK && !Info.keepEvaluatingAfterFailure())
       return false;
 
-    if (!EvaluateFloat(E->getLHS(), LHS, Info))
+    if (!EvaluateFloat(E->getLHS(), LHS, Info) || !LHSOK)
       return false;
 
     APFloat::cmpResult CR = LHS.compare(RHS);
@@ -4145,12 +4236,13 @@
 
   if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
     if (E->getOpcode() == BO_Sub || E->isComparisonOp()) {
-      LValue LHSValue;
-      if (!EvaluatePointer(E->getLHS(), LHSValue, Info))
+      LValue LHSValue, RHSValue;
+
+      bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info);
+      if (!LHSOK && Info.keepEvaluatingAfterFailure())
         return false;
 
-      LValue RHSValue;
-      if (!EvaluatePointer(E->getRHS(), RHSValue, Info))
+      if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK)
         return false;
 
       // Reject differing bases from the normal codepath; we special-case
@@ -4241,11 +4333,14 @@
 
   // The LHS of a constant expr is always evaluated and needed.
   CCValue LHSVal;
-  if (!EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info))
+
+  bool LHSOK = EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info);
+  if (!LHSOK && !Info.keepEvaluatingAfterFailure())
     return false;
 
-  if (!Visit(E->getRHS()))
+  if (!Visit(E->getRHS()) || !LHSOK)
     return false;
+
   CCValue &RHSVal = Result;
 
   // Handle cases like (unsigned long)&a + 4.
@@ -4860,9 +4955,10 @@
     return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
 
   APFloat RHS(0.0);
-  if (!EvaluateFloat(E->getLHS(), Result, Info))
+  bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info);
+  if (!LHSOK && !Info.keepEvaluatingAfterFailure())
     return false;
-  if (!EvaluateFloat(E->getRHS(), RHS, Info))
+  if (!EvaluateFloat(E->getRHS(), RHS, Info) || !LHSOK)
     return false;
 
   switch (E->getOpcode()) {
@@ -5131,11 +5227,12 @@
   if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
     return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
 
-  if (!Visit(E->getLHS()))
+  bool LHSOK = Visit(E->getLHS());
+  if (!LHSOK && !Info.keepEvaluatingAfterFailure())
     return false;
 
   ComplexValue RHS;
-  if (!EvaluateComplex(E->getRHS(), RHS, Info))
+  if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
     return false;
 
   assert(Result.isComplexFloat() == RHS.isComplexFloat() &&
@@ -6030,3 +6127,41 @@
 
   return IsConstExpr;
 }
+
+bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
+                                   llvm::SmallVectorImpl<
+                                     PartialDiagnosticAt> &Diags) {
+  // FIXME: It would be useful to check constexpr function templates, but at the
+  // moment the constant expression evaluator cannot cope with the non-rigorous
+  // ASTs which we build for dependent expressions.
+  if (FD->isDependentContext())
+    return true;
+
+  Expr::EvalStatus Status;
+  Status.Diag = &Diags;
+
+  EvalInfo Info(FD->getASTContext(), Status);
+  Info.CheckingPotentialConstantExpression = true;
+
+  const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+  const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : 0;
+
+  // FIXME: Fabricate an arbitrary expression on the stack and pretend that it
+  // is a temporary being used as the 'this' pointer.
+  LValue This;
+  ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy);
+  This.set(&VIE, Info.CurrentCall);
+
+  APValue Scratch;
+  ArrayRef<const Expr*> Args;
+
+  SourceLocation Loc = FD->getLocation();
+
+  if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+    HandleConstructorCall(Loc, This, Args, CD, Info, Scratch);
+  } else
+    HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : 0,
+                       Args, FD->getBody(), Info, Scratch);
+
+  return Diags.empty();
+}

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jan 26 19:14:48 2012
@@ -972,6 +972,15 @@
     }
   }
 
+  llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+  if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
+    Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr)
+      << isa<CXXConstructorDecl>(Dcl);
+    for (size_t I = 0, N = Diags.size(); I != N; ++I)
+      Diag(Diags[I].first, Diags[I].second);
+    return false;
+  }
+
   return true;
 }
 

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp Thu Jan 26 19:14:48 2012
@@ -127,3 +127,15 @@
 //    return value shall be one of those allowed in a constant expression.
 //
 // We implement the proposed resolution of DR1364 and ignore this bullet.
+// However, we implement the spirit of the check as part of the p5 checking that
+// a constexpr function must be able to produce a constant expression.
+namespace DR1364 {
+  constexpr int f(int k) {
+    return k; // ok, even though lvalue-to-rvalue conversion of a function
+              // parameter is not allowed in a constant expression.
+  }
+  int kGlobal; // expected-note {{here}}
+  constexpr int f() { // expected-error {{constexpr function never produces a constant expression}}
+    return kGlobal; // expected-note {{read of non-const}}
+  }
+}

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp Thu Jan 26 19:14:48 2012
@@ -14,6 +14,7 @@
 };
 struct Literal {
   constexpr Literal() {}
+  explicit Literal(int); // expected-note 2 {{here}}
   operator int() const { return 0; }
 };
 
@@ -190,9 +191,17 @@
 
 // - every constructor involved in initializing non-static data members and base
 //   class sub-objects shall be a constexpr constructor.
-//
-// FIXME: Implement this as part of the 'must be able to produce a constant
-// expression' rules.
+struct ConstexprBaseMemberCtors : Literal {
+  Literal l;
+
+  constexpr ConstexprBaseMemberCtors() : Literal(), l() {} // ok
+  constexpr ConstexprBaseMemberCtors(char) : // expected-error {{constexpr constructor never produces a constant expression}}
+    Literal(0), // expected-note {{non-constexpr constructor}}
+    l() {}
+  constexpr ConstexprBaseMemberCtors(double) : Literal(), // expected-error {{constexpr constructor never produces a constant expression}}
+    l(0) // expected-note {{non-constexpr constructor}}
+  {}
+};
 
 // - every assignment-expression that is an initializer-caluse appearing
 //   directly or indirectly within a brace-or-equal-initializer for a non-static
@@ -215,6 +224,14 @@
 //    expression.
 //
 // We implement the proposed resolution of DR1364 and ignore this bullet.
+// However, we implement the intent of this wording as part of the p5 check that
+// the function must be able to produce a constant expression.
+int kGlobal; // expected-note {{here}}
+struct Z {
+  constexpr Z(int a) : n(a) {}
+  constexpr Z() : n(kGlobal) {} // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
+  int n;
+};
 
 
 namespace StdExample {

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp Thu Jan 26 19:14:48 2012
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
 
 namespace StdExample {
 
@@ -15,18 +15,61 @@
 constexpr int c = 0;
 constexpr int g4() { return N::h(); }
 
-// FIXME: constexpr calls aren't recognized as ICEs yet, just as foldable.
-#define JOIN2(a, b) a ## b
-#define JOIN(a, b) JOIN2(a, b)
-#define CHECK(n, m) using JOIN(A, __LINE__) = int[n]; using JOIN(A, __LINE__) = int[m];
-CHECK(f(0), 0)
-CHECK(f('0'), 1)
-CHECK(g1(), 0)
-CHECK(g2(0), 1)
-CHECK(g2(1), 1)
-CHECK(g3(0), 1)
-CHECK(g3(1), 1)
-CHECK(N::h(), 5)
-CHECK(g4(), 5)
+static_assert(f(0) == 0, "");
+static_assert(f('0') == 1, "");
+static_assert(g1() == 0, "");
+static_assert(g2(0) == 1, "");
+static_assert(g2(1) == 1, "");
+static_assert(g3(0) == 1, "");
+static_assert(g3(1) == 1, "");
+static_assert(N::h() == 5, "");
+static_assert(g4() == 5, "");
+
+
+constexpr int f(bool b)
+  { return b ? throw 0 : 0; } // ok
+constexpr int f() { return throw 0, 0; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{subexpression}}
+
+struct B {
+  constexpr B(int x) : i(0) { }
+  int i;
+};
+
+int global; // expected-note {{declared here}}
+
+struct D : B {
+  constexpr D() : B(global) { } // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
+};
+
+}
+
+namespace PotentialConstant {
+
+constexpr int Comma(int n) { return // expected-error {{constexpr function never produces a constant expression}}
+  (void)(n * 2),
+  throw 0, // expected-note {{subexpression}}
+  0;
+}
+
+int ng; // expected-note 5{{here}}
+constexpr int BinaryOp1(int n) { return n + ng; } // expected-error {{never produces}} expected-note {{read}}
+constexpr int BinaryOp2(int n) { return ng + n; } // expected-error {{never produces}} expected-note {{read}}
+
+double dg; // expected-note 2{{here}}
+constexpr double BinaryOp1(double d) { return d + dg; } // expected-error {{never produces}} expected-note {{read}}
+constexpr double BinaryOp2(double d) { return dg + d; } // expected-error {{never produces}} expected-note {{read}}
+
+constexpr int Add(int a, int b, int c) { return a + b + c; }
+constexpr int FunctionArgs(int a) { return Add(a, ng, a); } // expected-error {{never produces}} expected-note {{read}}
+
+struct S { int a; int b; int c[2]; };
+constexpr S InitList(int a) { return { a, ng }; }; // expected-error {{never produces}} expected-note {{read}}
+constexpr S InitList2(int a) { return { a, a, { ng } }; }; // expected-error {{never produces}} expected-note {{read}}
+
+constexpr S InitList3(int a) { return a ? (S){ a, a } : (S){ a, ng }; }; // ok
+
+// FIXME: Check both arms of a ?: if the conditional is a potential constant
+// expression with an unknown value, and diagnose if neither is constant.
+constexpr S InitList4(int a) { return a ? (S){ a, ng } : (S){ a, ng }; };
 
 }

Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp Thu Jan 26 19:14:48 2012
@@ -190,8 +190,8 @@
 
 namespace CrossFuncLabelDiff {
   // Make sure we refuse to constant-fold the variable b.
-  constexpr long a() { return (long)&&lbl + (0 && ({lbl: 0;})); }
-  void test() { static long b = (long)&&lbl - a(); lbl: return; }
+  constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); }
+  void test() { static long b = (long)&&lbl - a(false); lbl: return; }
   // CHECK: sub nsw i64 ptrtoint (i8* blockaddress(@_ZN18CrossFuncLabelDiff4testEv, {{.*}}) to i64),
   // CHECK: store i64 {{.*}}, i64* @_ZZN18CrossFuncLabelDiff4testEvE1b, align 8
 }

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=149108&r1=149107&r2=149108&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Jan 26 19:14:48 2012
@@ -206,7 +206,9 @@
   constexpr int b = MaybeReturnNonstaticRef(true, 0); // expected-error {{constant expression}} expected-note {{in call to 'MaybeReturnNonstaticRef(1, 0)'}}
 
   constexpr int InternalReturnJunk(int n) {
-    // FIXME: We should reject this: it never produces a constant expression.
+    // TODO: We could reject this: it never produces a constant expression.
+    // However, we currently don't evaluate function calls while testing for
+    // potential constant expressions, for performance.
     return MaybeReturnJunk(true, n); // expected-note {{in call to 'MaybeReturnJunk(1, 0)'}}
   }
   constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'InternalReturnJunk(0)'}}
@@ -969,10 +971,9 @@
   struct B { B(); A& x; };
   static_assert(B().x == 3, "");  // expected-error {{constant expression}} expected-note {{non-literal type 'PR11595::B' cannot be used in a constant expression}}
 
-  constexpr bool f(int k) {
+  constexpr bool f(int k) { // expected-error {{constexpr function never produces a constant expression}}
     return B().x == k; // expected-note {{non-literal type 'PR11595::B' cannot be used in a constant expression}}
   }
-  constexpr int n = f(1); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'f(1)'}}
 }
 
 namespace ExprWithCleanups {





More information about the cfe-commits mailing list