forked from OSchip/llvm-project
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. llvm-svn: 148381
This commit is contained in:
parent
9351402fa4
commit
66e05fe630
|
@ -420,6 +420,11 @@ public:
|
||||||
bool isEvaluated = true) const;
|
bool isEvaluated = true) const;
|
||||||
bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) 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
|
/// 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.
|
/// IR as a constant, and thus can be used as a constant initializer in C.
|
||||||
bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const;
|
bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const;
|
||||||
|
|
|
@ -2927,11 +2927,16 @@ def warn_cxx98_compat_empty_scalar_initializer : Warning<
|
||||||
def err_illegal_initializer : Error<
|
def err_illegal_initializer : Error<
|
||||||
"illegal initializer (only variables can be initialized)">;
|
"illegal initializer (only variables can be initialized)">;
|
||||||
def err_illegal_initializer_type : Error<"illegal initializer type %0">;
|
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<
|
def err_init_list_variable_narrowing : Error<
|
||||||
"non-constant-expression cannot be narrowed from type %0 to %1 in "
|
"non-constant-expression cannot be narrowed from type %0 to %1 in "
|
||||||
"initializer list">;
|
"initializer list">;
|
||||||
def err_init_list_constant_narrowing : Error<
|
def err_init_list_constant_narrowing : Error<
|
||||||
"constant expression evaluates to %0 which cannot be narrowed to type %1">;
|
"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<
|
def warn_init_list_variable_narrowing : Warning<
|
||||||
"non-constant-expression cannot be narrowed from type %0 to %1 in "
|
"non-constant-expression cannot be narrowed from type %0 to %1 in "
|
||||||
"initializer list in C++11">,
|
"initializer list in C++11">,
|
||||||
|
|
|
@ -112,6 +112,23 @@ namespace clang {
|
||||||
|
|
||||||
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
|
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
|
/// StandardConversionSequence - represents a standard conversion
|
||||||
/// sequence (C++ 13.3.3.1.1). A standard conversion sequence
|
/// sequence (C++ 13.3.3.1.1). A standard conversion sequence
|
||||||
/// contains between zero and three conversions. If a particular
|
/// contains between zero and three conversions. If a particular
|
||||||
|
@ -218,6 +235,8 @@ namespace clang {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImplicitConversionRank getRank() const;
|
ImplicitConversionRank getRank() const;
|
||||||
|
NarrowingKind isNarrowing(ASTContext &Context, const Expr *Converted,
|
||||||
|
APValue &ConstantValue) const;
|
||||||
bool isPointerConversionToBool() const;
|
bool isPointerConversionToBool() const;
|
||||||
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
|
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
|
||||||
void DebugPrint() const;
|
void DebugPrint() const;
|
||||||
|
|
|
@ -1756,18 +1756,16 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
|
||||||
if (!CD->isTrivial() || !CD->isDefaultConstructor())
|
if (!CD->isTrivial() || !CD->isDefaultConstructor())
|
||||||
return false;
|
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) {
|
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,
|
// FIXME: If DiagDecl is an implicitly-declared special member function,
|
||||||
// we should be much more explicit about why it's not constexpr.
|
// we should be much more explicit about why it's not constexpr.
|
||||||
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
|
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
|
||||||
<< /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
|
<< /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
|
||||||
Info.Note(CD->getLocation(), diag::note_declared_at);
|
Info.Note(CD->getLocation(), diag::note_declared_at);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
|
Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
|
||||||
}
|
}
|
||||||
|
@ -5944,24 +5942,12 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::EvalResult Result;
|
APValue Result;
|
||||||
llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
|
if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc))
|
||||||
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)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
assert(Result.Val.isInt() && "pointer cast to int is not an ICE");
|
assert(Result.isInt() && "pointer cast to int is not an ICE");
|
||||||
if (Value) *Value = Result.Val.getInt();
|
if (Value) *Value = Result.getInt();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5988,3 +5974,28 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
|
||||||
llvm_unreachable("ICE cannot be evaluated!");
|
llvm_unreachable("ICE cannot be evaluated!");
|
||||||
return true;
|
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;
|
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
|
void
|
||||||
InitializationSequence
|
InitializationSequence
|
||||||
::AddAddressOverloadResolutionStep(FunctionDecl *Function,
|
::AddAddressOverloadResolutionStep(FunctionDecl *Function,
|
||||||
|
@ -5928,25 +5770,83 @@ void InitializationSequence::dump() const {
|
||||||
dump(llvm::errs());
|
dump(llvm::errs());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DiagnoseNarrowingInInitList(
|
static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
|
||||||
Sema& S, QualType EntityType, const Expr *InitE,
|
QualType EntityType,
|
||||||
bool Constant, const APValue &ConstantValue) {
|
const Expr *PreInit,
|
||||||
if (Constant) {
|
const Expr *PostInit) {
|
||||||
S.Diag(InitE->getLocStart(),
|
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
|
S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
|
||||||
? diag::err_init_list_constant_narrowing
|
? diag::err_init_list_constant_narrowing
|
||||||
: diag::warn_init_list_constant_narrowing)
|
: diag::warn_init_list_constant_narrowing)
|
||||||
<< InitE->getSourceRange()
|
<< PostInit->getSourceRange()
|
||||||
<< ConstantValue.getAsString(S.getASTContext(), EntityType)
|
<< ConstantValue.getAsString(S.getASTContext(), EntityType)
|
||||||
<< EntityType.getLocalUnqualifiedType();
|
<< EntityType.getLocalUnqualifiedType();
|
||||||
} else
|
break;
|
||||||
S.Diag(InitE->getLocStart(),
|
|
||||||
|
case NK_Variable_Narrowing:
|
||||||
|
// A variable's value may have been narrowed.
|
||||||
|
S.Diag(PostInit->getLocStart(),
|
||||||
S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
|
S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
|
||||||
? diag::err_init_list_variable_narrowing
|
? diag::err_init_list_variable_narrowing
|
||||||
: diag::warn_init_list_variable_narrowing)
|
: diag::warn_init_list_variable_narrowing)
|
||||||
<< InitE->getSourceRange()
|
<< PostInit->getSourceRange()
|
||||||
<< InitE->getType().getLocalUnqualifiedType()
|
<< PreNarrowingType.getLocalUnqualifiedType()
|
||||||
<< EntityType.getLocalUnqualifiedType();
|
<< EntityType.getLocalUnqualifiedType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
llvm::SmallString<128> StaticCast;
|
llvm::SmallString<128> StaticCast;
|
||||||
llvm::raw_svector_ostream OS(StaticCast);
|
llvm::raw_svector_ostream OS(StaticCast);
|
||||||
|
@ -5966,11 +5866,11 @@ static void DiagnoseNarrowingInInitList(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OS << ">(";
|
OS << ">(";
|
||||||
S.Diag(InitE->getLocStart(), diag::note_init_list_narrowing_override)
|
S.Diag(PostInit->getLocStart(), diag::note_init_list_narrowing_override)
|
||||||
<< InitE->getSourceRange()
|
<< PostInit->getSourceRange()
|
||||||
<< FixItHint::CreateInsertion(InitE->getLocStart(), OS.str())
|
<< FixItHint::CreateInsertion(PostInit->getLocStart(), OS.str())
|
||||||
<< FixItHint::CreateInsertion(
|
<< 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);
|
InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
|
||||||
Init.release();
|
Init.release();
|
||||||
|
|
||||||
bool Constant = false;
|
ExprResult Result = Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1));
|
||||||
APValue Result;
|
|
||||||
if (TopLevelOfInitList &&
|
if (!Result.isInvalid() && TopLevelOfInitList)
|
||||||
Seq.endsWithNarrowing(Context, InitE, &Constant, &Result)) {
|
DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(),
|
||||||
DiagnoseNarrowingInInitList(*this, Entity.getType(), InitE,
|
InitE, Result.get());
|
||||||
Constant, Result);
|
|
||||||
}
|
return Result;
|
||||||
return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,6 +258,163 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
|
||||||
return false;
|
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
|
/// DebugPrint - Print this standard conversion sequence to standard
|
||||||
/// error. Useful for debugging overloading issues.
|
/// error. Useful for debugging overloading issues.
|
||||||
void StandardConversionSequence::DebugPrint() const {
|
void StandardConversionSequence::DebugPrint() const {
|
||||||
|
|
|
@ -31,12 +31,20 @@ struct Agg {
|
||||||
T t;
|
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
|
// C++0x [dcl.init.list]p7: A narrowing conversion is an implicit conversion
|
||||||
//
|
//
|
||||||
// * from a floating-point type to an integer type, or
|
// * from a floating-point type to an integer type, or
|
||||||
|
|
||||||
void float_to_int() {
|
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> a2 = {1.0}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
|
||||||
Agg<char> a3 = {1.0L}; // 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> a4 = {f}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
|
||||||
Agg<char> a5 = {d}; // 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> 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
|
// * from long double to double or float, or from double to float, except where
|
||||||
|
@ -61,7 +72,7 @@ void shrink_float() {
|
||||||
|
|
||||||
// Variables.
|
// Variables.
|
||||||
Agg<float> f1 = {f}; // OK (no-op)
|
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}}
|
Agg<float> f3 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
|
||||||
// Exact constants.
|
// Exact constants.
|
||||||
Agg<float> f4 = {1.0}; // OK (double constant represented exactly)
|
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> f6 = {0.1}; // OK (double constant in range but rounded)
|
||||||
Agg<float> f7 = {0.1L}; // OK (long double constant in range but rounded)
|
Agg<float> f7 = {0.1L}; // OK (long double constant in range but rounded)
|
||||||
// Out of range constants.
|
// 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}}
|
Agg<float> f9 = {1E50L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
|
||||||
// More complex constant expression.
|
// More complex constant expression.
|
||||||
constexpr long double e40 = 1E40L, e30 = 1E30L, e39 = 1E39L;
|
constexpr long double e40 = 1E40L, e30 = 1E30L, e39 = 1E39L;
|
||||||
|
@ -89,6 +100,9 @@ void shrink_float() {
|
||||||
// More complex constant expression.
|
// More complex constant expression.
|
||||||
constexpr long double e315 = 1E315L, e305 = 1E305L, e314 = 1E314L;
|
constexpr long double e315 = 1E315L, e305 = 1E305L, e314 = 1E314L;
|
||||||
Agg<double> d7 = {e315 - 5 * e314 + e305 - 5 * e314}; // OK
|
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,
|
// * from an integer type or unscoped enumeration type to a floating-point type,
|
||||||
|
@ -107,6 +121,9 @@ void int_to_float() {
|
||||||
// Constants.
|
// Constants.
|
||||||
Agg<float> f4 = {12345678}; // OK (exactly fits in a float)
|
Agg<float> f4 = {12345678}; // OK (exactly fits in a float)
|
||||||
Agg<float> f5 = {123456789}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
|
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
|
// * 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.
|
// Conversions from pointers to booleans aren't narrowing conversions.
|
||||||
Agg<bool> b = {&b1}; // OK
|
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
|
// Be sure that type- and value-dependent expressions in templates get the error
|
||||||
|
|
Loading…
Reference in New Issue