Skip to content

Commit 3cc56dd

Browse files
authored
[Clang] [Sema] Fix -Wdouble-promotion in C++ list-initialization (#159992)
Resolves #33409. The information `IsListInit` is already passed to function `CheckImplicitConversion` for another use-case which makes adding a condition for the double-promotion case simple. Also adds tests, both for the changed list-initialization case as well as for normal explicit casts which already would have passed before this PR. These negative tests are added directly next to the positive tests in `warn-double-promotion.c` or for the C++-specific cases in a new .cpp version of that file.
1 parent 14a126b commit 3cc56dd

File tree

4 files changed

+307
-1
lines changed

4 files changed

+307
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ Bug Fixes to C++ Support
422422
``__builtin_addressof``, and related issues with builtin arguments. (#GH154034)
423423
- Fix an assertion failure when taking the address on a non-type template parameter argument of
424424
object type. (#GH151531)
425+
- Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409).
425426

426427
Bug Fixes to AST Handling
427428
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaChecking.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13043,7 +13043,19 @@ static void AnalyzeImplicitConversions(
1304313043

1304413044
// Skip past explicit casts.
1304513045
if (auto *CE = dyn_cast<ExplicitCastExpr>(E)) {
13046-
E = CE->getSubExpr()->IgnoreParenImpCasts();
13046+
E = CE->getSubExpr();
13047+
// In the special case of a C++ function-style cast with braces,
13048+
// CXXFunctionalCastExpr has an InitListExpr as direct child with a single
13049+
// initializer. This InitListExpr basically belongs to the cast itself, so
13050+
// we skip it too. Specifically this is needed to silence -Wdouble-promotion
13051+
if (isa<CXXFunctionalCastExpr>(CE)) {
13052+
if (auto *InitListE = dyn_cast<InitListExpr>(E)) {
13053+
if (InitListE->getNumInits() == 1) {
13054+
E = InitListE->getInit(0);
13055+
}
13056+
}
13057+
}
13058+
E = E->IgnoreParenImpCasts();
1304713059
if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
1304813060
S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
1304913061
WorkList.push_back({E, CC, IsListInit});

clang/test/Sema/warn-double-promotion.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -fsyntax-only %s -Wdouble-promotion
2+
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -fsyntax-only -x c++ %s -Wdouble-promotion
23

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

28+
double ReturnDoubleFromFloatWithExplicitCast(float f) {
29+
return (double)f;
30+
}
31+
32+
long double ReturnLongDoubleFromFloatWithExplicitCast(float f) {
33+
return (long double)f;
34+
}
35+
36+
long double ReturnLongDoubleFromDoubleWithExplicitCast(double d) {
37+
return (long double)d;
38+
}
39+
2740
void Assignment(float f, double d, long double ld) {
2841
d = f; //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
2942
ld = f; //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
3043
ld = d; //expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
44+
d = (double)f;
45+
ld = (long double)f;
46+
ld = (long double)d;
3147
f = d;
3248
f = ld;
3349
d = ld;
3450
}
3551

52+
void AssignmentWithExtraParens(float f, double d, long double ld) {
53+
d = (f); //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
54+
ld = (f); //expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
55+
ld = (d); //expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
56+
d = (double)(f);
57+
ld = (long double)(f);
58+
ld = (long double)(d);
59+
}
60+
3661
extern void DoubleParameter(double);
3762
extern void LongDoubleParameter(long double);
3863

3964
void ArgumentPassing(float f, double d) {
4065
DoubleParameter(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
4166
LongDoubleParameter(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
4267
LongDoubleParameter(d); // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
68+
DoubleParameter((double)f);
69+
LongDoubleParameter((long double)f);
70+
LongDoubleParameter((long double)d);
4371
}
4472

4573
void BinaryOperator(float f, double d, long double ld) {
@@ -49,12 +77,21 @@ void BinaryOperator(float f, double d, long double ld) {
4977
f = ld * f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
5078
d = d * ld; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
5179
d = ld * d; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
80+
f = (double)f * d;
81+
f = d * (double)f;
82+
f = (long double)f * ld;
83+
f = ld * (long double)f;
84+
d = (long double)d * ld;
85+
d = ld * (long double)d;
5286
}
5387

5488
void MultiplicationAssignment(float f, double d, long double ld) {
5589
d *= f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
5690
ld *= f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
5791
ld *= d; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
92+
d *= (double)f;
93+
ld *= (long double)f;
94+
ld *= (long double)d;
5895

5996
// FIXME: These cases should produce warnings as above.
6097
f *= d;
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -fsyntax-only %s -Wdouble-promotion
2+
3+
using LongDouble = long double;
4+
5+
double ReturnDoubleFromFloatWithExplicitCast(float f) {
6+
return static_cast<double>(f);
7+
}
8+
9+
long double ReturnLongDoubleFromFloatWithExplicitCast(float f) {
10+
return static_cast<long double>(f);
11+
}
12+
13+
long double ReturnLongDoubleFromDoubleWithExplicitCast(double d) {
14+
return static_cast<long double>(d);
15+
}
16+
17+
double ReturnDoubleFromFloatWithExplicitListInitialization(float f) {
18+
return double{f};
19+
}
20+
21+
long double ReturnLongDoubleFromFloatWithExplicitListInitialization(float f) {
22+
return LongDouble{f};
23+
}
24+
25+
long double ReturnLongDoubleFromDoubleWithExplicitListInitialization(double d) {
26+
return LongDouble{d};
27+
}
28+
29+
double ReturnDoubleFromFloatWithFunctionStyleCast(float f) {
30+
return double(f);
31+
}
32+
33+
long double ReturnLongDoubleFromFloatWithFunctionStyleCast(float f) {
34+
return LongDouble(f);
35+
}
36+
37+
long double ReturnLongDoubleFromDoubleWithFunctionStyleCast(double d) {
38+
return LongDouble(d);
39+
}
40+
41+
void InitializationWithParens(float f, double d) {
42+
{
43+
double d(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
44+
long double ld0(f); // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
45+
long double ld1(d); // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
46+
}
47+
{
48+
double d(static_cast<double>(f));
49+
long double ld0(static_cast<long double>(f));
50+
long double ld1(static_cast<long double>(d));
51+
}
52+
{
53+
double d(double{f});
54+
long double ld0(LongDouble{f});
55+
long double ld1(LongDouble{d});
56+
}
57+
{
58+
double d((double(f)));
59+
long double ld0((LongDouble(f)));
60+
long double ld1((LongDouble(d)));
61+
}
62+
}
63+
64+
void InitializationWithBraces(float f, double d) {
65+
{
66+
double d{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
67+
long double ld0{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
68+
long double ld1{d}; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
69+
}
70+
{
71+
double d{static_cast<double>(f)};
72+
long double ld0{static_cast<long double>(f)};
73+
long double ld1{static_cast<long double>(d)};
74+
}
75+
{
76+
double d{double{f}};
77+
long double ld0{LongDouble{f}};
78+
long double ld1{LongDouble{d}};
79+
}
80+
{
81+
double d{double(f)};
82+
long double ld0{LongDouble(f)};
83+
long double ld1{LongDouble(d)};
84+
}
85+
}
86+
87+
void Assignment(float f, double d, long double ld) {
88+
d = static_cast<double>(f);
89+
ld = static_cast<long double>(f);
90+
ld = static_cast<long double>(d);
91+
d = double{f};
92+
ld = LongDouble{f};
93+
ld = LongDouble{d};
94+
d = double(f);
95+
ld = LongDouble(f);
96+
ld = LongDouble(d);
97+
}
98+
99+
void AssignmentWithExtraParens(float f, double d, long double ld) {
100+
d = static_cast<double>((f));
101+
ld = static_cast<long double>((f));
102+
ld = static_cast<long double>((d));
103+
d = double{(f)};
104+
ld = LongDouble{(f)};
105+
ld = LongDouble{(d)};
106+
d = double((f));
107+
ld = LongDouble((f));
108+
ld = LongDouble((d));
109+
}
110+
111+
void AssignmentWithExtraBraces(float f, double d, long double ld) {
112+
d = double{{f}}; // expected-warning{{too many braces around scalar initializer}}
113+
ld = LongDouble{{f}}; // expected-warning{{too many braces around scalar initializer}}
114+
ld = LongDouble{{d}}; // expected-warning{{too many braces around scalar initializer}}
115+
}
116+
117+
extern void DoubleParameter(double);
118+
extern void LongDoubleParameter(long double);
119+
120+
void ArgumentPassing(float f, double d) {
121+
DoubleParameter(static_cast<double>(f));
122+
LongDoubleParameter(static_cast<long double>(f));
123+
LongDoubleParameter(static_cast<long double>(d));
124+
DoubleParameter(double{f});
125+
LongDoubleParameter(LongDouble{f});
126+
LongDoubleParameter(LongDouble{d});
127+
DoubleParameter(double(f));
128+
LongDoubleParameter(LongDouble(f));
129+
LongDoubleParameter(LongDouble(d));
130+
}
131+
132+
void BinaryOperator(float f, double d, long double ld) {
133+
f = static_cast<double>(f) * d;
134+
f = d * static_cast<double>(f);
135+
f = static_cast<long double>(f) * ld;
136+
f = ld * static_cast<long double>(f);
137+
d = static_cast<long double>(d) * ld;
138+
d = ld * static_cast<long double>(d);
139+
f = double{f} * d;
140+
f = d * double{f};
141+
f = LongDouble{f} * ld;
142+
f = ld * LongDouble{f};
143+
d = LongDouble{d} * ld;
144+
d = ld * LongDouble{d};
145+
f = double(f) * d;
146+
f = d * double(f);
147+
f = LongDouble(f) * ld;
148+
f = ld * LongDouble(f);
149+
d = LongDouble(d) * ld;
150+
d = ld * LongDouble(d);
151+
}
152+
153+
void MultiplicationAssignment(float f, double d, long double ld) {
154+
d *= static_cast<double>(f);
155+
ld *= static_cast<long double>(f);
156+
ld *= static_cast<long double>(d);
157+
d *= double{f};
158+
ld *= LongDouble{f};
159+
ld *= LongDouble{d};
160+
d *= double(f);
161+
ld *= LongDouble(f);
162+
ld *= LongDouble(d);
163+
}
164+
165+
struct ConstructWithDouble {
166+
ConstructWithDouble(double);
167+
};
168+
169+
struct ConstructWithLongDouble {
170+
ConstructWithLongDouble(long double);
171+
};
172+
173+
void Construct(float f, double d) {
174+
ConstructWithDouble{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
175+
ConstructWithLongDouble{f}; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
176+
ConstructWithLongDouble{d}; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
177+
ConstructWithDouble{static_cast<double>(f)};
178+
ConstructWithLongDouble{static_cast<long double>(f)};
179+
ConstructWithLongDouble{static_cast<long double>(d)};
180+
ConstructWithDouble{double{f}};
181+
ConstructWithLongDouble{LongDouble{f}};
182+
ConstructWithLongDouble{LongDouble{d}};
183+
ConstructWithDouble{double(f)};
184+
ConstructWithLongDouble{LongDouble(f)};
185+
ConstructWithLongDouble{LongDouble(d)};
186+
}
187+
188+
template <class T> T ReturnTFromFloat(float f) {
189+
return f; // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}} \
190+
// expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
191+
}
192+
193+
template <class T> T ReturnTFromDouble(double d) {
194+
return d; // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
195+
}
196+
197+
template <class T> T ReturnTFromFloatWithStaticCast(float f) {
198+
return static_cast<T>(f);
199+
}
200+
201+
template <class T> T ReturnTFromDoubleWithStaticCast(double d) {
202+
return static_cast<T>(d);
203+
}
204+
205+
template <class T> T ReturnTFromFloatWithExplicitListInitialization(float f) {
206+
return T{f};
207+
}
208+
209+
template <class T> T ReturnTFromDoubleWithExplicitListInitialization(double d) {
210+
return T{d};
211+
}
212+
213+
template <class T> T ReturnTFromFloatWithFunctionStyleCast(float f) {
214+
return T(f);
215+
}
216+
217+
template <class T> T ReturnTFromDoubleWithFunctionStyleCast(double d) {
218+
return T(d);
219+
}
220+
221+
void TestTemplate(float f, double d) {
222+
ReturnTFromFloat<double>(f); // expected-note{{in instantiation of function template specialization 'ReturnTFromFloat<double>' requested here}}
223+
ReturnTFromFloat<long double>(f); // expected-note{{in instantiation of function template specialization 'ReturnTFromFloat<long double>' requested here}}
224+
ReturnTFromDouble<long double>(d); // expected-note{{in instantiation of function template specialization 'ReturnTFromDouble<long double>' requested here}}
225+
ReturnTFromFloatWithStaticCast<double>(f);
226+
ReturnTFromFloatWithStaticCast<long double>(f);
227+
ReturnTFromDoubleWithStaticCast<long double>(d);
228+
ReturnTFromFloatWithExplicitListInitialization<double>(f);
229+
ReturnTFromFloatWithExplicitListInitialization<long double>(f);
230+
ReturnTFromDoubleWithExplicitListInitialization<long double>(d);
231+
ReturnTFromFloatWithFunctionStyleCast<double>(f);
232+
ReturnTFromFloatWithFunctionStyleCast<long double>(f);
233+
ReturnTFromDoubleWithFunctionStyleCast<long double>(d);
234+
}
235+
236+
struct MemberInitializerListParens {
237+
double m_d;
238+
long double m_ld0;
239+
long double m_ld1;
240+
MemberInitializerListParens(float f, double d):
241+
m_d(f), // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
242+
m_ld0(f), // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
243+
m_ld1(d) // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
244+
{}
245+
};
246+
247+
struct MemberInitializerListBraces {
248+
double m_d;
249+
long double m_ld0;
250+
long double m_ld1;
251+
MemberInitializerListBraces(float f, double d):
252+
m_d{f}, // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'double'}}
253+
m_ld0{f}, // expected-warning{{implicit conversion increases floating-point precision: 'float' to 'long double'}}
254+
m_ld1{d} // expected-warning{{implicit conversion increases floating-point precision: 'double' to 'long double'}}
255+
{}
256+
};

0 commit comments

Comments
 (0)