rsandifo-arm updated this revision to Diff 203546.
rsandifo-arm added a comment.

Add tests for ext_vector_type


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D62962/new/

https://reviews.llvm.org/D62962

Files:
  docs/SizelessTypes.rst
  include/clang/AST/Expr.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Initialization.h
  include/clang/Sema/Sema.h
  lib/AST/ASTContext.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/Type.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaFixItUtils.cpp
  lib/Sema/SemaInit.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/SemaPseudoObject.cpp
  lib/Sema/SemaStmt.cpp
  lib/Sema/SemaStmtAsm.cpp
  lib/Sema/SemaType.cpp
  test/Sema/sizeless-1.c
  test/SemaCXX/sizeless-1.cpp

Index: test/SemaCXX/sizeless-1.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/sizeless-1.cpp
@@ -0,0 +1,534 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++98 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++98 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++11 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++11 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++14 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++14 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++17 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++17 %s
+
+namespace std { struct type_info; }
+
+typedef __SVInt8_t svint8_t;
+typedef __SVInt16_t svint16_t;
+
+svint8_t global_int8; // expected-error {{non-local variable with sizeless type}}
+extern svint8_t extern_int8; // expected-error {{non-local variable with sizeless type}}
+static svint8_t static_int8; // expected-error {{non-local variable with sizeless type}}
+svint8_t *global_int8_ptr;
+extern svint8_t *extern_int8_ptr;
+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 {{incomplete type}}
+
+#if __cplusplus >= 201103L
+int alignof_int8 = alignof(svint8_t); // expected-error {{incomplete type}}
+#else
+int alignof_int8 = _Alignof(svint8_t); // expected-error {{incomplete type}}
+#endif
+
+void pass_int8(svint8_t); // expected-note {{no known conversion}}
+
+extern "C" svint8_t return_int8();
+
+typedef svint8_t vec_int8_a __attribute__((vector_size(64))); // expected-error {{invalid vector element type}}
+typedef svint8_t vec_int8_b __attribute__((ext_vector_type(4))); // expected-error {{invalid vector element type}}
+
+void dump(const volatile void *);
+
+void overf(svint8_t);
+void overf(svint16_t);
+
+void overf8(svint8_t); // expected-note + {{not viable}}
+void overf8(int); // expected-note + {{not viable}}
+
+void overf16(svint16_t); // expected-note + {{not viable}}
+void overf16(int); // expected-note + {{not viable}}
+
+void varargs(int, ...);
+
+void unused() {
+  svint8_t unused_int8; // expected-warning {{unused}}
+}
+
+void func(int sel) {
+  svint8_t local_int8;
+  svint16_t local_int16;
+
+  svint8_t __attribute__((aligned)) aligned_int8_1; // expected-error {{sizeless type}}
+  svint8_t __attribute__((aligned(4))) aligned_int8_2; // expected-error {{sizeless type}}
+  svint8_t _Alignas(int) aligned_int8_3; // expected-error {{sizeless type}}
+  int _Alignas(svint8_t) aligned_int; // expected-error {{incomplete type}}
+
+  (void)__atomic_is_lock_free(1, &local_int8);
+  (void)__atomic_always_lock_free(1, &local_int8);
+
+  local_int8; // expected-warning {{expression result unused}}
+
+  (void)local_int8;
+
+  local_int8, 0; // expected-warning + {{expression result unused}}
+
+  0, local_int8; // expected-warning + {{expression result unused}}
+
+  svint8_t init_int8 = local_int8;
+  svint8_t bad_init_int8 = for; // expected-error {{expected expression}}
+
+#if __cplusplus >= 201103L
+  int empty_brace_init_int = {};
+  svint8_t empty_brace_init_int8 = {};
+#else
+  int empty_brace_init_int = {}; // expected-error {{scalar initializer cannot be empty}}
+  svint8_t empty_brace_init_int8 = {}; // expected-error {{scalar initializer cannot be empty}}
+#endif
+  svint8_t brace_init_int8 = { local_int8 };
+  svint8_t bad_brace_init_int8 = { local_int8, 0 }; // expected-error {{excess elements in scalar initializer}}
+
+  const svint8_t const_int8 = local_int8; // expected-note {{declared const here}}
+
+  const svint8_t uninit_const_int8; // expected-error {{default initialization}}
+
+  volatile svint8_t volatile_int8;
+
+  const volatile svint8_t const_volatile_int8; // expected-error {{default initialization}} expected-note {{declared const here}}
+
+  _Atomic svint8_t atomic_int8; // expected-error {{_Atomic cannot be applied to incomplete type}}
+  __restrict svint8_t restrict_int8; // expected-error {{requires a pointer or reference}}
+
+  svint8_t array_int8[1]; // expected-error {{array has sizeless element type}}
+
+  bool test_int8 = init_int8; // expected-error {{cannot initialize}}
+
+  int int_int8 = init_int8; // expected-error {{cannot initialize}}
+
+  init_int8 = local_int8;
+  init_int8 = local_int16; // expected-error {{incompatible type}}
+  init_int8 = sel; // expected-error {{incompatible type}}
+
+  sel = local_int8; // expected-error {{incompatible type}}
+
+  local_int8 = (svint8_t)local_int8;
+  local_int8 = (const svint8_t)local_int8;
+  local_int8 = (svint8_t)local_int16; // expected-error {{not allowed}}
+
+  init_int8 = local_int8;
+  init_int8 = const_int8;
+  init_int8 = volatile_int8;
+  init_int8 = const_volatile_int8;
+
+  const_int8 = local_int8; // expected-error {{const-qualified type}}
+
+  volatile_int8 = local_int8;
+  volatile_int8 = const_int8;
+  volatile_int8 = volatile_int8;
+  volatile_int8 = const_volatile_int8;
+
+  const_volatile_int8 = local_int8; // expected-error {{const-qualified type}}
+
+  init_int8 = sel ? init_int8 : local_int8;
+  init_int8 = sel ? init_int8 : const_int8;
+  init_int8 = sel ? volatile_int8 : const_int8;
+  init_int8 = sel ? volatile_int8 : const_volatile_int8;
+
+  pass_int8(local_int8);
+  pass_int8(local_int16); // expected-error {{no matching function}}
+
+  local_int8 = return_int8();
+  local_int16 = return_int8(); // expected-error {{incompatible type}}
+
+  dump(&local_int8);
+  dump(&const_int8);
+  dump(&volatile_int8);
+  dump(&const_volatile_int8);
+
+  dump(&local_int8 + 1); // expected-error {{arithmetic on a pointer to an incomplete type}}
+
+  *&local_int8 = local_int8;
+  *&const_int8 = local_int8; // expected-error {{read-only variable}}
+  *&volatile_int8 = local_int8;
+  *&const_volatile_int8 = local_int8; // expected-error {{read-only variable}}
+
+  (&local_int8)[0] = local_int8; // expected-error {{subscript of pointer to incomplete type}}
+
+  overf(local_int8);
+  overf(local_int16);
+
+  overf8(local_int8);
+  overf8(local_int16); // expected-error {{no matching function}}
+
+  overf16(local_int8); // expected-error {{no matching function}}
+  overf16(local_int16);
+
+  varargs(1, local_int8, local_int16);
+
+  +init_int8; // expected-error {{invalid argument type}}
+  ++init_int8; // expected-error {{cannot increment}}
+  -init_int8; // expected-error {{invalid argument type}}
+  --init_int8; // expected-error {{cannot decrement}}
+  ~init_int8; // expected-error {{invalid argument type}}
+  !init_int8; // expected-error {{invalid argument type}}
+  *init_int8; // expected-error {{requires pointer operand}}
+  __real init_int8; // expected-error {{invalid type}}
+  __imag init_int8; // expected-error {{invalid type}}
+
+  local_int8 + init_int8; // expected-error {{invalid operands}}
+  local_int8 - init_int8; // expected-error {{invalid operands}}
+  local_int8 * init_int8; // expected-error {{invalid operands}}
+  local_int8 / init_int8; // expected-error {{invalid operands}}
+  local_int8 % init_int8; // expected-error {{invalid operands}}
+  local_int8 & init_int8; // expected-error {{invalid operands}}
+  local_int8 | init_int8; // expected-error {{invalid operands}}
+  local_int8 ^ init_int8; // expected-error {{invalid operands}}
+  local_int8 << init_int8; // expected-error {{invalid operands}}
+  local_int8 >> init_int8; // expected-error {{invalid operands}}
+  local_int8 < init_int8; // expected-error {{invalid operands}}
+  local_int8 <= init_int8; // expected-error {{invalid operands}}
+  local_int8 == init_int8; // expected-error {{invalid operands}}
+  local_int8 != init_int8; // expected-error {{invalid operands}}
+  local_int8 >= init_int8; // expected-error {{invalid operands}}
+  local_int8 > init_int8; // expected-error {{invalid operands}}
+  local_int8 && init_int8; // expected-error {{invalid operands}} expected-error {{not contextually convertible}}
+  local_int8 || init_int8; // expected-error {{invalid operands}} expected-error {{not contextually convertible}}
+
+  local_int8 += init_int8; // expected-error {{invalid operands}}
+  local_int8 -= init_int8; // expected-error {{invalid operands}}
+  local_int8 *= init_int8; // expected-error {{invalid operands}}
+  local_int8 /= init_int8; // expected-error {{invalid operands}}
+  local_int8 %= init_int8; // expected-error {{invalid operands}}
+  local_int8 &= init_int8; // expected-error {{invalid operands}}
+  local_int8 |= init_int8; // expected-error {{invalid operands}}
+  local_int8 ^= init_int8; // expected-error {{invalid operands}}
+  local_int8 <<= init_int8; // expected-error {{invalid operands}}
+  local_int8 >>= init_int8; // expected-error {{invalid operands}}
+
+  local_int8 + 0; // expected-error {{invalid operands}}
+  local_int8 - 0; // expected-error {{invalid operands}}
+  local_int8 * 0; // expected-error {{invalid operands}}
+  local_int8 / 0; // expected-error {{invalid operands}}
+  local_int8 % 0; // expected-error {{invalid operands}}
+  local_int8 & 0; // expected-error {{invalid operands}}
+  local_int8 | 0; // expected-error {{invalid operands}}
+  local_int8 ^ 0; // expected-error {{invalid operands}}
+  local_int8 << 0; // expected-error {{invalid operands}}
+  local_int8 >> 0; // expected-error {{invalid operands}}
+  local_int8 < 0; // expected-error {{invalid operands}}
+  local_int8 <= 0; // expected-error {{invalid operands}}
+  local_int8 == 0; // expected-error {{invalid operands}}
+  local_int8 != 0; // expected-error {{invalid operands}}
+  local_int8 >= 0; // expected-error {{invalid operands}}
+  local_int8 > 0; // expected-error {{invalid operands}}
+  local_int8 && 0; // expected-error {{invalid operands}} expected-error {{not contextually convertible}}
+  local_int8 || 0; // expected-error {{invalid operands}} expected-error {{not contextually convertible}}
+
+  if (local_int8) {} // expected-error {{not contextually convertible}}
+  while (local_int8) {} // expected-error {{not contextually convertible}}
+  do {} while (local_int8); // expected-error {{not contextually convertible}}
+  switch (local_int8) { default:; } // expected-error {{integer type}}
+}
+
+int vararg_receiver(int count, svint8_t first, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, first);
+  __builtin_va_arg(va, svint8_t);
+  __builtin_va_end(va);
+  return count;
+}
+
+struct sized_struct {
+  int f1;
+  svint8_t f2; // expected-error {{field has incomplete type}}
+  svint8_t f3 : 2; // expected-error {{incomplete type}}
+};
+
+union sized_union {
+  int f1;
+  svint8_t f2; // expected-error {{field has incomplete type}}
+  svint8_t f3 : 2; // expected-error {{incomplete type}}
+};
+
+void pass_int8_ref(svint8_t &); // expected-note {{not viable}}
+
+svint8_t &return_int8_ref();
+#if __cplusplus >= 201103L
+svint8_t &&return_int8_rvalue_ref();
+#endif
+
+template<typename T> struct s_template {
+  T y; // expected-error {{incomplete type}}
+};
+
+template<typename T> struct s_ptr_template {
+  s_ptr_template();
+  s_ptr_template(T, svint8_t = svint8_t());
+  s_ptr_template(const s_ptr_template &, svint8_t = svint8_t());
+  T *y;
+};
+
+template<typename T> struct s_array_template {
+  T y[1]; // expected-error {{array has sizeless element type}}
+};
+
+struct widget {
+  widget(s_ptr_template<int>);
+  svint8_t operator[](int);
+};
+
+template<typename T>
+struct wrapper_iterator {
+  T operator++();
+  T operator*() const;
+  bool operator!=(const wrapper_iterator &) const;
+};
+
+template<typename T>
+struct wrapper {
+  wrapper();
+  operator T() const;
+  wrapper_iterator<T> begin() const;
+  wrapper_iterator<T> end() const;
+};
+
+#if __cplusplus >= 201103L
+struct explicit_conv {
+  explicit operator svint8_t () const;
+};
+#endif
+
+struct constructible_from_sizeless {
+  constructible_from_sizeless(svint8_t);
+};
+
+void with_default(svint8_t = svint8_t());
+
+#if __cplusplus >= 201103L
+constexpr int ce_taking_int8(svint8_t) { return 1; } // expected-error {{not a literal type}}
+#endif
+
+#if __cplusplus < 201703L
+void throwing_func() throw(svint8_t); // expected-error {{incomplete type}}
+void throwing_pointer_func() throw(svint8_t *); // expected-error {{pointer to incomplete type}}
+void throwing_pointer_func() throw(svint8_t &); // expected-error {{reference to incomplete type}}
+#endif
+
+template<typename T> void template_fn_direct(T) {}
+template<typename T> void template_fn_ref(T &) {}
+template<typename T> void template_fn_const_ref(const T &) {}
+#if __cplusplus >= 201103L
+template<typename T> void template_fn_rvalue_ref(T &&) {}
+#endif
+
+void cxx_only() {
+  svint8_t local_int8;
+  svint16_t local_int16;
+
+  pass_int8_ref(local_int8);
+  pass_int8_ref(local_int16); // expected-error {{no matching function}}
+
+  local_int8 = return_int8_ref();
+  local_int16 = return_int8_ref(); // expected-error {{incompatible type}}
+  return_int8_ref() = local_int8;
+  return_int8_ref() = local_int16; // expected-error {{incompatible type}}
+
+#if __cplusplus >= 201103L
+  local_int8 = return_int8_rvalue_ref();
+  local_int16 = return_int8_rvalue_ref(); // expected-error {{incompatible type}}
+
+  return_int8_rvalue_ref() = local_int8; // expected-error {{not assignable}}
+  return_int8_rvalue_ref() = local_int16; // expected-error {{not assignable}}
+#endif
+
+  local_int8 = static_cast<svint8_t>(local_int8);
+  local_int8 = static_cast<svint8_t>(local_int16); // expected-error {{not allowed}}
+  local_int16 = static_cast<svint16_t>(local_int8); // expected-error {{not allowed}}
+
+  throw 1;
+  throw local_int8; // expected-error {{cannot throw object of incomplete type}}
+
+  try {} catch (int) {}
+  try {} catch (svint8_t) {} // expected-error {{cannot catch incomplete type}}
+  try {} catch (svint8_t *) {} // expected-error {{cannot catch pointer to incomplete type}}
+  try {} catch (svint8_t &) {} // expected-error {{cannot catch reference to incomplete type}}
+
+  new svint8_t; // expected-error {{allocation of incomplete type}}
+  new svint8_t(); // expected-error {{allocation of incomplete type}}
+
+  new (global_int8_ptr) svint8_t; // expected-error {{allocation of incomplete type}}
+  new (global_int8_ptr) svint8_t(); // expected-error {{allocation of incomplete type}}
+
+  local_int8.~__SVInt8_t(); // expected-error {{cannot be used in a pseudo-destructor}}
+  delete global_int8_ptr; // expected-error {{cannot delete expression of type}}
+  delete[] global_int8_ptr; // expected-error {{cannot delete expression of type}}
+
+  (void)svint8_t();
+
+  local_int8 = svint8_t();
+  local_int8 = svint16_t(); // expected-error {{incompatible type}}
+
+  s_template<int> st_int;
+  s_template<svint8_t> st_svint8; // expected-note {{in instantiation}}
+
+  s_ptr_template<int> st_ptr_int;
+  s_ptr_template<svint8_t> st_ptr_svint8;
+
+  widget w(1);
+  local_int8 = w[1];
+
+  s_array_template<int> st_array_int;
+  s_array_template<svint8_t> st_array_svint8; // expected-note {{in instantiation}}
+
+  local_int8 = static_cast<svint8_t>(wrapper<svint8_t>());
+  local_int16 = static_cast<svint8_t>(wrapper<svint8_t>()); // expected-error {{incompatible type}}
+
+  local_int8 = wrapper<svint8_t>();
+  local_int16 = wrapper<svint8_t>(); // expected-error {{incompatible type}}
+
+  svint8_t &ref_int8 = local_int8;
+  ref_int8 = ref_int8; // expected-warning {{to itself}}
+  ref_int8 = local_int8;
+  local_int8 = ref_int8;
+
+#if __cplusplus >= 201103L
+  svint8_t zero_init_int8 {};
+  svint8_t init_int8 { local_int8 };
+  svint8_t wrapper_init_int8 { wrapper<svint8_t>() };
+  svint8_t &ref_init_int8 { local_int8 };
+
+  template_fn_direct<svint8_t>({ wrapper<svint8_t> () });
+#endif
+
+  template_fn_direct(local_int8);
+  template_fn_ref(local_int8);
+  template_fn_const_ref(local_int8);
+#if __cplusplus >= 201103L
+  template_fn_rvalue_ref(local_int8);
+#endif
+
+#if __cplusplus >= 201103L
+  constexpr svint8_t ce_int8_a = wrapper<svint8_t>(); // expected-error {{constexpr variable cannot have non-literal type 'const svint8_t'}}
+#endif
+
+  (void) typeid (__SVInt8_t);
+  (void) typeid (__SVInt8_t *);
+  (void) typeid (local_int8);
+  (void) typeid (ref_int8);
+  (void) typeid (static_int8_ptr);
+
+  _Static_assert(__is_trivially_destructible(svint8_t), "");
+  _Static_assert(!__is_nothrow_assignable(svint8_t, svint8_t), "");
+  _Static_assert(__is_nothrow_assignable(svint8_t &, svint8_t), "");
+  _Static_assert(!__is_nothrow_assignable(svint8_t &, svint16_t), "");
+  _Static_assert(__is_constructible(svint8_t), "");
+  _Static_assert(__is_constructible(svint8_t, svint8_t), "");
+  _Static_assert(!__is_constructible(svint8_t, svint8_t, svint8_t), "");
+  _Static_assert(!__is_constructible(svint8_t, svint16_t), "");
+  _Static_assert(__is_nothrow_constructible(svint8_t), "");
+  _Static_assert(__is_nothrow_constructible(svint8_t, svint8_t), "");
+  _Static_assert(!__is_nothrow_constructible(svint8_t, svint16_t), "");
+  _Static_assert(!__is_assignable(svint8_t, svint8_t), "");
+  _Static_assert(__is_assignable(svint8_t &, svint8_t), "");
+  _Static_assert(!__is_assignable(svint8_t &, svint16_t), "");
+  _Static_assert(__has_nothrow_assign(svint8_t), "");
+  _Static_assert(__has_nothrow_move_assign(svint8_t), "");
+  _Static_assert(__has_nothrow_copy(svint8_t), "");
+  _Static_assert(__has_nothrow_constructor(svint8_t), "");
+  _Static_assert(__has_trivial_assign(svint8_t), "");
+  _Static_assert(__has_trivial_move_assign(svint8_t), "");
+  _Static_assert(__has_trivial_copy(svint8_t), "");
+  _Static_assert(__has_trivial_constructor(svint8_t), "");
+  _Static_assert(__has_trivial_move_constructor(svint8_t), "");
+  _Static_assert(__has_trivial_destructor(svint8_t), "");
+  _Static_assert(!__has_virtual_destructor(svint8_t), "");
+  _Static_assert(!__is_abstract(svint8_t), "");
+  _Static_assert(!__is_aggregate(svint8_t), "");
+  _Static_assert(!__is_base_of(svint8_t, svint8_t), "");
+  _Static_assert(!__is_class(svint8_t), "");
+  _Static_assert(__is_convertible_to(svint8_t, svint8_t), "");
+  _Static_assert(!__is_convertible_to(svint8_t, svint16_t), "");
+  _Static_assert(!__is_empty(svint8_t), "");
+  _Static_assert(!__is_enum(svint8_t), "");
+  _Static_assert(!__is_final(svint8_t), "");
+  _Static_assert(!__is_literal(svint8_t), "");
+  _Static_assert(__is_pod(svint8_t), "");
+  _Static_assert(!__is_polymorphic(svint8_t), "");
+  _Static_assert(__is_trivial(svint8_t), "");
+  _Static_assert(__is_object(svint8_t), "");
+  _Static_assert(__has_unique_object_representations(svint8_t), "");
+  _Static_assert(!__is_arithmetic(svint8_t), "");
+  _Static_assert(!__is_floating_point(svint8_t), "");
+  _Static_assert(!__is_integral(svint8_t), "");
+  _Static_assert(!__is_complete_type(svint8_t), "");
+  _Static_assert(!__is_void(svint8_t), "");
+  _Static_assert(!__is_array(svint8_t), "");
+  _Static_assert(!__is_function(svint8_t), "");
+  _Static_assert(!__is_reference(svint8_t), "");
+  _Static_assert(__is_reference(svint8_t &), "");
+  _Static_assert(__is_reference(const svint8_t &), "");
+  _Static_assert(!__is_lvalue_reference(svint8_t), "");
+  _Static_assert(__is_lvalue_reference(svint8_t &), "");
+#if __cplusplus >= 201103L
+  _Static_assert(!__is_lvalue_reference(svint8_t &&), "");
+#endif
+  _Static_assert(!__is_rvalue_reference(svint8_t), "");
+  _Static_assert(!__is_rvalue_reference(svint8_t &), "");
+#if __cplusplus >= 201103L
+  _Static_assert(__is_rvalue_reference(svint8_t &&), "");
+#endif
+  _Static_assert(!__is_fundamental(svint8_t), "");
+  _Static_assert(__is_object(svint8_t), "");
+  _Static_assert(!__is_scalar(svint8_t), "");
+  _Static_assert(!__is_compound(svint8_t), "");
+  _Static_assert(!__is_pointer(svint8_t), "");
+  _Static_assert(__is_pointer(svint8_t *), "");
+  _Static_assert(!__is_member_object_pointer(svint8_t), "");
+  _Static_assert(!__is_member_function_pointer(svint8_t), "");
+  _Static_assert(!__is_member_pointer(svint8_t), "");
+  _Static_assert(!__is_const(svint8_t), "");
+  _Static_assert(__is_const(const svint8_t), "");
+  _Static_assert(__is_const(const volatile svint8_t), "");
+  _Static_assert(!__is_volatile(svint8_t), "");
+  _Static_assert(__is_volatile(volatile svint8_t), "");
+  _Static_assert(__is_volatile(const volatile svint8_t), "");
+  _Static_assert(!__is_standard_layout(svint8_t), "");
+  // At present these types are opaque and don't have the properties
+  // implied by their name.
+  _Static_assert(!__is_signed(svint8_t), "");
+  _Static_assert(!__is_unsigned(svint8_t), "");
+
+#if __cplusplus >= 201103L
+  auto auto_int8 = local_int8;
+  auto auto_int16 = local_int16;
+#if __cplusplus >= 201703L
+  auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose}}
+#endif
+#endif
+
+  s_ptr_template<int> y;
+  s_ptr_template<int> &x = y;
+
+  constructible_from_sizeless cfs1(local_int8);
+  constructible_from_sizeless cfs2 = local_int8;
+#if __cplusplus >= 201103L
+  constructible_from_sizeless cfs3 { local_int8 };
+#endif
+
+#if __cplusplus >= 201103L
+  local_int8 = ([]() { return svint8_t(); })();
+  local_int8 = ([]() -> svint8_t { return svint8_t(); })();
+  auto fn1 = [&local_int8](svint8_t x) { local_int8 = x; };
+  auto fn2 = [&local_int8](svint8_t *ptr) { *ptr = local_int8; };
+  auto fn3 = [local_int8](svint8_t *ptr) { *ptr = local_int8; }; // expected-error {{by-copy capture}}
+
+  for (auto x : local_int8) {} // expected-error {{incomplete type}}
+  for (auto x : wrapper<svint8_t>()) { (void)x; }
+  for (const svint8_t &x : wrapper<svint8_t>()) { (void)x; } // expected-warning {{always a copy}} expected-note {{use non-reference type}}
+  for (const svint8_t x : wrapper<const svint8_t &>()) { (void)x; }
+#endif
+}
+
+#if __cplusplus >= 201103L
+svint8_t ret_bad_conv() { return explicit_conv(); } // expected-error {{no viable conversion from returned value of type 'explicit_conv' to function return type 'svint8_t'}}
+#endif
Index: test/Sema/sizeless-1.c
===================================================================
--- /dev/null
+++ test/Sema/sizeless-1.c
@@ -0,0 +1,258 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -Wno-comment -triple arm64-linux-gnu -target-feature +sve -std=c90 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=gnu90 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=c99 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=gnu99 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=c11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -W -triple arm64-linux-gnu -target-feature +sve -std=gnu11 %s
+
+typedef __SVInt8_t svint8_t;
+typedef __SVInt16_t svint16_t;
+
+svint8_t global_int8; // expected-error {{non-local variable with sizeless type}}
+extern svint8_t extern_int8; // expected-error {{non-local variable with sizeless type}}
+static svint8_t static_int8; // expected-error {{non-local variable with sizeless type}}
+svint8_t *global_int8_ptr;
+extern svint8_t *extern_int8_ptr;
+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 {{incomplete type}}
+
+int alignof_int8 = _Alignof(svint8_t); // expected-error {{incomplete type}}
+
+void pass_int8(svint8_t); // expected-note {{passing argument to parameter here}}
+
+svint8_t return_int8();
+
+typedef svint8_t vec_int8_a __attribute__((vector_size(64))); // expected-error {{invalid vector element type}}
+typedef svint8_t vec_int8_b __attribute__((ext_vector_type(4))); // expected-error {{invalid vector element type}}
+
+void dump(const volatile void *);
+
+void __attribute__((overloadable)) overf(svint8_t);
+void __attribute__((overloadable)) overf(svint16_t);
+
+void __attribute__((overloadable)) overf8(svint8_t); // expected-note + {{not viable}}
+void __attribute__((overloadable)) overf8(int); // expected-note + {{not viable}}
+
+void __attribute__((overloadable)) overf16(svint16_t); // expected-note + {{not viable}}
+void __attribute__((overloadable)) overf16(int); // expected-note + {{not viable}}
+
+void noproto();
+void varargs(int, ...);
+
+void unused() {
+  svint8_t unused_int8; // expected-warning {{unused}}
+}
+
+void func(int sel) {
+  svint8_t local_int8;
+  svint16_t local_int16;
+
+  svint8_t __attribute__((aligned)) aligned_int8_1; // expected-error {{sizeless type}}
+  svint8_t __attribute__((aligned(4))) aligned_int8_2; // expected-error {{sizeless type}}
+  svint8_t _Alignas(int) aligned_int8_3; // expected-error {{sizeless type}}
+  int _Alignas(svint8_t) aligned_int; // expected-error {{incomplete type}}
+
+  (void)__atomic_is_lock_free(1, &local_int8);
+  (void)__atomic_always_lock_free(1, &local_int8);
+
+  local_int8; // expected-warning {{expression result unused}}
+
+  (void)local_int8;
+
+  local_int8, 0; // expected-warning + {{expression result unused}}
+
+  0, local_int8; // expected-warning + {{expression result unused}}
+
+  svint8_t init_int8 = local_int8;
+  svint8_t bad_init_int8 = for; // expected-error {{expected expression}}
+
+  int empty_brace_init_int = {}; // expected-error {{scalar initializer cannot be empty}}
+  svint8_t empty_brace_init_int8 = {}; // expected-error {{scalar initializer cannot be empty}}
+  svint8_t brace_init_int8 = { local_int8 };
+  svint8_t bad_brace_init_int8 = { local_int8, 0 }; // expected-warning {{excess elements in scalar initializer}}
+
+  const svint8_t const_int8 = local_int8; // expected-note {{declared const here}}
+
+  const svint8_t uninit_const_int8;
+
+  volatile svint8_t volatile_int8;
+
+  const volatile svint8_t const_volatile_int8; // expected-note {{declared const here}}
+
+  _Atomic svint8_t atomic_int8; // expected-error {{_Atomic cannot be applied to incomplete type}}
+  __restrict svint8_t restrict_int8; // expected-error {{requires a pointer or reference}}
+
+  svint8_t array_int8[1]; // expected-error {{array has sizeless element type}}
+
+  _Bool test_int8 = init_int8; // expected-error {{incompatible type}}
+
+  int int_int8 = init_int8; // expected-error {{incompatible type}}
+
+  init_int8 = local_int8;
+  init_int8 = local_int16; // expected-error {{incompatible type}}
+  init_int8 = sel; // expected-error {{incompatible type}}
+
+  sel = local_int8; // expected-error {{incompatible type}}
+
+  local_int8 = (svint8_t)local_int8; // expected-error {{cast to incomplete type}}
+  local_int8 = (const svint8_t)local_int8; // expected-error {{cast to incomplete type}}
+  local_int8 = (svint8_t)local_int8; // expected-error {{cast to incomplete type}}
+
+  init_int8 = local_int8;
+  init_int8 = const_int8;
+  init_int8 = volatile_int8;
+  init_int8 = const_volatile_int8;
+
+  const_int8 = local_int8; // expected-error {{const-qualified type}}
+
+  volatile_int8 = local_int8;
+  volatile_int8 = const_int8;
+  volatile_int8 = volatile_int8;
+  volatile_int8 = const_volatile_int8;
+
+  const_volatile_int8 = local_int8; // expected-error {{const-qualified type}}
+
+  init_int8 = sel ? init_int8 : local_int8;
+  init_int8 = sel ? init_int8 : const_int8;
+  init_int8 = sel ? volatile_int8 : const_int8;
+  init_int8 = sel ? volatile_int8 : const_volatile_int8;
+
+  pass_int8(local_int8);
+  pass_int8(local_int16); // expected-error {{incompatible type}}
+
+  local_int8 = return_int8();
+  local_int16 = return_int8(); // expected-error {{incompatible type}}
+
+  dump(&local_int8);
+  dump(&const_int8);
+  dump(&volatile_int8);
+  dump(&const_volatile_int8);
+
+  dump(&local_int8 + 1); // expected-error {{arithmetic on a pointer to an incomplete type}}
+
+  *&local_int8 = local_int8;
+  *&const_int8 = local_int8; // expected-error {{read-only variable}}
+  *&volatile_int8 = local_int8;
+  *&const_volatile_int8 = local_int8; // expected-error {{read-only variable}}
+
+  (&local_int8)[0] = local_int8; // expected-error {{subscript of pointer to incomplete type}}
+
+  overf(local_int8);
+  overf(local_int16);
+
+  overf8(local_int8);
+  overf8(local_int16); // expected-error {{no matching function}}
+
+  overf16(local_int8); // expected-error {{no matching function}}
+  overf16(local_int16);
+
+  noproto(local_int8);
+  varargs(1, local_int8, local_int16);
+
+  +init_int8; // expected-error {{invalid argument type}}
+  ++init_int8; // expected-error {{cannot increment}}
+  -init_int8; // expected-error {{invalid argument type}}
+  --init_int8; // expected-error {{cannot decrement}}
+  ~init_int8; // expected-error {{invalid argument type}}
+  !init_int8; // expected-error {{invalid argument type}}
+  *init_int8; // expected-error {{requires pointer operand}}
+  __real init_int8; // expected-error {{invalid type}}
+  __imag init_int8; // expected-error {{invalid type}}
+
+  local_int8 + init_int8; // expected-error {{invalid operands}}
+  local_int8 - init_int8; // expected-error {{invalid operands}}
+  local_int8 * init_int8; // expected-error {{invalid operands}}
+  local_int8 / init_int8; // expected-error {{invalid operands}}
+  local_int8 % init_int8; // expected-error {{invalid operands}}
+  local_int8 & init_int8; // expected-error {{invalid operands}}
+  local_int8 | init_int8; // expected-error {{invalid operands}}
+  local_int8 ^ init_int8; // expected-error {{invalid operands}}
+  local_int8 << init_int8; // expected-error {{invalid operands}}
+  local_int8 >> init_int8; // expected-error {{invalid operands}}
+  local_int8 < init_int8; // expected-error {{invalid operands}}
+  local_int8 <= init_int8; // expected-error {{invalid operands}}
+  local_int8 == init_int8; // expected-error {{invalid operands}}
+  local_int8 != init_int8; // expected-error {{invalid operands}}
+  local_int8 >= init_int8; // expected-error {{invalid operands}}
+  local_int8 > init_int8; // expected-error {{invalid operands}}
+  local_int8 && init_int8; // expected-error {{invalid operands}}
+  local_int8 || init_int8; // expected-error {{invalid operands}}
+
+  local_int8 += init_int8; // expected-error {{invalid operands}}
+  local_int8 -= init_int8; // expected-error {{invalid operands}}
+  local_int8 *= init_int8; // expected-error {{invalid operands}}
+  local_int8 /= init_int8; // expected-error {{invalid operands}}
+  local_int8 %= init_int8; // expected-error {{invalid operands}}
+  local_int8 &= init_int8; // expected-error {{invalid operands}}
+  local_int8 |= init_int8; // expected-error {{invalid operands}}
+  local_int8 ^= init_int8; // expected-error {{invalid operands}}
+  local_int8 <<= init_int8; // expected-error {{invalid operands}}
+  local_int8 >>= init_int8; // expected-error {{invalid operands}}
+
+  local_int8 + 0; // expected-error {{invalid operands}}
+  local_int8 - 0; // expected-error {{invalid operands}}
+  local_int8 * 0; // expected-error {{invalid operands}}
+  local_int8 / 0; // expected-error {{invalid operands}}
+  local_int8 % 0; // expected-error {{invalid operands}}
+  local_int8 & 0; // expected-error {{invalid operands}}
+  local_int8 | 0; // expected-error {{invalid operands}}
+  local_int8 ^ 0; // expected-error {{invalid operands}}
+  local_int8 << 0; // expected-error {{invalid operands}}
+  local_int8 >> 0; // expected-error {{invalid operands}}
+  local_int8 < 0; // expected-error {{invalid operands}}
+  local_int8 <= 0; // expected-error {{invalid operands}}
+  local_int8 == 0; // expected-error {{invalid operands}}
+  local_int8 != 0; // expected-error {{invalid operands}}
+  local_int8 >= 0; // expected-error {{invalid operands}}
+  local_int8 > 0; // expected-error {{invalid operands}}
+  local_int8 && 0; // expected-error {{invalid operands}}
+  local_int8 || 0; // expected-error {{invalid operands}}
+
+  if (local_int8) {} // expected-error {{statement requires expression of scalar type}}
+  while (local_int8) {} // expected-error {{statement requires expression of scalar type}}
+  do {} while (local_int8); // expected-error {{statement requires expression of scalar type}}
+  switch (local_int8) { default:; } // expected-error {{integer type}}
+}
+
+int vararg_receiver(int count, svint8_t first, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, first);
+  __builtin_va_arg(va, svint8_t);
+  __builtin_va_end(va);
+  return count;
+}
+
+struct sized_struct {
+  int f1;
+  svint8_t f2; // expected-error {{field has incomplete type}}
+  svint8_t f3 : 2; // expected-error {{incomplete type}}
+};
+
+union sized_union {
+  int f1;
+  svint8_t f2; // expected-error {{field has incomplete type}}
+  svint8_t f3 : 2; // expected-error {{incomplete type}}
+};
+
+#if __STDC_VERSION__ >= 201112L
+void test_generic(void) {
+  svint8_t local_int8;
+  svint16_t local_int16;
+
+  int a1[_Generic (local_int8, svint8_t: 1, svint16_t: 2, default: 3) == 1 ? 1 : -1];
+  int a2[_Generic (local_int16, svint8_t: 1, svint16_t: 2, default: 3) == 2 ? 1 : -1];
+  int a3[_Generic (0, svint8_t: 1, svint16_t: 2, default: 3) == 3 ? 1 : -1];
+  (void)_Generic (0, svint8_t: 1, svint8_t: 2, default: 3); // expected-error {{compatible with previously specified}} expected-note {{compatible type}}
+}
+
+void test_compound_literal(void) {
+  svint8_t local_int8;
+
+  (void) (svint8_t) { local_int8 };
+}
+#endif
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -2130,6 +2130,12 @@
                               SourceRange Brackets, DeclarationName Entity) {
 
   SourceLocation Loc = Brackets.getBegin();
+
+  if (T->isSizelessType()) {
+    Diag(Loc, diag::err_array_of_sizeless) << T;
+    return QualType();
+  }
+
   if (getLangOpts().CPlusPlus) {
     // C++ [dcl.array]p1:
     //   T is called the array element type; this type shall not be a reference
@@ -7725,26 +7731,30 @@
   return RequireCompleteExprType(E, Diagnoser);
 }
 
-/// Ensure that the type T is a complete type.
+/// Ensure that the type T is a definite type.
 ///
-/// This routine checks whether the type @p T is complete in any
-/// context where a complete type is required. If @p T is a complete
-/// type, returns false. If @p T is a class template specialization,
-/// this routine then attempts to perform class template
-/// instantiation. If instantiation fails, or if @p T is incomplete
-/// and cannot be completed, issues the diagnostic @p diag (giving it
-/// the type @p T) and returns true.
+/// This routine checks whether the type @p T is definite in any
+/// context where a definite type is required.  @p AllowSizeless
+/// says whether sizeless types are allowed; it is false if
+/// complete (i.e. definite and sized) types are required.
+/// If @p T meets these conditions, returns false. If @p T is a class
+/// template specialization, this routine then attempts to perform class
+/// template instantiation. If instantiation fails, or if @p T is
+/// indefinite and cannot be made definite, issues the diagnostic @p diag
+/// (giving it the type @p T) and returns true.
 ///
 /// @param Loc  The location in the source that the incomplete type
 /// diagnostic should refer to.
 ///
 /// @param T  The type that this routine is examining for completeness.
 ///
+/// @param AllowSizeless  Whether to allow sizeless types.
+///
 /// @returns @c true if @p T is incomplete and a diagnostic was emitted,
 /// @c false otherwise.
-bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
-                               TypeDiagnoser &Diagnoser) {
-  if (RequireCompleteTypeImpl(Loc, T, &Diagnoser))
+bool Sema::RequireDefiniteType(SourceLocation Loc, QualType T,
+                               bool AllowSizeless, TypeDiagnoser &Diagnoser) {
+  if (RequireDefiniteTypeImpl(Loc, T, AllowSizeless, &Diagnoser))
     return true;
   if (const TagType *Tag = T->getAs<TagType>()) {
     if (!Tag->getDecl()->isCompleteDefinitionRequired()) {
@@ -7891,11 +7901,12 @@
   }
 }
 
-/// The implementation of RequireCompleteType
-bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
+/// The implementation of RequireDefiniteType
+bool Sema::RequireDefiniteTypeImpl(SourceLocation Loc, QualType T,
+                                   bool AllowSizeless,
                                    TypeDiagnoser *Diagnoser) {
   // FIXME: Add this assertion to make sure we always get instantiation points.
-  //  assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType");
+  //  assert(!Loc.isInvalid() && "Invalid location in RequireDefiniteType");
   // FIXME: Add this assertion to help us flush out problems with
   // checking for dependent types and type-dependent expressions.
   //
@@ -7920,7 +7931,7 @@
   }
 
   NamedDecl *Def = nullptr;
-  bool Incomplete = T->isIncompleteType(&Def);
+  bool Indefinite = T->isIndefiniteType(&Def);
 
   // Check that any necessary explicit specializations are visible. For an
   // enum, we just need the declaration, so don't check this.
@@ -7928,7 +7939,7 @@
     checkSpecializationVisibility(Loc, Def);
 
   // If we have a complete type, we're done.
-  if (!Incomplete) {
+  if (!Indefinite && (AllowSizeless || !T->isSizelessType())) {
     // If we know about the definition but it is not visible, complain.
     NamedDecl *SuggestedDef = nullptr;
     if (Def &&
@@ -7973,8 +7984,8 @@
           Source->CompleteType(IFace);
       // 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);
+      if (T->isDefiniteType() && (AllowSizeless || !T->isSizelessType()))
+        return RequireDefiniteTypeImpl(Loc, T, AllowSizeless, Diagnoser);
     }
   }
 
@@ -8021,8 +8032,8 @@
       // If we instantiated a definition, check that it's usable, even if
       // instantiation produced an error, so that repeated calls to this
       // function give consistent answers.
-      if (!T->isIncompleteType())
-        return RequireCompleteTypeImpl(Loc, T, Diagnoser);
+      if (T->isDefiniteType() && (AllowSizeless || !T->isSizelessType()))
+        return RequireDefiniteTypeImpl(Loc, T, AllowSizeless, Diagnoser);
     }
   }
 
@@ -8054,10 +8065,10 @@
   return true;
 }
 
-bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
-                               unsigned DiagID) {
+bool Sema::RequireDefiniteType(SourceLocation Loc, QualType T,
+                               bool AllowSizeless, unsigned DiagID) {
   BoundTypeDiagnoser<> Diagnoser(DiagID);
-  return RequireCompleteType(Loc, T, Diagnoser);
+  return RequireDefiniteType(Loc, T, AllowSizeless, Diagnoser);
 }
 
 /// Get diagnostic %select index for tag kind for
Index: lib/Sema/SemaStmtAsm.cpp
===================================================================
--- lib/Sema/SemaStmtAsm.cpp
+++ lib/Sema/SemaStmtAsm.cpp
@@ -312,10 +312,10 @@
       // Accept, even if we emitted an error diagnostic.
       break;
     }
-    case Expr::MLV_IncompleteType:
+    case Expr::MLV_IndefiniteType:
     case Expr::MLV_IncompleteVoidType:
-      if (RequireCompleteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(),
-                              diag::err_dereference_incomplete_type))
+      if (RequireDefiniteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(),
+                              true, diag::err_dereference_incomplete_type))
         return StmtError();
       LLVM_FALLTHROUGH;
     default:
@@ -324,6 +324,10 @@
                        << OutputExpr->getSourceRange());
     }
 
+    // FIXME: should have a mechanism for sizeless types too.
+    if (OutputExpr->getType()->isSizelessType())
+      continue;
+
     unsigned Size = Context.getTypeSize(OutputExpr->getType());
     if (!Context.getTargetInfo().validateOutputSize(Literal->getString(),
                                                     Size)) {
@@ -428,10 +432,17 @@
       continue;
 
     if (!Ty->isVoidType() || !Info.allowsMemory())
-      if (RequireCompleteType(InputExpr->getBeginLoc(), Exprs[i]->getType(),
-                              diag::err_dereference_incomplete_type))
+      // The test is for definiteness rather than completeness because
+      // the sizeless type extension allows sizeless types to be bound
+      // to register operands.
+      if (RequireDefiniteType(InputExpr->getBeginLoc(), Exprs[i]->getType(),
+                              true, diag::err_dereference_incomplete_type))
         return StmtError();
 
+    // FIXME: should have a mechanism for sizeless types too.
+    if (Ty->isSizelessType())
+      continue;
+
     unsigned Size = Context.getTypeSize(Ty);
     if (!Context.getTargetInfo().validateInputSize(Literal->getString(),
                                                    Size))
@@ -501,6 +512,7 @@
     // Now that we have the right indexes go ahead and check.
     StringLiteral *Literal = Constraints[ConstraintIdx];
     const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr();
+    // FIXME: should have a mechanism for sizeless types too.
     if (Ty->isDependentType() || Ty->isIncompleteType())
       continue;
 
@@ -583,6 +595,10 @@
     if (Context.hasSameType(InTy, OutTy))
       continue;  // All types can be tied to themselves.
 
+    // FIXME: should have a mechanism for sizeless types too.
+    if (InTy->isSizelessType() || OutTy->isSizelessType())
+      continue;
+
     // Decide if the input and output are in the same domain (integer/ptr or
     // floating point.
     enum AsmDomain {
@@ -762,6 +778,7 @@
   }
 
   // Otherwise, it needs to be a complete type.
+  // FIXME: should have a mechanism for sizeless types too.
   if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) {
     return ExprError();
   }
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -2795,7 +2795,9 @@
 
   QualType VariableType = VD->getType();
 
-  if (VariableType->isIncompleteType())
+  // "Indefinite" rather than "incomplete" since ranges can yield (incomplete)
+  // sizeless definite types.
+  if (VariableType->isIndefiniteType())
     return;
 
   const Expr *InitExpr = VD->getInit();
Index: lib/Sema/SemaPseudoObject.cpp
===================================================================
--- lib/Sema/SemaPseudoObject.cpp
+++ lib/Sema/SemaPseudoObject.cpp
@@ -239,7 +239,7 @@
       if (exp->isGLValue())
         return true;
       QualType ty = exp->getType();
-      assert(!ty->isIncompleteType());
+      assert(ty->isDefiniteType());
       assert(!ty->isDependentType());
 
       if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl())
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -4797,9 +4797,13 @@
   ImplicitConversionSequence Result;
   Result.setBad(BadConversionSequence::no_conversion, From, ToType);
 
-  // We need a complete type for what follows. Incomplete types can never be
+  // We need a definite type for what follows. Indefinite types can never be
   // initialized from init lists.
-  if (!S.isCompleteType(From->getBeginLoc(), ToType))
+  //
+  // The condition is "definiteness" rather than "completeness" because the
+  // sizeless type extension allows list construction of (incomplete) sizeless
+  // definite types.
+  if (!S.isDefiniteType(From->getBeginLoc(), ToType))
     return Result;
 
   // Per DR1467:
@@ -7028,7 +7032,10 @@
                                 &ConversionRef, VK_RValue);
 
   QualType ConversionType = Conversion->getConversionType();
-  if (!isCompleteType(From->getBeginLoc(), ConversionType)) {
+  // The condition is "definiteness" rather than "completeness" because the
+  // sizeless type extension allows user-defined conversions to (incomplete)
+  // sizeless definite types.
+  if (!isDefiniteType(From->getBeginLoc(), ConversionType)) {
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_bad_final_conversion;
     return;
@@ -9826,13 +9833,17 @@
     return;
   }
 
-  // Diagnose references or pointers to incomplete types differently,
-  // since it's far from impossible that the incompleteness triggered
+  // Diagnose references or pointers to indefinite types differently,
+  // since it's far from impossible that the indefiniteness triggered
   // the failure.
+  //
+  // The condition is "indefinite" rather than "incomplete" because
+  // (incomplete) sizeless definite types are never completed.  The
+  // diagnostics below are a better fit for them.
   QualType TempFromTy = FromTy.getNonReferenceType();
   if (const PointerType *PTy = TempFromTy->getAs<PointerType>())
     TempFromTy = PTy->getPointeeType();
-  if (TempFromTy->isIncompleteType()) {
+  if (TempFromTy->isIndefiniteType()) {
     // Emit the generic diagnostic and, optionally, add the hints to it.
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete)
         << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -474,8 +474,10 @@
 
     if (!LSI->ReturnType->isDependentType() &&
         !LSI->ReturnType->isVoidType()) {
-      if (RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType,
-                              diag::err_lambda_incomplete_result)) {
+      // The sizeless type extension allows (incomplete) sizeless
+      // definite types to be returned from functions.
+      if (RequireDefiniteType(CallOperator->getBeginLoc(), LSI->ReturnType,
+                              true, diag::err_lambda_incomplete_result)) {
         // Do nothing.
       }
     }
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -1114,14 +1114,18 @@
       // Special-case
       SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
           << IList->getInit(Index)->getSourceRange();
-    } else if (!T->isIncompleteType()) {
-      // Don't complain for incomplete types, since we'll get an error
+    } else if (!T->isIndefiniteType()) {
+      // Don't complain for indefinite types, since we'll get an error
       // elsewhere
       QualType CurrentObjectType = StructuredList->getType();
       int initKind =
         CurrentObjectType->isArrayType()? 0 :
         CurrentObjectType->isVectorType()? 1 :
-        CurrentObjectType->isScalarType()? 2 :
+        CurrentObjectType->isScalarType() ||
+        // Treat sizeless builtin types as scalars for the purposes of
+        // this diagnostic, since the rules are the same.  Calling them
+        // out as a special case is unlikely to be helpful.
+        CurrentObjectType->isSizelessBuiltinType()? 2 :
         CurrentObjectType->isUnionType()? 3 :
         4;
 
@@ -1179,7 +1183,7 @@
     // parts.
     CheckComplexType(Entity, IList, DeclType, Index,
                      StructuredList, StructuredIndex);
-  } else if (DeclType->isScalarType()) {
+  } else if (DeclType->isScalarType() || DeclType->isSizelessBuiltinType()) {
     CheckScalarType(Entity, IList, DeclType, Index,
                     StructuredList, StructuredIndex);
   } else if (DeclType->isVectorType()) {
@@ -3353,7 +3357,7 @@
   case FK_ReferenceBindingToInitList:
   case FK_InitListBadDestinationType:
   case FK_DefaultInitOfConst:
-  case FK_Incomplete:
+  case FK_Indefinite:
   case FK_ArrayTypeMismatch:
   case FK_NonConstantArrayInit:
   case FK_ListInitializationFailed:
@@ -3693,8 +3697,10 @@
   if (!S.isStdInitializerList(DestType, &E))
     return false;
 
+  // "Complete" and "definite" are the same here, because
+  // std::initializer_list<T> is always sized.
   if (!S.isCompleteType(List->getExprLoc(), E)) {
-    Sequence.setIncompleteTypeFailure(E);
+    Sequence.setIndefiniteTypeFailure(E);
     return true;
   }
 
@@ -3870,8 +3876,11 @@
       ILE ? MultiExprArg(ILE->getInits(), ILE->getNumInits()) : Args;
 
   // The type we're constructing needs to be complete.
+  //
+  // "Complete" and "definite" are the same here, since classes are
+  // always sized.
   if (!S.isCompleteType(Kind.getLocation(), DestType)) {
-    Sequence.setIncompleteTypeFailure(DestType);
+    Sequence.setIndefiniteTypeFailure(DestType);
     return;
   }
 
@@ -4156,8 +4165,10 @@
   }
 
   if (DestType->isRecordType() &&
+      // "Complete" and "definite" are the same here, since classes are
+      // always sized.
       !S.isCompleteType(InitList->getBeginLoc(), DestType)) {
-    Sequence.setIncompleteTypeFailure(DestType);
+    Sequence.setIndefiniteTypeFailure(DestType);
     return;
   }
 
@@ -6036,7 +6047,9 @@
     // proper call to the copy constructor.
     for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) {
       ParmVarDecl *Parm = Constructor->getParamDecl(I);
-      if (S.RequireCompleteType(Loc, Parm->getType(),
+      // The sizeless type extension allows parameters to have
+      // (incomplete) sizeless definite type.
+      if (S.RequireDefiniteType(Loc, Parm->getType(), true,
                                 diag::err_call_incomplete_argument))
         break;
 
@@ -8437,8 +8450,12 @@
 
     case OR_No_Viable_Function: {
       auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args);
-      if (!S.RequireCompleteType(Kind.getLocation(),
-                                 DestType.getNonReferenceType(),
+      // The condition is "definiteness" rather than "completeness" because
+      // (incomplete) sizeless definite types are never completed, and so
+      // completeness itself is not the problem.  The usual "not viable"
+      // diagnostics are better in that case.
+      if (!S.RequireDefiniteType(Kind.getLocation(),
+                                 DestType.getNonReferenceType(), true,
                           diag::err_typecheck_nonviable_condition_incomplete,
                                OnlyArg->getType(), Args[0]->getSourceRange()))
         S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
@@ -8726,9 +8743,9 @@
     }
     break;
 
-  case FK_Incomplete:
-    S.RequireCompleteType(Kind.getLocation(), FailedIncompleteType,
-                          diag::err_init_incomplete_type);
+  case FK_Indefinite:
+    S.RequireDefiniteType(Kind.getLocation(), FailedIndefiniteType,
+                          true, diag::err_init_incomplete_type);
     break;
 
   case FK_ListInitializationFailed: {
@@ -8891,8 +8908,8 @@
       OS << "default initialization of a const variable";
       break;
 
-    case FK_Incomplete:
-      OS << "initialization of incomplete type";
+    case FK_Indefinite:
+      OS << "initialization of indefinite type";
       break;
 
     case FK_ListInitializationFailed:
Index: lib/Sema/SemaFixItUtils.cpp
===================================================================
--- lib/Sema/SemaFixItUtils.cpp
+++ lib/Sema/SemaFixItUtils.cpp
@@ -198,6 +198,9 @@
 
 std::string
 Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
+  if (T->isSizelessBuiltinType() && LangOpts.CPlusPlus)
+    return std::string(" = ") + T.getAsString() + "()";
+
   if (T->isScalarType()) {
     std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
     if (!s.empty())
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -1418,8 +1418,11 @@
   // C++17 [expr.type.conv]p2:
   //   If the type is cv void and the initializer is (), the expression is a
   //   prvalue of the specified type that performs no initialization.
+  //
+  //   The sizeless type extension replaces "complete" with "definite",
+  //   so that sizeless definite types can be zero-initialized using ().
   if (!Ty->isVoidType() &&
-      RequireCompleteType(TyBeginLoc, ElemTy,
+      RequireDefiniteType(TyBeginLoc, ElemTy, true,
                           diag::err_invalid_incomplete_type_use, FullRange))
     return ExprError();
 
@@ -3339,7 +3342,8 @@
       // this, so we treat it as a warning unless we're in a SFINAE context.
       Diag(StartLoc, diag::ext_delete_void_ptr_operand)
         << Type << Ex.get()->getSourceRange();
-    } else if (Pointee->isFunctionType() || Pointee->isVoidType()) {
+    } else if (Pointee->isFunctionType() || Pointee->isVoidType() ||
+               Pointee->isSizelessType()) {
       return ExprError(Diag(StartLoc, diag::err_delete_operand)
         << Type << Ex.get()->getSourceRange());
     } else if (!Pointee->isDependentType()) {
@@ -4441,6 +4445,9 @@
 
   // C++1z [meta.unary.prop]:
   //   remove_all_extents_t<T> shall be a complete type or cv void.
+  //
+  // The sizeless type extension replaces "complete" with "definite",
+  // so that it's possible to apply traits to sizeless definite types.
   case UTT_IsAggregate:
   case UTT_IsTrivial:
   case UTT_IsTriviallyCopyable:
@@ -4473,8 +4480,8 @@
     if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
       return true;
 
-    return !S.RequireCompleteType(
-        Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+    return !S.RequireDefiniteType(
+        Loc, ArgTy, true, diag::err_incomplete_type_used_in_type_trait_expr);
   }
 }
 
@@ -4726,7 +4733,11 @@
     // C++14 [meta.unary.prop]:
     //   For incomplete types and function types, is_destructible<T>::value is
     //   false.
-    if (T->isIncompleteType() || T->isFunctionType())
+    //
+    // The sizeless type extension replaces "incomplete" with "indefinite",
+    // since sizeless definite types can be created with automatic storage
+    // duration and must therefore be destructible.
+    if (T->isIndefiniteType() || T->isFunctionType())
       return false;
 
     // A type that requires destruction (via a non-trivial destructor or ARC
@@ -4952,19 +4963,25 @@
     // Precondition: T and all types in the parameter pack Args shall be
     // complete types, (possibly cv-qualified) void, or arrays of
     // unknown bound.
+    //
+    // The sizeless type extension replaces "complete" with "definite",
+    // so that sizeless definite types can be used with the traits.
     for (const auto *TSI : Args) {
       QualType ArgTy = TSI->getType();
       if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType())
         continue;
 
-      if (S.RequireCompleteType(KWLoc, ArgTy,
+      if (S.RequireDefiniteType(KWLoc, ArgTy, true,
           diag::err_incomplete_type_used_in_type_trait_expr))
         return false;
     }
 
     // Make sure the first argument is not incomplete nor a function type.
+    //
+    // The sizeless type extension replaces "incomplete" with "indefinite",
+    // so that sizeless definite types can be used with the traits.
     QualType T = Args[0]->getType();
-    if (T->isIncompleteType() || T->isFunctionType())
+    if (T->isIndefiniteType() || T->isFunctionType())
       return false;
 
     // Make sure the first argument is not an abstract type.
@@ -5181,7 +5198,10 @@
       return LhsT->isVoidType();
 
     // A function definition requires a complete, non-abstract return type.
-    if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT))
+    //
+    // The sizeless type extension replaces "complete" with "definite",
+    // so that functions can return sizeless definite types.
+    if (!Self.isDefiniteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT))
       return false;
 
     // Compute the result of add_rvalue_reference.
@@ -5224,12 +5244,15 @@
     //
     //   For both, T and U shall be complete types, (possibly cv-qualified)
     //   void, or arrays of unknown bound.
+    //
+    //   The sizeless type extension replaces "complete" with "definite",
+    //   so that functions can return sizeless definite types.
     if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
-        Self.RequireCompleteType(KeyLoc, LhsT,
+        Self.RequireDefiniteType(KeyLoc, LhsT, true,
           diag::err_incomplete_type_used_in_type_trait_expr))
       return false;
     if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
-        Self.RequireCompleteType(KeyLoc, RhsT,
+        Self.RequireDefiniteType(KeyLoc, RhsT, true,
           diag::err_incomplete_type_used_in_type_trait_expr))
       return false;
 
@@ -7391,7 +7414,9 @@
   E = Res.get();
 
   if (!E->getType()->isVoidType())
-    RequireCompleteType(E->getExprLoc(), E->getType(),
+    // The test is based on definiteness rather than completeness because
+    // (incomplete) sizeless definite types can be used in an ignored result.
+    RequireDefiniteType(E->getExprLoc(), E->getType(), true,
                         diag::err_incomplete_type);
   return E;
 }
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -783,7 +783,11 @@
 /// Incomplete types are considered POD, since this check can be performed
 /// when we're in an unevaluated context.
 Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
-  if (Ty->isIncompleteType()) {
+  // "Indefinite" rather than "incomplete" since (incomplete) sizeless
+  // definite types can be passed to functions.  In practice the choice
+  // makes no difference here, since all sizeless types are POD and so
+  // are valid via that route.
+  if (Ty->isIndefiniteType()) {
     // C++11 [expr.call]p7:
     //   After these conversions, if the argument does not have arithmetic,
     //   enumeration, pointer, pointer to member, or class type, the program
@@ -929,8 +933,11 @@
     return Comma.get();
   }
 
+  // The sizeless type extension replaces "complete object type" with
+  // "definite object type" in C11 6.5.2.2p4, so that arguments can
+  // have sizeless definite type.
   if (!getLangOpts().CPlusPlus &&
-      RequireCompleteType(E->getExprLoc(), E->getType(),
+      RequireDefiniteType(E->getExprLoc(), E->getType(), true,
                           diag::err_call_incomplete_argument))
     return ExprError();
 
@@ -1483,8 +1490,11 @@
       } else {
         // C11 6.5.1.1p2 "The type name in a generic association shall specify a
         // complete object type other than a variably modified type."
+        //
+        // The sizeless type extension replaces "complete" with "definite",
+        // so that _Generic can be used with sizeless definite types.
         unsigned D = 0;
-        if (Types[i]->getType()->isIncompleteType())
+        if (Types[i]->getType()->isIndefiniteType())
           D = diag::err_assoc_type_incomplete;
         else if (!Types[i]->getType()->isObjectType())
           D = diag::err_assoc_type_nonobject;
@@ -5069,7 +5079,10 @@
     if (ArgIx < Args.size()) {
       Arg = Args[ArgIx++];
 
-      if (RequireCompleteType(Arg->getBeginLoc(), ProtoArgType,
+      // The sizeless type extension replaces "complete object type" with
+      // "definite object type" in C11 6.5.2.2p4, so that arguments can
+      // have sizeless definite type.
+      if (RequireDefiniteType(Arg->getBeginLoc(), ProtoArgType, true,
                               diag::err_call_incomplete_argument, Arg))
         return true;
 
@@ -5901,7 +5914,10 @@
         Arg = ArgE.getAs<Expr>();
       }
 
-      if (RequireCompleteType(Arg->getBeginLoc(), Arg->getType(),
+      // The sizeless type extension replaces "complete object type" with
+      // "definite object type" in C11 6.5.2.2p4, so that arguments can
+      // have sizeless definite type.
+      if (RequireDefiniteType(Arg->getBeginLoc(), Arg->getType(), true,
                               diag::err_call_incomplete_argument, Arg))
         return ExprError();
 
@@ -5967,7 +5983,10 @@
       return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init)
         << SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()));
   } else if (!literalType->isDependentType() &&
-             RequireCompleteType(LParenLoc, literalType,
+             // The sizeless type extension replaces "complete object type"
+             // with "definite object type" in C11 6.5.2.5p1, so that compound
+             // literals can have sizeless definite type.
+             RequireDefiniteType(LParenLoc, literalType, true,
                diag::err_typecheck_decl_incomplete_type,
                SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())))
     return ExprError();
@@ -7252,6 +7271,10 @@
       /*isIntFirstExpr=*/false))
     return LHSTy;
 
+  // Allow ?: operations in which both operands have the same sizeless type.
+  if (LHSTy->isSizelessType() && LHSTy == RHSTy)
+    return LHSTy;
+
   // Emit a better diagnostic if one of the expressions is a null pointer
   // constant and the other is not a pointer type. In this case, the user most
   // likely forgot to take the address of the other expression.
@@ -11408,7 +11431,7 @@
   case Expr::MLV_ClassTemporary:
     DiagID = diag::err_typecheck_expression_not_modifiable_lvalue;
     break;
-  case Expr::MLV_IncompleteType:
+  case Expr::MLV_IndefiniteType:
   case Expr::MLV_IncompleteVoidType:
     return S.RequireCompleteType(Loc, E->getType(),
              diag::err_typecheck_incomplete_type_not_modifiable_lvalue, E);
@@ -11692,7 +11715,10 @@
     if (RHS.isInvalid())
       return QualType();
     if (!RHS.get()->getType()->isVoidType())
-      S.RequireCompleteType(Loc, RHS.get()->getType(),
+      // The test is for definiteness rather than completeness because
+      // the sizeless type extension allows (incomplete) sizeless definite
+      // types on the rhs of a comma operator.
+      S.RequireDefiniteType(Loc, RHS.get()->getType(), true,
                             diag::err_incomplete_type);
   }
 
@@ -14010,7 +14036,11 @@
         << OrigExpr->getType() << E->getSourceRange());
 
   if (!TInfo->getType()->isDependentType()) {
-    if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(),
+    // The test is for definiteness rather than completeness because the
+    // sizeless type extension allows (incomplete) sizeless definite types
+    // to be passed to functions.
+    if (RequireDefiniteType(TInfo->getTypeLoc().getBeginLoc(),
+                            TInfo->getType(), true,
                             diag::err_second_parameter_to_va_arg_incomplete,
                             TInfo->getTypeLoc()))
       return ExprError();
@@ -16240,7 +16270,10 @@
 
 bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
                                CallExpr *CE, FunctionDecl *FD) {
-  if (ReturnType->isVoidType() || !ReturnType->isIncompleteType())
+  // The sizeless type extension replaces "complete object type" with
+  // "definite object type" in C11 6.5.2.2p1, so that functions can
+  // return sizeless definite types.
+  if (ReturnType->isVoidType() || ReturnType->isDefiniteType())
     return false;
 
   // If we're inside a decltype's expression, don't check for a valid return
@@ -16273,7 +16306,7 @@
     }
   } Diagnoser(FD, CE);
 
-  if (RequireCompleteType(Loc, ReturnType, Diagnoser))
+  if (RequireDefiniteType(Loc, ReturnType, true, Diagnoser))
     return true;
 
   return false;
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -247,7 +247,9 @@
 bool
 Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
                               SourceLocation EqualLoc) {
-  if (RequireCompleteType(Param->getLocation(), Param->getType(),
+  // The sizeless type extension allows parameters to have (incomplete)
+  // sizeless definite type.
+  if (RequireDefiniteType(Param->getLocation(), Param->getType(), true,
                           diag::err_typecheck_decl_incomplete_type)) {
     Param->setInvalidDecl();
     return true;
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -3899,7 +3899,9 @@
     if (const auto *ED = dyn_cast<EnumDecl>(D))
       UnderlyingTy = ED->getIntegerType();
   }
-  if (DiagTy->isDependentType() || DiagTy->isIncompleteType())
+  // "Indefinite" rather than "incomplete" because we want to raise an
+  // error for (incomplete) sizeless definite types below.
+  if (DiagTy->isDependentType() || DiagTy->isIndefiniteType())
     return;
 
   // C++11 [dcl.align]p5, C11 6.7.5/4:
@@ -3907,6 +3909,7 @@
   //   not specify an alignment that is less strict than the alignment that
   //   would otherwise be required for the entity being declared.
   AlignedAttr *AlignasAttr = nullptr;
+  AlignedAttr *LastAlignedAttr = nullptr;
   unsigned Align = 0;
   for (auto *I : D->specific_attrs<AlignedAttr>()) {
     if (I->isAlignmentDependent())
@@ -3914,9 +3917,13 @@
     if (I->isAlignas())
       AlignasAttr = I;
     Align = std::max(Align, I->getAlignment(Context));
+    LastAlignedAttr = I;
   }
 
-  if (AlignasAttr && Align) {
+  if (Align && DiagTy->isSizelessType()) {
+    Diag(LastAlignedAttr->getLocation(), diag::err_attribute_sizeless_type)
+      << LastAlignedAttr->getSpelling() << DiagTy;
+  } else if (AlignasAttr && Align) {
     CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align);
     CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy);
     if (NaturalAlign > RequestedAlign)
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -1705,7 +1705,7 @@
   if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D))
     return false;
 
-  // Types of valid local variables should be complete, so this should succeed.
+  // Types of valid local variables should be definite, so this should succeed.
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
 
     // White-list anything with an __attribute__((unused)) type.
@@ -1717,9 +1717,9 @@
         return false;
     }
 
-    // If we failed to complete the type for some reason, or if the type is
-    // dependent, don't diagnose the variable.
-    if (Ty->isIncompleteType() || Ty->isDependentType())
+    // If we failed to make the type definite for some reason, or if the type
+    // is dependent, don't diagnose the variable.
+    if (Ty->isIndefiniteType() || Ty->isDependentType())
       return false;
 
     // Look at the element type to ensure that the warning behaviour is
@@ -7565,6 +7565,12 @@
     return;
   }
 
+  if (!NewVD->hasLocalStorage() && T->isSizelessType()) {
+    Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T;
+    NewVD->setInvalidDecl();
+    return;
+  }
+
   if (isVM && NewVD->hasAttr<BlocksAttr>()) {
     Diag(NewVD->getLocation(), diag::err_block_on_vm);
     NewVD->setInvalidDecl();
@@ -10309,7 +10315,9 @@
     // But, issue any diagnostic on the first declaration only.
     if (Previous.empty() && NewFD->isExternC()) {
       QualType R = NewFD->getReturnType();
-      if (R->isIncompleteType() && !R->isVoidType())
+      // "Indefinite" rather than "incomplete" because C functions can
+      // return (incomplete) sizeless definite types.
+      if (R->isIndefiniteType() && !R->isVoidType())
         Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete)
             << NewFD << R;
       else if (!R.isPODType(Context) && !R->isVoidType() &&
@@ -11121,7 +11129,10 @@
     QualType BaseDeclType = VDecl->getType();
     if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType))
       BaseDeclType = Array->getElementType();
-    if (RequireCompleteType(VDecl->getLocation(), BaseDeclType,
+    // The sizeless type extension replaces "complete object type" with
+    // "definite object type" in C11 6.7.9p3, to allow initialization of
+    // identifiers with sizeless definite type.
+    if (RequireDefiniteType(VDecl->getLocation(), BaseDeclType, true,
                             diag::err_typecheck_decl_incomplete_type)) {
       RealDecl->setInvalidDecl();
       return;
@@ -11512,9 +11523,11 @@
   QualType Ty = VD->getType();
   if (Ty->isDependentType()) return;
 
-  // Require a complete type.
-  if (RequireCompleteType(VD->getLocation(),
-                          Context.getBaseElementType(Ty),
+  // The sizeless type extension replaces "complete object type" with
+  // "definite object type" in C11 6.7.9p3, to allow initialization of
+  // identifiers with sizeless definite type.
+  if (RequireDefiniteType(VD->getLocation(),
+                          Context.getBaseElementType(Ty), true,
                           diag::err_typecheck_decl_incomplete_type)) {
     VD->setInvalidDecl();
     return;
@@ -11603,9 +11616,13 @@
       // Block scope. C99 6.7p7: If an identifier for an object is
       // declared with no linkage (C99 6.2.2p6), the type for the
       // object shall be complete.
+      //
+      // In practice this if statement appears to be dead, since no such
+      // variable would be classified as DeclarationOnly.  Logically it
+      // should include (incomplete) sizeless definite types though.
       if (!Type->isDependentType() && Var->isLocalVarDecl() &&
           !Var->hasLinkage() && !Var->isInvalidDecl() &&
-          RequireCompleteType(Var->getLocation(), Type,
+          RequireDefiniteType(Var->getLocation(), Type, true,
                               diag::err_typecheck_decl_incomplete_type))
         Var->setInvalidDecl();
 
@@ -11686,8 +11703,10 @@
       return;
 
     if (!Var->hasAttr<AliasAttr>()) {
-      if (RequireCompleteType(Var->getLocation(),
-                              Context.getBaseElementType(Type),
+      // The sizeless type extension replaces "complete" with "definite"
+      // in C11 6.7p7, to allow declarations with sizeless definite type.
+      if (RequireDefiniteType(Var->getLocation(),
+                              Context.getBaseElementType(Type), true,
                               diag::err_typecheck_decl_incomplete_type)) {
         Var->setInvalidDecl();
         return;
@@ -13030,11 +13049,13 @@
   }
 
   // The return type of a function definition must be complete
-  // (C99 6.9.1p3, C++ [dcl.fct]p6).
+  // (C99 6.9.1p3, C++ [dcl.fct]p6).  The sizeless type extension replaces
+  // "complete object type" with "definite object type", so that functions
+  // can return sizeless definite types.
   QualType ResultType = FD->getReturnType();
   if (!ResultType->isDependentType() && !ResultType->isVoidType() &&
       !FD->isInvalidDecl() &&
-      RequireCompleteType(FD->getLocation(), ResultType,
+      RequireDefiniteType(FD->getLocation(), ResultType, true,
                           diag::err_func_def_incomplete_result))
     FD->setInvalidDecl();
 
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -12505,9 +12505,12 @@
     // function declarator that is part of a function definition of
     // that function shall not have incomplete type.
     //
+    // The sizeless type extension replaces "incomplete" with "indefinite",
+    // so that (incomplete) sizeless definite types can be passed to functions.
+    //
     // This is also C++ [dcl.fct]p6.
     if (!Param->isInvalidDecl() &&
-        RequireCompleteType(Param->getLocation(), Param->getType(),
+        RequireDefiniteType(Param->getLocation(), Param->getType(), true,
                             diag::err_typecheck_decl_incomplete_type)) {
       Param->setInvalidDecl();
       HasInvalidParm = true;
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2159,16 +2159,18 @@
 }
 
 bool QualType::isCXX98PODType(const ASTContext &Context) const {
-  // The compiler shouldn't query this for incomplete types, but the user might.
+  // The compiler shouldn't query this for indefinite types, but the user might.
   // We return false for that case. Except for incomplete arrays of PODs, which
   // are PODs according to the standard.
+  //
+  // Sizeless built-in types (like other built-in types) are POD.
   if (isNull())
     return false;
 
   if ((*this)->isIncompleteArrayType())
     return Context.getBaseElementType(*this).isCXX98PODType(Context);
 
-  if ((*this)->isIncompleteType())
+  if ((*this)->isIndefiniteType())
     return false;
 
   if (hasNonTrivialObjCLifetime())
@@ -2216,9 +2218,10 @@
   if ((*this)->isArrayType())
     return Context.getBaseElementType(*this).isTrivialType(Context);
 
-  // Return false for incomplete types after skipping any incomplete array
+  // Return false for indefinite types after skipping any incomplete array
   // types which are expressly allowed by the standard and thus our API.
-  if ((*this)->isIncompleteType())
+  // Fall through to the code below for (incomplete) sizeless definite types.
+  if ((*this)->isIndefiniteType())
     return false;
 
   if (hasNonTrivialObjCLifetime())
@@ -2234,7 +2237,11 @@
   //   types.
 
   // As an extension, Clang treats vector types as Scalar types.
-  if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
+  // Built-in sizeless types are an extension to the standard and they
+  // are all trivial.
+  if (CanonicalType->isScalarType() ||
+      CanonicalType->isSizelessBuiltinType() ||
+      CanonicalType->isVectorType())
     return true;
   if (const auto *RT = CanonicalType->getAs<RecordType>()) {
     if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
@@ -2270,13 +2277,18 @@
   if (CanonicalType->isDependentType())
     return false;
 
-  // Return false for incomplete types after skipping any incomplete array types
+  // Return false for indefinite types after skipping any incomplete array types
   // which are expressly allowed by the standard and thus our API.
-  if (CanonicalType->isIncompleteType())
+  // Fall through to the code below for (incomplete) sizeless definite types.
+  if (CanonicalType->isIndefiniteType())
     return false;
 
   // As an extension, Clang treats vector types as Scalar types.
-  if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
+  // Built-in sizeless types are an extension to the standard and they
+  // are all trivially copyable.
+  if (CanonicalType->isScalarType() ||
+      CanonicalType->isSizelessBuiltinType() ||
+      CanonicalType->isVectorType())
     return true;
 
   if (const auto *RT = CanonicalType->getAs<RecordType>()) {
@@ -2507,13 +2519,19 @@
   const Type *BaseTy = ty->getBaseElementTypeUnsafe();
   assert(BaseTy && "NULL element type");
 
-  // Return false for incomplete types after skipping any incomplete array
+  // Return false for indefinite types after skipping any incomplete array
   // types which are expressly allowed by the standard and thus our API.
-  if (BaseTy->isIncompleteType())
+  // Fall through to the code below for (incomplete) sizeless definite types.
+  if (BaseTy->isIndefiniteType())
     return false;
 
   // As an extension, Clang treats vector types as Scalar types.
-  if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+  // Built-in sizeless types are an extension to the standard and they
+  // are all POD.
+  if (BaseTy->isScalarType() ||
+      BaseTy->isSizelessBuiltinType() ||
+      BaseTy->isVectorType())
+    return true;
   if (const auto *RT = BaseTy->getAs<RecordType>()) {
     if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
       // C++11 [class]p10:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -637,9 +637,11 @@
   // Arrays are not modifiable, only their elements are.
   if (CT->isArrayType())
     return Cl::CM_ArrayType;
-  // Incomplete types are not modifiable.
-  if (CT->isIncompleteType())
-    return Cl::CM_IncompleteType;
+  // Incomplete types are not modifiable (C11 6.3.2.1p1).  The sizeless type
+  // extension replaces "incomplete" with "indefinite", so that sizeless
+  // definite types are modifiable lvalues.
+  if (CT->isIndefiniteType())
+    return Cl::CM_IndefiniteType;
 
   // Records with any const fields (recursively) are not modifiable.
   if (const RecordType *R = CT->getAs<RecordType>())
@@ -701,7 +703,7 @@
   case Cl::CM_ConstQualifiedField: return MLV_ConstQualifiedField;
   case Cl::CM_ConstAddrSpace: return MLV_ConstAddrSpace;
   case Cl::CM_ArrayType: return MLV_ArrayType;
-  case Cl::CM_IncompleteType: return MLV_IncompleteType;
+  case Cl::CM_IndefiniteType: return MLV_IndefiniteType;
   }
   llvm_unreachable("Unhandled modifiable type");
 }
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -2475,6 +2475,10 @@
            StructSize.getValue() == static_cast<int64_t>(getTypeSize(Ty));
   }
 
+  // Sizeless built-in types have a unique representation.
+  if (Ty->isSizelessBuiltinType())
+    return true;
+
   // FIXME: More cases to handle here (list by rsmith):
   // vectors (careful about, eg, vector of 3 foo)
   // _Complex int and friends
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1628,7 +1628,8 @@
   void CheckAddressOfNoDeref(const Expr *E);
   void CheckMemberAccessOfNoDeref(const MemberExpr *E);
 
-  bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
+  bool RequireDefiniteTypeImpl(SourceLocation Loc, QualType T,
+                               bool AllowSizeless,
                                TypeDiagnoser *Diagnoser);
 
   struct ModuleScope {
@@ -1718,14 +1719,33 @@
 
   bool isUsualDeallocationFunction(const CXXMethodDecl *FD);
 
+  bool isDefiniteType(SourceLocation Loc, QualType T) {
+    return !RequireDefiniteTypeImpl(Loc, T, true, nullptr);
+  }
+  bool isIndefiniteType(SourceLocation Loc, QualType T) {
+    return !isDefiniteType(Loc, T);
+  }
   bool isCompleteType(SourceLocation Loc, QualType T) {
-    return !RequireCompleteTypeImpl(Loc, T, nullptr);
+    return !RequireDefiniteTypeImpl(Loc, T, false, nullptr);
   }
-  bool RequireCompleteType(SourceLocation Loc, QualType T,
+  bool RequireDefiniteType(SourceLocation Loc, QualType T, bool AllowSizeless,
                            TypeDiagnoser &Diagnoser);
-  bool RequireCompleteType(SourceLocation Loc, QualType T,
+  bool RequireDefiniteType(SourceLocation Loc, QualType T, bool AllowSizeless,
                            unsigned DiagID);
-
+  template <typename... Ts>
+  bool RequireDefiniteType(SourceLocation Loc, QualType T, bool AllowSizeless,
+                           unsigned DiagID, const Ts &...Args) {
+    BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...);
+    return RequireDefiniteType(Loc, T, AllowSizeless, Diagnoser);
+  }
+  bool RequireCompleteType(SourceLocation Loc, QualType T,
+                           TypeDiagnoser &Diagnoser) {
+    return RequireDefiniteType(Loc, T, false, Diagnoser);
+  }
+  bool RequireCompleteType(SourceLocation Loc, QualType T,
+                           unsigned DiagID) {
+    return RequireDefiniteType(Loc, T, false, DiagID);
+  }
   template <typename... Ts>
   bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID,
                            const Ts &...Args) {
Index: include/clang/Sema/Initialization.h
===================================================================
--- include/clang/Sema/Initialization.h
+++ include/clang/Sema/Initialization.h
@@ -1044,8 +1044,8 @@
     /// Default-initialization of a 'const' object.
     FK_DefaultInitOfConst,
 
-    /// Initialization of an incomplete type.
-    FK_Incomplete,
+    /// Initialization of an indefinite type.
+    FK_Indefinite,
 
     /// Variable-length array must not have an initializer.
     FK_VariableLengthArrayHasInitializer,
@@ -1075,8 +1075,8 @@
   /// The candidate set created when initialization failed.
   OverloadCandidateSet FailedCandidateSet;
 
-  /// The incomplete type that caused a failure.
-  QualType FailedIncompleteType;
+  /// The indefinite type that caused a failure.
+  QualType FailedIndefiniteType;
 
   /// The fixit that needs to be applied to make this initialization
   /// succeed.
@@ -1346,8 +1346,8 @@
   void SetFailed(FailureKind Failure) {
     SequenceKind = FailedSequence;
     this->Failure = Failure;
-    assert((Failure != FK_Incomplete || !FailedIncompleteType.isNull()) &&
-           "Incomplete type failure requires a type!");
+    assert((Failure != FK_Indefinite || !FailedIndefiniteType.isNull()) &&
+           "Indefinite type failure requires a type!");
   }
 
   /// Note that this initialization sequence failed due to failed
@@ -1367,10 +1367,10 @@
   }
 
   /// Note that this initialization sequence failed due to an
-  /// incomplete type.
-  void setIncompleteTypeFailure(QualType IncompleteType) {
-    FailedIncompleteType = IncompleteType;
-    SetFailed(FK_Incomplete);
+  /// indefinite type.
+  void setIndefiniteTypeFailure(QualType IndefiniteType) {
+    FailedIndefiniteType = IndefiniteType;
+    SetFailed(FK_Indefinite);
   }
 
   /// Determine why initialization failed.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2547,6 +2547,8 @@
   "redeclaration has different alignment requirement (%1 vs %0)">;
 def err_alignas_underaligned : Error<
   "requested alignment is less than minimum alignment of %1 for type %0">;
+def err_attribute_sizeless_type : Error<
+  "%0 attribute cannot be applied to sizeless type %1">;
 def err_attribute_argument_n_type : Error<
   "%0 attribute requires parameter %1 to be %select{int or bool|an integer "
   "constant|a string|an identifier}2">;
@@ -6432,6 +6434,8 @@
   "implicit conversion from array size expression of type %0 to "
   "%select{integral|enumeration}1 type %2 is a C++11 extension">,
   InGroup<CXX11>;
+def err_array_of_sizeless : Error<
+  "array has sizeless element type %0">;
 def warn_cxx98_compat_array_size_conversion : Warning<
   "implicit conversion from array size expression of type %0 to "
   "%select{integral|enumeration}1 type %2 is incompatible with C++98">,
@@ -8339,6 +8343,8 @@
   "__block attribute not allowed, only allowed on local variables">;
 def err_block_on_vm : Error<
   "__block attribute not allowed on declaration with a variably modified type">;
+def err_sizeless_nonlocal : Error<
+  "non-local variable with sizeless type %0">;
 
 def err_vec_builtin_non_vector : Error<
  "first two arguments to %0 must be vectors">;
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -282,7 +282,7 @@
     MLV_DuplicateVectorComponents,
     MLV_InvalidExpression,
     MLV_LValueCast,           // Specialized form of MLV_InvalidExpression.
-    MLV_IncompleteType,
+    MLV_IndefiniteType,
     MLV_ConstQualified,
     MLV_ConstQualifiedField,
     MLV_ConstAddrSpace,
@@ -337,7 +337,7 @@
       CM_ConstQualifiedField,
       CM_ConstAddrSpace,
       CM_ArrayType,
-      CM_IncompleteType
+      CM_IndefiniteType
     };
 
   private:
Index: docs/SizelessTypes.rst
===================================================================
--- /dev/null
+++ docs/SizelessTypes.rst
@@ -0,0 +1,568 @@
+==============
+Sizeless types
+==============
+
+As an extension, Clang supports the concept of “sizeless” object types in
+both C and C++.  The types are so called because it is an error to measure
+their size directly using ``sizeof`` or indirectly via operations like
+pointer arithmetic.
+
+Forbidding ``sizeof`` and related operations means that the amount of
+data that the types contain does not need to be a compile-time constant.
+It can instead depend on runtime properties, and for example can adapt
+to different hardware configurations.
+
+Sizeless types are only intended for objects that hold temporary working
+data, such as “scalable” or variable-length vectors.  They are not
+intended for long-term storage and cannot be used in aggregates.
+
+At present, the only sizeless types that Clang provides are:
+
+AArch64 SVE vector types
+  These vector types are built into the compiler under names like
+  ``__SVInt8_t``, as required by the `Procedure Call Standard for the
+  Arm® 64-bit Architecture`_.  They represent the longest vector of a
+  particular element type that can be stored in an SVE vector register.
+  Functions can pass and return these vectors in registers.
+
+  The header file ``<arm_sve.h>`` makes the types available under more
+  user-friendly names like ``svint8_t``.  It also provides a set of
+  intrinsic functions for operating on the types.  See the `ARM C
+  Language Extensions for SVE`_ for more information about these types
+  and intrinsics.
+
+  .. _Procedure Call Standard for the Arm® 64-bit Architecture:
+     https://developer.arm.com/docs/ihi0055/latest/
+  .. _ARM C Language Extensions for SVE:
+     https://developer.arm.com/docs/100987/latest
+
+`ARM C Language Extensions for SVE`_ contains the original specification of
+sizeless types, but the description below is intended to be self-contained.
+
+Outline of the type system changes
+==================================
+
+C and C++ classify object types as “complete” (the size of objects
+of that type can be calculated) or “incomplete” (the size of objects
+of that type cannot be calculated).  There is very little you can do with
+a type until it becomes complete.
+
+This categorization implicitly ties two concepts: whether it is possible
+to manipulate objects of a particular type, and whether it is possible
+to measure their size (which in C++ must be constant).  The key idea
+behind the sizeless type extension is to split these concepts apart.
+
+To do this, the extension classifies types as:
+
+* “indefinite” (lacking sufficient information to create an object of
+  that type) or “definite” (having sufficient information)
+
+* “sized” (will have a measurable size when definite) or “sizeless”
+  (will never have a measurable size)
+
+* “incomplete” (lacking sufficient information to determine the size of
+  objects of that type) or “complete” (having sufficient information)
+
+where the wording for the final bullet is taken verbatim from the
+C standard.  All standard types are “sized” (even ``void``, although
+it is always indefinite).
+
+The idea is that “definite” types are as fully-defined as they
+ever can be, even if their size is still not known at compile time.
+“Complete” is then equivalent to “sized and definite”.
+
+On its own, this puts sizeless types into a similar position
+to incomplete structure types, which is conservatively correct
+but severely limits what the types can do.
+
+The next step is to relax certain rules so that they use the distinction
+between “indefinite” and “definite” rather than “incomplete” and “complete”.
+The goal of this process is to allow:
+
+* automatic variables with sizeless type
+* function parameters and return values with sizeless type
+* use of sizeless types with ``_Generic``
+* pointers to sizeless types
+* applying ``typeid`` to a sizeless type
+* use of sizeless types with C++ type traits
+
+In contrast, the following must remain invalid, by keeping the usual rules
+for incomplete types unchanged:
+
+* using ``sizeof``, ``_Alignof`` and ``alignof`` with a sizeless type
+  (or object of sizeless type)
+* creating or accessing arrays that have sizeless type
+* doing pointer arithmetic on pointers to sizeless types
+* unions or structures with sizeless members
+* applying ``_Atomic`` to a sizeless type
+* throwing or catching objects of sizeless type
+* capturing sizeless objects by value in lambda expressions
+
+There is also an extra restriction:
+
+* variables with sizeless type must not have static or thread-local
+  storage duration
+
+In practice it is impossible to *define* such variables with incomplete type,
+but having an explicit rule means that things like:
+
+.. code-block:: c
+
+   extern __SVInt8_t foo;
+
+are outright invalid rather than simply useless (because no other
+translation unit could ever define ``foo``).  Similarly, without an
+explicit rule:
+
+.. code-block:: c
+
+   __SVInt8_t foo;
+
+would be a valid tentative definition at the point it occurs and only
+become invalid at the end of the translation unit, because ``__SVInt8_t``
+is never completed.
+
+Edits to the standards
+======================
+
+Edits to the C standard
+-----------------------
+
+This section specifies the behavior for sizeless types in C, as an edit
+to the N1570 draft of C11.
+
+6.2.5 Types
+~~~~~~~~~~~
+
+In 6.2.5p1, replace:
+
+    At various points within a translation unit an object type may be
+    *incomplete* …
+
+onwards with:
+
+    Object types are further partitioned into *sized* and *sizeless*; all
+    basic and derived types defined in this standard are sized, but an
+    implementation may provide additional sizeless types.
+
+and add two additional clauses:
+
+* At various points within a translation unit an object type may be
+  *indefinite* (lacking sufficient information to construct an object
+  of that type) or *definite* (having sufficient information).
+  An object type is said to be *complete* if it is both sized and
+  definite; all other object types are said to be *incomplete*.
+  Complete types have sufficient information to determine the size
+  of an object of that type while incomplete types do not.
+
+* Arrays, structures, unions and enumerated types are always sized,
+  so for them the term *incomplete* is equivalent to (and used
+  interchangeably with) the term *indefinite*.
+
+Change 6.2.5p19 to:
+
+    The void type comprises an empty set of values; it is a sized
+    indefinite object type that cannot be completed (made definite).
+
+Replace “incomplete” with “indefinite” and “complete” with “definite” in
+6.2.5p37, which describes how a type's state can change throughout a
+translation unit.
+
+6.3.2.1 Lvalues, arrays, and function designators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “incomplete” with “indefinite” in 6.3.2.1p1, so that sizeless
+definite types are modifiable lvalues.
+
+Make the same replacement in 6.3.2.1p2, to prevent undefined behavior
+when lvalues have sizeless definite type.
+
+6.5.1.1 Generic selection
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete object type” with “definite object type” in 6.5.1.1p2,
+so that the type name in a generic association can be a sizeless definite
+type.
+
+6.5.2.2 Function calls
+~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete object type” with “definite object type” in 6.5.2.2p1,
+so that functions can return sizeless definite types.
+
+Make the same change in 6.5.2.2p4, so that arguments can also have
+sizeless definite type.
+
+6.5.2.5 Compound literals
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete object type” with “definite object type” in 6.5.2.5p1,
+so that compound literals can have sizeless definite type.
+
+6.7 Declarations
+~~~~~~~~~~~~~~~~
+
+Insert the following new clause after 6.7p4:
+
+* If an identifier for an object does not have automatic storage duration,
+  its type must be sized rather than sizeless.
+
+Replace “complete” with “definite” in 6.7p7, which describes when the
+type of an object becomes definite.
+
+6.7.6.3 Function declarators (including prototypes)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “incomplete type” with “indefinite type” in 6.7.6.3p4, so that
+parameters can also have sizeless definite type.
+
+Make the same change in 6.7.6.3p12, which allows even indefinite types
+to be function parameters if no function definition is present.
+
+6.7.9 Initialization
+~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete object type” with “definite object type” in 6.7.9p3,
+to allow initialization of identifiers with sizeless definite type.
+
+6.9.1 Function definitions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete object type” with “definite object type” in 6.9.1p3,
+so that functions can return sizeless definite types.
+
+Make the same change in 6.9.1p7, so that adjusted parameter types can be
+sizeless definite types.
+
+J.2 Undefined behavior
+~~~~~~~~~~~~~~~~~~~~~~
+
+Update the entries that refer to the clauses above.
+
+Edits to the C++ standard
+-------------------------
+
+This section specifies the behavior for sizeless types in C++,
+as an edit to the N3797 draft of C++17.
+
+3.1 Declarations and definitions [basic.def]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “incomplete” with “indefinite” in [basic.def]p5, so that definitions
+of an object can give it sizeless definite type.  Add a further clause
+after [basic.def]p5:
+
+* A program is ill-formed if any declaration of an object gives it both
+  a sizeless type and either static or thread-local storage duration.
+
+3.9 Types [basic.types]
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace [basic.types]p5 with:
+
+    A class that has been declared but not defined, an enumeration type
+    in certain contexts (7.2), or an array of unknown size or of
+    indefinite element type, is an indefinite object type.45)
+    Indefinite object types and the void types are indefinite types (3.9.1).
+    Objects shall not be defined to have an indefinite type.
+
+and add three additional clauses:
+
+* Object and void types are further partitioned into *sized* and *sizeless*;
+  all basic and derived types defined in this standard are sized, but an
+  implementation may provide additional sizeless types.
+
+* An object or void type is said to be *complete* if it is both sized and
+  definite; all other object and void types are said to be *incomplete*.
+  The term *completely-defined object type* is synonymous with *complete
+  object type*.
+
+* Arrays, class types and enumeration types are always sized, so for
+  them the term *incomplete* is equivalent to (and used interchangeably
+  with) the term *indefinite*.
+
+(Note that the wording of footnote 45 continues to apply as-is.)
+
+Also replace “incomplete” with “indefinite” in the forward reference
+in [basic.types]p7.
+
+3.9.1 Fundamental Types [basic.fundamental]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In [basic.fundamental]p9, replace the second sentence with:
+
+    The void type is a sized indefinite type that cannot be completed
+    (made definite).
+
+leaving the rest of the clause unchanged.
+
+3.9.2. Compound Types [basic.compound]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this part of [basic.compound]p3:
+
+    Pointers to incomplete types are allowed although there are
+    restrictions on what can be done with them …
+
+add “(including indefinite types)” after “incomplete types”.
+
+3.10 Lvalues and rvalues [basic.lval]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete” with “definite” and “incomplete” with “indefinite” in
+[basic.lval]p4, so that prvalues can have definite type and (in contrast)
+glvalues can have indefinite type.
+
+Replace “incomplete” with “indefinite” and “complete” with “definite” in
+[basic.lval]p7, so that the target of a pointer can be modifiable if it has
+sizeless definite type.
+
+4.1 Lvalue-to-rvalue conversion [conv.lval]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “incomplete” with “indefinite” in [conv.lval]p1, so that sizeless
+definite glvalues can be converted to prvalues.
+
+5.2.2 Function call [expr.call]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “completely-defined” with “definite” and “incomplete class type” with
+“indefinite type” in [expr.call]p4, so that parameters can have sizeless
+definite type.
+
+Replace “incomplete” with “indefinite” and “complete” with “definite” in
+[expr.call]p11, so that function call prvalues can have sizeless definite type.
+
+5.2.3 Explicit type conversion (function notation) [expr.type.conv]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete” with “definite” in [expr.type.conv]p2, so that ``T()``
+can be used for sizeless definite T.
+
+5.3.1 Unary operators [expr.unary.op]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “incomplete” with “indefinite” in [expr.unary.op]p1, so that a
+dereferenced pointer to a sizeless definite object can be converted to
+a prvalue.
+
+5.3.5 Delete [expr.delete]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+After the first sentence in [expr.delete]p2 (which describes converting an
+operand with class type to a pointer type), add:
+
+    The type of the operand must now be a pointer to a sized type,
+    otherwise the program is ill-formed.
+
+7.1.6.2 Simple type specifiers [dcl.type.simple]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete” with “definite” in [dcl.type.simple]p5, so that the special
+treatment for decltypes of function calls applies to indefinite rather
+than incomplete return types.  This is for consistency with the change
+to [expr.call]p11 above.
+
+8.3.4 Arrays [dcl.array]
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+In [dcl.array]p1, add “a sizeless type” to the list of things that array
+element type T cannot be.
+
+9.4.2 Static data members [class.static.data]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “an incomplete type” with “a sized indefinite type” in
+[class.static.data]p2, to avoid giving the impression that static data
+members can have sizeless type.
+
+Make this explicit by adding the following after [class.static.data]p7:
+
+* A static data member shall not have sizeless type.
+
+14.3.1 Template type parameters [temp.arg.type]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “incomplete” with “indefinite” in [temp.arg.type]p2, which notes that
+template type parameters need not be fully defined.
+
+14.7.1 Implicit instantiation [temp.inst]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “completely-defined object type” with “definite object type”
+in [temp.inst]p1 and [temp.inst]p6, so that the language edits do not affect
+the rules for implicit instantiation.
+
+17.6.4.8 Other functions [res.on.functions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “incomplete” with “incomplete or indefinite” in [res.on.functions]p2,
+so that the library requires the rest of the program to honor the rules
+for both categories of type.
+
+20.10.4.3 Type properties [meta.unary.prop]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete” with “definite” in [meta.unary.prop]p3 and in the table
+that follows.  This specifically includes ``is_destructible``; since sizeless
+definite types can have automatic storage duration, it must be possible
+to destroy them.  The changes are redundant but harmless for cases in
+which the completeness rule applies only to class types.
+
+20.10.6 Relationships between types [meta.rel]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete” with “definite” in table 51.
+
+20.10.7.6 Other transformations [meta.trans.other]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace “complete” with “definite” in table 57.
+
+Notes for Clang developers
+==========================
+
+Applying the extension to other cases
+-------------------------------------
+
+The summary and standard edits above describe how the sizeless type
+extension interacts with the core parts of the C and C++ standards.
+However, Clang supports many other extensions to the core languages,
+and will support new versions of the core languages as they evolve
+over time.  It is therefore necessary to describe how sizeless types
+should interact with future extensions and language developments.
+
+The general principle is that we should continue to keep using the
+distinction between incomplete types and complete types unless there is
+a specific known benefit to doing otherwise.  Treating sizeless types as
+incomplete types should be the conservatively correct choice in almost
+all cases.  We can later decide to relax specific rules to use the
+distinction between indefinite and definite types once we are sure
+that that is the right thing to do.
+
+Note that no decision needs to be made for any rules that are specific
+to complete or incomplete aggregates (arrays, structs, unions or classes),
+since aggregates are always sized.
+
+Rationale for this extension
+============================
+
+Requirements
+------------
+
+The main question that prompted this extension was: how do we add
+scalable vector types to the type system?  The key requirements were:
+
+* The approach must work in both C and C++.
+
+* It must be possible to define automatic variables with these types.
+
+* It must be possible to pass and return objects of these types
+  (since that is what intrinsics and vector library routines need to do).
+
+* It must be possible to use the types in ``_Generic`` associations
+  (since the SVE ACLE uses ``_Generic`` to provide ``tgmath.h``\ -style
+  overloads).
+
+* It must be possible to create pointers or references to the types
+  (for passing or returning by pointer or reference, and because not
+  allowing references would be semantically difficult in C++).
+
+Possible approaches
+-------------------
+
+Any approach to defining scalable types would fall into one of three
+categories:
+
+(1) Limit the types in such a way that there is no concept of size.
+
+(2) Define the size of the types to be variable.
+
+(3) Define the size of the types to be constant, either with the
+    constant being large enough for all possible vector lengths or
+    with the types pointing to separate memory (as for C++ classes
+    like ``std::string``).
+
+\ (2) seemed initially appealing since C already has the concept of
+variable-length arrays.  However, variable-length built-in types
+would work in a significantly different way.  Arrays often decay to
+pointers (which of course are fixed-length types), whereas vector
+types never would.  Unlike arrays, it should be possible to pass
+variable-length vectors to functions, return them from functions,
+and assign them by value.
+
+One particular difficulty is that the semantics of variable-length arrays
+rely on having a point at which the array size is evaluated.  It would
+be difficult to extend this approach to built-in types, or to declarations
+of functions that return variable-length types.  It would also not be an
+accurate model of how an implementation actually behaves, since the
+implementation would not evaluate the vector lengths at these points and
+would not react to the results of the calculation.
+
+As well as the extension itself being relatively complex (especially
+for C++), it might be difficult to define it in a way that interacts
+naturally with other extensions.  Also, variable-length arrays were added
+to an early draft of C++14, but were later removed as too controversial and
+did not make it into the final standard.  C++17 still requires ``sizeof``
+to be constant and C11 makes variable-length arrays optional.
+
+\ (2) therefore felt like a complicated dead-end.
+
+\ (3) can be divided into two parts:
+
+a) The vector types have a constant size and are large enough for all
+   possible vector lengths.
+
+   The main problem with this approach is that the maximum SVE vector
+   length of 2048 bits is much larger than the minimum of 128 bits.  Using
+   a fixed size of 2048 bits would be extremely inefficient for smaller
+   vector lengths, and of course the whole point of using vectors is to
+   make things *more* efficient.
+
+   Also, we would need to define the types such that only the bytes
+   associated with the actual vector length are significant.  This would
+   make it possible to pass or return the types in registers and treat
+   them as register values when copying.  This perhaps has some similarity
+   with overaligned structures such as:
+
+   .. code-block:: c
+
+      struct s { _Alignas(16) int i; };
+
+   except that the amount of padding is only known at runtime.
+
+   There is also a significant conceptual problem: encoding a fixed size
+   goes against the guiding principle of SVE, in which there is no preferred
+   vector length.  There is nothing particularly magical about the current
+   limit of 2048 bits and it would be better to avoid an ABI break if the
+   maximum ever did increase in future.
+
+b) The vector types have a constant size and refer to separate storage
+   (as for C++ classes like ``std::string``).
+
+   This would be difficult to do without C++-style constructor, destructor,
+   copy and move semantics, so would not work well in C.  And in C++ it would
+   be less efficient than the other approaches, since presumably an allocator
+   would be needed to allocate the separate storage.  It would be difficult
+   to map this kind of type to a self-contained register-based ABI type.
+
+These are all negative reasons for (1) being the best approach.
+A more positive justification is that (1) seems to meet the requirements
+in the most efficient way possible.  The vectors can use their natural
+(native) representation, and the type system prevents uses that would
+make that representation problematic.
+
+Also, the approach of starting with very restricted types and then
+specifically allowing certain things should be more future-proof
+and interact better with other (unseen) language extensions.  By default,
+any language extension would treat the new types like other incomplete
+types and choose conservatively-correct behavior.  It would then be
+possible to relax the rules if this default behavior turns out to be
+too restrictive.
+
+(That said, treating the types as permanently incomplete will
+not avoid all clashes with other extensions.  For example, we need to
+allow objects of automatic storage duration to have certain forms of
+incomplete type, whereas an extension might implicitly assume that all
+such objects must already have complete type.  The approach should still
+avoid the worst effects though.)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to