[cfe-commits] r146479 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/Basic/DiagnosticASTKinds.td include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp test/CXX/expr/expr.const/p2-0x.cpp test/SemaCXX/constant-expression-cxx11.cpp test/SemaCXX/enum-bitfield.cpp

Richard Smith richard-llvm at metafoo.co.uk
Mon Dec 12 22:39:58 PST 2011


Author: rsmith
Date: Tue Dec 13 00:39:58 2011
New Revision: 146479

URL: http://llvm.org/viewvc/llvm-project?rev=146479&view=rev
Log:
Add checks and diagnostics for many of the cases which C++11 considers to not
be constant expressions.

Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/enum-bitfield.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Dec 13 00:39:58 2011
@@ -3162,6 +3162,12 @@
                   DiagnosticsEngine::ak_nameddecl);
   return DB;
 }
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+                                           const NamedDecl* ND) {
+  PD.AddTaggedVal(reinterpret_cast<intptr_t>(ND),
+                  DiagnosticsEngine::ak_nameddecl);
+  return PD;
+}
 
 template<typename decl_type>
 void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Tue Dec 13 00:39:58 2011
@@ -15,6 +15,24 @@
 def note_constexpr_invalid_cast : Note<
   "%select{reinterpret_cast|dynamic_cast|cast which performs the conversions of"
   " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">;
+def note_constexpr_overflow : Note<
+  "value %0 is outside the range of representable values of type %1">;
+def note_constexpr_invalid_function : Note<
+  "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
+  "be used in a constant expression">;
+def note_constexpr_nonliteral : Note<
+  "non-literal type %0 cannot be used in a constant expression">;
+def note_constexpr_non_global : Note<
+  "%select{pointer|reference}0 to %select{|subobject of }1"
+  "%select{temporary|%4}2 %select{is not a constant expression|"
+  "cannot be returned from a constexpr function|"
+  "cannot be used to initialize a member in a constant expression}3">;
+def note_constexpr_past_end : Note<
+  "dereferenced pointer past the end of %select{|subobject of}0 "
+  "%select{temporary|%2}1 is not a constant expression">;
+def note_constexpr_temporary_here : Note<"temporary created here">;
+def note_constexpr_depth_limit_exceeded : Note<
+  "constexpr evaluation exceeded maximum depth of %0 calls">;
 
 // inline asm related.
 let CategoryName = "Inline Assembly Issue" in {

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Tue Dec 13 00:39:58 2011
@@ -18,6 +18,7 @@
 def fatal_too_many_errors
   : Error<"too many errors emitted, stopping now">, DefaultFatal; 
 
+def note_declared_at : Note<"declared here">;
 def note_previous_definition : Note<"previous definition is here">;
 def note_previous_declaration : Note<"previous declaration is here">;
 def note_previous_implicit_declaration : Note<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Dec 13 00:39:58 2011
@@ -485,7 +485,6 @@
   "multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore;
 def warn_accessor_property_type_mismatch : Warning<
   "type of property %0 does not match type of accessor %1">;
-def note_declared_at : Note<"declared here">;
 def note_method_declared_at : Note<"method declared here">;
 def err_setter_type_void : Error<"type of setter must be void">;
 def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Dec 13 00:39:58 2011
@@ -293,11 +293,15 @@
     /// declaration whose initializer is being evaluated, if any.
     APValue *EvaluatingDeclValue;
 
+    /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
+    /// notes attached to it will also be stored, otherwise they will not be.
+    bool HasActiveDiagnostic;
+
 
     EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
       : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
         CallStackDepth(0), BottomFrame(*this, 0, 0), EvaluatingDecl(0),
-        EvaluatingDeclValue(0) {}
+        EvaluatingDeclValue(0), HasActiveDiagnostic(false) {}
 
     const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const {
       MapTy::const_iterator i = OpaqueValues.find(e);
@@ -312,33 +316,55 @@
 
     const LangOptions &getLangOpts() const { return Ctx.getLangOptions(); }
 
-    bool atCallLimit() const {
-      return CallStackDepth > getLangOpts().ConstexprCallDepth;
+    bool CheckCallLimit(SourceLocation Loc) {
+      if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
+        return true;
+      Diag(Loc, diag::note_constexpr_depth_limit_exceeded)
+        << getLangOpts().ConstexprCallDepth;
+      return false;
     }
 
+  private:
+    /// Add a diagnostic to the diagnostics list.
+    PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
+      PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
+      EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
+      return EvalStatus.Diag->back().second;
+    }
+
+  public:
     /// Diagnose that the evaluation cannot be folded.
-    OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId) {
+    OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId,
+                            unsigned ExtraNotes = 0) {
       // 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.
       if (EvalStatus.Diag) {
+        HasActiveDiagnostic = true;
         EvalStatus.Diag->clear();
-        EvalStatus.Diag->reserve(1);
-        PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
-        EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
+        EvalStatus.Diag->reserve(1 + ExtraNotes);
         // FIXME: Add a call stack for constexpr evaluation.
-        return OptionalDiagnostic(&EvalStatus.Diag->back().second);
+        return OptionalDiagnostic(&addDiag(Loc, DiagId));
       }
+      HasActiveDiagnostic = false;
       return OptionalDiagnostic();
     }
 
     /// Diagnose that the evaluation does not produce a C++11 core constant
     /// expression.
-    OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId) {
+    OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId,
+                               unsigned ExtraNotes = 0) {
       // Don't override a previous diagnostic.
       if (!EvalStatus.Diag || !EvalStatus.Diag->empty())
         return OptionalDiagnostic();
-      return Diag(Loc, DiagId);
+      return Diag(Loc, DiagId, ExtraNotes);
+    }
+
+    /// Add a note to a prior diagnostic.
+    OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId) {
+      if (!HasActiveDiagnostic)
+        return OptionalDiagnostic();
+      return OptionalDiagnostic(&addDiag(Loc, DiagId));
     }
   };
 
@@ -515,11 +541,20 @@
       return castBack(Base);
     }
   };
+
+  /// Kinds of constant expression checking, for diagnostics.
+  enum CheckConstantExpressionKind {
+    CCEK_Constant,    ///< A normal constant.
+    CCEK_ReturnValue, ///< A constexpr function return value.
+    CCEK_MemberInit   ///< A constexpr constructor mem-initializer.
+  };
 }
 
 static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E);
 static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
-                                       const LValue &This, const Expr *E);
+                                       const LValue &This, const Expr *E,
+                                       CheckConstantExpressionKind CCEK
+                                        = CCEK_Constant);
 static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
@@ -586,22 +621,53 @@
 /// value for a constant expression. Type T should be either LValue or CCValue.
 template<typename T>
 static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
-                                          const T &LVal, APValue &Value) {
-  if (!IsGlobalLValue(LVal.getLValueBase())) {
-    Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+                                          const T &LVal, APValue &Value,
+                                          CheckConstantExpressionKind CCEK) {
+  APValue::LValueBase Base = LVal.getLValueBase();
+  const SubobjectDesignator &Designator = LVal.getLValueDesignator();
+
+  if (!IsGlobalLValue(Base)) {
+    if (Info.getLangOpts().CPlusPlus0x) {
+      const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+      Info.Diag(E->getExprLoc(), diag::note_constexpr_non_global, 1)
+        << E->isGLValue() << !Designator.Entries.empty()
+        << !!VD << CCEK << VD;
+      if (VD)
+        Info.Note(VD->getLocation(), diag::note_declared_at);
+      else
+        Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+                  diag::note_constexpr_temporary_here);
+    } else {
+      Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+    }
     return false;
   }
 
-  const SubobjectDesignator &Designator = LVal.getLValueDesignator();
   // A constant expression must refer to an object or be a null pointer.
   if (Designator.Invalid ||
       (!LVal.getLValueBase() && !Designator.Entries.empty())) {
-    // FIXME: This is not a constant expression.
+    // FIXME: This is not a core constant expression. We should have already
+    // produced a CCE diagnostic.
     Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
                     APValue::NoLValuePath());
     return true;
   }
 
+  // Does this refer one past the end of some object?
+  // This is technically not an address constant expression nor a reference
+  // constant expression, but we allow it for address constant expressions.
+  if (E->isGLValue() && Base && Designator.OnePastTheEnd) {
+    const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+    Info.Diag(E->getExprLoc(), diag::note_constexpr_past_end, 1)
+      << !Designator.Entries.empty() << !!VD << VD;
+    if (VD)
+      Info.Note(VD->getLocation(), diag::note_declared_at);
+    else
+      Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+                diag::note_constexpr_temporary_here);
+    return false;
+  }
+
   Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
                   Designator.Entries, Designator.OnePastTheEnd);
   return true;
@@ -611,12 +677,14 @@
 /// constant expression, and if it is, produce the corresponding constant value.
 /// If not, report an appropriate diagnostic.
 static bool CheckConstantExpression(EvalInfo &Info, const Expr *E,
-                                    const CCValue &CCValue, APValue &Value) {
+                                    const CCValue &CCValue, APValue &Value,
+                                    CheckConstantExpressionKind CCEK
+                                      = CCEK_Constant) {
   if (!CCValue.isLValue()) {
     Value = CCValue;
     return true;
   }
-  return CheckLValueConstantExpression(Info, E, CCValue, Value);
+  return CheckLValueConstantExpression(Info, E, CCValue, Value, CCEK);
 }
 
 const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
