diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 05:21:49 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 05:21:49 +0000 |
commit | 4c3fc9b38d3723f73e4ded594cebf38c76f91d93 (patch) | |
tree | cdba7956c4da548d2d932d58a1e99b14be707e05 /lib/Sema/SemaInit.cpp | |
parent | 8013afe5752551d72d290991046c3942138d2df1 (diff) |
Move narrowing conversion detection code from SemaInit to SemaOverload, ready
for it to be used in converted constant expression checking, and fix a couple
of issues:
- Conversion operators implicitly invoked prior to the narrowing conversion
were not being correctly handled when determining whether a constant value
was narrowed.
- For conversions from floating-point to integral types, the diagnostic text
incorrectly always claimed that the source expression was not a constant
expression.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148381 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r-- | lib/Sema/SemaInit.cpp | 259 |
1 files changed, 79 insertions, 180 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 2f9b33edeb..bd9701ef37 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2464,164 +2464,6 @@ bool InitializationSequence::isConstructorInitialization() const { return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization; } -bool InitializationSequence::endsWithNarrowing(ASTContext &Ctx, - const Expr *Initializer, - bool *isInitializerConstant, - APValue *ConstantValue) const { - if (Steps.empty() || Initializer->isValueDependent()) - return false; - - const Step &LastStep = Steps.back(); - if (LastStep.Kind != SK_ConversionSequence) - return false; - - const ImplicitConversionSequence &ICS = *LastStep.ICS; - const StandardConversionSequence *SCS = NULL; - switch (ICS.getKind()) { - case ImplicitConversionSequence::StandardConversion: - SCS = &ICS.Standard; - break; - case ImplicitConversionSequence::UserDefinedConversion: - SCS = &ICS.UserDefined.After; - break; - case ImplicitConversionSequence::AmbiguousConversion: - case ImplicitConversionSequence::EllipsisConversion: - case ImplicitConversionSequence::BadConversion: - return false; - } - - // Check if SCS represents a narrowing conversion, according to C++0x - // [dcl.init.list]p7: - // - // A narrowing conversion is an implicit conversion ... - ImplicitConversionKind PossibleNarrowing = SCS->Second; - QualType FromType = SCS->getToType(0); - QualType ToType = SCS->getToType(1); - switch (PossibleNarrowing) { - // * from a floating-point type to an integer type, or - // - // * from an integer type or unscoped enumeration type to a floating-point - // type, except where the source is a constant expression and the actual - // value after conversion will fit into the target type and will produce - // the original value when converted back to the original type, or - case ICK_Floating_Integral: - if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) { - *isInitializerConstant = false; - return true; - } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) { - llvm::APSInt IntConstantValue; - if (Initializer && - Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) { - // Convert the integer to the floating type. - llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType)); - Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(), - llvm::APFloat::rmNearestTiesToEven); - // And back. - llvm::APSInt ConvertedValue = IntConstantValue; - bool ignored; - Result.convertToInteger(ConvertedValue, - llvm::APFloat::rmTowardZero, &ignored); - // If the resulting value is different, this was a narrowing conversion. - if (IntConstantValue != ConvertedValue) { - *isInitializerConstant = true; - *ConstantValue = APValue(IntConstantValue); - return true; - } - } else { - // Variables are always narrowings. - *isInitializerConstant = false; - return true; - } - } - return false; - - // * from long double to double or float, or from double to float, except - // where the source is a constant expression and the actual value after - // conversion is within the range of values that can be represented (even - // if it cannot be represented exactly), or - case ICK_Floating_Conversion: - if (1 == Ctx.getFloatingTypeOrder(FromType, ToType)) { - // FromType is larger than ToType. - Expr::EvalResult InitializerValue; - // FIXME: Check whether Initializer is a constant expression according - // to C++0x [expr.const], rather than just whether it can be folded. - if (Initializer->EvaluateAsRValue(InitializerValue, Ctx) && - !InitializerValue.HasSideEffects && InitializerValue.Val.isFloat()) { - // Constant! (Except for FIXME above.) - llvm::APFloat FloatVal = InitializerValue.Val.getFloat(); - // Convert the source value into the target type. - bool ignored; - llvm::APFloat::opStatus ConvertStatus = FloatVal.convert( - Ctx.getFloatTypeSemantics(ToType), - llvm::APFloat::rmNearestTiesToEven, &ignored); - // If there was no overflow, the source value is within the range of - // values that can be represented. - if (ConvertStatus & llvm::APFloat::opOverflow) { - *isInitializerConstant = true; - *ConstantValue = InitializerValue.Val; - return true; - } - } else { - *isInitializerConstant = false; - return true; - } - } - return false; - - // * from an integer type or unscoped enumeration type to an integer type - // that cannot represent all the values of the original type, except where - // the source is a constant expression and the actual value after - // conversion will fit into the target type and will produce the original - // value when converted back to the original type. - case ICK_Boolean_Conversion: // Bools are integers too. - if (!FromType->isIntegralOrUnscopedEnumerationType()) { - // Boolean conversions can be from pointers and pointers to members - // [conv.bool], and those aren't considered narrowing conversions. - return false; - } // Otherwise, fall through to the integral case. - case ICK_Integral_Conversion: { - assert(FromType->isIntegralOrUnscopedEnumerationType()); - assert(ToType->isIntegralOrUnscopedEnumerationType()); - const bool FromSigned = FromType->isSignedIntegerOrEnumerationType(); - const unsigned FromWidth = Ctx.getIntWidth(FromType); - const bool ToSigned = ToType->isSignedIntegerOrEnumerationType(); - const unsigned ToWidth = Ctx.getIntWidth(ToType); - - if (FromWidth > ToWidth || - (FromWidth == ToWidth && FromSigned != ToSigned)) { - // Not all values of FromType can be represented in ToType. - llvm::APSInt InitializerValue; - if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) { - *isInitializerConstant = true; - *ConstantValue = APValue(InitializerValue); - - // Add a bit to the InitializerValue so we don't have to worry about - // signed vs. unsigned comparisons. - InitializerValue = InitializerValue.extend( - InitializerValue.getBitWidth() + 1); - // Convert the initializer to and from the target width and signed-ness. - llvm::APSInt ConvertedValue = InitializerValue; - ConvertedValue = ConvertedValue.trunc(ToWidth); - ConvertedValue.setIsSigned(ToSigned); - ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth()); - ConvertedValue.setIsSigned(InitializerValue.isSigned()); - // If the result is different, this was a narrowing conversion. - return ConvertedValue != InitializerValue; - } else { - // Variables are always narrowings. - *isInitializerConstant = false; - return true; - } - } - return false; - } - - default: - // Other kinds of conversions are not narrowings. - return false; - } -} - void InitializationSequence ::AddAddressOverloadResolutionStep(FunctionDecl *Function, @@ -5928,25 +5770,83 @@ void InitializationSequence::dump() const { dump(llvm::errs()); } -static void DiagnoseNarrowingInInitList( - Sema& S, QualType EntityType, const Expr *InitE, - bool Constant, const APValue &ConstantValue) { - if (Constant) { - S.Diag(InitE->getLocStart(), +static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq, + QualType EntityType, + const Expr *PreInit, + const Expr *PostInit) { + if (Seq.step_begin() == Seq.step_end() || PreInit->isValueDependent()) + return; + + // A narrowing conversion can only appear as the final implicit conversion in + // an initialization sequence. + const InitializationSequence::Step &LastStep = Seq.step_end()[-1]; + if (LastStep.Kind != InitializationSequence::SK_ConversionSequence) + return; + + const ImplicitConversionSequence &ICS = *LastStep.ICS; + const StandardConversionSequence *SCS = 0; + switch (ICS.getKind()) { + case ImplicitConversionSequence::StandardConversion: + SCS = &ICS.Standard; + break; + case ImplicitConversionSequence::UserDefinedConversion: + SCS = &ICS.UserDefined.After; + break; + case ImplicitConversionSequence::AmbiguousConversion: + case ImplicitConversionSequence::EllipsisConversion: + case ImplicitConversionSequence::BadConversion: + return; + } + + // Determine the type prior to the narrowing conversion. If a conversion + // operator was used, this may be different from both the type of the entity + // and of the pre-initialization expression. + QualType PreNarrowingType = PreInit->getType(); + if (Seq.step_begin() + 1 != Seq.step_end()) + PreNarrowingType = Seq.step_end()[-2].Type; + + // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion. + APValue ConstantValue; + switch (SCS->isNarrowing(S.Context, PostInit, ConstantValue)) { + case NK_Not_Narrowing: + // No narrowing occurred. + return; + + case NK_Type_Narrowing: + // This was a floating-to-integer conversion, which is always considered a + // narrowing conversion even if the value is a constant and can be + // represented exactly as an integer. + S.Diag(PostInit->getLocStart(), + S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt + ? diag::err_init_list_type_narrowing + : diag::warn_init_list_type_narrowing) + << PostInit->getSourceRange() + << PreNarrowingType.getLocalUnqualifiedType() + << EntityType.getLocalUnqualifiedType(); + break; + + case NK_Constant_Narrowing: + // A constant value was narrowed. + S.Diag(PostInit->getLocStart(), S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt ? diag::err_init_list_constant_narrowing : diag::warn_init_list_constant_narrowing) - << InitE->getSourceRange() + << PostInit->getSourceRange() << ConstantValue.getAsString(S.getASTContext(), EntityType) << EntityType.getLocalUnqualifiedType(); - } else - S.Diag(InitE->getLocStart(), + break; + + case NK_Variable_Narrowing: + // A variable's value may have been narrowed. + S.Diag(PostInit->getLocStart(), S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt ? diag::err_init_list_variable_narrowing : diag::warn_init_list_variable_narrowing) - << InitE->getSourceRange() - << InitE->getType().getLocalUnqualifiedType() + << PostInit->getSourceRange() + << PreNarrowingType.getLocalUnqualifiedType() << EntityType.getLocalUnqualifiedType(); + break; + } llvm::SmallString<128> StaticCast; llvm::raw_svector_ostream OS(StaticCast); @@ -5966,11 +5866,11 @@ static void DiagnoseNarrowingInInitList( return; } OS << ">("; - S.Diag(InitE->getLocStart(), diag::note_init_list_narrowing_override) - << InitE->getSourceRange() - << FixItHint::CreateInsertion(InitE->getLocStart(), OS.str()) + S.Diag(PostInit->getLocStart(), diag::note_init_list_narrowing_override) + << PostInit->getSourceRange() + << FixItHint::CreateInsertion(PostInit->getLocStart(), OS.str()) << FixItHint::CreateInsertion( - S.getPreprocessor().getLocForEndOfToken(InitE->getLocEnd()), ")"); + S.getPreprocessor().getLocForEndOfToken(PostInit->getLocEnd()), ")"); } //===----------------------------------------------------------------------===// @@ -6010,12 +5910,11 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); Init.release(); - bool Constant = false; - APValue Result; - if (TopLevelOfInitList && - Seq.endsWithNarrowing(Context, InitE, &Constant, &Result)) { - DiagnoseNarrowingInInitList(*this, Entity.getType(), InitE, - Constant, Result); - } - return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1)); + ExprResult Result = Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1)); + + if (!Result.isInvalid() && TopLevelOfInitList) + DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(), + InitE, Result.get()); + + return Result; } |