[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