@@ -693,26 +761,41 @@
   return HandleConversionToBool(Val, Result);
 }
 
-static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
-                                   APFloat &Value, const ASTContext &Ctx) {
-  unsigned DestWidth = Ctx.getIntWidth(DestType);
+template<typename T>
+static bool HandleOverflow(EvalInfo &Info, const Expr *E,
+                           const T &SrcValue, QualType DestType) {
+  llvm::SmallVector<char, 32> Buffer;
+  SrcValue.toString(Buffer);
+  Info.Diag(E->getExprLoc(), diag::note_constexpr_overflow)
+    << StringRef(Buffer.data(), Buffer.size()) << DestType;
+  return false;
+}
+
+static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
+                                 QualType SrcType, const APFloat &Value,
+                                 QualType DestType, APSInt &Result) {
+  unsigned DestWidth = Info.Ctx.getIntWidth(DestType);
   // Determine whether we are converting to unsigned or signed.
   bool DestSigned = DestType->isSignedIntegerOrEnumerationType();
 
-  // FIXME: Warning for overflow.
-  APSInt Result(DestWidth, !DestSigned);
+  Result = APSInt(DestWidth, !DestSigned);
   bool ignored;
-  (void)Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored);
-  return Result;
+  if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
+      & APFloat::opInvalidOp)
+    return HandleOverflow(Info, E, Value, DestType);
+  return true;
 }
 
-static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
-                                      APFloat &Value, const ASTContext &Ctx) {
+static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
+                                   QualType SrcType, QualType DestType,
+                                   APFloat &Result) {
+  APFloat Value = Result;
   bool ignored;
-  APFloat Result = Value;
-  Result.convert(Ctx.getFloatTypeSemantics(DestType),
-                 APFloat::rmNearestTiesToEven, &ignored);
-  return Result;
+  if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
+                     APFloat::rmNearestTiesToEven, &ignored)
+      & APFloat::opOverflow)
+    return HandleOverflow(Info, E, Value, DestType);
+  return true;
 }
 
 static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
@@ -726,13 +809,15 @@
   return Result;
 }
 
-static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
-                                    APSInt &Value, const ASTContext &Ctx) {
-
-  APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1);
-  Result.convertFromAPInt(Value, Value.isSigned(),
-                          APFloat::rmNearestTiesToEven);
-  return Result;
+static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
+                                 QualType SrcType, const APSInt &Value,
+                                 QualType DestType, APFloat &Result) {
+  Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
+  if (Result.convertFromAPInt(Value, Value.isSigned(),
+                              APFloat::rmNearestTiesToEven)
+      & APFloat::opOverflow)
+    return HandleOverflow(Info, E, Value, DestType);
+  return true;
 }
 
 static bool FindMostDerivedObject(EvalInfo &Info, const LValue &LVal,
@@ -1311,7 +1396,7 @@
 }
 
 // Evaluate a statement.
-static EvalStmtResult EvaluateStmt(CCValue &Result, EvalInfo &Info,
+static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
                                    const Stmt *S) {
   switch (S->getStmtClass()) {
   default:
@@ -1321,10 +1406,15 @@
   case Stmt::DeclStmtClass:
     return ESR_Succeeded;
 
-  case Stmt::ReturnStmtClass:
-    if (Evaluate(Result, Info, cast<ReturnStmt>(S)->getRetValue()))
-      return ESR_Returned;
-    return ESR_Failed;
+  case Stmt::ReturnStmtClass: {
+    CCValue CCResult;
+    const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
+    if (!Evaluate(CCResult, Info, RetExpr) ||
+        !CheckConstantExpression(Info, RetExpr, CCResult, Result,
+                                 CCEK_ReturnValue))
+      return ESR_Failed;
+    return ESR_Returned;
+  }
 
   case Stmt::CompoundStmtClass: {
     const CompoundStmt *CS = cast<CompoundStmt>(S);
@@ -1339,6 +1429,27 @@
   }
 }
 
+/// CheckConstexprFunction - Check that a function can be called in a constant
+/// expression.
+static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
+                                   const FunctionDecl *Declaration,
+                                   const FunctionDecl *Definition) {
+  // Can we evaluate this function call?
+  if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
+    return true;
+
+  if (Info.getLangOpts().CPlusPlus0x) {
+    const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
+    Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1)
+      << DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl)
+      << DiagDecl;
+    Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
+  } else {
+    Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
+  }
+  return false;
+}
+
 namespace {
 typedef SmallVector<CCValue, 8> ArgVector;
 }
