[clang] 39969c7 - [Sema][SVE] Reject sizeof and alignof for sizeless types

Richard Sandiford via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 12 10:11:53 PDT 2020


Author: Richard Sandiford
Date: 2020-03-12T17:06:53Z
New Revision: 39969c7d3a6da8a60ac3ac7d10f471dea87cfca5

URL: https://github.com/llvm/llvm-project/commit/39969c7d3a6da8a60ac3ac7d10f471dea87cfca5
DIFF: https://github.com/llvm/llvm-project/commit/39969c7d3a6da8a60ac3ac7d10f471dea87cfca5.diff

LOG: [Sema][SVE] Reject sizeof and alignof for sizeless types

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.
However, the second function is invalid ACLE code and generates a
zero-length memcpy.  The point of this patch is to reject the use
of sizeof in the second case instead.

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.

Implementation-wise, the patch adds a new CompleteTypeKind enum
that controls whether RequireCompleteType & friends accept sizeless
built-in types.  For now the default is to maintain the status quo
and accept sizeless types.  However, the end of the series will flip
the default and remove the Default enum value.

The patch also adds new ...CompleteSized... wrappers that callers can
use if they explicitly want to reject sizeless types.  The callers then
use diagnostics that have an extra 0/1 parameter to indicats whether
the type is sizeless or not.

The idea is to have three cases:

1. calls that explicitly reject sizeless types, with a tweaked diagnostic
   for the sizeless case

2. calls that explicitly allow sizeless types

3. normal/old-style calls that don't make an explicit choice either way

Once the default is flipped, the 3. calls will conservatively reject
sizeless types, using the same diagnostic as for other incomplete types.

Differential Revision: https://reviews.llvm.org/D75572

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4193b0390ce0..3a532fedac48 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5939,9 +5939,9 @@ def ext_sizeof_alignof_void_type : Extension<
 def err_opencl_sizeof_alignof_type : Error<
   "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' "
   "to a void type">;
-def err_sizeof_alignof_incomplete_type : Error<
+def err_sizeof_alignof_incomplete_or_sizeless_type : Error<
   "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' "
-  "to an incomplete type %1">;
+  "to %select{an incomplete|sizeless}1 type %2">;
 def err_sizeof_alignof_function_type : Error<
   "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' "
   "to a function type">;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 95f77c4d675c..ee02d3189816 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1739,6 +1739,7 @@ class Sema final {
   static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();}
 
   template <typename... Ts> class BoundTypeDiagnoser : public TypeDiagnoser {
+  protected:
     unsigned DiagID;
     std::tuple<const Ts &...> Args;
 
@@ -1763,6 +1764,37 @@ class Sema final {
     }
   };
 
+  /// A derivative of BoundTypeDiagnoser for which the diagnostic's type
+  /// parameter is preceded by a 0/1 enum that is 1 if the type is sizeless.
+  /// For example, a diagnostic with no other parameters would generally have
+  /// the form "...%select{incomplete|sizeless}0 type %1...".
+  template <typename... Ts>
+  class SizelessTypeDiagnoser : public BoundTypeDiagnoser<Ts...> {
+  public:
+    SizelessTypeDiagnoser(unsigned DiagID, const Ts &... Args)
+        : BoundTypeDiagnoser<Ts...>(DiagID, Args...) {}
+
+    void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
+      const SemaDiagnosticBuilder &DB = S.Diag(Loc, this->DiagID);
+      this->emit(DB, std::index_sequence_for<Ts...>());
+      DB << T->isSizelessType() << T;
+    }
+  };
+
+  enum class CompleteTypeKind {
+    /// Apply the normal rules for complete types.  In particular,
+    /// treat all sizeless types as incomplete.
+    Normal,
+
+    /// Relax the normal rules for complete types so that they include
+    /// sizeless built-in types.
+    AcceptSizeless,
+
+    // FIXME: Eventually we should flip the default to Normal and opt in
+    // to AcceptSizeless rather than opt out of it.
+    Default = AcceptSizeless
+  };
+
 private:
   /// Methods for marking which expressions involve dereferencing a pointer
   /// marked with the 'noderef' attribute. Expressions are checked bottom up as
