[cfe-commits] r148439 - in /cfe/trunk: include/clang/Basic/ include/clang/Sema/ lib/Sema/ test/CXX/basic/basic.types/ test/CXX/expr/expr.const/ test/CXX/stmt.stmt/stmt.select/stmt.switch/ test/CodeGenCXX/ test/SemaCXX/
Richard Smith
richard-llvm at metafoo.co.uk
Wed Jan 18 15:55:53 PST 2012
Author: rsmith
Date: Wed Jan 18 17:55:52 2012
New Revision: 148439
URL: http://llvm.org/viewvc/llvm-project?rev=148439&view=rev
Log:
constexpr: converted constant expression handling for enumerator values, case
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.
Added:
cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp
cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
cfe/trunk/test/CodeGenCXX/mangle-98.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Overload.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/CXX/basic/basic.types/p10.cpp
cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
cfe/trunk/test/CodeGenCXX/mangle.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
cfe/trunk/test/SemaCXX/enum-scoped.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jan 18 17:55:52 2012
@@ -20,6 +20,17 @@
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<
Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Wed Jan 18 17:55:52 2012
@@ -235,8 +235,8 @@
}
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;
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 18 17:55:52 2012
@@ -1474,6 +1474,15 @@
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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 18 17:55:52 2012
@@ -9555,18 +9555,30 @@
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 @@
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 @@
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.
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Jan 18 17:55:52 2012
@@ -5807,7 +5807,7 @@
// 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;
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 18 17:55:52 2012
@@ -289,8 +289,9 @@
/// \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 @@
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.
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Jan 18 17:55:52 2012
@@ -266,24 +266,26 @@
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))
- return StmtError();
-
- // GCC extension: The expression shall be an integer constant.
-
- if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
- VerifyIntegerConstantExpression(RHSVal)) {
- RHSVal = 0; // Recover by just forgetting about it.
- }
-
if (getCurFunction()->SwitchStack.empty()) {
Diag(CaseLoc, diag::err_case_not_in_switch);
return StmtError();
}
+ 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();
+
+ // GCC extension: The expression shall be an integer constant.
+
+ 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,
ColonLoc);
getCurFunction()->SwitchStack.back()->addSwitchCase(CS);
@@ -622,8 +624,6 @@
} 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 @@
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 @@
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.
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jan 18 17:55:52 2012
@@ -3737,14 +3737,70 @@
// 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 @@
// 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();
Modified: cfe/trunk/test/CXX/basic/basic.types/p10.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.types/p10.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.types/p10.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.types/p10.cpp Wed Jan 18 17:55:52 2012
@@ -120,8 +120,8 @@
// 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}}
}
}
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=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Wed Jan 18 17:55:52 2012
@@ -119,7 +119,7 @@
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 @@
}
// PR9999
-template<bool v>
+template<unsigned int v>
class bitWidthHolding {
public:
static const
@@ -420,3 +420,6 @@
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, "");
Added: cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp?rev=148439&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp Wed Jan 18 17:55:52 2012
@@ -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 };
+}
Added: cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp?rev=148439&view=auto
==============================================================================
--- cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp (added)
+++ cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp Wed Jan 18 17:55:52 2012
@@ -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;
+ }
+}
Added: cfe/trunk/test/CodeGenCXX/mangle-98.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-98.cpp?rev=148439&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-98.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/mangle-98.cpp Wed Jan 18 17:55:52 2012
@@ -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>) {}
Modified: cfe/trunk/test/CodeGenCXX/mangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle.cpp Wed Jan 18 17:55:52 2012
@@ -76,9 +76,6 @@
// CHECK: define void @_Z1f2S3ILb0EE
void f(S3<false>) {}
-// CHECK: define void @_Z2f22S3ILb1EE
-void f2(S3<100>) {}
-
struct S;
// CHECK: define void @_Z1fM1SKFvvE
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=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed Jan 18 17:55:52 2012
@@ -92,9 +92,8 @@
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;
}
}
Modified: cfe/trunk/test/SemaCXX/enum-scoped.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-scoped.cpp?rev=148439&r1=148438&r2=148439&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/enum-scoped.cpp (original)
+++ cfe/trunk/test/SemaCXX/enum-scoped.cpp Wed Jan 18 17:55:52 2012
@@ -39,7 +39,7 @@
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 {
More information about the cfe-commits
mailing list