[clang] [C23] Allow deducing restrict and _Atomic qualifiers (PR #207994)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 7 05:48:39 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Aaron Ballman (AaronBallman)
<details>
<summary>Changes</summary>
We were limiting the logic to __auto_type when it should apply to auto as well.
Fixes #<!-- -->207466
---
Full diff: https://github.com/llvm/llvm-project/pull/207994.diff
4 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+3)
- (modified) clang/lib/Sema/SemaType.cpp (+4-13)
- (modified) clang/test/C/C23/n3007.c (+26-4)
- (modified) clang/test/Parser/c2x-auto.c (+1-2)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 77b6f89e39f83..6df1d8c3b8811 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -284,6 +284,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- Clang now recognizes the C23 `H`, `D`, and `DD` length modifiers in
format strings and diagnoses their use because Clang does not yet support
the corresponding decimal floating-point types, `_Decimal32`, `_Decimal64`, and `_Decimal128`. (#GH116962)
+- Fixed a bug with deducing qualified inferred types with `auto`. `auto` can now
+ be combined with `restrict` or `_Atomic` to form a properly-qualified type. (#GH207466)
+
### Objective-C Language Changes
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3640bf00b77a4..1378c7baca92e 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1608,14 +1608,6 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
return "type name";
}
-static bool isDependentOrGNUAutoType(QualType T) {
- if (T->isDependentType())
- return true;
-
- const auto *AT = dyn_cast<AutoType>(T);
- return AT && AT->isGNUAutoType();
-}
-
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
Qualifiers Qs, const DeclSpec *DS) {
if (T.isNull())
@@ -1646,10 +1638,9 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
if (!EltTy->isIncompleteOrObjectType())
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
- } else if (!isDependentOrGNUAutoType(T)) {
- // For an __auto_type variable, we may not have seen the initializer yet
- // and so have no idea whether the underlying type is a pointer type or
- // not.
+ } else if (!T->isDependentType() && !isa<AutoType>(T)) {
+ // For an inferred type, we may not have seen the initializer yet and so
+ // have no idea whether the underlying type is a pointer type or not.
DiagID = diag::err_typecheck_invalid_restrict_not_pointer;
EltTy = T;
}
@@ -10394,7 +10385,7 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
}
QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
- if (!isDependentOrGNUAutoType(T)) {
+ if (!T->isDependentType() && !isa<AutoType>(T)) {
// FIXME: It isn't entirely clear whether incomplete atomic types
// are allowed or not; for simplicity, ban them for the moment.
if (RequireCompleteType(Loc, T, diag::err_atomic_specifier_bad_type, 0))
diff --git a/clang/test/C/C23/n3007.c b/clang/test/C/C23/n3007.c
index fd81a6b9436b7..a881b89443462 100644
--- a/clang/test/C/C23/n3007.c
+++ b/clang/test/C/C23/n3007.c
@@ -19,25 +19,47 @@ void test_qualifiers(int x, const int y, int * restrict z) {
auto yup = ci;
yup = 12;
+ // Because inference happens after lvalue conversion, top-level qualifiers
+ // are stripped. So r_test will not be restrict qualified, while r_test_2
+ // will be because of the explicit use of the qualifier.
auto r_test = z;
+ auto restrict r_test_2 = z;
+
+ // Yes, you can unfortunately infer the type when _Atomic is used as a
+ // qualifier. (Remember, string literals in C are not const char[], they are
+ // char[].)
+ _Atomic auto atom_int = 12;
+ _Atomic auto atom_float = 1.2f;
+ _Atomic auto atom_str = "really?";
_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));
+ _Static_assert(_Generic(&r_test, int ** : 1));
+ _Static_assert(_Generic(&r_test_2, int * restrict * : 1));
+ _Static_assert(_Generic(&atom_int, _Atomic(int) * : 1));
+ _Static_assert(_Generic(&atom_float, _Atomic(float) * : 1));
+ _Static_assert(_Generic(&atom_str, _Atomic(char *) * : 1));
}
void test_atomic(void) {
- _Atomic auto i = 12; // expected-error {{_Atomic cannot be applied to type 'auto' in C23}}
+ // As silly as this seems, it's required to accept `_Atomic auto` because
+ // _Atomic is a qualifier in that case. But it's required to reject
+ // `_Atomic(auto)` because _Atomic is a type specifier in that case and you
+ // cannot combine auto with other type specifiers (e.g., no `_Complex auto`
+ // either).
+ _Atomic auto i = 12;
_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}}
+ // Despite being valid as a construct, it's only valid if you can actually
+ // deduce the type, which requires an initializer. So it cannot be used in a
+ // generic association.
+ _Static_assert(_Generic(&i, _Atomic auto *: 1)); // expected-error {{'auto' not allowed here}}
_Static_assert(_Generic(k, int: 1));
}
diff --git a/clang/test/Parser/c2x-auto.c b/clang/test/Parser/c2x-auto.c
index d60c96e2b168f..dc0e1f34dabdc 100644
--- a/clang/test/Parser/c2x-auto.c
+++ b/clang/test/Parser/c2x-auto.c
@@ -123,8 +123,7 @@ void atomic(void) {
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}}
+ _Atomic auto atom2 = 12; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
}
void attributes(void) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/207994
More information about the cfe-commits
mailing list