@@ -1776,7 +1808,7 @@ class Sema final {
   void CheckMemberAccessOfNoDeref(const MemberExpr *E);
 
   bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
-                               TypeDiagnoser *Diagnoser);
+                               CompleteTypeKind Kind, TypeDiagnoser *Diagnoser);
 
   struct ModuleScope {
     SourceLocation BeginLoc;
@@ -1867,13 +1899,22 @@ class Sema final {
 
   bool isUsualDeallocationFunction(const CXXMethodDecl *FD);
 
-  bool isCompleteType(SourceLocation Loc, QualType T) {
-    return !RequireCompleteTypeImpl(Loc, T, nullptr);
+  bool isCompleteType(SourceLocation Loc, QualType T,
+                      CompleteTypeKind Kind = CompleteTypeKind::Default) {
+    return !RequireCompleteTypeImpl(Loc, T, Kind, nullptr);
   }
   bool RequireCompleteType(SourceLocation Loc, QualType T,
-                           TypeDiagnoser &Diagnoser);
+                           CompleteTypeKind Kind, TypeDiagnoser &Diagnoser);
+  bool RequireCompleteType(SourceLocation Loc, QualType T,
+                           CompleteTypeKind Kind, unsigned DiagID);
+
   bool RequireCompleteType(SourceLocation Loc, QualType T,
-                           unsigned DiagID);
+                           TypeDiagnoser &Diagnoser) {
+    return RequireCompleteType(Loc, T, CompleteTypeKind::Default, Diagnoser);
+  }
+  bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID) {
+    return RequireCompleteType(Loc, T, CompleteTypeKind::Default, DiagID);
+  }
 
   template <typename... Ts>
   bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID,
@@ -1882,14 +1923,29 @@ class Sema final {
     return RequireCompleteType(Loc, T, Diagnoser);
   }
 
+  template <typename... Ts>
+  bool RequireCompleteSizedType(SourceLocation Loc, QualType T, unsigned DiagID,
+                                const Ts &... Args) {
+    SizelessTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...);
+    return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, Diagnoser);
+  }
+
   void completeExprArrayBound(Expr *E);
-  bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser);
+  bool RequireCompleteExprType(Expr *E, CompleteTypeKind Kind,
+                               TypeDiagnoser &Diagnoser);
   bool RequireCompleteExprType(Expr *E, unsigned DiagID);
 
   template <typename... Ts>
   bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) {
     BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...);
-    return RequireCompleteExprType(E, Diagnoser);
+    return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser);
+  }
+
+  template <typename... Ts>
+  bool RequireCompleteSizedExprType(Expr *E, unsigned DiagID,
+                                    const Ts &... Args) {
+    SizelessTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...);
+    return RequireCompleteExprType(E, CompleteTypeKind::Normal, Diagnoser);
   }
 
   bool RequireLiteralType(SourceLocation Loc, QualType T,

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 29592456d7b1..b2fe4fe2c588 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3969,14 +3969,15 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
   // be complete (and will attempt to complete it if it's an array of unknown
   // bound).
   if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) {
-    if (RequireCompleteType(E->getExprLoc(),
-                            Context.getBaseElementType(E->getType()),
-                            diag::err_sizeof_alignof_incomplete_type, ExprKind,
-                            E->getSourceRange()))
+    if (RequireCompleteSizedType(
+            E->getExprLoc(), Context.getBaseElementType(E->getType()),
+            diag::err_sizeof_alignof_incomplete_or_sizeless_type, ExprKind,
+            E->getSourceRange()))
       return true;
   } else {
-    if (RequireCompleteExprType(E, diag::err_sizeof_alignof_incomplete_type,
-                                ExprKind, E->getSourceRange()))
+    if (RequireCompleteSizedExprType(
+            E, diag::err_sizeof_alignof_incomplete_or_sizeless_type, ExprKind,
+            E->getSourceRange()))
       return true;
   }
 
@@ -4073,9 +4074,9 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
                                       ExprKind))
     return false;
 
-  if (RequireCompleteType(OpLoc, ExprType,
-                          diag::err_sizeof_alignof_incomplete_type,
-                          ExprKind, ExprRange))
+  if (RequireCompleteSizedType(
+          OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type,
+          ExprKind, ExprRange))
     return true;
 
   if (ExprType->isFunctionType()) {

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 4dee030a9362..1d9826f1970d 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -7892,12 +7892,14 @@ void Sema::completeExprArrayBound(Expr *E) {
 /// case of a reference type, the referred-to type).
 ///
 /// \param E The expression whose type is required to be complete.
+/// \param Kind Selects which completeness rules should be applied.
 /// \param Diagnoser The object that will emit a diagnostic if the type is
 /// incomplete.
 ///
 /// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
 /// otherwise.
-bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) {
+bool Sema::RequireCompleteExprType(Expr *E, CompleteTypeKind Kind,
+                                   TypeDiagnoser &Diagnoser) {
   QualType T = E->getType();
 
   // Incomplete array types may be completed by the initializer attached to
@@ -7912,12 +7914,12 @@ bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) {
   // FIXME: Are there other cases which require instantiating something other
   // than the type to complete the type of an expression?
 
-  return RequireCompleteType(E->getExprLoc(), T, Diagnoser);
+  return RequireCompleteType(E->getExprLoc(), T, Kind, Diagnoser);
 }
 
 bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
   BoundTypeDiagnoser<> Diagnoser(DiagID);
-  return RequireCompleteExprType(E, Diagnoser);
+  return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser);
 }
 
 /// Ensure that the type T is a complete type.
@@ -7935,11 +7937,14 @@ bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
 ///
 /// @param T  The type that this routine is examining for completeness.
 ///
+/// @param Kind Selects which completeness rules should be applied.
+///
 /// @returns @c true if @p T is incomplete and a diagnostic was emitted,
 /// @c false otherwise.
 bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
+                               CompleteTypeKind Kind,
                                TypeDiagnoser &Diagnoser) {
-  if (RequireCompleteTypeImpl(Loc, T, &Diagnoser))
+  if (RequireCompleteTypeImpl(Loc, T, Kind, &Diagnoser))
     return true;
   if (const TagType *Tag = T->getAs<TagType>()) {
     if (!Tag->getDecl()->isCompleteDefinitionRequired()) {
@@ -8088,6 +8093,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
 
 /// The implementation of RequireCompleteType
 bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
+                                   CompleteTypeKind Kind,
                                    TypeDiagnoser *Diagnoser) {
   // FIXME: Add this assertion to make sure we always get instantiation points.
   //  assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType");
@@ -8101,7 +8107,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
     if (!MPTy->getClass()->isDependentType()) {
       if (getLangOpts().CompleteMemberPointers &&
           !MPTy->getClass()->getAsCXXRecordDecl()->isBeingDefined() &&
-          RequireCompleteType(Loc, QualType(MPTy->getClass(), 0),
+          RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), Kind,
                               diag::err_memptr_incomplete))
         return true;
 
@@ -8115,7 +8121,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
   }
 
   NamedDecl *Def = nullptr;
-  bool Incomplete = T->isIncompleteType(&Def);
+  bool AcceptSizeless = (Kind == CompleteTypeKind::AcceptSizeless);
+  bool Incomplete = (T->isIncompleteType(&Def) ||
+                     (!AcceptSizeless && T->isSizelessBuiltinType()));
 
   // Check that any necessary explicit specializations are visible. For an
   // enum, we just need the declaration, so don't check this.
@@ -8169,7 +8177,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
       // If the external source completed the type, go through the motions
       // again to ensure we're allowed to use the completed type.
       if (!T->isIncompleteType())
-        return RequireCompleteTypeImpl(Loc, T, Diagnoser);
+        return RequireCompleteTypeImpl(Loc, T, Kind, Diagnoser);
     }
   }
 
@@ -8221,7 +8229,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
       // instantiation produced an error, so that repeated calls to this
       // function give consistent answers.
       if (!T->isIncompleteType())
-        return RequireCompleteTypeImpl(Loc, T, Diagnoser);
+        return RequireCompleteTypeImpl(Loc, T, Kind, Diagnoser);
     }
   }
 
@@ -8254,9 +8262,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
 }
 
 bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
-                               unsigned DiagID) {
+                               CompleteTypeKind Kind, unsigned DiagID) {
   BoundTypeDiagnoser<> Diagnoser(DiagID);
-  return RequireCompleteType(Loc, T, Diagnoser);
+  return RequireCompleteType(Loc, T, Kind, Diagnoser);
 }
 
 /// Get diagnostic %select index for tag kind for

diff  --git a/clang/test/Sema/aarch64-sve-types.c b/clang/test/Sema/aarch64-sve-types.c
index f85e0f8b61fe..989bc71d33c1 100644
--- 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
index cd30d1a68062..3f1bfb93a298 100644
--- a/clang/test/Sema/sizeless-1.c
+++ b/clang/test/Sema/sizeless-1.c
@@ -12,6 +12,14 @@ static svint8_t *static_int8_ptr;
 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();
@@ -43,6 +51,8 @@ void func(int sel) {
   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
index e0f44f7bafd0..a2ee6205ec97 100644
--- a/clang/test/SemaCXX/sizeless-1.cpp
+++ b/clang/test/SemaCXX/sizeless-1.cpp
@@ -17,6 +17,20 @@ static svint8_t *static_int8_ptr;
 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();
@@ -47,6 +61,8 @@ void func(int sel) {
   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), "");


        


More information about the cfe-commits mailing list