зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
8013afe575
Коммит
4c3fc9b38d
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче