]> granicus.if.org Git - clang/commitdiff
constexpr: converted constant expression handling for enumerator values, case
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 18 Jan 2012 23:55:52 +0000 (23:55 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 18 Jan 2012 23:55:52 +0000 (23:55 +0000)
values and non-type template arguments of integral and enumeration types.

This change causes some legal C++98 code to no longer compile in C++11 mode, by
enforcing the C++11 rule that narrowing integral conversions are not permitted
in the final implicit conversion sequence for the above cases.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148439 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Overload.h
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/basic/basic.types/p10.cpp
test/CXX/expr/expr.const/p2-0x.cpp
test/CXX/expr/expr.const/p3-0x.cpp [new file with mode: 0644]
test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp [new file with mode: 0644]
test/CodeGenCXX/mangle-98.cpp [new file with mode: 0644]
test/CodeGenCXX/mangle.cpp
test/SemaCXX/constant-expression-cxx11.cpp
test/SemaCXX/enum-scoped.cpp

index 5f361cdf0d918a77c915f6e292206399ec5c441f..41e723722fdc3947e91477c563dc438eca7da6bb 100644 (file)
@@ -20,6 +20,17 @@ def err_expr_not_ice : Error<
 def ext_expr_not_ice : Extension<
   "expression is not an %select{integer|integral}0 constant expression; "
   "folding it to a constant is a GNU extension">, InGroup<GNU>;
+def err_typecheck_converted_constant_expression : Error<
+  "value of type %0 is not implicitly convertible to %1">;
+def err_typecheck_converted_constant_expression_disallowed : Error<
+  "conversion from %0 to %1 is not allowed in a converted constant expression">;
+def err_expr_not_cce : Error<
+  "%select{case value|enumerator value|non-type template argument}0 "
+  "is not a constant expression">;
+def err_cce_narrowing : Error<
+  "%select{case value|enumerator value|non-type template argument}0 "
+  "%select{cannot be narrowed from type %2 to %3|"
+  "evaluates to %2, which cannot be narrowed to type %3}1">;
 
 // Semantic analysis of constant literals.
 def ext_predef_outside_function : Warning<
index 9a3397d235186e997fcb6b4642943f4b6bf39fbf..d745b4befb59e8e7cb8083f8f302174492ce3ca9 100644 (file)
@@ -235,8 +235,8 @@ namespace clang {
     }
     
     ImplicitConversionRank getRank() const;
-    NarrowingKind isNarrowing(ASTContext &Context, const Expr *Converted,
-                              APValue &ConstantValue) const;
+    NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted,
+                                   APValue &ConstantValue) const;
     bool isPointerConversionToBool() const;
     bool isPointerConversionToVoidPointer(ASTContext& Context) const;
     void DebugPrint() const;
index 238b0edec6ac002963aa8a0ec7c66cb6ab4cc46f..c3bdad80dfa99347f154b85431df24d4141ab1f4 100644 (file)
@@ -1474,6 +1474,15 @@ public:
   ExprResult PerformContextuallyConvertToBool(Expr *From);
   ExprResult PerformContextuallyConvertToObjCPointer(Expr *From);
 
+  /// Contexts in which a converted constant expression is required.
+  enum CCEKind {
+    CCEK_CaseValue,  ///< Expression in a case label.
+    CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
+    CCEK_TemplateArg ///< Value of a non-type template parameter.
+  };
+  ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
+                                              llvm::APSInt &Value, CCEKind CCE);
+
   ExprResult
   ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE,
                                      const PartialDiagnostic &NotIntDiag,
index f2af0a7075e199016137c4128f7c952e4d8c8685..9dc00c36259196f9f6ea6285f14cc8192103afec 100644 (file)
@@ -9555,18 +9555,30 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
     if (Enum->isDependentType() || Val->isTypeDependent())
       EltTy = Context.DependentTy;
     else {
-      // C99 6.7.2.2p2: Make sure we have an integer constant expression.
       SourceLocation ExpLoc;
-      if (!Val->isValueDependent() &&
-          VerifyIntegerConstantExpression(Val, &EnumVal)) {
+      if (getLangOptions().CPlusPlus0x && Enum->isFixed()) {
+        // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
+        // constant-expression in the enumerator-definition shall be a converted
+        // constant expression of the underlying type.
+        EltTy = Enum->getIntegerType();
+        ExprResult Converted =
+          CheckConvertedConstantExpression(Val, EltTy, EnumVal,
+                                           CCEK_Enumerator);
+        if (Converted.isInvalid())
+          Val = 0;
+        else
+          Val = Converted.take();
+      } else if (!Val->isValueDependent() &&
+                 VerifyIntegerConstantExpression(Val, &EnumVal)) {
+        // C99 6.7.2.2p2: Make sure we have an integer constant expression.
         Val = 0;
-      } else {        
+      } else {
         if (!getLangOptions().CPlusPlus) {
           // C99 6.7.2.2p2:
           //   The expression that defines the value of an enumeration constant
-          //   shall be an integer constant expression that has a value 
+          //   shall be an integer constant expression that has a value
           //   representable as an int.
-          
+
           // Complain if the value is not representable in an int.
           if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
             Diag(IdLoc, diag::ext_enum_value_not_int)
@@ -9577,25 +9589,24 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
             Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).take();
           }
         }
-        
+
         if (Enum->isFixed()) {
           EltTy = Enum->getIntegerType();
 
-          // C++0x [dcl.enum]p5:
-          //   ... if the initializing value of an enumerator cannot be
-          //   represented by the underlying type, the program is ill-formed.
+          // In Obj-C and Microsoft mode, require the enumeration value to be
+          // representable in the underlying type of the enumeration. In C++11,
+          // we perform a non-narrowing conversion as part of converted constant
+          // expression checking.
           if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
             if (getLangOptions().MicrosoftExt) {
               Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
               Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
-            } else 
-              Diag(IdLoc, diag::err_enumerator_too_large)
-                << EltTy;
+            } else
+              Diag(IdLoc, diag::err_enumerator_too_large) << EltTy;
           } else
             Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
-        }
-        else {
-          // C++0x [dcl.enum]p5:
+        } else {
+          // C++11 [dcl.enum]p5:
           //   If the underlying type is not fixed, the type of each enumerator
           //   is the type of its initializing value:
           //     - If an initializer is specified for an enumerator, the 
@@ -9700,11 +9711,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
 Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
                               SourceLocation IdLoc, IdentifierInfo *Id,
                               AttributeList *Attr,
-                              SourceLocation EqualLoc, Expr *val) {
+                              SourceLocation EqualLoc, Expr *Val) {
   EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl);
   EnumConstantDecl *LastEnumConst =
     cast_or_null<EnumConstantDecl>(lastEnumConst);
-  Expr *Val = static_cast<Expr*>(val);
 
   // The scope passed in may not be a decl scope.  Zip up the scope tree until
   // we find one that is.
index bd9701ef37714fe01a7cf6f7cb760d5a6181c321..f4f2663bc8bc65e7a4e236280a32f445586159ce 100644 (file)
@@ -5807,7 +5807,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
 
   // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
   APValue ConstantValue;
