https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/224019
>From 22306d4baabb27701a4ba3bdec21f1b83d738a6e Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Wed, 16 Sep 2026 06:49:13 -0700 Subject: [PATCH] [Clang][C23] Fix typedef-name after 'auto' as storage-class use --- clang/lib/Parse/ParseDecl.cpp | 31 +++++++++++++++++++++++++++++++ clang/test/C/C23/n3007.c | 18 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a4bdec00ca80a..e123a07204ebc 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4119,6 +4119,27 @@ void Parser::ParseDeclarationSpecifiers( break; case tok::kw_auto: if (getLangOpts().CPlusPlus11 || getLangOpts().C23) { + // FIXME: In C++, `auto` as a storage-class specifier is a + // deprecated extension. This lookahead runs for C only; teaching it + // to also recognize typedef-names in C++ would require broader + // design discussion around `ext_auto_storage_class`. See + // https://github.com/llvm/llvm-project/issues/164930. + auto IsTypedefName = [&](const Token &T) { + if (!T.is(tok::identifier)) + return false; + IdentifierInfo *II = T.getIdentifierInfo(); + if (!II) + return false; + // Use a raw suppressed lookup (rather than Sema::getTypeName) to + // avoid emitting deprecation/availability diagnostics on the + // typedef during this speculative peek — the real parse will look + // the name up again and emit them at the right time. + LookupResult R(Actions, II, T.getLocation(), Sema::LookupOrdinaryName); + Actions.LookupName(R, getCurScope(), + /*AllowBuiltinCreation=*/false); + R.suppressDiagnostics(); + return R.isSingleResult() && isa<TypeDecl>(R.getFoundDecl()); + }; auto MayBeTypeSpecifier = [&]() { // In pre-C23 C, auto can be used as a storage-class specifier. // C23 removes auto from the storage-class specifiers and repurposes @@ -4133,6 +4154,16 @@ void Parser::ParseDeclarationSpecifiers( if (isKnownToBeTypeSpecifier(T)) return true; + // C23: a bare identifier that names a typedef is a type + // specifier here, so `auto typedefName varName;` should be + // parsed with `auto` as the storage-class specifier — not as + // type inference. Without this check the parser would consume + // `auto` as type-inference and then error on the missing + // initializer for what it thinks is `typedefName` (issue + // #164930). + if (getLangOpts().C23 && IsTypedefName(T)) + return true; + if (getLangOpts().C23 && isTypeSpecifierQualifier(T)) ++I; else diff --git a/clang/test/C/C23/n3007.c b/clang/test/C/C23/n3007.c index a881b89443462..143a2fcc6796e 100644 --- a/clang/test/C/C23/n3007.c +++ b/clang/test/C/C23/n3007.c @@ -209,3 +209,21 @@ void test_macros(int in_int) { _Static_assert(_Generic(c, int : 1)); _Static_assert(_Generic(result, int : 1)); } + +// Regression test for #164930: `auto <typedef-name> <var>;` should parse as a +// declaration of <var> with type <typedef-name> (auto used as storage-class in +// C23 with an explicit type-name), not as inferred type deduction on the +// typedef. +void test_auto_typedef(void) { + typedef int T; + { + auto T at_local; + at_local = 42; + _Static_assert(_Generic(at_local, int : 1)); + } + { + // Also works with qualifiers. + const auto T at_const = 1; + _Static_assert(_Generic(&at_const, const int * : 1)); + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
