[clang] 42b6a6f - [Clang] Fixed the behavior of C23 auto when an array type was specified for a `char *` (#189722)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 2 09:40:26 PDT 2026
Author: Tony Guillot
Date: 2026-04-02T18:40:21+02:00
New Revision: 42b6a6faaa0014f7e39c57c6221fec1855ec4409
URL: https://github.com/llvm/llvm-project/commit/42b6a6faaa0014f7e39c57c6221fec1855ec4409
DIFF: https://github.com/llvm/llvm-project/commit/42b6a6faaa0014f7e39c57c6221fec1855ec4409.diff
LOG: [Clang] Fixed the behavior of C23 auto when an array type was specified for a `char *` (#189722)
At the time of the implementation of
[N3007](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3007.htm) in
Clang, when an array type was specified, an error was emitted unless the
deduced type was a `char *`.
After further inspection in the C standard, it turns out that the
inferred type of an `char[]` should be deduced to a `char *`, which
should emit an error if an array type is specified with `auto`.
This now invalidates the following cases:
```c
auto s1[] = "test";
auto s2[4] = "test";
auto s3[5] = "test";
```
Fixes #162694
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/test/C/C23/n3006.c
clang/test/C/C23/n3007.c
clang/test/CodeGen/auto.c
clang/test/Sema/auto-type.c
clang/test/Sema/c2x-auto.c
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e36cffdd84647..688f0a2c2bb75 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -396,6 +396,7 @@ Bug Fixes in This Version
with an explicit return type of void. The diagnostic now correctly refers
to "lambda" instead of "block". (#GH188661)
- Fixed a crash on _BitInt(N) arrays where 129 ≤ N ≤ 192 due to incorrect array filler lowering. (#GH189643)
+- Fixed the behavior in C23 of ``auto``, by emitting an error when an array type is specified for a ``char *``. (#GH162694)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index f18a34415ba43..c71c40526ccdc 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5224,14 +5224,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
return TemplateDeductionResult::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 TemplateDeductionResult::Success;
+ auto *InitList = dyn_cast<InitListExpr>(Init);
+ bool IsArrayType = Type.getType()->isArrayType();
+ if (!getLangOpts().CPlusPlus && (InitList || IsArrayType)) {
+ Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c)
+ << (int)AT->getKeyword() << IsArrayType;
+ return TemplateDeductionResult::AlreadyDiagnosed;
}
// Emit a warning if 'auto*' is used in pedantic and in C23 mode.
@@ -5239,13 +5237,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
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)
- << (int)AT->getKeyword() << getLangOpts().C23;
- return TemplateDeductionResult::AlreadyDiagnosed;
- }
-
// Deduce type of TemplParam in Func(Init)
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
diff --git a/clang/test/C/C23/n3006.c b/clang/test/C/C23/n3006.c
index 14d73da9db49c..69674d8e8f4b2 100644
--- a/clang/test/C/C23/n3006.c
+++ b/clang/test/C/C23/n3006.c
@@ -11,7 +11,7 @@ void struct_test(void) {
auto normal_struct2 = (struct S1) { .x = 1, .y = 2 };
auto underspecified_struct = (struct S2 { int x, y; }){ 1, 2 };
auto underspecified_struct_redef = (struct S1 { char x, y; }){ 'A', 'B'}; // expected-error {{type 'struct S1' has incompatible definitions}} \
- expected-error {{cannot use 'auto' with array in C}} \
+ expected-error {{cannot use 'auto' with initializer list in C}} \
expected-note {{field 'x' has type 'char' here}}
auto underspecified_empty_struct = (struct S3 { }){ };
auto zero_init_struct = (struct S4 { int x; }){ 0 };
@@ -25,7 +25,7 @@ void union_test(void) {
auto normal_union_double = (union U1){ .b = 2.4 };
auto underspecified_union = (union U2 { int a; double b; }){ .a = 34 };
auto underspecified_union_redef = (union U1 { char a; double b; }){ .a = 'A' }; // expected-error {{type 'union U1' has incompatible definitions}} \
- expected-error {{cannot use 'auto' with array in C}} \
+ expected-error {{cannot use 'auto' with initializer list in C}} \
expected-note {{field 'a' has type 'char' here}}
auto underspecified_empty_union = (union U3 { }){ };
}
@@ -37,7 +37,7 @@ void enum_test(void) {
auto normal_enum_bar = (enum E1){ BAR };
auto underspecified_enum = (enum E2 { BAZ, QUX }){ BAZ };
auto underspecified_enum_redef = (enum E1 { ONE, TWO }){ ONE }; // expected-error {{type 'enum E1' has incompatible definitions}} \
- expected-error {{cannot use 'auto' with array in C}} \
+ expected-error {{cannot use 'auto' with initializer list in C}} \
expected-note {{enumerator 'ONE' with value 0 here}}
auto underspecified_empty_enum = (enum E3 { }){ }; // expected-error {{use of empty enum}}
auto underspecified_undeclared_enum = (enum E4){ FOO }; // expected-error {{variable has incomplete type 'enum E4'}} \
diff --git a/clang/test/C/C23/n3007.c b/clang/test/C/C23/n3007.c
index b8b84519fc19d..fd81a6b9436b7 100644
--- a/clang/test/C/C23/n3007.c
+++ b/clang/test/C/C23/n3007.c
@@ -77,10 +77,10 @@ void test_arrary(void) {
}
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 a = {}; // expected-error {{cannot use 'auto' with initializer list in C}}
+ auto b = { 0 }; // expected-error {{cannot use 'auto' with initializer list in C}}
+ auto c = { 1, }; // expected-error {{cannot use 'auto' with initializer list in C}}
+ auto d = { 1 , 2 }; // expected-error {{cannot use 'auto' with initializer list in C}}
auto e = (int [3]){ 1, 2, 3 };
}
@@ -107,12 +107,11 @@ 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 test_char_ptr2[] = "another test"; // expected-error {{cannot use 'auto' with array in C}}
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) {
diff --git a/clang/test/CodeGen/auto.c b/clang/test/CodeGen/auto.c
index e5bc1bf66138f..844fd37b309b9 100644
--- a/clang/test/CodeGen/auto.c
+++ b/clang/test/CodeGen/auto.c
@@ -7,7 +7,6 @@ void basic_types(void) {
auto bl = true; // CHECK: alloca i8
auto chr = 'A'; // CHECK: alloca i{{8|32}}
auto str = "Test"; // CHECK: alloca ptr
- auto str2[] = "Test"; // CHECK: alloca [5 x i8]
auto nptr = nullptr; // CHECK: alloca ptr
}
diff --git a/clang/test/Sema/auto-type.c b/clang/test/Sema/auto-type.c
index b66f58b923287..b80948d6db66f 100644
--- a/clang/test/Sema/auto-type.c
+++ b/clang/test/Sema/auto-type.c
@@ -89,3 +89,12 @@ void Issue55702(void) {
(void)_Generic(v, long double : 0, double : 0, default : 1); // OK
_Static_assert(_Generic(v, long double : 0, default : 1) == 1, "fail");
}
+
+
+void incompatible_initializer(void) {
+ __auto_type s1[] = "test"; // expected-error {{cannot use '__auto_type' with array in C}}
+ __auto_type s2[4] = "test"; // expected-error {{cannot use '__auto_type' with array in C}}
+ __auto_type s3[5] = "test"; // expected-error {{cannot use '__auto_type' with array in C}}
+ __auto_type i = { 1 }; // expected-error {{cannot use '__auto_type' with initializer list in C}}
+ __auto_type i2 = { 1, 2 }; // expected-error {{cannot use '__auto_type' with initializer list in C}}
+}
diff --git a/clang/test/Sema/c2x-auto.c b/clang/test/Sema/c2x-auto.c
index 7d62db9ea6c28..a11c42aa6fb49 100644
--- a/clang/test/Sema/c2x-auto.c
+++ b/clang/test/Sema/c2x-auto.c
@@ -84,16 +84,16 @@ void test_qualifiers(const int y) {
_Static_assert(_Generic(pc, int * : 1));
}
-void test_strings(void) {
+void test_parens(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";
+ auto (str2) = "this is a string";
+ auto (((str3))) = "this is a string";
+ auto ((((x)))) = 12;
_Static_assert(_Generic(str, char * : 1));
_Static_assert(_Generic(str2, char * : 1));
_Static_assert(_Generic(str3, char * : 1));
- _Static_assert(_Generic(str4, char * : 1));
+ _Static_assert(_Generic(x, int : 1));
}
void test_pointers(void) {
@@ -137,3 +137,12 @@ void test_scopes(void) {
expected-error {{'auto' not allowed in function return type}}
return x;
}
+
+
+void test_incompatible_initializer(void) {
+ auto s1[] = "test"; // expected-error {{cannot use 'auto' with array in C}}
+ auto s2[4] = "test"; // expected-error {{cannot use 'auto' with array in C}}
+ auto s3[5] = "test"; // expected-error {{cannot use 'auto' with array in C}}
+ auto i = { 1 }; // expected-error {{cannot use 'auto' with initializer list in C}}
+ auto i2 = { 1, 2 }; // expected-error {{cannot use 'auto' with initializer list in C}}
+}
More information about the cfe-commits
mailing list