-  switch (SCS->isNarrowing(S.Context, PostInit, ConstantValue)) {
+  switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue)) {
   case NK_Not_Narrowing:
     // No narrowing occurred.
     return;
index d800e9382008d77451195ce7a588ae25e4bf9a28..931573bb296864a496bf43406977533182be0683 100644 (file)
@@ -289,8 +289,9 @@ static const Expr *IgnoreNarrowingConversion(const Expr *Converted) {
 /// \param ConstantValue  If this is an NK_Constant_Narrowing conversion, the
 ///        value of the expression prior to the narrowing conversion.
 NarrowingKind
-StandardConversionSequence::isNarrowing(ASTContext &Ctx, const Expr *Converted,
-                                        APValue &ConstantValue) const {
+StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
+                                             const Expr *Converted,
+                                             APValue &ConstantValue) const {
   assert(Ctx.getLangOptions().CPlusPlus && "narrowing check outside C++");
 
   // C++11 [dcl.init.list]p7:
@@ -4531,6 +4532,167 @@ ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
   return ExprError();
 }
 
+/// Check that the specified conversion is permitted in a converted constant
+/// expression, according to C++11 [expr.const]p3. Return true if the conversion
+/// is acceptable.
+static bool CheckConvertedConstantConversions(Sema &S,
+                                              StandardConversionSequence &SCS) {
+  // Since we know that the target type is an integral or unscoped enumeration
+  // type, most conversion kinds are impossible. All possible First and Third
+  // conversions are fine.
+  switch (SCS.Second) {
+  case ICK_Identity:
+  case ICK_Integral_Promotion:
+  case ICK_Integral_Conversion:
+    return true;
+
+  case ICK_Boolean_Conversion:
+    // Conversion from an integral or unscoped enumeration type to bool is
+    // classified as ICK_Boolean_Conversion, but it's also an integral
+    // conversion, so it's permitted in a converted constant expression.
+    return SCS.getFromType()->isIntegralOrUnscopedEnumerationType() &&
+           SCS.getToType(2)->isBooleanType();
+
+  case ICK_Floating_Integral:
+  case ICK_Complex_Real:
+    return false;
+
+  case ICK_Lvalue_To_Rvalue:
+  case ICK_Array_To_Pointer:
+  case ICK_Function_To_Pointer:
+  case ICK_NoReturn_Adjustment:
+  case ICK_Qualification:
+  case ICK_Compatible_Conversion:
+  case ICK_Vector_Conversion:
+  case ICK_Vector_Splat:
+  case ICK_Derived_To_Base:
+  case ICK_Pointer_Conversion:
+  case ICK_Pointer_Member:
+  case ICK_Block_Pointer_Conversion:
+  case ICK_Writeback_Conversion:
+  case ICK_Floating_Promotion:
+  case ICK_Complex_Promotion:
+  case ICK_Complex_Conversion:
+  case ICK_Floating_Conversion:
+  case ICK_TransparentUnionConversion:
+    llvm_unreachable("unexpected second conversion kind");
+
+  case ICK_Num_Conversion_Kinds:
+    break;
+  }
+
+  llvm_unreachable("unknown conversion kind");
+}
+
+/// CheckConvertedConstantExpression - Check that the expression From is a
+/// converted constant expression of type T, perform the conversion and produce
+/// the converted expression, per C++11 [expr.const]p3.
+ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
+                                                  llvm::APSInt &Value,
+                                                  CCEKind CCE) {
+  assert(LangOpts.CPlusPlus0x && "converted constant expression outside C++11");
+  assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
+
+  if (checkPlaceholderForOverload(*this, From))
+    return ExprError();
+
+  // C++11 [expr.const]p3 with proposed wording fixes:
+  //  A converted constant expression of type T is a core constant expression,
+  //  implicitly converted to a prvalue of type T, where the converted
+  //  expression is a literal constant expression and the implicit conversion
+  //  sequence contains only user-defined conversions, lvalue-to-rvalue
+  //  conversions, integral promotions, and integral conversions other than
+  //  narrowing conversions.
+  ImplicitConversionSequence ICS =
+    TryImplicitConversion(From, T,
+                          /*SuppressUserConversions=*/false,
+                          /*AllowExplicit=*/false,
+                          /*InOverloadResolution=*/false,
+                          /*CStyle=*/false,
+                          /*AllowObjcWritebackConversion=*/false);
+  StandardConversionSequence *SCS = 0;
+  switch (ICS.getKind()) {
+  case ImplicitConversionSequence::StandardConversion:
+    if (!CheckConvertedConstantConversions(*this, ICS.Standard))
+      return Diag(From->getSourceRange().getBegin(),
+                  diag::err_typecheck_converted_constant_expression_disallowed)
+               << From->getType() << From->getSourceRange() << T;
+    SCS = &ICS.Standard;
+    break;
+  case ImplicitConversionSequence::UserDefinedConversion:
+    // We are converting from class type to an integral or enumeration type, so
+    // the Before sequence must be trivial.
+    if (!CheckConvertedConstantConversions(*this, ICS.UserDefined.After))
+      return Diag(From->getSourceRange().getBegin(),
+                  diag::err_typecheck_converted_constant_expression_disallowed)
+               << From->getType() << From->getSourceRange() << T;
+    SCS = &ICS.UserDefined.After;
+    break;
+  case ImplicitConversionSequence::AmbiguousConversion:
+  case ImplicitConversionSequence::BadConversion:
+    if (!DiagnoseMultipleUserDefinedConversion(From, T))
+      return Diag(From->getSourceRange().getBegin(),
+                  diag::err_typecheck_converted_constant_expression)
+                    << From->getType() << From->getSourceRange() << T;
+    return ExprError();
+
+  case ImplicitConversionSequence::EllipsisConversion:
+    llvm_unreachable("ellipsis conversion in converted constant expression");
+  }
+
+  ExprResult Result = PerformImplicitConversion(From, T, ICS, AA_Converting);
+  if (Result.isInvalid())
+    return Result;
+
+  // Check for a narrowing implicit conversion.
+  APValue PreNarrowingValue;
+  switch (SCS->getNarrowingKind(Context, Result.get(), PreNarrowingValue)) {
+  case NK_Variable_Narrowing:
+    // Implicit conversion to a narrower type, and the value is not a constant
+    // expression. We'll diagnose this in a moment.
+  case NK_Not_Narrowing:
+    break;
+
+  case NK_Constant_Narrowing:
+    Diag(From->getSourceRange().getBegin(), diag::err_cce_narrowing)
+      << CCE << /*Constant*/1
+      << PreNarrowingValue.getAsString(Context, QualType()) << T;
+    break;
+
+  case NK_Type_Narrowing:
+    Diag(From->getSourceRange().getBegin(), diag::err_cce_narrowing)
+      << CCE << /*Constant*/0 << From->getType() << T;
+    break;
+  }
+
+  // Check the expression is a constant expression.
+  llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+  Expr::EvalResult Eval;
+  Eval.Diag = &Notes;
+
+  if (!Result.get()->EvaluateAsRValue(Eval, Context)) {
+    // The expression can't be folded, so we can't keep it at this position in
+    // the AST.
+    Result = ExprError();
+  } else if (Notes.empty()) {
+    // It's a constant expression.
+    Value = Eval.Val.getInt();
+    return Result;
+  }
+
+  // It's not a constant expression. Produce an appropriate diagnostic.
+  if (Notes.size() == 1 &&
+      Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr)
+    Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
+  else {
+    Diag(From->getSourceRange().getBegin(), diag::err_expr_not_cce)
+      << CCE << From->getSourceRange();
+    for (unsigned I = 0; I < Notes.size(); ++I)
+      Diag(Notes[I].first, Notes[I].second);
+  }
+  return ExprError();
+}
+
 /// dropPointerConversions - If the given standard conversion sequence
 /// involves any pointer conversions, remove them.  This may change
 /// the result type of the conversion sequence.
index 23dc7e9d20aa72f23f254888c8fa2832be519aaa..a53e397243bfdcaf614e3dc25debfcc8f6749986 100644 (file)
@@ -266,22 +266,24 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
                     SourceLocation ColonLoc) {
   assert((LHSVal != 0) && "missing expression in case statement");
 
-  // C99 6.8.4.2p3: The expression shall be an integer constant.
-  // However, GCC allows any evaluatable integer expression.
-  if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
-      VerifyIntegerConstantExpression(LHSVal))
+  if (getCurFunction()->SwitchStack.empty()) {
+    Diag(CaseLoc, diag::err_case_not_in_switch);
     return StmtError();
+  }
 
-  // GCC extension: The expression shall be an integer constant.
+  if (!getLangOptions().CPlusPlus0x) {
+    // C99 6.8.4.2p3: The expression shall be an integer constant.
+    // However, GCC allows any evaluatable integer expression.
+    if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
+        VerifyIntegerConstantExpression(LHSVal))
+      return StmtError();
 
-  if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
-      VerifyIntegerConstantExpression(RHSVal)) {
-    RHSVal = 0;  // Recover by just forgetting about it.
-  }
+    // GCC extension: The expression shall be an integer constant.
 
-  if (getCurFunction()->SwitchStack.empty()) {
-    Diag(CaseLoc, diag::err_case_not_in_switch);
-    return StmtError();
+    if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
+        VerifyIntegerConstantExpression(RHSVal)) {
+      RHSVal = 0;  // Recover by just forgetting about it.
+    }
   }
 
   CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
@@ -622,8 +624,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
     } else {
       CaseStmt *CS = cast<CaseStmt>(SC);
 
-      // We already verified that the expression has a i-c-e value (C99
-      // 6.8.4.2p3) - get that value now.
       Expr *Lo = CS->getLHS();
 
       if (Lo->isTypeDependent() || Lo->isValueDependent()) {
@@ -631,19 +631,39 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
         break;
       }
 
-      llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context);
+      llvm::APSInt LoVal;
 
-      // Convert the value to the same width/sign as the condition.
+      if (getLangOptions().CPlusPlus0x) {
+        // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+        // constant expression of the promoted type of the switch condition.
+        ExprResult ConvLo =
+          CheckConvertedConstantExpression(Lo, CondType, LoVal, CCEK_CaseValue);
+        if (ConvLo.isInvalid()) {
+          CaseListIsErroneous = true;
+          continue;
+        }
+        Lo = ConvLo.take();
+      } else {
+        // We already verified that the expression has a i-c-e value (C99
+        // 6.8.4.2p3) - get that value now.
+        LoVal = Lo->EvaluateKnownConstInt(Context);
+
+        // If the LHS is not the same type as the condition, insert an implicit
+        // cast.
+        Lo = DefaultLvalueConversion(Lo).take();
+        Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
+      }
+
+      // Convert the value to the same width/sign as the condition had prior to
+      // integral promotions.
+      //
+      // FIXME: This causes us to reject valid code:
+      //   switch ((char)c) { case 256: case 0: return 0; }
+      // Here we claim there is a duplicated condition value, but there is not.
       ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
                                          Lo->getLocStart(),
                                          diag::warn_case_value_overflow);
 
-      // If the LHS is not the same type as the condition, insert an implicit
-      // cast.
-      // FIXME: In C++11, the value is a converted constant expression of the
-      // promoted type of the switch condition.
-      Lo = DefaultLvalueConversion(Lo).take();
-      Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
       CS->setLHS(Lo);
 
       // If this is a case range, remember it in CaseRanges, otherwise CaseVals.
@@ -709,19 +729,33 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
         llvm::APSInt &LoVal = CaseRanges[i].first;
         CaseStmt *CR = CaseRanges[i].second;
         Expr *Hi = CR->getRHS();
-        llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context);
+        llvm::APSInt HiVal;
+
+        if (getLangOptions().CPlusPlus0x) {
+          // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+          // constant expression of the promoted type of the switch condition.
+          ExprResult ConvHi =
+            CheckConvertedConstantExpression(Hi, CondType, HiVal,
+                                             CCEK_CaseValue);
+          if (ConvHi.isInvalid()) {
+            CaseListIsErroneous = true;
+            continue;
+          }
+          Hi = ConvHi.take();
+        } else {
+          HiVal = Hi->EvaluateKnownConstInt(Context);
+
+          // If the RHS is not the same type as the condition, insert an
+          // implicit cast.
+          Hi = DefaultLvalueConversion(Hi).take();
+          Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
+        }
 
         // Convert the value to the same width/sign as the condition.
         ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
                                            Hi->getLocStart(),
                                            diag::warn_case_value_overflow);
 
-        // If the RHS is not the same type as the condition, insert an implicit
-        // cast.
-        // FIXME: In C++11, the value is a converted constant expression of the
-        // promoted type of the switch condition.
-        Hi = DefaultLvalueConversion(Hi).take();
-        Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
         CR->setRHS(Hi);
 
         // If the low value is bigger than the high value, the case is empty.
index f58e965934d4b8792c393f7f62ff6382045cdb8b..0c66133968099983b24e9a06a250fdda44c93e97 100644 (file)
@@ -3737,14 +3737,70 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
   //   template-argument cannot be converted to the type of the
   //   corresponding template-parameter then the program is
   //   ill-formed.