@@ -1356,12 +1467,9 @@
 /// Evaluate a function call.
 static bool HandleFunctionCall(const Expr *CallExpr, const LValue *This,
                                ArrayRef<const Expr*> Args, const Stmt *Body,
-                               EvalInfo &Info, CCValue &Result) {
-  if (Info.atCallLimit()) {
-    // FIXME: Add a specific proper diagnostic for this.
-    Info.Diag(CallExpr->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+                               EvalInfo &Info, APValue &Result) {
+  if (!Info.CheckCallLimit(CallExpr->getExprLoc()))
     return false;
-  }
 
   ArgVector ArgValues(Args.size());
   if (!EvaluateArgs(Args, ArgValues, Info))
@@ -1377,11 +1485,8 @@
                                   const CXXConstructorDecl *Definition,
                                   EvalInfo &Info,
                                   APValue &Result) {
-  if (Info.atCallLimit()) {
-    // FIXME: Add a specific diagnostic for this.
-    Info.Diag(CallExpr->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+  if (!Info.CheckCallLimit(CallExpr->getExprLoc()))
     return false;
-  }
 
   ArgVector ArgValues(Args.size());
   if (!EvaluateArgs(Args, ArgValues, Info))
@@ -1430,12 +1535,12 @@
       HandleLValueMember(Info, Subobject, FD, &Layout);
       if (RD->isUnion()) {
         Result = APValue(FD);
-        if (!EvaluateConstantExpression(Result.getUnionValue(), Info,
-                                        Subobject, (*I)->getInit()))
+        if (!EvaluateConstantExpression(Result.getUnionValue(), Info, Subobject,
+                                        (*I)->getInit(), CCEK_MemberInit))
           return false;
       } else if (!EvaluateConstantExpression(
                    Result.getStructField(FD->getFieldIndex()),
-                   Info, Subobject, (*I)->getInit()))
+                   Info, Subobject, (*I)->getInit(), CCEK_MemberInit))
         return false;
     } else {
       // FIXME: handle indirect field initializers
@@ -1745,16 +1850,12 @@
     } else
       return Error(E);
 
-    const FunctionDecl *Definition;
+    const FunctionDecl *Definition = 0;
     Stmt *Body = FD->getBody(Definition);
-    CCValue CCResult;
     APValue Result;
 
-    if (!Body || !Definition->isConstexpr() || Definition->isInvalidDecl())
-      return Error(E);
-
-    if (!HandleFunctionCall(E, This, Args, Body, Info, CCResult) ||
-        !CheckConstantExpression(Info, E, CCResult, Result))
+    if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) ||
+        !HandleFunctionCall(E, This, Args, Body, Info, Result))
       return false;
 
     return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E);
@@ -1878,6 +1979,10 @@
       if (!EvaluatePointer(E->getBase(), Result, this->Info))
         return false;
       BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
+    } else if (E->getBase()->isRValue()) {
+      if (!EvaluateTemporary(E->getBase(), Result, this->Info))
+        return false;
+      BaseTy = E->getBase()->getType();
     } else {
       if (!this->Visit(E->getBase()))
         return false;
@@ -2516,8 +2621,8 @@
   const FunctionDecl *Definition = 0;
   FD->getBody(Definition);
 
-  if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl())
-    return Error(E);
+  if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
+    return false;
 
   // FIXME: Elide the copy/move construction wherever we can.
   if (E->isElidable())
@@ -2837,8 +2942,8 @@
   const FunctionDecl *Definition = 0;
   FD->getBody(Definition);
 
-  if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl())
-    return Error(E);
+  if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
+    return false;
 
   // FIXME: The Subobject here isn't necessarily right. This rarely matters,
   // but sometimes does:
@@ -3881,7 +3986,10 @@
     if (!EvaluateFloat(SubExpr, F, Info))
       return false;
 
-    return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+    APSInt Value;
+    if (!HandleFloatToIntCast(Info, E, SrcType, F, DestType, Value))
+      return false;
+    return Success(Value, E);
   }
   }
 
@@ -4130,19 +4238,16 @@
 
   case CK_IntegralToFloating: {
     APSInt IntResult;
-    if (!EvaluateInteger(SubExpr, IntResult, Info))
-      return false;
-    Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(),
-                                  IntResult, Info.Ctx);
-    return true;
+    return EvaluateInteger(SubExpr, IntResult, Info) &&
+           HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult,
+                                E->getType(), Result);
   }
 
   case CK_FloatingCast: {
     if (!Visit(SubExpr))
       return false;
-    Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(),
-                                    Result, Info.Ctx);
-    return true;
+    return HandleFloatToFloatCast(Info, E, SubExpr->getType(), E->getType(),
+                                  Result);
   }
 
   case CK_FloatingComplexToReal: {
@@ -4289,11 +4394,8 @@
     QualType From
       = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
 
-    Result.FloatReal
-      = HandleFloatToFloatCast(To, From, Result.FloatReal, Info.Ctx);
-    Result.FloatImag
-      = HandleFloatToFloatCast(To, From, Result.FloatImag, Info.Ctx);
-    return true;
+    return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
+           HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
   }
 
   case CK_FloatingComplexToIntegralComplex: {
@@ -4304,9 +4406,10 @@
     QualType From
       = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
     Result.makeComplexInt();
-    Result.IntReal = HandleFloatToIntCast(To, From, Result.FloatReal, Info.Ctx);
-    Result.IntImag = HandleFloatToIntCast(To, From, Result.FloatImag, Info.Ctx);
-    return true;
+    return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
+                                To, Result.IntReal) &&
+           HandleFloatToIntCast(Info, E, From, Result.FloatImag,
+                                To, Result.IntImag);
   }
 
   case CK_IntegralRealToComplex: {
@@ -4340,9 +4443,10 @@
     QualType From
       = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
     Result.makeComplexFloat();
-    Result.FloatReal = HandleIntToFloatCast(To, From, Result.IntReal, Info.Ctx);
-    Result.FloatImag = HandleIntToFloatCast(To, From, Result.IntImag, Info.Ctx);
-    return true;
+    return HandleIntToFloatCast(Info, E, From, Result.IntReal,
+                                To, Result.FloatReal) &&
+           HandleIntToFloatCast(Info, E, From, Result.IntImag,
+                                To, Result.FloatImag);
   }
   }
 
@@ -4581,8 +4685,16 @@
       return false;
     Result = Info.CurrentCall->Temporaries[E];
   } else if (E->getType()->isVoidType()) {
+    if (Info.getLangOpts().CPlusPlus0x)
+      Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_nonliteral)
+        << E->getType();
+    else
+      Info.CCEDiag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
     if (!EvaluateVoid(E, Info))
       return false;
+  } else if (Info.getLangOpts().CPlusPlus0x) {
+    Info.Diag(E->getExprLoc(), diag::note_constexpr_nonliteral) << E->getType();
+    return false;
   } else {
     Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
     return false;
@@ -4596,7 +4708,8 @@
 /// since later initializers for an object can indirectly refer to subobjects
 /// which were initialized earlier.
 static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
-                                       const LValue &This, const Expr *E) {
+                                       const LValue &This, const Expr *E,
+                                       CheckConstantExpressionKind CCEK) {
   if (E->isRValue() && E->getType()->isLiteralType()) {
     // Evaluate arrays and record types in-place, so that later initializers can
     // refer to earlier-initialized members of the object.
@@ -4609,7 +4722,7 @@
   // For any other type, in-place evaluation is unimportant.
   CCValue CoreConstResult;
   return Evaluate(CoreConstResult, Info, E) &&
-         CheckConstantExpression(Info, E, CoreConstResult, Result);
+         CheckConstantExpression(Info, E, CoreConstResult, Result, CCEK);
 }
 
 /// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
@@ -4681,7 +4794,8 @@
 
   LValue LV;
   return EvaluateLValue(this, LV, Info) && !Result.HasSideEffects &&
-         CheckLValueConstantExpression(Info, this, LV, Result.Val);
+         CheckLValueConstantExpression(Info, this, LV, Result.Val,
+                                       CCEK_Constant);
 }
 
 /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be

Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Tue Dec 13 00:39:58 2011
@@ -1,4 +1,357 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -pedantic -verify -fcxx-exceptions %s
+
+// A conditional-expression is a core constant expression unless it involves one
+// of the following as a potentially evaluated subexpression [...]:
+
+// - this (5.1.1 [expr.prim.general]) [Note: when evaluating a constant
+//   expression, function invocation substitution (7.1.5 [dcl.constexpr])
+//   replaces each occurrence of this in a constexpr member function with a
+//   pointer to the class object. -end note];
+struct This {
+  int this1 : this1; // expected-error {{undeclared}}
+  int this2 : this->this1; // expected-error {{invalid}}
+  void this3() {
+    int n1[this->this1]; // expected-warning {{variable length array}}
+    int n2[this1]; // expected-warning {{variable length array}}
+    (void)n1, (void)n2;
+  }
+};
+
+// - an invocation of a function other than a constexpr constructor for a
+//   literal class or a constexpr function [ Note: Overload resolution (13.3)
+//   is applied as usual - end note ];
+struct NonConstexpr1 {
+  static int f() { return 1; } // expected-note {{here}}
+  int n : f(); // expected-error {{constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}}
+};
+struct NonConstexpr2 {
+  constexpr NonConstexpr2(); // expected-note {{here}}
+  int n;
+};
+struct NonConstexpr3 {
+  NonConstexpr3();
+  int m : NonConstexpr2().n; // expected-error {{constant expression}} expected-note {{undefined constructor 'NonConstexpr2'}}
+};
+struct NonConstexpr4 {
+  NonConstexpr4();
+  int n;
+};
+struct NonConstexpr5 {
+  int n : NonConstexpr4().n; // expected-error {{constant expression}} expected-note {{non-literal type 'NonConstexpr4' cannot be used in a constant expression}}
+};
+
+// - an invocation of an undefined constexpr function or an undefined
+//   constexpr constructor;
+struct UndefinedConstexpr {
+  constexpr UndefinedConstexpr();
+  static constexpr int undefinedConstexpr1(); // expected-note {{here}}
+  int undefinedConstexpr2 : undefinedConstexpr1(); // expected-error {{constant expression}} expected-note {{undefined function 'undefinedConstexpr1' cannot be used in a constant expression}}
+};
+
+// - an invocation of a constexpr function with arguments that, when substituted
+//   by function invocation substitution (7.1.5), do not produce a constant
+//   expression;
+namespace NonConstExprReturn {
+  static constexpr const int &id_ref(const int &n) {
+    return n; // expected-note {{reference to temporary cannot be returned from a constexpr function}}
+  }
+  struct NonConstExprFunction {
+    int n : id_ref( // expected-error {{constant expression}}
+        16 // expected-note {{temporary created here}}
+        );
+  };
+  constexpr const int *address_of(const int &a) {
+    return &a; // expected-note {{pointer to 'n' cannot be returned from a constexpr function}}
+  }
+  constexpr const int *return_param(int n) { // expected-note {{declared here}}
+    return address_of(n);
+  }
+  struct S {
+    int n : *return_param(0); // expected-error {{constant expression}}
+  };
+}
+
+// - an invocation of a constexpr constructor with arguments that, when
+//   substituted by function invocation substitution (7.1.5), do not produce all
+//   constant expressions for the constructor calls and full-expressions in the
+//   mem-initializers (including conversions);
+namespace NonConstExprCtor {
+  struct T {
+    constexpr T(const int &r) :
+      r(r) { // expected-note {{reference to temporary cannot be used to initialize a member in a constant expression}}
+    }
+    const int &r;
+  };
+  constexpr int n = 0;
+  constexpr T t1(n); // ok
+  constexpr T t2(0); // expected-error {{must be initialized by a constant expression}}
+
+  struct S {
+    int n : T(4).r; // expected-error {{constant expression}} expected-note {{temporary created here}}
+  };
+}
+
+// - an invocation of a constexpr function or a constexpr constructor that would
+//   exceed the implementation-defined recursion limits (see Annex B);
+namespace RecursionLimits {
+  constexpr int RecurseForever(int n) {
+    return n + RecurseForever(n+1); // expected-note {{constexpr evaluation exceeded maximum depth of 512 calls}}
+  }
+  struct AlsoRecurseForever {
+    constexpr AlsoRecurseForever(int n) :
+      n(AlsoRecurseForever(n+1).n) // expected-note {{constexpr evaluation exceeded maximum depth of 512 calls}}
+    {}
+    int n;
+  };
+  struct S {
+    int k : RecurseForever(0); // expected-error {{constant expression}}
+    int l : AlsoRecurseForever(0).n; // expected-error {{constant expression}}
+  };
+}
+
+// FIXME:
+// - an operation that would have undefined behavior [Note: including, for
+//   example, signed integer overflow (Clause 5 [expr]), certain pointer
+//   arithmetic (5.7 [expr.add]), division by zero (5.6 [expr.mul]), or certain
+//   shift operations (5.8 [expr.shift]) -end note];
+namespace UndefinedBehavior {
+  void f(int n) {
+    switch (n) {
+    case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}}
+    case (int)(unsigned)(long long)4.4e9: // ok
+    case (float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}}
+    case (int)((float)1e37 / 1e30): // ok
+    case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type 'half'}}
+      break;
+    }
+  }
+
+  struct S {
+    int m;
+  };
+  constexpr S s = { 5 }; // expected-note {{declared here}}
+  constexpr const int *p = &s.m + 1;
+  constexpr const int &f(const int *q) {
+    return q[0]; // expected-note {{dereferenced pointer past the end of subobject of 's' is not a constant expression}}
+  }
+  struct T {
+    int n : f(p); // expected-error {{not an integer constant expression}}
+  };
+}
+
+// - a lambda-expression (5.1.2);
+struct Lambda {
+  // FIXME: clang crashes when trying to parse this! Revisit this check once
+  // lambdas are fully implemented.
+  //int n : []{ return 1; }();
+};
+
+// FIXME:
+// - an lvalue-to-rvalue conversion (4.1) unless it is applied to
+//
+//   - a non-volatile glvalue of integral or enumeration type that refers to a
+//   non-volatile const object with a preceding initialization, initialized with
+//   a constant expression  [Note: a string literal (2.14.5 [lex.string])
+//   corresponds to an array of such objects. -end note], or
+//
+//   - a non-volatile glvalue of literal type that refers to a non-volatile
+//   object defined with constexpr, or that refers to a sub-object of such an
+//   object, or
+//
+//   - a non-volatile glvalue of literal type that refers to a non-volatile
+//   temporary object whose lifetime has not ended, initialized with a constant
+//   expression;
+
+// FIXME:
+//
+// DR1312: The proposed wording for this defect has issues, so we instead
+// prohibit casts from pointers to cv void (see core-20842 and core-20845).
+//
+// - an lvalue-to-rvalue conversion (4.1 [conv.lval]) that is applied to a
+// glvalue of type cv1 T that refers to an object of type cv2 U, where T and U
+// are neither the same type nor similar types (4.4 [conv.qual]);
+
+// FIXME:
+// - an lvalue-to-rvalue conversion (4.1) that is applied to a glvalue that
+// refers to a non-active member of a union or a subobject thereof;
+
+// FIXME:
+// - an id-expression that refers to a variable or data member of reference type
+//   unless the reference has a preceding initialization, initialized with a
+//   constant expression;
+namespace References {
+  const int a = 2;
+  int &b = *const_cast<int*>(&a);
+  int c = 10;
+  int &d = c;
+  constexpr int e = 42;
+  int &f = const_cast<int&>(e);
+  extern int &g;
+  constexpr int &h(); // expected-note {{here}}
+  int &i = h();
+  constexpr int &j() { return b; }
+  int &k = j();
+
+  struct S {
+    int A : a;
+    int B : b;
+    int C : c; // expected-error {{constant expression}}
+    int D : d; // expected-error {{constant expression}}
+    int D2 : &d - &c + 1;
+    int E : e / 2;
+    int F : f - 11;
+    int G : g; // expected-error {{constant expression}}
+    int H : h(); // expected-error {{constant expression}} expected-note {{undefined function 'h'}}
+    int I : i; // expected-error {{constant expression}}
+    int J : j();
+    int K : k;
+  };
+}
+
+// - a dynamic_cast (5.2.7);
+namespace DynamicCast {
+  struct S { int n; };
+  constexpr S s { 16 };
+  struct T {
+    int n : dynamic_cast<const S*>(&s)->n; // expected-warning {{constant expression}} expected-note {{dynamic_cast}}
+  };
+}
+
+// - a reinterpret_cast (5.2.10);
+namespace ReinterpretCast {
+  struct S { int n; };
+  constexpr S s { 16 };
+  struct T {
+    int n : reinterpret_cast<const S*>(&s)->n; // expected-warning {{constant expression}} expected-note {{reinterpret_cast}}
+  };
+  struct U {
+    int m : (long)(S*)6; // expected-warning {{constant expression}} expected-note {{reinterpret_cast}}
+  };
+}
+
+// - a pseudo-destructor call (5.2.4);
+namespace PseudoDtor {
+  int k;
+  typedef int I;
+  struct T {
+    int n : (k.~I(), 0); // expected-error {{constant expression}} expected-note{{subexpression}}
+  };
+}
+
+// - increment or decrement operations (5.2.6, 5.3.2);
+namespace IncDec {
+  int k = 2;
+  struct T {
+    int n : ++k; // expected-error {{constant expression}}
+    int m : --k; // expected-error {{constant expression}}
+  };
+}
+
+// - a typeid expression (5.2.8) whose operand is of a polymorphic class type;
+namespace std {
+  struct type_info {
+    virtual ~type_info();
+    const char *name;
+  };
+}
+namespace TypeId {
+  struct S { virtual void f(); };
+  constexpr S *p = 0;
+  constexpr const std::type_info &ti1 = typeid(*p); // expected-error {{must be initialized by a constant expression}}
+
+  // FIXME: Implement typeid evaluation.
+  struct T {} t;
+  constexpr const std::type_info &ti2 = typeid(t); // unexpected-error {{must be initialized by a constant expression}}
+}
+
+// - a new-expression (5.3.4);
+// - a delete-expression (5.3.5);
+namespace NewDelete {
+  int *p = 0;
+  struct T {
+    int n : *new int(4); // expected-error {{constant expression}} expected-note {{subexpression}}
+    int m : (delete p, 2); // expected-error {{constant expression}} expected-note {{subexpression}}
+  };
+}
+
+// - a relational (5.9) or equality (5.10) operator where the result is
+//   unspecified;
+namespace UnspecifiedRelations {
+  int a, b;
+  constexpr int *p = &a, *q = &b;
+  // C++11 [expr.rel]p2: If two pointers p and q of the same type point to
+  // different objects that are not members of the same array or to different
+  // functions, or if only one of them is null, the results of p<q, p>q, p<=q,
+  // and p>=q are unspecified.
+  constexpr bool u1 = p < q; // expected-error {{constant expression}}
+  constexpr bool u2 = p > q; // expected-error {{constant expression}}
+  constexpr bool u3 = p <= q; // expected-error {{constant expression}}
+  constexpr bool u4 = p >= q; // expected-error {{constant expression}}
+  constexpr bool u5 = p < 0; // expected-error {{constant expression}}
+  constexpr bool u6 = p <= 0; // expected-error {{constant expression}}
+  constexpr bool u7 = p > 0; // expected-error {{constant expression}}
+  constexpr bool u8 = p >= 0; // expected-error {{constant expression}}
+  constexpr bool u9 = 0 < q; // expected-error {{constant expression}}
+  constexpr bool u10 = 0 <= q; // expected-error {{constant expression}}
+  constexpr bool u11 = 0 > q; // expected-error {{constant expression}}
+  constexpr bool u12 = 0 >= q; // expected-error {{constant expression}}
+  void f(), g();
+
+  constexpr void (*pf)() = &f, (*pg)() = &g;
+  constexpr bool u13 = pf < pg; // expected-error {{constant expression}}
+  constexpr bool u14 = pf == pg;
+
+  // FIXME:
+  // If two pointers point to non-static data members of the same object with
+  // different access control, the result is unspecified.
+
+  // FIXME:
+  // [expr.rel]p3: Pointers to void can be compared [...] if both pointers
+  // represent the same address or are both the null pointer [...]; otherwise
+  // the result is unspecified.
+
+  // FIXME: Implement comparisons of pointers to members.
+  // [expr.eq]p2: If either is a pointer to a virtual member function and
+  // neither is null, the result is unspecified.
+}
+
+// - an assignment or a compound assignment (5.17); or
+namespace Assignment {
+  int k;
+  struct T {
+    int n : (k = 9); // expected-error {{constant expression}}
+    int m : (k *= 2); // expected-error {{constant expression}}
+  };
+
+  struct Literal {
+    constexpr Literal(const char *name) : name(name) {}
+    const char *name;
+  };
+  struct Expr {
+    constexpr Expr(Literal l) : IsLiteral(true), l(l) {}
+    bool IsLiteral;
+    union {
+      Literal l;
+      // ...
+    };
+  };
+  struct MulEq {
+    constexpr MulEq(Expr a, Expr b) : LHS(a), RHS(b) {}
+    Expr LHS;
+    Expr RHS;
+  };
+  constexpr MulEq operator*=(Expr a, Expr b) { return MulEq(a, b); }
+  Literal a("a");
+  Literal b("b");
+  MulEq c = a *= b; // ok
+}
+
+// - a throw-expression (15.1)
+namespace Throw {
+  struct S {
+    int n : (throw "hello", 10); // expected-error {{constant expression}} expected-note {{subexpression}}
+  };
+}
 
 // PR9999
 template<bool v>

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=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Dec 13 00:39:58 2011
@@ -10,7 +10,7 @@
 
 // FIXME: support const T& parameters here.
 //template<typename T> constexpr T id(const T &t) { return t; }
-template<typename T> constexpr T id(T t) { return t; }
+template<typename T> constexpr T id(T t) { return t; } // expected-note {{here}}
 // FIXME: support templates here.
 //template<typename T> constexpr T min(const T &a, const T &b) {
 //  return a < b ? a : b;
@@ -95,9 +95,9 @@
   void f(int n) {
     switch (n) {
     // FIXME: Produce the 'add ()' fixit for this.
-    case MemberZero().zero: // desired-error {{did you mean to call it with no arguments?}} expected-error {{not an integer constant expression}}
+    case MemberZero().zero: // desired-error {{did you mean to call it with no arguments?}} expected-error {{not an integer constant expression}} expected-note {{non-literal type '<bound member function type>'}}
     // FIXME: This should be accepted once we implement the new ICE rules.
-    case id(1): // expected-error {{not an integer constant expression}}
+    case id(1): // expected-error {{not an integer constant expression}} expected-note {{undefined function}}
       return;
     }
   }

Modified: cfe/trunk/test/SemaCXX/enum-bitfield.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-bitfield.cpp?rev=146479&r1=146478&r2=146479&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/enum-bitfield.cpp (original)
+++ cfe/trunk/test/SemaCXX/enum-bitfield.cpp Tue Dec 13 00:39:58 2011
@@ -2,7 +2,7 @@
 
 enum E {};
 
-struct Z {};
+struct Z {}; // expected-note {{here}}
 typedef int Integer;
 
 struct X {
@@ -14,5 +14,5 @@
 
 struct Y {
   enum E : int(2);
-  enum E : Z(); // expected-error{{not an integer constant}}
+  enum E : Z(); // expected-error{{not an integer constant}} expected-note {{non-constexpr constructor 'Z'}}
 };





More information about the cfe-commits mailing list