rsandifo-arm created this revision.
rsandifo-arm added reviewers: sdesmalen, efriedma, rovka, rjmccall.
Herald added subscribers: cfe-commits, psnobl, rkruppe, tschuett.
Herald added a reviewer: rengolin.
Herald added a project: clang.
rsandifo-arm added parent revisions: D75570: [AST][SVE] Add new Type queries 
for sizeless types, D75571: [Sema][SVE] Add tests for valid and invalid type 
usage.

clang current accepts:

  void foo1(__SVInt8_t *x, __SVInt8_t *y) { *x = *y; }
  void foo2(__SVInt8_t *x, __SVInt8_t *y) {
    memcpy(y, x, sizeof(__SVInt8_t));
  }

The first function is valid ACLE code and generates correct LLVM IR.
The second function is invalid ACLE code and generates a zero-length
memcpy.

The patch means that we diagnose the problem in the second case,
rather than silently generating incorrect code.

There's no similar wrong-code bug for alignof.  However, the SVE ACLE
conservatively treats alignof in the same way as sizeof, just as the
C++ standard does for incomplete types.  The idea is that layout of
sizeless types is an implementation property and isn't defined at
the language level.

We could relax the alignof rules in future if they turn out to be
too restrictive.  It would be harder to go the other way though,
and forbid alignof after previously treating it as valid.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75572

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExpr.cpp
  clang/test/Sema/aarch64-sve-types.c
  clang/test/Sema/sizeless-1.c
  clang/test/SemaCXX/sizeless-1.cpp

Index: clang/test/SemaCXX/sizeless-1.cpp
===================================================================
--- clang/test/SemaCXX/sizeless-1.cpp
+++ 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), "");
Index: clang/test/Sema/sizeless-1.c
===================================================================
--- clang/test/Sema/sizeless-1.c
+++ 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), "");
Index: clang/test/Sema/aarch64-sve-types.c
===================================================================
--- clang/test/Sema/aarch64-sve-types.c
+++ 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'}}
 }
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ 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))
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ 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<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to