diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -145,6 +145,7 @@ previous placeholder value. Clang continues to accept ``-std=c2x`` and ``-std=gnu2x`` as aliases for C23 and GNU C23, respectively. - Clang now supports `requires c23` for module maps. +- Clang now supports ``N3007 Type inference for object definitions``. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -240,6 +240,10 @@ "imaginary constants are a GNU extension">, InGroup; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup; +def ext_c23_auto_non_plain_identifier : Extension< + "type inference of a declaration other than a plain identifier with optional " + "trailing attributes is a Clang extension">, + InGroup>; def err_invalid_saturation_spec : Error<"'_Sat' specifier is only valid on " "'_Fract' or '_Accum', not '%0'">; @@ -2388,7 +2392,8 @@ "|in conversion function type|here|in lambda parameter" "|in type allocated by 'new'|in K&R-style function parameter" "|in template parameter|in friend declaration|in function prototype that is " - "not a function declaration|in requires expression parameter}1">; + "not a function declaration|in requires expression parameter" + "|in array declaration}1">; def err_dependent_deduced_tst : Error< "typename specifier refers to " "%select{class template|function template|variable template|alias template|" @@ -2461,7 +2466,8 @@ def err_malformed_std_initializer_list : Error< "std::initializer_list must be a class template with a single type parameter">; def err_auto_init_list_from_c : Error< - "cannot use __auto_type with initializer list in C">; + "cannot use %select{'auto'||'__auto_type'}0 with " + "%select{initializer list|array}1 in C">; def err_auto_bitfield : Error< "cannot pass bit-field as __auto_type initializer in C">; @@ -6664,8 +6670,8 @@ def err_atomic_specifier_bad_type : Error<"_Atomic cannot be applied to " "%select{incomplete |array |function |reference |atomic |qualified " - "|sizeless ||integer }0type " - "%1 %select{|||||||which is not trivially copyable|}0">; + "|sizeless ||integer |}0type " + "%1 %select{|||||||which is not trivially copyable||in C23}0">; def warn_atomic_member_access : Warning< "accessing a member of an atomic structure or union is undefined behavior">, InGroup>, DefaultError; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4038,7 +4038,7 @@ isStorageClass = true; break; case tok::kw_auto: - if (getLangOpts().CPlusPlus11) { + if (getLangOpts().CPlusPlus11 || getLangOpts().C23) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, Policy); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1375,8 +1375,9 @@ StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class - // specifier in a pre-C++11 dialect of C++. - if (!S.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) + // specifier in a pre-C++11 dialect of C++ or in a pre-C23 dialect of C. + if (!S.getLangOpts().CPlusPlus11 && !S.getLangOpts().C23 && + TypeSpecType == TST_auto) S.Diag(TSTLoc, diag::ext_auto_type_specifier); if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11 && StorageClassSpec == SCS_auto) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12863,6 +12863,15 @@ DeducedType *Deduced = Type->getContainedDeducedType(); assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); + // Diagnose auto array declarations in C23, unless it's a supported extension. + if (getLangOpts().C23 && Type->isArrayType() && + !isa_and_present(Init)) { + Diag(Range.getBegin(), diag::err_auto_not_allowed) + << (int)Deduced->getContainedAutoType()->getKeyword() + << /*in array decl*/ 23 << Range; + return QualType(); + } + // C++11 [dcl.spec.auto]p3 if (!Init) { assert(VDecl && "no init for init capture deduction?"); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -4842,9 +4842,25 @@ return TDK_Success; } + // Make sure that we treat 'char[]' equaly as 'char*' in C23 mode. + auto *String = dyn_cast(Init); + if (getLangOpts().C23 && String && Type.getType()->isArrayType()) { + Diag(Type.getBeginLoc(), diag::ext_c23_auto_non_plain_identifier); + TypeLoc TL = TypeLoc(Init->getType(), Type.getOpaqueData()); + Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(TL); + assert(!Result.isNull() && "substituting DependentTy can't fail"); + return TDK_Success; + } + + // Emit a warning if 'auto*' is used in pedantic and in C23 mode. + if (getLangOpts().C23 && Type.getType()->isPointerType()) { + Diag(Type.getBeginLoc(), diag::ext_c23_auto_non_plain_identifier); + } + auto *InitList = dyn_cast(Init); if (!getLangOpts().CPlusPlus && InitList) { - Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); + Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c) + << (int)AT->getKeyword() << getLangOpts().C23; return TDK_AlreadyDiagnosed; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9880,11 +9880,14 @@ DisallowedKind = 5; else if (T->isSizelessType()) DisallowedKind = 6; - else if (!T.isTriviallyCopyableType(Context)) + else if (!T.isTriviallyCopyableType(Context) && getLangOpts().CPlusPlus) // Some other non-trivially-copyable type (probably a C++ class) DisallowedKind = 7; else if (T->isBitIntType()) DisallowedKind = 8; + else if (getLangOpts().C23 && T->isUndeducedAutoType()) + // _Atomic auto is prohibited in C23 + DisallowedKind = 9; if (DisallowedKind != -1) { Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; diff --git a/clang/test/C/C2x/n3007.c b/clang/test/C/C2x/n3007.c new file mode 100644 --- /dev/null +++ b/clang/test/C/C2x/n3007.c @@ -0,0 +1,186 @@ +// RUN: %clang_cc1 -std=c2x -verify -pedantic -Wno-comments %s + +/* WG14 N3007: Yes + * Type Inference for object definitions + */ +void test_qualifiers(int x, const int y, int * restrict z) { + const auto a = x; + auto b = y; + static auto c = 1UL; + int* pa = &a; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} + const int* pb = &b; + int* pc = &c; // expected-warning {{incompatible pointer types initializing 'int *' with an expression of type 'unsigned long *'}} + + const int ci = 12; + auto yup = ci; + yup = 12; + + auto r_test = z; + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(c, unsigned long : 1)); + _Static_assert(_Generic(pa, int * : 1)); + _Static_assert(_Generic(pb, const int * : 1)); + _Static_assert(_Generic(r_test, int * : 1)); +} + +void test_atomic(void) { + _Atomic auto i = 12; // expected-error {{_Atomic cannot be applied to type 'auto' in C23}} + _Atomic(auto) j = 12; // expected-error {{'auto' not allowed here}} \ + expected-error {{a type specifier is required for all declarations}} + + _Atomic(int) foo(void); + auto k = foo(); + + _Static_assert(_Generic(&i, _Atomic auto *: 1)); // expected-error {{_Atomic cannot be applied to type 'auto' in C23}} \ + expected-error {{'auto' not allowed here}} + _Static_assert(_Generic(k, int: 1)); +} + +void test_double(void) { + double A[3] = { 0 }; + auto pA = A; + auto qA = &A; + auto pi = 3.14; + + _Static_assert(_Generic(A, double * : 1)); + _Static_assert(_Generic(pA, double * : 1)); + _Static_assert(_Generic(qA, double (*)[3] : 1)); + _Static_assert(_Generic(pi, double : 1)); +} + +int test_auto_param(auto a) { // expected-error {{'auto' not allowed in function prototype}} + return (int)(a * 2); +} + +auto test_auto_return(float a, int b) { // expected-error {{'auto' not allowed in function return type}} + return ((a * b) * (a / b)); +} + +[[clang::overloadable]] auto test(auto x) { // expected-error {{'auto' not allowed in function prototype}} \ + expected-error {{'auto' not allowed in function return type}} + return x; +} + +void test_sizeof_alignas(void) { + (void)sizeof(auto); // expected-error {{expected expression}} + _Alignas(auto) int a[4]; // expected-error {{expected expression}} +} + +void test_arrary(void) { + auto a[4]; // expected-error {{'auto' not allowed in array declaration}} + auto b[] = {1, 2}; // expected-error {{cannot use 'auto' with array in C}} +} + +void test_initializer_list(void) { + auto a = {}; // expected-error {{cannot use 'auto' with array in C}} + auto b = { 0 }; // expected-error {{cannot use 'auto' with array in C}} + auto c = { 1, }; // expected-error {{cannot use 'auto' with array in C}} + auto d = { 1 , 2 }; // expected-error {{cannot use 'auto' with array in C}} + auto e = (int [3]){ 1, 2, 3 }; +} + +void test_structs(void) { + // FIXME: Both of these should be diagnosed as invalid underspecified + // declarations as described in N3006. + auto p1 = (struct { int a; } *)0; + struct s; + auto p2 = (struct s { int a; } *)0; + + struct B { auto b; }; // expected-error {{'auto' not allowed in struct member}} +} + +void test_typedefs(void) { + typedef auto auto_type; // expected-error {{'auto' not allowed in typedef}} + + typedef auto (*fp)(void); // expected-error {{'auto' not allowed in typedef}} + typedef void (*fp)(auto); // expected-error {{'auto' not allowed in function prototype}} + + _Generic(0, auto : 1); // expected-error {{'auto' not allowed here}} +} + +void test_misc(void) { + auto something; // expected-error {{declaration of variable 'something' with deduced type 'auto' requires an initializer}} + auto test_char = 'A'; + auto test_char_ptr = "test"; + auto test_char_ptr2[] = "another test"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto auto_size = sizeof(auto); // expected-error {{expected expression}} + + _Static_assert(_Generic(test_char, int : 1)); + _Static_assert(_Generic(test_char_ptr, char * : 1)); + _Static_assert(_Generic(test_char_ptr2, char * : 1)); +} + +void test_no_integer_promotions(void) { + short s; + auto a = s; + _Generic(a, int : 1); // expected-error {{controlling expression type 'short' not compatible with any generic association type}} +} + +void test_compound_literals(void) { + auto a = (int){}; + auto b = (int){ 0 }; + auto c = (int){ 0, }; + auto d = (int){ 0, 1 }; // expected-warning {{excess elements in scalar initializer}} + + auto auto_cl = (auto){13}; // expected-error {{expected expression}} + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(b, int : 1)); + _Static_assert(_Generic(c, int : 1)); +} + +void test_pointers(void) { + int a; + auto *ptr = &a; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto *ptr2 = a; // expected-error {{variable 'ptr2' with type 'auto *' has incompatible initializer of type 'int'}} \ + expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto nptr = nullptr; + + _Static_assert(_Generic(ptr, int * : 1)); + _Static_assert(_Generic(ptr2, int * : 1)); +} + +void test_scopes(void) { + double a = 7; + double b = 9; + { + auto a = a * a; // expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} \ + expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} + } + { + auto b = a * a; + auto a = b; + + _Static_assert(_Generic(a, double : 1)); + _Static_assert(_Generic(b, double : 1)); + } +} + +void test_loop(void) { + auto j = 4; + for (auto i = j; i < 2 * j; i++); + + _Static_assert(_Generic(j, int : 1)); +} + +#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) \ +auto _NAME = ARG + (ARG2 / ARG3); + +// This macro should only work with integers due to the usage of binary operators +#define AUTO_INT_MACRO(_NAME, ARG, ARG2, ARG3) \ +auto _NAME = (ARG ^ ARG2) & ARG3; + +void test_macros(int in_int) { + auto a = in_int + 1; + AUTO_MACRO(b, 1.3, 2.5f, 3); + AUTO_INT_MACRO(c, 64, 23, 0xff); + AUTO_INT_MACRO(not_valid, 51.5, 25, 0xff); // expected-error {{invalid operands to binary expression ('double' and 'int')}} + + auto result = (a + (int)b) - c; + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(b, double : 1)); + _Static_assert(_Generic(c, int : 1)); + _Static_assert(_Generic(result, int : 1)); +} diff --git a/clang/test/CodeGen/auto.c b/clang/test/CodeGen/auto.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/auto.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -std=c2x -emit-llvm %s -o - | FileCheck %s + +void basic_types(void) { + auto nb = 4; // CHECK: %nb = alloca i32, align 4 + auto dbl = 4.3; // CHECK: %dbl = alloca double, align 8 + auto lng = 4UL; // CHECK: %lng = alloca i{{32|64}}, align {{4|8}} + auto bl = true; // CHECK: %bl = alloca i8, align 1 + auto chr = 'A'; // CHECK: %chr = alloca i{{8|32}}, align {{1|4}} + auto str = "Test"; // CHECK: %str = alloca ptr, align 8 + auto str2[] = "Test"; // CHECK: %str2 = alloca [5 x i8], align 1 + auto nptr = nullptr; // CHECK: %nptr = alloca ptr, align 8 +} + +void misc_declarations(void) { + // FIXME: this should end up being rejected when we implement underspecified + // declarations in N3006. + auto strct_ptr = (struct { int a; } *)0; // CHECK: %strct_ptr = alloca ptr, align 8 + auto int_cl = (int){13}; // CHECK: %int_cl = alloca i32, align 4 + auto double_cl = (double){2.5}; // CHECK: %double_cl = alloca double, align 8 + + auto se = ({ // CHECK: %se = alloca i32, align 4 + auto snb = 12; // CHECK: %snb = alloca i32, align 4 + snb; + }); +} + +void loop(void) { + auto j = 4; // CHECK: %j = alloca i32, align 4 + for (auto i = j; i < 2 * j; i++); // CHECK: %i = alloca i32, align 4 +} + +#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) auto _NAME = ARG + (ARG2 / ARG3); + +#define AUTO_INT_MACRO(_NAME, ARG, ARG2, ARG3) auto _NAME = (ARG ^ ARG2) & ARG3; + +int macros(int in_int) { + auto a = in_int + 1; // CHECK: %a = alloca i32, align 4 + AUTO_MACRO(b, 1.3, 2.5f, 3); // CHECK: %b = alloca double, align 8 + AUTO_INT_MACRO(c, 64, 23, 0xff); // CHECK: %c = alloca i32, align 4 + return (a + (int)b) - c; // CHECK: ret i32 %sub +} diff --git a/clang/test/Parser/c2x-auto.c b/clang/test/Parser/c2x-auto.c new file mode 100644 --- /dev/null +++ b/clang/test/Parser/c2x-auto.c @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=expected,c23 -std=c23 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,c17 -std=c17 %s + +#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) \ +auto _NAME = ARG + (ARG2 / ARG3); + +struct S { + int a; + auto b; // c23-error {{'auto' not allowed in struct member}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + union { + char c; + auto smth; // c23-error {{'auto' not allowed in union member}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + } u; +}; + +enum E : auto { // c23-error {{'auto' not allowed here}} \ + c17-error {{expected a type}} \ + c17-error {{type name does not allow storage class to be specified}} + One, + Two, + Tree, +}; + +auto basic_usage(auto auto) { // c23-error {{'auto' not allowed in function prototype}} \ + c23-error {{'auto' not allowed in function return type}} \ + c23-error {{cannot combine with previous 'auto' declaration specifier}} \ + c17-error {{invalid storage class specifier in function declarator}} \ + c17-error {{illegal storage class on function}} \ + c17-warning {{duplicate 'auto' declaration specifier}} \ + c17-warning {{omitting the parameter name in a function definition is a C23 extension}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto = 4; // expected-error {{expected identifier or '('}} + + auto a = 4; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto auto aa = 12; // c23-error {{cannot combine with previous 'auto' declaration specifier}} \ + c17-warning {{duplicate 'auto' declaration specifier}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto b[4]; // c23-error {{'auto' not allowed in array declaration}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto array[auto]; // expected-error {{expected expression}} \ + c23-error {{declaration of variable 'array' with deduced type 'auto' requires an initializer}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + AUTO_MACRO(auto, 1, 2, 3); // c23-error {{cannot combine with previous 'auto' declaration specifier}} \ + expected-error {{expected identifier or '('}} \ + c17-warning {{duplicate 'auto' declaration specifier}} + + auto c = (auto)a; // expected-error {{expected expression}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto ci = (auto){12}; // expected-error {{expected expression}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + int auto_cxx_decl = auto(0); // expected-error {{expected expression}} + + return c; +} + +void structs(void) { + struct s_auto { auto a; }; // c23-error {{'auto' not allowed in struct member}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + // FIXME: this should end up being rejected when we implement underspecified + // declarations in N3006. + auto s_int = (struct { int a; } *)0; // c17-error {{incompatible pointer to integer conversion initializing 'int' with an expression of type}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + typedef auto auto_type; // c23-error {{'auto' not allowed in typedef}} \ + c17-error {{cannot combine with previous 'typedef' declaration specifier}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void sizeof_alignas(void) { + auto auto_size = sizeof(auto); // expected-error {{expected expression}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void generic_alignof_alignas(void) { + int g; + _Generic(g, auto : 0); // c23-error {{'auto' not allowed here}} \ + c17-error {{expected a type}} \ + c17-error {{type name does not allow storage class to be specified}} + + _Alignof(auto); // expected-error {{expected expression}} \ + expected-warning {{'_Alignof' applied to an expression is a GNU extension}} + + _Alignas(auto); // expected-error {{expected expression}} \ + expected-warning {{declaration does not declare anything}} +} + +void function_designators(void) { + extern auto auto_ret_func(void); // c23-error {{'auto' not allowed in function return type}} \ + c17-error {{cannot combine with previous 'extern' declaration specifier}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + extern void auto_param_func(auto); // c23-error {{'auto' not allowed in function prototype}} \ + c17-error {{invalid storage class specifier in function declarator}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + auto (auto_ret_func)(void); // c23-error {{'auto' not allowed in function return type}} \ + c17-error {{illegal storage class on function}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + void (auto_param_func)(auto); // c23-error {{'auto' not allowed in function prototype}} \ + c17-error {{invalid storage class specifier in function declarator}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void atomic(void) { + _Atomic(auto) atom1 = 12; // c23-error {{'auto' not allowed here}} \ + c23-error {{a type specifier is required for all declarations}} \ + c17-error {{expected a type}} \ + c17-error {{type name does not allow storage class to be specified}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + + _Atomic auto atom2 = 12; // c23-error {{_Atomic cannot be applied to type 'auto' in C23}} \ + c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} + +void attributes(void) { + auto ident [[clang::annotate("this works")]] = 12; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} +} diff --git a/clang/test/Sema/c2x-auto.c b/clang/test/Sema/c2x-auto.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/c2x-auto.c @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 -std=c2x -verify -pedantic -Wno-comments %s + +void test_basic_types(void) { + auto undefined; // expected-error {{declaration of variable 'undefined' with deduced type 'auto' requires an initializer}} + auto auto_int = 4; + auto auto_long = 4UL; + signed auto a = 1L; // expected-error {{'auto' cannot be signed or unsigned}} + + _Static_assert(_Generic(auto_int, int : 1)); + _Static_assert(_Generic(auto_long, unsigned long : 1)); +} + +void test_complex_types(void) { + _Complex auto i = 12.0; // expected-error {{'_Complex auto' is invalid}} +} + +void test_gnu_extensions(void) { + auto t = ({ // expected-warning {{use of GNU statement expression extension}} + auto b = 12; + b; + }); + _Static_assert(_Generic(t, int : 1)); +} + +void test_sizeof_typeof(void) { + auto auto_size = sizeof(auto); // expected-error {{expected expression}} + typeof(auto) tpof = 4; // expected-error {{expected expression}} +} + +void test_casts(void) { + auto int_cast = (int)(4 + 3); + auto double_cast = (double)(1 / 3); + auto long_cast = (long)(4UL + 3UL); + auto auto_cast = (auto)(4 + 3); // expected-error {{expected expression}} + + _Static_assert(_Generic(int_cast, int : 1)); + _Static_assert(_Generic(double_cast, double : 1)); + _Static_assert(_Generic(long_cast, long : 1)); +} + +void test_compound_literral(void) { + auto int_cl = (int){13}; + auto double_cl = (double){2.5}; + auto array[] = { 1, 2, 3 }; // expected-error {{cannot use 'auto' with array in C}} + + auto auto_cl = (auto){13}; // expected-error {{expected expression}} + + _Static_assert(_Generic(int_cl, int : 1)); + _Static_assert(_Generic(double_cl, double : 1)); +} + +void test_array_pointers(void) { + double array[3] = { 0 }; + auto a = array; + auto b = &array; + + _Static_assert(_Generic(array, double * : 1)); + _Static_assert(_Generic(a, double * : 1)); + _Static_assert(_Generic(b, double (*)[3] : 1)); +} + +void test_typeof() { + int typeof_target(); + auto result = (typeof(typeof_target())){12}; + + _Static_assert(_Generic(result, int : 1)); +} + +void test_qualifiers(const int y) { + const auto a = 12; + auto b = y; + static auto c = 1UL; + int* pa = &a; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} + const int* pb = &b; + int* pc = &c; // expected-warning {{incompatible pointer types initializing 'int *' with an expression of type 'unsigned long *'}} + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(b, int : 1)); + _Static_assert(_Generic(c, unsigned long : 1)); + _Static_assert(_Generic(pa, int * : 1)); + _Static_assert(_Generic(pb, const int * : 1)); + _Static_assert(_Generic(pc, int * : 1)); +} + +void test_strings(void) { + auto str = "this is a string"; + auto str2[] = "this is a string"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto (str3) = "this is a string"; + auto (((str4))) = "this is a string"; + + _Static_assert(_Generic(str, char * : 1)); + _Static_assert(_Generic(str2, char * : 1)); + _Static_assert(_Generic(str3, char * : 1)); + _Static_assert(_Generic(str4, char * : 1)); +} + +void test_pointers(void) { + auto a = 12; + auto *ptr = &a; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto *str = "this is a string"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + const auto *str2 = "this is a string"; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + auto *b = &a; // expected-warning {{type inference of a declaration other than a plain identifier with optional trailing attributes is a Clang extension}} + *b = &a; // expected-error {{incompatible pointer to integer conversion assigning to 'int' from 'int *'; remove &}} + auto nptr = nullptr; + + _Static_assert(_Generic(a, int : 1)); + _Static_assert(_Generic(ptr, int * : 1)); + _Static_assert(_Generic(str, char * : 1)); + _Static_assert(_Generic(str2, const char * : 1)); + _Static_assert(_Generic(b, int * : 1)); + _Static_assert(_Generic(nptr, typeof(nullptr) : 1)); +} + +void test_prototypes(void) { + extern void foo(int a, int array[({ auto x = 12; x;})]); // expected-warning {{use of GNU statement expression extension}} +} + +void test_scopes(void) { + double a = 7; + double b = 9; + { + auto a = a * a; // expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} \ + expected-error {{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}} + } + { + auto b = a * a; + auto a = b; + + _Static_assert(_Generic(b, double : 1)); + _Static_assert(_Generic(a, double : 1)); + } +} + +[[clang::overloadable]] auto test(auto x) { // expected-error {{'auto' not allowed in function prototype}} \ + expected-error {{'auto' not allowed in function return type}} + return x; +} diff --git a/clang/www/c_status.html b/clang/www/c_status.html --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -1186,12 +1186,12 @@ Underspecified object definitions N3006 - Unknown + No Type inference for object declarations N3007 - No + Clang 18 constexpr for object definitions