-  //
-  //     -- for a non-type template-parameter of integral or
-  //        enumeration type, integral promotions (4.5) and integral
-  //        conversions (4.7) are applied.
   QualType ParamType = InstantiatedParamType;
   if (ParamType->isIntegralOrEnumerationType()) {
-    // FIXME: In C++11, the argument is a converted constant expression of the
-    // type of the template parameter.
+    // C++11:
+    //   -- for a non-type template-parameter of integral or
+    //      enumeration type, conversions permitted in a converted
+    //      constant expression are applied.
+    //
+    // C++98:
+    //   -- for a non-type template-parameter of integral or
+    //      enumeration type, integral promotions (4.5) and integral
+    //      conversions (4.7) are applied.
+
+    if (CTAK == CTAK_Deduced &&
+        !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) {
+      // C++ [temp.deduct.type]p17:
+      //   If, in the declaration of a function template with a non-type
+      //   template-parameter, the non-type template-parameter is used
+      //   in an expression in the function parameter-list and, if the
+      //   corresponding template-argument is deduced, the
+      //   template-argument type shall match the type of the
+      //   template-parameter exactly, except that a template-argument
+      //   deduced from an array bound may be of any integral type.
+      Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
+        << Arg->getType().getUnqualifiedType()
+        << ParamType.getUnqualifiedType();
+      Diag(Param->getLocation(), diag::note_template_param_here);
+      return ExprError();
+    }
+
+    if (getLangOptions().CPlusPlus0x) {
+      // We can't check arbitrary value-dependent arguments.
+      // FIXME: If there's no viable conversion to the template parameter type,
+      // we should be able to diagnose that prior to instantiation.
+      if (Arg->isValueDependent()) {
+        Converted = TemplateArgument(Arg);
+        return Owned(Arg);
+      }
+
+      // C++ [temp.arg.nontype]p1:
+      //   A template-argument for a non-type, non-template template-parameter
+      //   shall be one of:
+      //
+      //     -- for a non-type template-parameter of integral or enumeration
+      //        type, a converted constant expression of the type of the
+      //        template-parameter; or
+      llvm::APSInt Value;
+      ExprResult ArgResult =
+        CheckConvertedConstantExpression(Arg, ParamType, Value,
+                                         CCEK_TemplateArg);
+      if (ArgResult.isInvalid())
+        return ExprError();
+
+      // Widen the argument value to sizeof(parameter type). This is almost
+      // always a no-op, except when the parameter type is bool. In
+      // that case, this may extend the argument from 1 bit to 8 bits.
+      QualType IntegerType = ParamType;
+      if (const EnumType *Enum = IntegerType->getAs<EnumType>())
+        IntegerType = Enum->getDecl()->getIntegerType();
+      Value = Value.extOrTrunc(Context.getTypeSize(IntegerType));
+
+      Converted = TemplateArgument(Value, Context.getCanonicalType(ParamType));
+      return ArgResult;
+    }
+
     ExprResult ArgResult = DefaultLvalueConversion(Arg);
     if (ArgResult.isInvalid())
       return ExprError();
@@ -3782,19 +3838,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     // Try to convert the argument to the parameter's type.
     if (Context.hasSameType(ParamType, ArgType)) {
       // Okay: no conversion necessary
-    } else if (CTAK == CTAK_Deduced) {
-      // C++ [temp.deduct.type]p17:
-      //   If, in the declaration of a function template with a non-type
-      //   template-parameter, the non-type template- parameter is used
-      //   in an expression in the function parameter-list and, if the
-      //   corresponding template-argument is deduced, the
-      //   template-argument type shall match the type of the
-      //   template-parameter exactly, except that a template-argument
-      //   deduced from an array bound may be of any integral type.
-      Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
-        << ArgType << ParamType;
-      Diag(Param->getLocation(), diag::note_template_param_here);
-      return ExprError();
     } else if (ParamType->isBooleanType()) {
       // This is an integral-to-boolean conversion.
       Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean).take();
index 725be09c0850bec46d87d92e66f39af8a6423d9e..11c2f5fc498bb3546fd8e57a4ac85294f678589a 100644 (file)
@@ -120,8 +120,8 @@ namespace MutableMembers {
   // Here's one reason why allowing this would be a disaster...
   template<int n> struct Id { int k = n; };
   int f() {
-    constexpr MM m = { 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type 'const MutableMembers::MM' cannot be used in a constant expression}}
+    constexpr MM m = { 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type 'const MutableMembers::MM' cannot be used in a constant expression}} expected-note {{here}}
     ++m.n;
-    return Id<m.n>().k; // expected-error {{not an integral constant expression}}
+    return Id<m.n>().k; // expected-error {{not a constant expression}} expected-note {{initializer of 'm' is not a constant expression}}
   }
 }
index 05ebb31effb3c37eb1e8a959cfcdc2f14a32dd11..2570c605120aabd8d69ab4978b8b002bb956324e 100644 (file)
@@ -119,7 +119,7 @@ namespace UndefinedBehavior {
     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)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;
@@ -398,7 +398,7 @@ namespace Throw {
 }
 
 // PR9999
-template<bool v>
+template<unsigned int v>
 class bitWidthHolding {
 public:
   static const
@@ -420,3 +420,6 @@ struct and_or {
 
 static const bool and_value = and_or<true>::and_value;
 static const bool or_value = and_or<true>::or_value;
+
+static_assert(and_value == false, "");
+static_assert(or_value == true, "");
diff --git a/test/CXX/expr/expr.const/p3-0x.cpp b/test/CXX/expr/expr.const/p3-0x.cpp
new file mode 100644 (file)
index 0000000..6ddd11b
--- /dev/null
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+// A converted constant expression of type T is a core constant expression,
+int nonconst = 8; // expected-note 3 {{here}}
+enum NonConstE : unsigned char { NCE = nonconst }; // expected-error {{enumerator value is not a constant expression}} expected-note {{read of non-const}}
+template<int = nonconst> struct NonConstT {}; // expected-error {{non-type template argument is not a constant expression}} expected-note {{read of non-const}}
+void NonConstF() {
+  switch (nonconst) {
+    case nonconst: // expected-error {{case value is not a constant expression}} expected-note {{read of non-const}}
+      break;
+  }
+  return;
+}
+
+// implicitly converted to a prvalue of type T, where the converted expression
+// is a literal constant expression
+
+bool a(int n) {
+  constexpr char vowels[] = "aeiou";
+  switch (n) {
+  case vowels[0]:
+  case vowels[1]:
+  case vowels[2]:
+  case vowels[3]:
+  case vowels[4]:
+    static_assert(!vowels[5], "unexpected number of vowels");
+    return true;
+  }
+  return false;
+}
+
+// and the implicit conversion sequence contains only
+//
+//  user-defined conversions,
+struct S { constexpr operator int() const { return 5; } };
+enum E : unsigned char { E5 = S(), E6, E10 = S() * 2, E1 = E5 / 5 };
+
+//  lvalue-to-rvalue conversions,
+const E e10 = E10;
+template<E> struct T {};
+T<e10> s10;
+
+//  integral promotions, and
+enum class EE { EE32 = ' ', EE65 = 'A', EE1 = (short)1, EE5 = E5 };
+
+//  integral conversions other than narrowing conversions
+int b(unsigned n) {
+  switch (n) {
+    case E6:
+    case EE::EE32: // expected-error {{not implicitly convertible}}
+    case (int)EE::EE32:
+    case 1000:
+    case (long long)1e10: // expected-error {{case value evaluates to 10000000000, which cannot be narrowed to type 'unsigned int'}}
+    case -3: // expected-error {{case value evaluates to -3, which cannot be narrowed to type 'unsigned int'}}
+      return n;
+  }
+  return 0;
+}
+enum class EEE : unsigned short {
+  a = E6,
+  b = EE::EE32, // expected-error {{not implicitly convertible}}
+  c = (int)EE::EE32,
+  d = 1000,
+  e = 123456, // expected-error {{enumerator value evaluates to 123456, which cannot be narrowed to type 'unsigned short'}}
+  f = -3 // expected-error {{enumerator value evaluates to -3, which cannot be narrowed to type 'unsigned short'}}
+};
+template<unsigned char> using A = int;
+using Int = A<E6>;
+using Int = A<EE::EE32>; // expected-error {{not implicitly convertible}}
+using Int = A<(int)EE::EE32>;
+using Int = A<200>;
+using Int = A<1000>; // expected-error {{template argument evaluates to 1000, which cannot be narrowed to type 'unsigned char'}}
+using Int = A<-3>; // expected-error {{template argument evaluates to -3, which cannot be narrowed to type 'unsigned char'}}
+
+// Note, conversions from integral or unscoped enumeration types to bool are
+// integral conversions as well as boolean conversions.
+template<typename T, T v> struct Val { static constexpr T value = v; };
+static_assert(Val<bool, E1>::value == 1, ""); // ok
+static_assert(Val<bool, '\0'>::value == 0, ""); // ok
+static_assert(Val<bool, U'\1'>::value == 1, ""); // ok
+static_assert(Val<bool, E5>::value == 1, ""); // expected-error {{5, which cannot be narrowed to type 'bool'}}
+
+// (no other conversions are permitted)
+using Int = A<1.0>; // expected-error {{conversion from 'double' to 'unsigned char' is not allowed in a converted constant expression}}
+enum B : bool {
+  True = &a, // expected-error {{conversion from 'bool (*)(int)' to 'bool' is not allowed in a converted constant expression}}
+  False = nullptr // expected-error {{conversion from 'nullptr_t' to 'bool' is not allowed in a converted constant expression}}
+};
+void c() {
+  // Note, promoted type of switch is 'int'.
+  switch (bool b = a(5)) { // expected-warning {{boolean value}}
+  case 0.0f: // expected-error {{conversion from 'float' to 'int' is not allowed in a converted constant expression}}
+    break;
+  }
+}
+template<bool B> int f() { return B; }
+template int f<&S::operator int>(); // expected-error {{does not refer to a function template}}
+template int f<(bool)&S::operator int>();
+
+int n = Val<bool, &S::operator int>::value; // expected-error {{conversion from 'int (S::*)() const' to 'bool' is not allowed in a converted constant expression}}
+
+namespace NonConstLValue {
+  struct S {
+    constexpr operator int() { return 10; }
+  };
+  S s; // not constexpr
+  // Under the FDIS, this is not a converted constant expression.
+  // Under the new proposed wording, it is.
+  enum E : char { e = s };
+}
diff --git a/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp b/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
new file mode 100644 (file)
index 0000000..000c870
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+struct Value {
+  constexpr Value(int n) : n(n) {}
+  constexpr operator short() { return n; }
+  int n;
+};
+enum E { E0, E1 };
+struct Alt {
+  constexpr operator E() { return E0; }
+};
+
+constexpr short s = Alt();
+
+void test(Value v) {
+  switch (v) {
+    case Alt():
+    case E1:
+    case Value(2):
+    case 3:
+      break;
+  }
+  switch (Alt a = Alt()) {
+    case Alt():
+    case E1:
+    case Value(2):
+    case 3:
+      break;
+  }
+  switch (E0) {
+    case Alt():
+    case E1:
+    // FIXME: These should produce a warning that 2 and 3 are not values of the
+    // enumeration.
+    case Value(2):
+    case 3:
+      break;
+  }
+}
diff --git a/test/CodeGenCXX/mangle-98.cpp b/test/CodeGenCXX/mangle-98.cpp
new file mode 100644 (file)
index 0000000..a9ab6ca
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++98 | FileCheck %s
+
+template <bool B> struct S3 {};
+
+// CHECK: define void @_Z1f2S3ILb1EE
+void f(S3<true>) {}
+
+// CHECK: define void @_Z1f2S3ILb0EE
+void f(S3<false>) {}
+
+// CHECK: define void @_Z2f22S3ILb1EE
+void f2(S3<100>) {}
index 47c42a7347fab681ad053dcb9008b680cf1777b9..17232fd060ee39914c7e16d6bbd7e61e5f5ee9ae 100644 (file)
@@ -76,9 +76,6 @@ void f(S3<true>) {}
 // CHECK: define void @_Z1f2S3ILb0EE
 void f(S3<false>) {}
 
-// CHECK: define void @_Z2f22S3ILb1EE
-void f2(S3<100>) {}
-
 struct S;
 
 // CHECK: define void @_Z1fM1SKFvvE
index 5ccb398c32619e7c36dd41789d4814f07e8258f4..e1b3781f9f4ea6b4debfa5d475535be91de0dbdf 100644 (file)
@@ -92,9 +92,8 @@ namespace TemplateArgumentConversion {
 namespace CaseStatements {
   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 integral constant expression}} expected-note {{non-literal type '<bound member function type>'}}
-    case id(1):
+    case MemberZero().zero: // expected-error {{did you mean to call it with no arguments?}} expected-note {{previous}}
+    case id(0): // expected-error {{duplicate case value '0'}}
       return;
     }
   }
index aed8f08ebba1bb060bd7c96f6cb3372d47f5bd30..791fcf153e843c983e0bb3cde0dd3914574db045 100644 (file)
@@ -39,7 +39,7 @@ int* p2 = new int[E1::Val1]; // FIXME Expected-error{{must have integral}}
 enum class E4 {
   e1 = -2147483648, // ok
   e2 = 2147483647, // ok
-  e3 = 2147483648 // expected-error{{value is not representable}}
+  e3 = 2147483648 // expected-error{{enumerator value evaluates to 2147483648, which cannot be narrowed to type 'int'}}
 };
 
 enum class E5 {