[C2X] N3007 Type inference for object definitions
This patches implements the auto keyword from the N3007 standard
specification.
This allows deducing the type of the variable like in C++:
```
auto nb = 1;
auto chr = 'A';
auto str = "String";
```
The list of statements which allows the usage of auto:
* Basic variables declarations (int, float, double, char, char*...)
* Macros declaring a variable with the auto type
The list of statements which will not work with the auto keyword:
* auto arrays
* sizeof(), alignas()
* auto parameters, auto return type
* auto as a struct/typedef member
* uninitialized auto variables
* auto in an union
* auto as a enum type specifier
* auto casts
* auto in an compound literals
Differential Revision: https://reviews.llvm.org/D133289
This commit is contained in:
committed by
Aaron Ballman
parent
58678d3bcf
commit
5d78b78c85
@@ -240,6 +240,10 @@ def ext_imaginary_constant : Extension<
|
||||
"imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>;
|
||||
def ext_integer_complex : Extension<
|
||||
"complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
|
||||
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<DiagGroup<"auto-decl-extensions">>;
|
||||
|
||||
def err_invalid_saturation_spec : Error<"'_Sat' specifier is only valid on "
|
||||
"'_Fract' or '_Accum', not '%0'">;
|
||||
@@ -2388,7 +2392,8 @@ def err_auto_not_allowed : Error<
|
||||
"|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_implied_std_initializer_list_not_found : Error<
|
||||
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'|<ERROR>|'__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_func_def_incomplete_result : Error<
|
||||
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<DiagGroup<"atomic-access">>, DefaultError;
|
||||
|
||||
@@ -4038,7 +4038,7 @@ void Parser::ParseDeclarationSpecifiers(
|
||||
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);
|
||||
|
||||
@@ -1375,8 +1375,9 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
|
||||
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)
|
||||
|
||||
@@ -12863,6 +12863,15 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
|
||||
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<StringLiteral, InitListExpr>(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?");
|
||||
|
||||
@@ -4842,9 +4842,25 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
|
||||
return TDK_Success;
|
||||
}
|
||||
|
||||
// Make sure that we treat 'char[]' equaly as 'char*' in C23 mode.
|
||||
auto *String = dyn_cast<StringLiteral>(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<InitListExpr>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -9880,11 +9880,14 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
|
||||
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;
|
||||
|
||||
186
clang/test/C/C2x/n3007.c
Normal file
186
clang/test/C/C2x/n3007.c
Normal file
@@ -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));
|
||||
}
|
||||
41
clang/test/CodeGen/auto.c
Normal file
41
clang/test/CodeGen/auto.c
Normal file
@@ -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 i32, align 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
|
||||
}
|
||||
132
clang/test/Parser/c2x-auto.c
Normal file
132
clang/test/Parser/c2x-auto.c
Normal file
@@ -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}}
|
||||
}
|
||||
137
clang/test/Sema/c2x-auto.c
Normal file
137
clang/test/Sema/c2x-auto.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -1186,12 +1186,12 @@ conformance.</p>
|
||||
<tr>
|
||||
<td>Underspecified object definitions</td>
|
||||
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3006.htm">N3006</a></td>
|
||||
<td class="unknown" align="center">Unknown</td>
|
||||
<td class="none" align="center">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Type inference for object declarations</td>
|
||||
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3007.htm">N3007</a></td>
|
||||
<td class="none" align="center">No</td>
|
||||
<td class="unreleased" align="center">Clang 18</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>constexpr for object definitions</td>
|
||||
|
||||
Reference in New Issue
Block a user