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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits