Author: Aaron Ballman
Date: 2026-07-07T13:22:14Z
New Revision: 849d90b64e2a91892d45d2fa75f405fa075d3c3d

URL: 
https://github.com/llvm/llvm-project/commit/849d90b64e2a91892d45d2fa75f405fa075d3c3d
DIFF: 
https://github.com/llvm/llvm-project/commit/849d90b64e2a91892d45d2fa75f405fa075d3c3d.diff

LOG: [C23] Allow deducing restrict and _Atomic qualifiers (#207994)

We were limiting the logic to __auto_type when it should apply to auto
as well.

Fixes #207466

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.md
    clang/lib/Sema/SemaType.cpp
    clang/test/C/C23/n3007.c
    clang/test/Parser/c2x-auto.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index cc85604343da9..c7806878a4ff4 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -299,6 +299,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) {


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to