aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaInit.cpp259
-rw-r--r--lib/Sema/SemaOverload.cpp157
2 files changed, 236 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;
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index e39735e256..3708f6c9d0 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -258,6 +258,163 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
return false;
}
+/// Skip any implicit casts which could be either part of a narrowing conversion
+/// or after one in an implicit conversion.
+static const Expr *IgnoreNarrowingConversion(const Expr *Converted) {
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
+ switch (ICE->getCastKind()) {
+ case CK_NoOp:
+ case CK_IntegralCast:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ Converted = ICE->getSubExpr();
+ continue;
+
+ default:
+ return Converted;
+ }
+ }
+
+ return Converted;
+}
+
+/// Check if this standard conversion sequence represents a narrowing
+/// conversion, according to C++11 [dcl.init.list]p7.
+///
+/// \param Ctx The AST context.
+/// \param Converted The result of applying this standard conversion sequence.
+/// \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 {
+ assert(Ctx.getLangOptions().CPlusPlus && "narrowing check outside C++");
+
+ // C++11 [dcl.init.list]p7:
+ // A narrowing conversion is an implicit conversion ...
+ QualType FromType = getToType(0);
+ QualType ToType = getToType(1);
+ switch (Second) {
+ // -- 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)) {
+ return NK_Type_Narrowing;
+ } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
+ llvm::APSInt IntConstantValue;
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ 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) {
+ ConstantValue = APValue(IntConstantValue);
+ return NK_Constant_Narrowing;
+ }
+ } else {
+ // Variables are always narrowings.
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+
+ // -- 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 (FromType->isRealFloatingType() && ToType->isRealFloatingType() &&
+ Ctx.getFloatingTypeOrder(FromType, ToType) == 1) {
+ // FromType is larger than ToType.
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer->isCXX11ConstantExpr(Ctx, &ConstantValue)) {
+ // Constant!
+ assert(ConstantValue.isFloat());
+ llvm::APFloat FloatVal = ConstantValue.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)
+ return NK_Constant_Narrowing;
+ } else {
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+
+ // -- 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 NK_Not_Narrowing;
+ } // 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;
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
+ 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.
+ if (ConvertedValue != InitializerValue)
+ return NK_Constant_Narrowing;
+ } else {
+ // Variables are always narrowings.
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+ }
+
+ default:
+ // Other kinds of conversions are not narrowings.
+ return NK_Not_Narrowing;
+ }
+}
+
/// DebugPrint - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
void StandardConversionSequence::DebugPrint() const {