[clang] [clang-tools-extra] [clang] Do not cache variable linkage before type deduction (PR #221474)

Vedran Miletić via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 5 11:17:14 PDT 2026


https://github.com/vedranmiletic updated https://github.com/llvm/llvm-project/pull/221474

>From a5a5dd45ba810c8fb30ca56b8f11bf59146253ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vedran=20Mileti=C4=87?= <vedran at miletic.net>
Date: Sun, 2 Aug 2026 20:15:23 +0200
Subject: [PATCH] [clang] Do not cache variable linkage before type deduction

The linkage of a variable can depend on its deduced type. Avoid caching
linkage while the type is still undeduced so early queries cannot leave
a stale result.

Fixes #22203
Fixes #200597

Assisted-by: Codex (OpenAI ChatGPT)
---
 .../clangd/test/crash-auto-lambda-linkage.test       | 12 ++++++++++++
 clang/lib/AST/Decl.cpp                               |  6 ++++++
 clang/test/SemaCXX/crash-auto-lambda-linkage.cpp     |  4 ++++
 clang/test/SemaCXX/reserved-identifier.cpp           |  2 ++
 .../SemaCXX/warn-missing-variable-declarations.cpp   |  5 +++++
 5 files changed, 29 insertions(+)
 create mode 100644 clang-tools-extra/clangd/test/crash-auto-lambda-linkage.test
 create mode 100644 clang/test/SemaCXX/crash-auto-lambda-linkage.cpp

diff --git a/clang-tools-extra/clangd/test/crash-auto-lambda-linkage.test b/clang-tools-extra/clangd/test/crash-auto-lambda-linkage.test
new file mode 100644
index 0000000000000..f8a3d63800f8b
--- /dev/null
+++ b/clang-tools-extra/clangd/test/crash-auto-lambda-linkage.test
@@ -0,0 +1,12 @@
+# RUN: clangd -lit-test < %s
+# https://github.com/llvm/llvm-project/issues/200597
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"auto a = [] {\n\n"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":1,"character":0}}}
+---
+{"jsonrpc":"2.0","id":2,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index a620e9f211ca6..5514a90689050 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1591,6 +1591,12 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
     return *LI;
 
   LinkageInfo LV = computeLVForDecl(D, computation);
+
+  // A variable's linkage may depend on its deduced type.
+  if (const auto *VD = dyn_cast<VarDecl>(D);
+      VD && VD->getType()->isUndeducedType())
+    return LV;
+
   if (D->hasCachedLinkage())
     assert(D->getCachedLinkage() == LV.getLinkage());
 
diff --git a/clang/test/SemaCXX/crash-auto-lambda-linkage.cpp b/clang/test/SemaCXX/crash-auto-lambda-linkage.cpp
new file mode 100644
index 0000000000000..def91d820e558
--- /dev/null
+++ b/clang/test/SemaCXX/crash-auto-lambda-linkage.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+// https://github.com/llvm/llvm-project/issues/22203
+auto g = [] { virtual g() // expected-error {{a type specifier is required for all declarations}} expected-warning {{empty parentheses interpreted as a function declaration}} expected-note {{replace parentheses with an initializer to declare a variable}} expected-error {{expected ';' at end of declaration}} expected-error {{expected '}'}} expected-note {{to match this '{'}} expected-error {{expected ';' after top level declarator}}
diff --git a/clang/test/SemaCXX/reserved-identifier.cpp b/clang/test/SemaCXX/reserved-identifier.cpp
index a3e6d8ead61fd..b1ac3653a088d 100644
--- a/clang/test/SemaCXX/reserved-identifier.cpp
+++ b/clang/test/SemaCXX/reserved-identifier.cpp
@@ -113,4 +113,6 @@ namespace N {
   extern "C" int _namespace_b; // expected-warning {{identifier '_namespace_b' is reserved because it starts with '_' and has C language linkage}}
   void _namespace_c();
   extern "C" void _namespace_d(); // expected-warning {{identifier '_namespace_d' is reserved because it starts with '_' and has C language linkage}}
+  auto _namespace_e = []{};   // no-warning
+  auto _namespace_f = 0;      // no-warning
 }
diff --git a/clang/test/SemaCXX/warn-missing-variable-declarations.cpp b/clang/test/SemaCXX/warn-missing-variable-declarations.cpp
index b50eeed30e7ae..b2183aaa8243a 100644
--- a/clang/test/SemaCXX/warn-missing-variable-declarations.cpp
+++ b/clang/test/SemaCXX/warn-missing-variable-declarations.cpp
@@ -83,3 +83,8 @@ template<> int var_template<int[5]>; // expected-warning {{no previous extern de
 // the linkage from the template! We should not warn here.
 template<> int static_var_template<int[5]>; // expected-warning {{no previous extern declaration}}
 // expected-note at -1{{declare 'static' if the variable is not intended to be used outside of this translation unit}}
+
+namespace deduced {
+  auto lambda_a = []{}; // no-warning
+  auto _lambda_b = []{}; // no-warning
+}



More information about the cfe-commits mailing list