rsandifo-arm created this revision. Herald added subscribers: cfe-commits, kristof.beyls, rengolin. Herald added a reviewer: javed.absar.
`[ Not intended for commit. I'm just posting it to back up an RFC on cfe-dev. ] This patch adds the concept of "sizeless" types to core C and C++. It's a prerequisite for adding AArch64 SVE intrinsics. The patch relies on two new type categorisations: - sized vs. sizeless All standard types are "sized" (even void). Sizeless types are purely an extension. - indefinite vs. definite Indefinite types can be used to declare objects but can't be used to construct them. For sized types, "indefinite" is the same as the standard definition of "incomplete". The patch then redefines "complete" to mean "sized and definite". All sizeless types are permanently incomplete, since their size is never known at compile time. The cfe-dev RFC will have more details; the above is only a summary. The patch doesn't reword the diagnostics to talk about "indefinite" rather than "incomplete" since "indefinite" won't mean much to most users. The FIXMEs about inline asms are resolved by later SVE patches.` Repository: rC Clang https://reviews.llvm.org/D46308 Files: include/clang/AST/CanonicalType.h include/clang/AST/Expr.h include/clang/AST/Type.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/SemaCodeComplete.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/SemaOpenMP.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,479 @@ +// 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 + +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}} + +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 {{no known conversion}} + +extern "C" svint8_t return_int8(); + +typedef svint8_t vec_int8 __attribute__((vector_size(64))); // 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; + +#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); +}; + +struct foo_iterator { + svint8_t operator++(); + svint8_t operator*() const; + bool operator!=(const foo_iterator &) const; +}; + +struct foo { + foo(); + operator svint8_t() const; + foo_iterator begin() const; + foo_iterator end() const; +}; + +struct constructible_from_sizeless { + constructible_from_sizeless(svint8_t); +}; + +void with_default(svint8_t = svint8_t()); + +#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}} + + (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>(foo()); + local_int16 = static_cast<svint8_t>(foo()); // expected-error {{incompatible type}} + + local_int8 = foo(); + local_int16 = foo(); // 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 }; +#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 + + _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 + for (auto x : local_int8) {} // expected-error {{incomplete type}} + + for (const svint8_t &x : foo()) { (void)x; } // expected-warning {{always a copy}} expected-note {{use non-reference type}} +#endif +} Index: test/Sema/sizeless-1.c =================================================================== --- /dev/null +++ test/Sema/sizeless-1.c @@ -0,0 +1,246 @@ +// 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}} + +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 __attribute__((vector_size(64))); // 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 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}} + + 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; + + 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}} + + 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}} + 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 @@ -2033,6 +2033,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 @@ -7422,26 +7428,30 @@ return RequireCompleteExprType(E, Diagnoser); } -/// @brief Ensure that the type T is a complete type. +/// @brief 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 +/// completed (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()) { @@ -7566,11 +7576,12 @@ } } -/// \brief The implementation of RequireCompleteType -bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, +/// \brief 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. // @@ -7589,15 +7600,16 @@ } 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. if (Def && !isa<EnumDecl>(Def)) 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 && @@ -7657,8 +7669,9 @@ } // 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(&Def) && + (AllowSizeless || !T->isSizelessType())) + return RequireDefiniteTypeImpl(Loc, T, AllowSizeless, Diagnoser); } } @@ -7706,8 +7719,9 @@ // 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(&Def) && + (AllowSizeless || !T->isSizelessType())) + return RequireDefiniteTypeImpl(Loc, T, AllowSizeless, Diagnoser); } } @@ -7739,10 +7753,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); } /// \brief Get diagnostic %select index for tag kind for @@ -7991,7 +8005,9 @@ // The enum could be incomplete if we're parsing its definition or // recovering from an error. NamedDecl *FwdDecl = nullptr; - if (BaseType->isIncompleteType(&FwdDecl)) { + // "Complete" and "definite" are the same here, since enums are + // never sizeless. + if (BaseType->isIndefiniteType(&FwdDecl)) { Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; return QualType(); Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -274,18 +274,22 @@ // Accept, even if we emitted an error diagnostic. break; } - case Expr::MLV_IncompleteType: + case Expr::MLV_IndefiniteType: case Expr::MLV_IncompleteVoidType: - if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), - diag::err_dereference_incomplete_type)) + if (RequireDefiniteType(OutputExpr->getLocStart(), Exprs[i]->getType(), + true, diag::err_dereference_incomplete_type)) return StmtError(); LLVM_FALLTHROUGH; default: return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_output) << 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)) @@ -373,10 +377,17 @@ continue; if (!Ty->isVoidType() || !Info.allowsMemory()) - if (RequireCompleteType(InputExpr->getLocStart(), 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->getLocStart(), 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)) @@ -438,6 +449,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; @@ -517,6 +529,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 { @@ -668,6 +684,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 @@ -2744,7 +2744,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 @@ -241,7 +241,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 @@ -3467,7 +3467,8 @@ Diag(From->getLocStart(), diag::err_typecheck_ambiguous_condition) << From->getType() << ToType << From->getSourceRange(); else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) { - if (!RequireCompleteType(From->getLocStart(), ToType, + // Allow user-defined conversions to (incomplete) sizeless definite types. + if (!RequireDefiniteType(From->getLocStart(), ToType, true, diag::err_typecheck_nonviable_condition_incomplete, From->getType(), From->getSourceRange())) Diag(From->getLocStart(), diag::err_typecheck_nonviable_condition) @@ -4726,9 +4727,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->getLocStart(), ToType)) + // + // The condition is "definiteness" rather than "completeness" because the + // sizeless type extension allows list construction of (incomplete) sized + // definite types. + if (!S.isDefiniteType(From->getLocStart(), ToType)) return Result; // Per DR1467: @@ -6946,7 +6951,10 @@ &ConversionRef, VK_RValue); QualType ConversionType = Conversion->getConversionType(); - if (!isCompleteType(From->getLocStart(), ConversionType)) { + // The condition is "definiteness" rather than "completeness" because the + // sizeless type extension allows user-defined conversions to (incomplete) + // sized definite types. + if (!isDefiniteType(From->getLocStart(), ConversionType)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_final_conversion; return; @@ -9628,13 +9636,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) sized 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) FnKind << FnDesc Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -11643,8 +11643,7 @@ static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, DSAStackTy *Stack, QualType QTy, bool FullCheck = true) { - NamedDecl *ND; - if (QTy->isIncompleteType(&ND)) { + if (QTy->isIncompleteType()) { SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; return false; } Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -479,8 +479,10 @@ if (!LSI->ReturnType->isDependentType() && !LSI->ReturnType->isVoidType()) { - if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType, - diag::err_lambda_incomplete_result)) { + // The sizeless type extension allows (incomplete) sizeless + // definite types to be returned from functions. + if (RequireDefiniteType(CallOperator->getLocStart(), LSI->ReturnType, + true, diag::err_lambda_incomplete_result)) { // Do nothing. } } Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -1076,14 +1076,18 @@ // Special-case SemaRef.Diag(IList->getInit(Index)->getLocStart(), 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; @@ -1120,7 +1124,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()) { @@ -1252,7 +1256,8 @@ } // Fall through for subaggregate initialization - } else if (ElemType->isScalarType() || ElemType->isAtomicType()) { + } else if (ElemType->isScalarType() || ElemType->isAtomicType() || + ElemType->isSizelessBuiltinType()) { // FIXME: Need to handle atomic aggregate types with implicit init lists. return CheckScalarType(Entity, IList, ElemType, Index, StructuredList, StructuredIndex); @@ -3213,7 +3218,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: @@ -3559,8 +3564,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; } @@ -3734,8 +3741,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 we don't yet support + // sizeless structures. if (!S.isCompleteType(Kind.getLocation(), DestType)) { - Sequence.setIncompleteTypeFailure(DestType); + Sequence.setIndefiniteTypeFailure(DestType); return; } @@ -4020,8 +4030,10 @@ } if (DestType->isRecordType() && + // "Complete" and "definite" are the same here, since we don't yet + // support sizeless structures. !S.isCompleteType(InitList->getLocStart(), DestType)) { - Sequence.setIncompleteTypeFailure(DestType); + Sequence.setIndefiniteTypeFailure(DestType); return; } @@ -4257,7 +4269,9 @@ const RecordType *T2RecordType = nullptr; if ((T2RecordType = T2->getAs<RecordType>()) && - S.isCompleteType(Kind.getLocation(), T2)) { + // "Complete" and "definite" are the same here, since we don't yet + // support sizeless structures. + S.isDefiniteType(Kind.getLocation(), T2)) { // The type we're converting from is a class type, enumerate its conversion // functions. CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl()); @@ -5850,7 +5864,11 @@ // 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(), + // C++ [dcl.fct]/9: "the type of a parameter ... shall not be an + // incomplete class type". The sizeless type extension leaves this + // wording as-is, so that it doesn't apply to sizeless definite types, + // which at present are never class types. + if (S.RequireDefiniteType(Loc, Parm->getType(), true, diag::err_call_incomplete_argument)) break; @@ -6558,10 +6576,13 @@ return E; // C++1z [conv.rval]/1: T shall be a complete type. + // The sizeless type extension replaces "complete" with "definite", + // so that temporaries with sizeless definite type can be created. + // // FIXME: Does this ever matter (can we form a prvalue of incomplete type)? // If so, we should check for a non-abstract class type here too. QualType T = E->getType(); - if (RequireCompleteType(E->getExprLoc(), T, diag::err_incomplete_type)) + if (RequireDefiniteType(E->getExprLoc(), T, true, diag::err_incomplete_type)) return ExprError(); return CreateMaterializeTemporaryExpr(E->getType(), E, false); @@ -7670,8 +7691,12 @@ break; case OR_No_Viable_Function: - 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, Args[0]->getType(), Args[0]->getSourceRange())) S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) @@ -7953,9 +7978,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: { @@ -8118,8 +8143,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 @@ -199,6 +199,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 @@ -1350,8 +1350,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(); @@ -4313,6 +4316,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: @@ -4345,8 +4351,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); } } @@ -4598,7 +4604,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 @@ -4824,19 +4834,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. @@ -4977,8 +4993,11 @@ if (!BaseInterface || !DerivedInterface) return false; - if (Self.RequireCompleteType( - KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) + // The sizeless type extension replaces "complete" with "definite", + // so that sizeless definite types can be used with the traits. + if (Self.RequireDefiniteType( + KeyLoc, RhsT, true, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; return BaseInterface->isSuperClassOf(DerivedInterface); @@ -5046,7 +5065,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. @@ -5089,12 +5111,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; @@ -7243,7 +7268,10 @@ E = Res.get(); if (!E->getType()->isVoidType()) - RequireCompleteType(E->getExprLoc(), E->getType(), + // The test is based on definiteness rather than completeness + // because (incomplete) sized 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 @@ -760,7 +760,9 @@ /// 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. + 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 @@ -908,8 +910,11 @@ return Comma.get(); } + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.5.2.2/4, 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(); @@ -1373,8 +1378,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; @@ -4832,8 +4840,10 @@ if (ArgIx < Args.size()) { Arg = Args[ArgIx++]; - if (RequireCompleteType(Arg->getLocStart(), - ProtoArgType, + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.5.2.2/4, so that arguments can + // have sizeless definite type. + if (RequireDefiniteType(Arg->getLocStart(), ProtoArgType, true, diag::err_call_incomplete_argument, Arg)) return true; @@ -5588,8 +5598,10 @@ Arg = ArgE.getAs<Expr>(); } - if (RequireCompleteType(Arg->getLocStart(), - Arg->getType(), + // The sizeless type extension replaces "complete object type" with + // "definite object type" in C11 6.5.2.2/4, so that arguments can + // have sizeless definite type. + if (RequireDefiniteType(Arg->getLocStart(), Arg->getType(), true, diag::err_call_incomplete_argument, Arg)) return ExprError(); @@ -5653,7 +5665,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.5/1, 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(); @@ -6884,6 +6899,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. @@ -10689,7 +10708,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); @@ -10965,7 +10984,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) sized definite + // types on the rhs of a comma operator. + S.RequireDefiniteType(Loc, RHS.get()->getType(), true, diag::err_incomplete_type); } @@ -13266,7 +13288,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 extensions 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(); @@ -15339,7 +15365,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.2/1, 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 @@ -15370,8 +15399,8 @@ << FD->getDeclName(); } } 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 @@ -251,7 +251,11 @@ bool Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { - if (RequireCompleteType(Param->getLocation(), Param->getType(), + // C++ [dcl.fct]/9: "the type of a parameter ... shall not be an + // incomplete class type". The sizeless type extension leaves this + // wording as-is, so that it doesn't apply to sizeless definite types, + // which at present are never class types. + 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 @@ -3578,24 +3578,31 @@ 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: // The combined effect of all alignment attributes in a declaration shall // 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()) return; 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 @@ -1680,7 +1680,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. @@ -1692,9 +1692,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 @@ -7477,6 +7477,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(); @@ -9819,7 +9825,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() && @@ -10632,7 +10640,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.9/3, to allow initialization of + // identifiers with sizeless definite type. + if (RequireDefiniteType(VDecl->getLocation(), BaseDeclType, true, diag::err_typecheck_decl_incomplete_type)) { RealDecl->setInvalidDecl(); return; @@ -11006,9 +11017,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.9/3, 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; @@ -11097,9 +11110,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(); @@ -11180,8 +11197,10 @@ return; if (!Var->hasAttr<AliasAttr>()) { - if (RequireCompleteType(Var->getLocation(), - Context.getBaseElementType(Type), + // The sizeless type extension replaces "complete" with "definite" + // in C11 6.7/7, to allow declarations with sizeless definite type. + if (RequireDefiniteType(Var->getLocation(), + Context.getBaseElementType(Type), true, diag::err_typecheck_decl_incomplete_type)) { Var->setInvalidDecl(); return; @@ -12511,11 +12530,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(); @@ -14875,7 +14896,7 @@ InvalidDecl = true; } else { NamedDecl *Def; - EltTy->isIncompleteType(&Def); + EltTy->isIndefiniteType(&Def); if (Def && Def->isInvalidDecl()) { Record->setInvalidDecl(); InvalidDecl = true; Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -4492,8 +4492,9 @@ if (!CodeCompleter) return; - // A complete type is needed to lookup for constructors. - if (!isCompleteType(Loc, Type)) + // A definite type is needed to lookup for constructors. Fall through + // to the handling below for (incomplete) sizeless definite types. + if (!isDefiniteType(Loc, Type)) return; CXXRecordDecl *RD = Type->getAsCXXRecordDecl(); Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -10999,9 +10999,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 @@ -1987,10 +1987,11 @@ return !isa<VariableArrayType>(CanonicalType); } -/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) -/// - a type that can describe objects, but which lacks information needed to -/// determine its size. -bool Type::isIncompleteType(NamedDecl **Def) const { +/// isIndefiniteType - Return true if this is an indefinite type - a type that +/// can describe objects, but which lacks information needed to construct +/// them. For sized types, "indefinite" is equivalent to "incomplete" +/// (C99 6.2.5p1). +bool Type::isIndefiniteType(NamedDecl **Def) const { if (Def) *Def = nullptr; @@ -2020,7 +2021,7 @@ // We don't handle variable arrays (they're not allowed in C++) or // dependent-sized arrays (dependent types are never treated as incomplete). return cast<ArrayType>(CanonicalType)->getElementType() - ->isIncompleteType(Def); + ->isIndefiniteType(Def); case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; @@ -2048,7 +2049,7 @@ } case ObjCObject: return cast<ObjCObjectType>(CanonicalType)->getBaseType() - ->isIncompleteType(Def); + ->isIndefiniteType(Def); case ObjCInterface: { // ObjC interfaces are incomplete if they are @class, not @interface. ObjCInterfaceDecl *Interface @@ -2086,16 +2087,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()) @@ -2143,9 +2146,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()) @@ -2161,7 +2165,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())) { @@ -2197,13 +2205,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>()) { @@ -2378,13 +2391,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 @@ -633,9 +633,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.1/1). 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>()) @@ -697,7 +699,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 @@ -2295,6 +2295,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 @@ -1516,7 +1516,8 @@ }; private: - bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, + bool RequireDefiniteTypeImpl(SourceLocation Loc, QualType T, + bool AllowSizeless, TypeDiagnoser *Diagnoser); struct ModuleScope { @@ -1599,14 +1600,33 @@ SourceLocation Loc, const NamedDecl *D, ArrayRef<const NamedDecl *> Equiv); + 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 @@ -1023,8 +1023,8 @@ /// \brief Default-initialization of a 'const' object. FK_DefaultInitOfConst, - /// \brief Initialization of an incomplete type. - FK_Incomplete, + /// \brief Initialization of an indefinite type. + FK_Indefinite, /// \brief Variable-length array must not have an initializer. FK_VariableLengthArrayHasInitializer, @@ -1054,8 +1054,8 @@ /// \brief The candidate set created when initialization failed. OverloadCandidateSet FailedCandidateSet; - /// \brief The incomplete type that caused a failure. - QualType FailedIncompleteType; + /// \brief The indefinite type that caused a failure. + QualType FailedIndefiniteType; /// \brief The fixit that needs to be applied to make this initialization /// succeed. @@ -1324,8 +1324,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!"); } /// \brief Note that this initialization sequence failed due to failed @@ -1345,10 +1345,10 @@ } /// \brief 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); } /// \brief Determine why initialization failed. Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2483,6 +2483,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">; @@ -6399,6 +6401,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">, @@ -8205,6 +8209,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/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1722,18 +1722,39 @@ bool isSizelessType() const; bool isSizelessBuiltinType() const; + /// As an extension, we classify types as one of "definite" or "indefinite"; + /// every type is one or the other. Indefinite types are types that can + /// describe objects but don't have enough information to construct them. + /// This is true iff the type is both "sized" and incomplete according + /// to the standard definition. + /// + /// \brief Def If non-null, and the type refers to some kind of declaration + /// that can be made definite (such as a C struct, C++ class, or Objective-C + /// class), will be set to the declaration. + bool isIndefiniteType(NamedDecl **Def = nullptr) const; + bool isDefiniteType(NamedDecl **Def = nullptr) const { + return !isIndefiniteType(Def); + } + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. /// Return true if this is an incomplete type. /// A type that can describe objects, but which lacks information needed to /// determine its size (e.g. void, or a fwd declared struct). Clients of this /// routine will need to determine if the size is actually required. /// - /// \brief Def If non-null, and the type refers to some kind of declaration - /// that can be completed (such as a C struct, C++ class, or Objective-C - /// class), will be set to the declaration. - bool isIncompleteType(NamedDecl **Def = nullptr) const; + /// A type is incomplete according to our definition iff: + /// - it is incomplete according to the standard definition; or + /// - it is "sizeless" + /// + /// The intention is that the usual rules for incomplete types will + /// by default apply to sizeless types as well. Specifically-chosen + /// rules can then be redefined in terms of "definite" and "indefinite" + /// if sizeless definite types are acceptable. + bool isIncompleteType() const { + return isIndefiniteType() || isSizelessType(); + } /// Return true if this is an incomplete or object /// type, in other words, not a function type. Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -273,7 +273,7 @@ MLV_DuplicateVectorComponents, MLV_InvalidExpression, MLV_LValueCast, // Specialized form of MLV_InvalidExpression. - MLV_IncompleteType, + MLV_IndefiniteType, MLV_ConstQualified, MLV_ConstQualifiedField, MLV_ConstAddrSpace, @@ -328,7 +328,7 @@ CM_ConstQualifiedField, CM_ConstAddrSpace, CM_ArrayType, - CM_IncompleteType + CM_IndefiniteType }; private: Index: include/clang/AST/CanonicalType.h =================================================================== --- include/clang/AST/CanonicalType.h +++ include/clang/AST/CanonicalType.h @@ -265,6 +265,8 @@ // Type predicates LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDefiniteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIndefiniteType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSizelessType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSizelessBuiltinType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits