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@+1{{invalid operands to binary expression}} x43_u + y43_s; - // expected-error@+1{{invalid operands to binary expression}} x4_s - y4_u; - // expected-error@+1{{invalid operands to binary expression}} x43_s * y43_u; - // expected-error@+1{{invalid operands to binary expression}} x4_u / y4_s; // Different Sizes. - // expected-error@+1{{invalid operands to binary expression}} x43_s + y4_s; - // expected-error@+1{{invalid operands to binary expression}} x43_s - y4_u; - // expected-error@+1{{invalid operands to binary expression}} x43_u * y4_u; - // expected-error@+1{{invalid operands to binary expression}} x4_u / y43_u; // Mixed with standard types. - // expected-error@+1{{invalid operands to binary expression}} x43_s + x_int; - // expected-error@+1{{invalid operands to binary expression}} x43_u - x_int; - // expected-error@+1{{invalid operands to binary expression}} x32_s * x_int; - // expected-error@+1{{invalid operands to binary expression}} x32_u / x_int; - // expected-error@+1{{invalid operands to binary expression}} x32_s * x_uint; - // expected-error@+1{{invalid operands to binary expression}} x32_u / x_uint; - // expected-error@+1{{invalid operands to binary expression}} x4_s + x_int; - // expected-error@+1{{invalid operands to binary expression}} x4_u - x_int; - // expected-error@+1{{invalid operands to binary expression}} x4_s + b; - // expected-error@+1{{invalid operands to binary expression}} x4_u - b; - // expected-error@+1{{invalid operands to binary expression}} x43_s + b; - // expected-error@+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@+1{{invalid operands to binary expression}} x43_s % y4_u; - // expected-error@+1{{invalid operands to binary expression}} x43_u % y4_s; - // expected-error@+1{{invalid operands to binary expression}} x4_s | y43_u; - // expected-error@+1{{invalid operands to binary expression}} x4_u | y43_s; // compassign. - // expected-error@+1{{invalid operands to binary expression}} x43_s += 33; // Comparisons. - // expected-error@+1{{invalid operands to binary expression}} x43_s > 33; - // expected-error@+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@+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, ""); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits