[clang] 6bb042e - Implement _ExtInt conversion rules
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 22 06:11:39 PDT 2021
Author: Aaron Ballman
Date: 2021-07-22T09:10:36-04:00
New Revision: 6bb042e70024354acc65457e153b40d50cada4f5
URL: https://github.com/llvm/llvm-project/commit/6bb042e70024354acc65457e153b40d50cada4f5
DIFF: https://github.com/llvm/llvm-project/commit/6bb042e70024354acc65457e153b40d50cada4f5.diff
LOG: Implement _ExtInt conversion rules
Clang implemented the _ExtInt datatype as a bit-precise integer type,
which was then proposed to WG14. WG14 has accepted the proposal
(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2709.pdf), but Clang
requires some additional work as a result.
In the original Clang implementation, we elected to disallow implicit
conversions involving these types until after WG14 finalized the rules.
This patch implements the rules decided by WG14: no integer promotion
for bit-precise types, conversions prefer the larger of the two types
and in the event of a tie (say _ExtInt(32) and a 32-bit int), the
standard type wins.
There are more changes still needed to conform to N2709, but those will
be handled in follow-up patches.
Added:
Modified:
clang/lib/Sema/SemaExpr.cpp
clang/test/Sema/ext-int.c
clang/test/SemaCXX/ext-int.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 80f9c1e1b372..3926c49077ce 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1541,11 +1541,6 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
if (LHSType == RHSType)
return LHSType;
- // ExtInt types aren't subject to conversions between them or normal integers,
- // so this fails.
- if(LHSType->isExtIntType() || RHSType->isExtIntType())
- return QualType();
-
// At this point, we have two
diff erent arithmetic types.
// Diagnose attempts to convert between __float128 and long double where
diff --git a/clang/test/Sema/ext-int.c b/clang/test/Sema/ext-int.c
index 6996942a204b..9cca3d296ada 100644
--- a/clang/test/Sema/ext-int.c
+++ b/clang/test/Sema/ext-int.c
@@ -1,12 +1,75 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -Wimplicit-int-conversion -triple x86_64-gnu-linux
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wimplicit-int-conversion -Wno-unused -triple x86_64-gnu-linux
typedef _ExtInt(31) EI31;
void Ternary(_ExtInt(30) s30, EI31 s31a, _ExtInt(31) s31b,
_ExtInt(32) s32, int b) {
- b ? s30 : s31a; // expected-error{{incompatible operand types}}
- b ? s31a : s30; // expected-error{{incompatible operand types}}
- b ? s32 : 0; // expected-error{{incompatible operand types}}
+ b ? s30 : s31a;
+ b ? s31a : s30;
+ b ? s32 : 0;
(void)(b ? s31a : s31b);
(void)(s30 ? s31a : s31b);
}
+
+struct CursedBitField {
+ _ExtInt(4) A : 8; // expected-error {{width of bit-field 'A' (8 bits) exceeds the width of its type (4 bits)}}
+};
+
+#define EXPR_HAS_TYPE(EXPR, TYPE) _Generic((EXPR), default : 0, TYPE : 1)
+
+void Ops(void) {
+ _ExtInt(4) x4_s = 1;
+ _ExtInt(32) x32_s = 1;
+ _ExtInt(43) x43_s = 1;
+ unsigned _ExtInt(4) x4_u = 1;
+ unsigned _ExtInt(43) x43_u = 1;
+ unsigned _ExtInt(32) x32_u = 1;
+ int x_int = 1;
+ unsigned x_uint = 1;
+
+ // Same size/sign ops don't change type.
+ _Static_assert(EXPR_HAS_TYPE(x43_s + x43_s, _ExtInt(43)), "");
+ _Static_assert(EXPR_HAS_TYPE(x4_s - x4_s, _ExtInt(4)), "");
+ _Static_assert(EXPR_HAS_TYPE(x43_u * x43_u, unsigned _ExtInt(43)), "");
+ _Static_assert(EXPR_HAS_TYPE(x4_u / x4_u, unsigned _ExtInt(4)), "");
+
+ // Unary ops shouldn't go through integer promotions.
+ _Static_assert(EXPR_HAS_TYPE(x4_s++, _ExtInt(4)), "");
+ _Static_assert(EXPR_HAS_TYPE(++x4_s, _ExtInt(4)), "");
+ _Static_assert(EXPR_HAS_TYPE(x4_u++, unsigned _ExtInt(4)), "");
+ _Static_assert(EXPR_HAS_TYPE(++x4_u, unsigned _ExtInt(4)), "");
+ _Static_assert(EXPR_HAS_TYPE(+x4_s, _ExtInt(4)), "");
+ _Static_assert(EXPR_HAS_TYPE(-x4_s, _ExtInt(4)), "");
+ _Static_assert(EXPR_HAS_TYPE(~x4_u, unsigned _ExtInt(4)), "");
+
+ // This one really does convert to a
diff erent result type though.
+ _Static_assert(EXPR_HAS_TYPE(!x4_u, int), "");
+
+ // Test binary ops pick the correct common type.
+ _Static_assert(EXPR_HAS_TYPE(x43_s + x_int, _ExtInt(43)), "");
+ _Static_assert(EXPR_HAS_TYPE(x43_u + x_int, unsigned _ExtInt(43)), "");
+ _Static_assert(EXPR_HAS_TYPE(x32_s + x_int, int), "");
+ _Static_assert(EXPR_HAS_TYPE(x32_u + x_int, unsigned int), "");
+ _Static_assert(EXPR_HAS_TYPE(x32_s + x_uint, unsigned int), "");
+ _Static_assert(EXPR_HAS_TYPE(x32_u + x_uint, unsigned int), "");
+ _Static_assert(EXPR_HAS_TYPE(x4_s + x_int, int), "");
+ _Static_assert(EXPR_HAS_TYPE(x4_u + x_int, int), "");
+ _Static_assert(EXPR_HAS_TYPE(x4_s + x_uint, unsigned int), "");
+ _Static_assert(EXPR_HAS_TYPE(x4_u + x_uint, unsigned int), "");
+}
+
+void FromPaper1(void) {
+ // Test the examples of conversion and promotion rules from C2x 6.3.1.8.
+ _ExtInt(2) a2 = 1;
+ _ExtInt(3) a3 = 2;
+ _ExtInt(33) a33 = 1;
+ char c = 3;
+
+ _Static_assert(EXPR_HAS_TYPE(a2 * a3, _ExtInt(3)), "");
+ _Static_assert(EXPR_HAS_TYPE(a2 * c, int), "");
+ _Static_assert(EXPR_HAS_TYPE(a33 * c, _ExtInt(33)), "");
+}
+
+void FromPaper2(_ExtInt(8) a1, _ExtInt(24) a2) {
+ _Static_assert(EXPR_HAS_TYPE(a1 * (_ExtInt(32))a2, _ExtInt(32)), "");
+}
diff --git a/clang/test/SemaCXX/ext-int.cpp b/clang/test/SemaCXX/ext-int.cpp
index a619cd2eb5de..a3e8dd82fc5d 100644
--- a/clang/test/SemaCXX/ext-int.cpp
+++ b/clang/test/SemaCXX/ext-int.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -Wimplicit-int-conversion -triple x86_64-gnu-linux
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wimplicit-int-conversion -Wno-unused -Wunevaluated-expression -triple x86_64-gnu-linux
template<int Bounds>
struct HasExtInt {
@@ -110,72 +110,54 @@ void Ops() {
unsigned x_uint = 1, y_uint = 1;
bool b;
- // Disabling mixed conversions:
// Signed/unsigned mixed.
- // expected-error at +1{{invalid operands to binary expression}}
x43_u + y43_s;
- // expected-error at +1{{invalid operands to binary expression}}
x4_s - y4_u;
- // expected-error at +1{{invalid operands to binary expression}}
x43_s * y43_u;
- // expected-error at +1{{invalid operands to binary expression}}
x4_u / y4_s;
// Different Sizes.
- // expected-error at +1{{invalid operands to binary expression}}
x43_s + y4_s;
- // expected-error at +1{{invalid operands to binary expression}}
x43_s - y4_u;
- // expected-error at +1{{invalid operands to binary expression}}
x43_u * y4_u;
- // expected-error at +1{{invalid operands to binary expression}}
x4_u / y43_u;
// Mixed with standard types.
- // expected-error at +1{{invalid operands to binary expression}}
x43_s + x_int;
- // expected-error at +1{{invalid operands to binary expression}}
x43_u - x_int;
- // expected-error at +1{{invalid operands to binary expression}}
x32_s * x_int;
- // expected-error at +1{{invalid operands to binary expression}}
x32_u / x_int;
- // expected-error at +1{{invalid operands to binary expression}}
x32_s * x_uint;
- // expected-error at +1{{invalid operands to binary expression}}
x32_u / x_uint;
- // expected-error at +1{{invalid operands to binary expression}}
x4_s + x_int;
- // expected-error at +1{{invalid operands to binary expression}}
x4_u - x_int;
- // expected-error at +1{{invalid operands to binary expression}}
x4_s + b;
- // expected-error at +1{{invalid operands to binary expression}}
x4_u - b;
- // expected-error at +1{{invalid operands to binary expression}}
x43_s + b;
- // expected-error at +1{{invalid operands to binary expression}}
x43_u - b;
+ static_assert(is_same<decltype(x43_s + x_int), _ExtInt(43)>::value, "");
+ static_assert(is_same<decltype(x43_u + x_int), unsigned _ExtInt(43)>::value, "");
+ static_assert(is_same<decltype(x32_s + x_int), int>::value, "");
+ static_assert(is_same<decltype(x32_u + x_int), unsigned int>::value, "");
+ static_assert(is_same<decltype(x32_s + x_uint), unsigned int>::value, "");
+ static_assert(is_same<decltype(x32_u + x_uint), unsigned int>::value, "");
+ static_assert(is_same<decltype(x4_s + x_int), int>::value, "");
+ static_assert(is_same<decltype(x4_u + x_int), int>::value, "");
+ static_assert(is_same<decltype(x4_s + x_uint), unsigned int>::value, "");
+ static_assert(is_same<decltype(x4_u + x_uint), unsigned int>::value, "");
// Bitwise checks.
- // expected-error at +1{{invalid operands to binary expression}}
x43_s % y4_u;
- // expected-error at +1{{invalid operands to binary expression}}
x43_u % y4_s;
- // expected-error at +1{{invalid operands to binary expression}}
x4_s | y43_u;
- // expected-error at +1{{invalid operands to binary expression}}
x4_u | y43_s;
// compassign.
- // expected-error at +1{{invalid operands to binary expression}}
x43_s += 33;
// Comparisons.
- // expected-error at +1{{invalid operands to binary expression}}
x43_s > 33;
- // expected-error at +1{{invalid operands to binary expression}}
- x4_s > 33;
+ x4_s > 33; // expected-warning {{result of comparison of constant 33 with expression of type '_ExtInt(4)' is always false}}
// Same size/sign ops don't change type.
static_assert(is_same<decltype(x43_s + y43_s), _ExtInt(43)>::value,"");
@@ -262,6 +244,10 @@ struct UsedAsBitField {
_ExtInt(3) H : 3;
};
+struct CursedBitField {
+ _ExtInt(4) A : 8; // expected-warning {{width of bit-field 'A' (8 bits) exceeds the width of its type; value will be truncated to 4 bits}}
+};
+
// expected-error at +1{{mode attribute only supported for integer and floating-point types}}
typedef _ExtInt(33) IllegalMode __attribute__((mode(DI)));
@@ -279,9 +265,29 @@ void ImplicitCasts(_ExtInt(31) s31, _ExtInt(33) s33, int i) {
void Ternary(_ExtInt(30) s30, _ExtInt(31) s31a, _ExtInt(31) s31b,
_ExtInt(32) s32, bool b) {
- b ? s30 : s31a; // expected-error{{incompatible operand types}}
- b ? s31a : s30; // expected-error{{incompatible operand types}}
- b ? s32 : (int)0; // expected-error{{incompatible operand types}}
+ b ? s30 : s31a;
+ b ? s31a : s30;
+ b ? s32 : (int)0;
(void)(b ? s31a : s31b);
(void)(s30 ? s31a : s31b);
+
+ static_assert(is_same<decltype(b ? s30 : s31a), _ExtInt(31)>::value, "");
+ static_assert(is_same<decltype(b ? s32 : s30), _ExtInt(32)>::value, "");
+ static_assert(is_same<decltype(b ? s30 : 0), int>::value, "");
+}
+
+void FromPaper1() {
+ // Test the examples of conversion and promotion rules from C2x 6.3.1.8.
+ _ExtInt(2) a2 = 1;
+ _ExtInt(3) a3 = 2;
+ _ExtInt(33) a33 = 1;
+ char c = 3;
+
+ static_assert(is_same<decltype(a2 * a3), _ExtInt(3)>::value, "");
+ static_assert(is_same<decltype(a2 * c), int>::value, "");
+ static_assert(is_same<decltype(a33 * c), _ExtInt(33)>::value, "");
+}
+
+void FromPaper2(_ExtInt(8) a1, _ExtInt(24) a2) {
+ static_assert(is_same<decltype(a1 * (_ExtInt(32))a2), _ExtInt(32)>::value, "");
}
More information about the cfe-commits
mailing list