Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 7f3dc4d

Browse files
committed
Sema: disable implicit conversion from _Complex to real types in C++.
Converting a _Complex type to a real one simply discards the imaginary part. This can easily lead to loss of information so for safety (and GCC compatibility) this patch disallows that when the conversion would be implicit. The one exception is bool, which actually compares both real and imaginary parts and so is safe. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310427 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a7bbae3 commit 7f3dc4d

10 files changed

+37
-248
lines changed

Diff for: include/clang/Basic/DiagnosticSemaKinds.td

+2
Original file line numberDiff line numberDiff line change
@@ -3087,6 +3087,8 @@ def warn_impcast_vector_scalar : Warning<
30873087
def warn_impcast_complex_scalar : Warning<
30883088
"implicit conversion discards imaginary component: %0 to %1">,
30893089
InGroup<Conversion>, DefaultIgnore;
3090+
def err_impcast_complex_scalar : Error<
3091+
"implicit conversion from %0 to %1 is not permitted in C++">;
30903092
def warn_impcast_float_precision : Warning<
30913093
"implicit conversion loses floating-point precision: %0 to %1">,
30923094
InGroup<Conversion>, DefaultIgnore;

Diff for: lib/Sema/SemaChecking.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -9431,10 +9431,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
94319431
// Strip complex types.
94329432
if (isa<ComplexType>(Source)) {
94339433
if (!isa<ComplexType>(Target)) {
9434-
if (S.SourceMgr.isInSystemMacro(CC))
9434+
if (S.SourceMgr.isInSystemMacro(CC) || Target->isBooleanType())
94359435
return;
94369436

9437-
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar);
9437+
return DiagnoseImpCast(S, E, T, CC,
9438+
S.getLangOpts().CPlusPlus
9439+
? diag::err_impcast_complex_scalar
9440+
: diag::warn_impcast_complex_scalar);
94389441
}
94399442

94409443
Source = cast<ComplexType>(Source)->getElementType().getTypePtr();

Diff for: lib/Sema/SemaExpr.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -7530,6 +7530,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
75307530
if (unsupportedTypeConversion(*this, LHSType, RHSType))
75317531
return Incompatible;
75327532

7533+
// Disallow assigning a _Complex to a real type in C++ mode since it simply
7534+
// discards the imaginary part.
7535+
if (getLangOpts().CPlusPlus && RHSType->getAs<ComplexType>() &&
7536+
!LHSType->getAs<ComplexType>())
7537+
return Incompatible;
7538+
75337539
// Arithmetic conversions.
75347540
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
75357541
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {

Diff for: test/CodeGenCXX/stmtexpr.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ extern "C" int cleanup_exit_lvalue_local(bool cond) {
173173
_Complex float bar_complex(A, int);
174174
extern "C" int cleanup_exit_complex(bool b) {
175175
_Complex float v = bar_complex(A(1), ({ if (b) return 42; 13; }));
176-
return v;
176+
return (float)v;
177177
}
178178

179179
// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_complex({{.*}})

Diff for: test/OpenMP/atomic_capture_codegen.cpp

-44
Original file line numberDiff line numberDiff line change
@@ -611,50 +611,6 @@ int main() {
611611
// CHECK: store i8 [[DESIRED_I8]], i8* @{{.+}},
612612
#pragma omp atomic capture
613613
{bx = civ - bx; bv = bx;}
614-
// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0)
615-
// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1)
616-
// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic
617-
// CHECK: br label %[[CONT:.+]]
618-
// CHECK: [[CONT]]
619-
// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
620-
// CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32
621-
// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to float
622-
// <Skip checks for complex calculations>
623-
// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
624-
// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]]
625-
// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
626-
// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]]
627-
// CHECK: [[NEW:%.+]] = fptoui float [[X_RE]] to i16
628-
// CHECK: store i16 [[NEW]], i16* [[TEMP:%.+]],
629-
// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]],
630-
// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic
631-
// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0
632-
// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1
633-
// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
634-
// CHECK: [[EXIT]]
635-
// CHECK: store i16 [[NEW]], i16* @{{.+}},
636-
#pragma omp atomic capture
637-
usv = usx /= cfv;
638-
// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0)
639-
// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1)
640-
// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic
641-
// CHECK: br label %[[CONT:.+]]
642-
// CHECK: [[CONT]]
643-
// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
644-
// CHECK: [[X_RVAL:%.+]] = sitofp i64 [[EXPECTED]] to double
645-
// CHECK: [[ADD_RE:%.+]] = fadd double [[X_RVAL]], [[EXPR_RE]]
646-
// CHECK: [[ADD_IM:%.+]] = fadd double 0.000000e+00, [[EXPR_IM]]
647-
// CHECK: [[DESIRED:%.+]] = fptosi double [[ADD_RE]] to i64
648-
// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]],
649-
// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]],
650-
// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
651-
// CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0
652-
// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
653-
// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
654-
// CHECK: [[EXIT]]
655-
// CHECK: store i64 [[EXPECTED]], i64* @{{.+}},
656-
#pragma omp atomic capture
657-
{llv = llx; llx += cdv;}
658614
// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}}
659615
// CHECK: load i8, i8*
660616
// CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32

Diff for: test/OpenMP/atomic_update_codegen.cpp

-42
Original file line numberDiff line numberDiff line change
@@ -554,48 +554,6 @@ int main() {
554554
// CHECK: [[EXIT]]
555555
#pragma omp atomic
556556
bx = civ - bx;
557-
// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0)
558-
// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1)
559-
// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic
560-
// CHECK: br label %[[CONT:.+]]
561-
// CHECK: [[CONT]]
562-
// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
563-
// CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32
564-
// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to float
565-
// <Skip checks for complex calculations>
566-
// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
567-
// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]]
568-
// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
569-
// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]]
570-
// CHECK: [[DESIRED:%.+]] = fptoui float [[X_RE]] to i16
571-
// CHECK: store i16 [[DESIRED]], i16* [[TEMP:%.+]]
572-
// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]]
573-
// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic
574-
// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0
575-
// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1
576-
// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
577-
// CHECK: [[EXIT]]
578-
#pragma omp atomic update
579-
usx /= cfv;
580-
// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0)
581-
// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1)
582-
// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic
583-
// CHECK: br label %[[CONT:.+]]
584-
// CHECK: [[CONT]]
585-
// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
586-
// CHECK: [[X_RVAL:%.+]] = sitofp i64 [[EXPECTED]] to double
587-
// CHECK: [[ADD_RE:%.+]] = fadd double [[X_RVAL]], [[EXPR_RE]]
588-
// CHECK: [[ADD_IM:%.+]] = fadd double 0.000000e+00, [[EXPR_IM]]
589-
// CHECK: [[DESIRED:%.+]] = fptosi double [[ADD_RE]] to i64
590-
// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]]
591-
// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]]
592-
// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
593-
// CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0
594-
// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
595-
// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
596-
// CHECK: [[EXIT]]
597-
#pragma omp atomic
598-
llx += cdv;
599557
// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}}
600558
// CHECK: load i8, i8*
601559
// CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32

Diff for: test/SemaCXX/complex-conversion.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
template<typename T> void take(T);
4+
5+
void func(float Real, _Complex float Complex) {
6+
Real += Complex; // expected-error {{assigning to 'float' from incompatible type '_Complex float'}}
7+
Real += (float)Complex;
8+
9+
Real = Complex; // expected-error {{implicit conversion from '_Complex float' to 'float' is not permitted in C++}}
10+
Real = (float)Complex;
11+
12+
take<float>(Complex); // expected-error {{implicit conversion from '_Complex float' to 'float' is not permitted in C++}}
13+
take<double>(1.0i); // expected-error {{implicit conversion from '_Complex double' to 'double' is not permitted in C++}}
14+
take<_Complex float>(Complex);
15+
16+
// Conversion to bool doesn't actually discard the imaginary part.
17+
take<bool>(Complex);
18+
}

Diff for: test/SemaCXX/complex-overload.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ char *foo(float);
44
void test_foo_1(float fv, double dv, float _Complex fc, double _Complex dc) {
55
char *cp1 = foo(fv);
66
char *cp2 = foo(dv);
7-
// Note: GCC and EDG reject these two, but they are valid C99 conversions
8-
char *cp3 = foo(fc);
9-
char *cp4 = foo(dc);
7+
// Note: GCC and EDG reject these two, they are valid C99 conversions but
8+
// shouldn't be accepted in C++ because the result is surprising.
9+
char *cp3 = foo(fc); // expected-error {{implicit conversion from '_Complex float' to 'float' is not permitted in C++}}
10+
char *cp4 = foo(dc); // expected-error {{implicit conversion from '_Complex double' to 'float' is not permitted in C++}}
1011
}
1112

1213
int *foo(float _Complex);

Diff for: test/SemaCXX/integer-overflow.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ uint64_t check_integer_overflows(int i) { //expected-note {{declared here}}
164164
// expected-warning@+3 {{array index 536870912 is past the end of the array (which contains 10 elements)}}
165165
// expected-note@+1 {{array 'a' declared here}}
166166
uint64_t a[10];
167-
a[4608 * 1024 * 1024] = 1i;
167+
a[4608 * 1024 * 1024] = 1;
168168

169169
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
170170
return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024)));

0 commit comments

Comments
 (0)