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
This commit is contained in:
Richard Smith 2012-01-18 05:21:49 +00:00
Родитель 8013afe575
Коммит 4c3fc9b38d
7 изменённых файлов: 326 добавлений и 210 удалений

Просмотреть файл

@ -420,6 +420,11 @@ public:
bool isEvaluated = true) const;
bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const;
/// isCXX11ConstantExpr - Return true if this expression is a constant
/// expression in C++11. Can only be used in C++.
bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0,
SourceLocation *Loc = 0) const;
/// isConstantInitializer - Returns true if this expression can be emitted to
/// IR as a constant, and thus can be used as a constant initializer in C.
bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const;

Просмотреть файл

@ -2927,11 +2927,16 @@ def warn_cxx98_compat_empty_scalar_initializer : Warning<
def err_illegal_initializer : Error<
"illegal initializer (only variables can be initialized)">;
def err_illegal_initializer_type : Error<"illegal initializer type %0">;
def err_init_list_type_narrowing : Error<
"type %0 cannot be narrowed to %1 in initializer list">;
def err_init_list_variable_narrowing : Error<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list">;
def err_init_list_constant_narrowing : Error<
"constant expression evaluates to %0 which cannot be narrowed to type %1">;
def warn_init_list_type_narrowing : Warning<
"type %0 cannot be narrowed to %1 in initializer list in C++11">,
InGroup<CXX11Narrowing>, DefaultIgnore;
def warn_init_list_variable_narrowing : Warning<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list in C++11">,

Просмотреть файл

@ -112,6 +112,23 @@ namespace clang {
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
/// NarrowingKind - The kind of narrowing conversion being performed by a
/// standard conversion sequence according to C++11 [dcl.init.list]p7.
enum NarrowingKind {
/// Not a narrowing conversion.
NK_Not_Narrowing,
/// A narrowing conversion by virtue of the source and destination types.
NK_Type_Narrowing,
/// A narrowing conversion, because a constant expression got narrowed.
NK_Constant_Narrowing,
/// A narrowing conversion, because a non-constant-expression variable might
/// have got narrowed.
NK_Variable_Narrowing
};
/// StandardConversionSequence - represents a standard conversion
/// sequence (C++ 13.3.3.1.1). A standard conversion sequence
/// contains between zero and three conversions. If a particular
@ -218,6 +235,8 @@ namespace clang {
}
ImplicitConversionRank getRank() const;
NarrowingKind isNarrowing(ASTContext &Context, const Expr *Converted,
APValue &ConstantValue) const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
void DebugPrint() const;

Просмотреть файл

@ -1756,18 +1756,16 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
if (!CD->isTrivial() || !CD->isDefaultConstructor())
return false;
if (!CD->isConstexpr()) {
// Value-initialization does not call a trivial default constructor, so such a
// call is a core constant expression whether or not the constructor is
// constexpr.
if (!CD->isConstexpr() && !IsValueInitialization) {
if (Info.getLangOpts().CPlusPlus0x) {
// Value-initialization does not call a trivial default constructor, so
// such a call is a core constant expression whether or not the
// constructor is constexpr.
if (!IsValueInitialization) {
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
<< /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
Info.Note(CD->getLocation(), diag::note_declared_at);
}
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
<< /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
Info.Note(CD->getLocation(), diag::note_declared_at);
} else {
Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}
@ -5944,24 +5942,12 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
return false;
}
Expr::EvalResult Result;
llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
Result.Diag = &Diags;
EvalInfo Info(Ctx, Result);
bool IsICE = EvaluateAsRValue(Info, E, Result.Val);
if (!Diags.empty()) {
IsICE = false;
if (Loc) *Loc = Diags[0].first;
} else if (!IsICE && Loc) {
*Loc = E->getExprLoc();
}
if (!IsICE)
APValue Result;
if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc))
return false;
assert(Result.Val.isInt() && "pointer cast to int is not an ICE");
if (Value) *Value = Result.Val.getInt();
assert(Result.isInt() && "pointer cast to int is not an ICE");
if (Value) *Value = Result.getInt();
return true;
}
@ -5988,3 +5974,28 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
llvm_unreachable("ICE cannot be evaluated!");
return true;
}
bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
SourceLocation *Loc) const {
// We support this checking in C++98 mode in order to diagnose compatibility
// issues.
assert(Ctx.getLangOptions().CPlusPlus);
Expr::EvalStatus Status;
llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
Status.Diag = &Diags;
EvalInfo Info(Ctx, Status);
APValue Scratch;
bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch);
if (!Diags.empty()) {
IsConstExpr = false;
if (Loc) *Loc = Diags[0].first;
} else if (!IsConstExpr) {
// FIXME: This shouldn't happen.
if (Loc) *Loc = getExprLoc();
}
return IsConstExpr;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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 {

Просмотреть файл

@ -31,12 +31,20 @@ struct Agg {
T t;
};
template<typename T>
struct Convert {
constexpr Convert(T v) : v(v) {}
constexpr operator T() const { return v; }
T v;
};
template<typename T> Convert<T> ConvertVar();
// C++0x [dcl.init.list]p7: A narrowing conversion is an implicit conversion
//
// * from a floating-point type to an integer type, or
void float_to_int() {
Agg<char> a1 = {1.0F}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> a1 = {1.0F}; // expected-error {{type 'float' cannot be narrowed to 'char'}} expected-note {{override}}
Agg<char> a2 = {1.0}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> a3 = {1.0L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
@ -46,6 +54,9 @@ void float_to_int() {
Agg<char> a4 = {f}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> a5 = {d}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> a6 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> ce1 = { Convert<float>(1.0) }; // expected-error {{type 'float' cannot be narrowed to 'char'}} expected-note {{override}}
Agg<char> ce2 = { ConvertVar<double>() }; // expected-error {{type 'double' cannot be narrowed to 'char'}} expected-note {{override}}
}
// * from long double to double or float, or from double to float, except where
@ -61,7 +72,7 @@ void shrink_float() {
// Variables.
Agg<float> f1 = {f}; // OK (no-op)
Agg<float> f2 = {d}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<float> f2 = {d}; // expected-error {{non-constant-expression cannot be narrowed from type 'double' to 'float'}} expected-note {{override}}
Agg<float> f3 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
// Exact constants.
Agg<float> f4 = {1.0}; // OK (double constant represented exactly)
@ -70,7 +81,7 @@ void shrink_float() {
Agg<float> f6 = {0.1}; // OK (double constant in range but rounded)
Agg<float> f7 = {0.1L}; // OK (long double constant in range but rounded)
// Out of range constants.
Agg<float> f8 = {1E50}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<float> f8 = {1E50}; // expected-error {{constant expression evaluates to 1.000000e+50 which cannot be narrowed to type 'float'}} expected-note {{override}}
Agg<float> f9 = {1E50L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
// More complex constant expression.
constexpr long double e40 = 1E40L, e30 = 1E30L, e39 = 1E39L;
@ -89,6 +100,9 @@ void shrink_float() {
// More complex constant expression.
constexpr long double e315 = 1E315L, e305 = 1E305L, e314 = 1E314L;
Agg<double> d7 = {e315 - 5 * e314 + e305 - 5 * e314}; // OK
Agg<float> ce1 = { Convert<double>(1e300) }; // expected-error {{constant expression evaluates to 1.000000e+300 which cannot be narrowed to type 'float'}} expected-note {{override}}
Agg<double> ce2 = { ConvertVar<long double>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'long double' to 'double'}} expected-note {{override}}
}
// * from an integer type or unscoped enumeration type to a floating-point type,
@ -107,6 +121,9 @@ void int_to_float() {
// Constants.
Agg<float> f4 = {12345678}; // OK (exactly fits in a float)
Agg<float> f5 = {123456789}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<float> ce1 = { Convert<int>(123456789) }; // expected-error {{constant expression evaluates to 123456789 which cannot be narrowed to type 'float'}} expected-note {{override}}
Agg<double> ce2 = { ConvertVar<long long>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'long long' to 'double'}} expected-note {{override}}
}
// * from an integer type or unscoped enumeration type to an integer type that
@ -147,6 +164,9 @@ void shrink_int() {
// Conversions from pointers to booleans aren't narrowing conversions.
Agg<bool> b = {&b1}; // OK
Agg<short> ce1 = { Convert<int>(100000) }; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}} expected-note {{override}} expected-warning {{changes value from 100000 to -31072}}
Agg<char> ce2 = { ConvertVar<short>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}}
}
// Be sure that type- and value-dependent expressions in templates get the error