diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5932,6 +5932,9 @@ def err_sizeof_alignof_function_type : Error< "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' " "to a function type">; +def err_sizeof_alignof_sizeless_type : Error< + "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' " + "to sizeless type %1">; def err_openmp_default_simd_align_expr : Error< "invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">; def err_sizeof_alignof_typeof_bitfield : Error< diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3964,6 +3964,15 @@ E->getSourceRange(), ExprKind)) return false; + // Trying to complete E won't change whether it's sizeless, so the + // checks are valid in either order. Prefer to diagnose the more + // specific failure first. + if (E->getType()->isSizelessType()) { + Diag(E->getExprLoc(), diag::err_sizeof_alignof_sizeless_type) + << ExprKind << E->getType() << E->getSourceRange(); + return true; + } + // 'alignof' applied to an expression only requires the base element type of // the expression to be complete. 'sizeof' requires the expression's type to // be complete (and will attempt to complete it if it's an array of unknown @@ -4073,6 +4082,15 @@ ExprKind)) return false; + // Trying to complete ExprType won't change whether it's sizeless, + // so the checks are valid in either order. Prefer to diagnose the + // more specific failure first. + if (ExprType->isSizelessType()) { + Diag(OpLoc, diag::err_sizeof_alignof_sizeless_type) + << ExprKind << ExprType << ExprRange; + return true; + } + if (RequireCompleteType(OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_type, ExprKind, ExprRange)) diff --git a/clang/test/Sema/aarch64-sve-types.c b/clang/test/Sema/aarch64-sve-types.c --- a/clang/test/Sema/aarch64-sve-types.c +++ b/clang/test/Sema/aarch64-sve-types.c @@ -1,52 +1,39 @@ // RUN: %clang_cc1 %s -triple aarch64-none-linux-gnu -target-feature +sve -fsyntax-only -verify -// This test is invalid under the sizeless type extension and is a stop-gap -// until that extension is added. The test makes sure that sizeof and -// alignof queries are handled without assertion failures, since at -// present there is nothing to prevent such queries being made. -// -// Under this scheme, sizeof returns 0 for all built-in sizeless types. -// This is compatible with correct usage but it relies on the user being -// careful to avoid constructs that depend directly or indirectly on the -// value of sizeof. (The sizeless type extension avoids this by treating -// such constructs as an error.) - -// expected-no-diagnostics - void f() { - int size_s8[sizeof(__SVInt8_t) == 0 ? 1 : -1]; - int align_s8[__alignof__(__SVInt8_t) == 16 ? 1 : -1]; + int size_s8[sizeof(__SVInt8_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVInt8_t'}} + int align_s8[__alignof__(__SVInt8_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVInt8_t'}} - int size_s16[sizeof(__SVInt16_t) == 0 ? 1 : -1]; - int align_s16[__alignof__(__SVInt16_t) == 16 ? 1 : -1]; + int size_s16[sizeof(__SVInt16_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVInt16_t'}} + int align_s16[__alignof__(__SVInt16_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVInt16_t'}} - int size_s32[sizeof(__SVInt32_t) == 0 ? 1 : -1]; - int align_s32[__alignof__(__SVInt32_t) == 16 ? 1 : -1]; + int size_s32[sizeof(__SVInt32_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVInt32_t'}} + int align_s32[__alignof__(__SVInt32_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVInt32_t'}} - int size_s64[sizeof(__SVInt64_t) == 0 ? 1 : -1]; - int align_s64[__alignof__(__SVInt64_t) == 16 ? 1 : -1]; + int size_s64[sizeof(__SVInt64_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVInt64_t'}} + int align_s64[__alignof__(__SVInt64_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVInt64_t'}} - int size_u8[sizeof(__SVUint8_t) == 0 ? 1 : -1]; - int align_u8[__alignof__(__SVUint8_t) == 16 ? 1 : -1]; + int size_u8[sizeof(__SVUint8_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVUint8_t'}} + int align_u8[__alignof__(__SVUint8_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVUint8_t'}} - int size_u16[sizeof(__SVUint16_t) == 0 ? 1 : -1]; - int align_u16[__alignof__(__SVUint16_t) == 16 ? 1 : -1]; + int size_u16[sizeof(__SVUint16_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVUint16_t'}} + int align_u16[__alignof__(__SVUint16_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVUint16_t'}} - int size_u32[sizeof(__SVUint32_t) == 0 ? 1 : -1]; - int align_u32[__alignof__(__SVUint32_t) == 16 ? 1 : -1]; + int size_u32[sizeof(__SVUint32_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVUint32_t'}} + int align_u32[__alignof__(__SVUint32_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVUint32_t'}} - int size_u64[sizeof(__SVUint64_t) == 0 ? 1 : -1]; - int align_u64[__alignof__(__SVUint64_t) == 16 ? 1 : -1]; + int size_u64[sizeof(__SVUint64_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVUint64_t'}} + int align_u64[__alignof__(__SVUint64_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVUint64_t'}} - int size_f16[sizeof(__SVFloat16_t) == 0 ? 1 : -1]; - int align_f16[__alignof__(__SVFloat16_t) == 16 ? 1 : -1]; + int size_f16[sizeof(__SVFloat16_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVFloat16_t'}} + int align_f16[__alignof__(__SVFloat16_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVFloat16_t'}} - int size_f32[sizeof(__SVFloat32_t) == 0 ? 1 : -1]; - int align_f32[__alignof__(__SVFloat32_t) == 16 ? 1 : -1]; + int size_f32[sizeof(__SVFloat32_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVFloat32_t'}} + int align_f32[__alignof__(__SVFloat32_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVFloat32_t'}} - int size_f64[sizeof(__SVFloat64_t) == 0 ? 1 : -1]; - int align_f64[__alignof__(__SVFloat64_t) == 16 ? 1 : -1]; + int size_f64[sizeof(__SVFloat64_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVFloat64_t'}} + int align_f64[__alignof__(__SVFloat64_t) == 16 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVFloat64_t'}} - int size_b8[sizeof(__SVBool_t) == 0 ? 1 : -1]; - int align_b8[__alignof__(__SVBool_t) == 2 ? 1 : -1]; + int size_b8[sizeof(__SVBool_t) == 0 ? 1 : -1]; // expected-error {{invalid application of 'sizeof' to sizeless type '__SVBool_t'}} + int align_b8[__alignof__(__SVBool_t) == 2 ? 1 : -1]; // expected-error {{invalid application of '__alignof' to sizeless type '__SVBool_t'}} } diff --git a/clang/test/Sema/sizeless-1.c b/clang/test/Sema/sizeless-1.c --- a/clang/test/Sema/sizeless-1.c +++ b/clang/test/Sema/sizeless-1.c @@ -15,6 +15,14 @@ typedef svint8_t int8_typedef; typedef svint8_t *int8_ptr_typedef; +int sizeof_int8 = sizeof(svint8_t); // expected-error {{invalid application of 'sizeof' to sizeless type 'svint8_t'}} +int sizeof_int8_var = sizeof(*extern_int8_ptr); // expected-error {{invalid application of 'sizeof' to sizeless type 'svint8_t'}} +int sizeof_int8_var_ptr = sizeof(extern_int8_ptr); + +int alignof_int8 = _Alignof(svint8_t); // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} +int alignof_int8_var = _Alignof(*extern_int8_ptr); // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} expected-warning {{GNU extension}} +int alignof_int8_var_ptr = _Alignof(extern_int8_ptr); // expected-warning {{GNU extension}} + void pass_int8(svint8_t); // expected-note {{passing argument to parameter here}} svint8_t return_int8(); @@ -46,6 +54,8 @@ svint8_t local_int8; svint16_t local_int16; + int _Alignas(svint8_t) aligned_int; // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} + // Using pointers to sizeless data isn't wrong here, but because the // type is incomplete, it doesn't provide any alignment guarantees. _Static_assert(__atomic_is_lock_free(1, &local_int8) == __atomic_is_lock_free(1, incomplete_ptr), ""); diff --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp --- a/clang/test/SemaCXX/sizeless-1.cpp +++ b/clang/test/SemaCXX/sizeless-1.cpp @@ -19,6 +19,20 @@ typedef svint8_t int8_typedef; typedef svint8_t *int8_ptr_typedef; +int sizeof_int8 = sizeof(svint8_t); // expected-error {{invalid application of 'sizeof' to sizeless type 'svint8_t'}} +int sizeof_int8_var = sizeof(*extern_int8_ptr); // expected-error {{invalid application of 'sizeof' to sizeless type 'svint8_t'}} +int sizeof_int8_var_ptr = sizeof(extern_int8_ptr); + +#if __cplusplus >= 201103L +int alignof_int8 = alignof(svint8_t); // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} +int alignof_int8_var = alignof(*extern_int8_ptr); // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} expected-warning {{GNU extension}} +int alignof_int8_var_ptr = alignof(extern_int8_ptr); // expected-warning {{GNU extension}} +#else +int alignof_int8 = _Alignof(svint8_t); // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} +int alignof_int8_var = _Alignof(*extern_int8_ptr); // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} expected-warning {{GNU extension}} +int alignof_int8_var_ptr = _Alignof(extern_int8_ptr); // expected-warning {{GNU extension}} +#endif + void pass_int8(svint8_t); // expected-note {{no known conversion}} svint8_t return_int8(); @@ -49,6 +63,8 @@ svint8_t local_int8; svint16_t local_int16; + int _Alignas(svint8_t) aligned_int; // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} + // Using pointers to sizeless data isn't wrong here, but because the // type is incomplete, it doesn't provide any alignment guarantees. _Static_assert(__atomic_is_lock_free(1, &local_int8) == __atomic_is_lock_free(1, incomplete_ptr), "");