diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 23:55:52 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 23:55:52 +0000 |
commit | 8ef7b203332b0c8d65876a1f5e6d1db4e6f40e4b (patch) | |
tree | dee9b186a48a66f3c8be5c56c4e774338408bece /lib/Sema | |
parent | d6c7c67313634b317a0d63c32be0511a121bb33d (diff) |
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
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 46 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 166 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 92 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 81 |
5 files changed, 318 insertions, 69 deletions
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<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. 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<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. 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<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. 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<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(); |