Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ Bug Fixes to C++ Support
``__builtin_addressof``, and related issues with builtin arguments. (#GH154034)
- Fix an assertion failure when taking the address on a non-type template parameter argument of
object type. (#GH151531)
- Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12909,7 +12909,19 @@ static void AnalyzeImplicitConversions(

// Skip past explicit casts.
if (auto *CE = dyn_cast<ExplicitCastExpr>(E)) {
E = CE->getSubExpr()->IgnoreParenImpCasts();
E = CE->getSubExpr();
// In the special case of C++ function-style cast with braces,
// CXXFunctionalCastExpr has InitListExpr as direct child with a single
// initializer. This InitListExpr basically belongs to the cast itself, so
// we skip it too. Specifically this is needed to silence -Wdouble-promotion
if (isa<CXXFunctionalCastExpr>(CE)) {
if (auto *InitListE = dyn_cast<InitListExpr>(E)) {
if (InitListE->getNumInits() == 1) {
E = InitListE->getInit(0);
}
}
}
E = E->IgnoreParenImpCasts();
if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
WorkList.push_back({E, CC, IsListInit});
Expand Down
37 changes: 37 additions & 0 deletions clang/test/Sema/warn-double-promotion.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -fsyntax-only %s -Wdouble-promotion
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -fsyntax-only -x c++ %s -Wdouble-promotion

float ReturnFloatFromDouble(double d) {
return d;
Expand All @@ -24,22 +25,49 @@ long double ReturnLongDoubleFromDouble(double d) {
return d; //expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
}

double ReturnDoubleFromFloatWithExplicitCast(float f) {
return (double)f;
}

long double ReturnLongDoubleFromFloatWithExplicitCast(float f) {
return (long double)f;
}

long double ReturnLongDoubleFromDoubleWithExplicitCast(double d) {
return (long double)d;
}

void Assignment(float f, double d, long double ld) {
d = f; //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
ld = f; //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
ld = d; //expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
d = (double)f;
ld = (long double)f;
ld = (long double)d;
f = d;
f = ld;
d = ld;
}

void AssignmentWithExtraParens(float f, double d, long double ld) {
d = (f); //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
ld = (f); //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
ld = (d); //expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
d = (double)(f);
ld = (long double)(f);
ld = (long double)(d);
}

extern void DoubleParameter(double);
extern void LongDoubleParameter(long double);

void ArgumentPassing(float f, double d) {
DoubleParameter(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
LongDoubleParameter(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
LongDoubleParameter(d); // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
DoubleParameter((double)f);
LongDoubleParameter((long double)f);
LongDoubleParameter((long double)d);
}

void BinaryOperator(float f, double d, long double ld) {
Expand All @@ -49,12 +77,21 @@ void BinaryOperator(float f, double d, long double ld) {
f = ld * f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
d = d * ld; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
d = ld * d; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
f = (double)f * d;
f = d * (double)f;
f = (long double)f * ld;
f = ld * (long double)f;
d = (long double)d * ld;
d = ld * (long double)d;
}

void MultiplicationAssignment(float f, double d, long double ld) {
d *= f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
ld *= f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
ld *= d; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
d *= (double)f;
ld *= (long double)f;
ld *= (long double)d;

// FIXME: These cases should produce warnings as above.
f *= d;
Expand Down
250 changes: 250 additions & 0 deletions clang/test/Sema/warn-double-promotion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -fsyntax-only %s -Wdouble-promotion

using LongDouble = long double;

double ReturnDoubleFromFloatWithExplicitCast(float f) {
return static_cast<double>(f);
}

long double ReturnLongDoubleFromFloatWithExplicitCast(float f) {
return static_cast<long double>(f);
}

long double ReturnLongDoubleFromDoubleWithExplicitCast(double d) {
return static_cast<long double>(d);
}

double ReturnDoubleFromFloatWithExplicitListInitialization(float f) {
return double{f};
}

long double ReturnLongDoubleFromFloatWithExplicitListInitialization(float f) {
return LongDouble{f};
}

long double ReturnLongDoubleFromDoubleWithExplicitListInitialization(double d) {
return LongDouble{d};
}

double ReturnDoubleFromFloatWithFunctionStyleCast(float f) {
return double(f);
}

long double ReturnLongDoubleFromFloatWithFunctionStyleCast(float f) {
return LongDouble(f);
}

long double ReturnLongDoubleFromDoubleWithFunctionStyleCast(double d) {
return LongDouble(d);
}

void InitializationWithParens(float f, double d) {
{
double d(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
long double ld0(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
long double ld1(d); // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
}
{
double d(static_cast<double>(f));
long double ld0(static_cast<long double>(f));
long double ld1(static_cast<long double>(d));
}
{
double d(double{f});
long double ld0(LongDouble{f});
long double ld1(LongDouble{d});
}
{
double d((double(f)));
long double ld0((LongDouble(f)));
long double ld1((LongDouble(d)));
}
}

void InitializationWithBraces(float f, double d) {
{
double d{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
long double ld0{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
long double ld1{d}; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
}
{
double d{static_cast<double>(f)};
long double ld0{static_cast<long double>(f)};
long double ld1{static_cast<long double>(d)};
}
{
double d{double{f}};
long double ld0{LongDouble{f}};
long double ld1{LongDouble{d}};
}
{
double d{double(f)};
long double ld0{LongDouble(f)};
long double ld1{LongDouble(d)};
}
}

void Assignment(float f, double d, long double ld) {
d = static_cast<double>(f);
ld = static_cast<long double>(f);
ld = static_cast<long double>(d);
d = double{f};
ld = LongDouble{f};
ld = LongDouble{d};
d = double(f);
ld = LongDouble(f);
ld = LongDouble(d);
}

void AssignmentWithExtraParens(float f, double d, long double ld) {
d = static_cast<double>((f));
ld = static_cast<long double>((f));
ld = static_cast<long double>((d));
d = double{(f)};
ld = LongDouble{(f)};
ld = LongDouble{(d)};
d = double((f));
ld = LongDouble((f));
ld = LongDouble((d));
}

extern void DoubleParameter(double);
extern void LongDoubleParameter(long double);

void ArgumentPassing(float f, double d) {
DoubleParameter(static_cast<double>(f));
LongDoubleParameter(static_cast<long double>(f));
LongDoubleParameter(static_cast<long double>(d));
DoubleParameter(double{f});
LongDoubleParameter(LongDouble{f});
LongDoubleParameter(LongDouble{d});
DoubleParameter(double(f));
LongDoubleParameter(LongDouble(f));
LongDoubleParameter(LongDouble(d));
}

void BinaryOperator(float f, double d, long double ld) {
f = static_cast<double>(f) * d;
f = d * static_cast<double>(f);
f = static_cast<long double>(f) * ld;
f = ld * static_cast<long double>(f);
d = static_cast<long double>(d) * ld;
d = ld * static_cast<long double>(d);
f = double{f} * d;
f = d * double{f};
f = LongDouble{f} * ld;
f = ld * LongDouble{f};
d = LongDouble{d} * ld;
d = ld * LongDouble{d};
f = double(f) * d;
f = d * double(f);
f = LongDouble(f) * ld;
f = ld * LongDouble(f);
d = LongDouble(d) * ld;
d = ld * LongDouble(d);
}

void MultiplicationAssignment(float f, double d, long double ld) {
d *= static_cast<double>(f);
ld *= static_cast<long double>(f);
ld *= static_cast<long double>(d);
d *= double{f};
ld *= LongDouble{f};
ld *= LongDouble{d};
d *= double(f);
ld *= LongDouble(f);
ld *= LongDouble(d);
}

struct ConstructWithDouble {
ConstructWithDouble(double);
};

struct ConstructWithLongDouble {
ConstructWithLongDouble(long double);
};

void Construct(float f, double d) {
ConstructWithDouble{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
ConstructWithLongDouble{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
ConstructWithLongDouble{d}; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
ConstructWithDouble{static_cast<double>(f)};
ConstructWithLongDouble{static_cast<long double>(f)};
ConstructWithLongDouble{static_cast<long double>(d)};
ConstructWithDouble{double{f}};
ConstructWithLongDouble{LongDouble{f}};
ConstructWithLongDouble{LongDouble{d}};
ConstructWithDouble{double(f)};
ConstructWithLongDouble{LongDouble(f)};
ConstructWithLongDouble{LongDouble(d)};
}

template <class T> T ReturnTFromFloat(float f) {
return f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}} \
// expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
}

template <class T> T ReturnTFromDouble(double d) {
return d; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
}

template <class T> T ReturnTFromFloatWithStaticCast(float f) {
return static_cast<T>(f);
}

template <class T> T ReturnTFromDoubleWithStaticCast(double d) {
return static_cast<T>(d);
}

template <class T> T ReturnTFromFloatWithExplicitListInitialization(float f) {
return T{f};
}

template <class T> T ReturnTFromDoubleWithExplicitListInitialization(double d) {
return T{d};
}

template <class T> T ReturnTFromFloatWithFunctionStyleCast(float f) {
return T(f);
}

template <class T> T ReturnTFromDoubleWithFunctionStyleCast(double d) {
return T(d);
}

void TestTemplate(float f, double d) {
ReturnTFromFloat<double>(f); // expected-note{{in instantiation of function template specialization 'ReturnTFromFloat<double>' requested here}}
ReturnTFromFloat<long double>(f); // expected-note{{in instantiation of function template specialization 'ReturnTFromFloat<long double>' requested here}}
ReturnTFromDouble<long double>(d); // expected-note{{in instantiation of function template specialization 'ReturnTFromDouble<long double>' requested here}}
ReturnTFromFloatWithStaticCast<double>(f);
ReturnTFromFloatWithStaticCast<long double>(f);
ReturnTFromDoubleWithStaticCast<long double>(d);
ReturnTFromFloatWithExplicitListInitialization<double>(f);
ReturnTFromFloatWithExplicitListInitialization<long double>(f);
ReturnTFromDoubleWithExplicitListInitialization<long double>(d);
ReturnTFromFloatWithFunctionStyleCast<double>(f);
ReturnTFromFloatWithFunctionStyleCast<long double>(f);
ReturnTFromDoubleWithFunctionStyleCast<long double>(d);
}

struct MemberInitializerListParens {
double m_d;
long double m_ld0;
long double m_ld1;
MemberInitializerListParens(float f, double d):
m_d(f), // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
m_ld0(f), // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
m_ld1(d) // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
{}
};

struct MemberInitializerListBraces {
double m_d;
long double m_ld0;
long double m_ld1;
MemberInitializerListBraces(float f, double d):
m_d{f}, // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
m_ld0{f}, // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
m_ld1{d} // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
{}
};