[cfe-commits] r148381 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Overload.h lib/AST/ExprConstant.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Tue Jan 17 21:21:50 PST 2012
Author: rsmith
Date: Tue Jan 17 23:21:49 2012
New Revision: 148381
URL: http://llvm.org/viewvc/llvm-project?rev=148381&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Overload.h
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=148381&r1=148380&r2=148381&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Tue Jan 17 23:21:49 2012
@@ -420,6 +420,11 @@
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;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=148381&r1=148380&r2=148381&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 17 23:21:49 2012
@@ -2927,11 +2927,16 @@
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">,
Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=148381&r1=148380&r2=148381&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Tue Jan 17 23:21:49 2012
@@ -112,6 +112,23 @@
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 @@
}
ImplicitConversionRank getRank() const;
+ NarrowingKind isNarrowing(ASTContext &Context, const Expr *Converted,
+ APValue &ConstantValue) const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
void DebugPrint() const;
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=148381&r1=148380&r2=148381&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Jan 17 23:21:49 2012
@@ -1756,18 +1756,16 @@
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 @@
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 @@
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;
+}
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=148381&r1=148380&r2=148381&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jan 17 23:21:49 2012
@@ -2464,164 +2464,6 @@
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 @@
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 @@
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 @@
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;
}
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=148381&r1=148380&r2=148381&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jan 17 23:21:49 2012
@@ -258,6 +258,163 @@
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 {
Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp?rev=148381&r1=148380&r2=148381&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp Tue Jan 17 23:21:49 2012
@@ -31,12 +31,20 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
// 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
More information about the cfe-commits
mailing list