From: Richard Smith Date: Wed, 18 Jan 2012 23:55:52 +0000 (+0000) Subject: constexpr: converted constant expression handling for enumerator values, case X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8ef7b203332b0c8d65876a1f5e6d1db4e6f40e4b;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148439 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5f361cdf0d..41e723722f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; +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< diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index 9a3397d235..d745b4befb 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -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; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 238b0edec6..c3bdad80df 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f2af0a7075..9dc00c3625 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null(lastEnumConst); - Expr *Val = static_cast(val); // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index bd9701ef37..f4f2663bc8 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index d800e93820..931573bb29 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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 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. diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 23dc7e9d20..a53e397243 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -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(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. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f58e965934..0c66133968 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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()) + 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(); diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp index 725be09c08..11c2f5fc49 100644 --- a/test/CXX/basic/basic.types/p10.cpp +++ b/test/CXX/basic/basic.types/p10.cpp @@ -120,8 +120,8 @@ namespace MutableMembers { // Here's one reason why allowing this would be a disaster... template 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().k; // expected-error {{not an integral constant expression}} + return Id().k; // expected-error {{not a constant expression}} expected-note {{initializer of 'm' is not a constant expression}} } } diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index 05ebb31eff..2570c60512 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -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 +template class bitWidthHolding { public: static const @@ -420,3 +420,6 @@ struct and_or { static const bool and_value = and_or::and_value; static const bool or_value = and_or::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 index 0000000000..6ddd11bcee --- /dev/null +++ b/test/CXX/expr/expr.const/p3-0x.cpp @@ -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 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 struct T {}; +T 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 using A = int; +using Int = A; +using Int = A; // 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 struct Val { static constexpr T value = v; }; +static_assert(Val::value == 1, ""); // ok +static_assert(Val::value == 0, ""); // ok +static_assert(Val::value == 1, ""); // ok +static_assert(Val::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 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::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 index 0000000000..000c870d59 --- /dev/null +++ b/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp @@ -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 index 0000000000..a9ab6ca423 --- /dev/null +++ b/test/CodeGenCXX/mangle-98.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++98 | FileCheck %s + +template struct S3 {}; + +// CHECK: define void @_Z1f2S3ILb1EE +void f(S3) {} + +// CHECK: define void @_Z1f2S3ILb0EE +void f(S3) {} + +// CHECK: define void @_Z2f22S3ILb1EE +void f2(S3<100>) {} diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index 47c42a7347..17232fd060 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -76,9 +76,6 @@ void f(S3) {} // CHECK: define void @_Z1f2S3ILb0EE void f(S3) {} -// CHECK: define void @_Z2f22S3ILb1EE -void f2(S3<100>) {} - struct S; // CHECK: define void @_Z1fM1SKFvvE diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 5ccb398c32..e1b3781f9f 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -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 ''}} - 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; } } diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp index aed8f08ebb..791fcf153e 100644 --- a/test/SemaCXX/enum-scoped.cpp +++ b/test/SemaCXX/enum-scoped.cpp @@ -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 {