[llvm-branch-commits] [clang] 461ec35 - [Sema] Skip expansion statements when determing local extern context (#210512) (#211745)
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Jul 25 08:38:45 PDT 2026
Author: Oliver Hunt
Date: 2026-07-25T17:38:32+02:00
New Revision: 461ec356ec7448dd0e04c24b2e4a6a58a52abb86
URL: https://github.com/llvm/llvm-project/commit/461ec356ec7448dd0e04c24b2e4a6a58a52abb86
DIFF: https://github.com/llvm/llvm-project/commit/461ec356ec7448dd0e04c24b2e4a6a58a52abb86.diff
LOG: [Sema] Skip expansion statements when determing local extern context (#210512) (#211745)
This bug showed up as a failed assertion that was asserting that if
not in a function or method context we should be in the global/file
context.
The root cause is that when determining the linkage context for a
decl we were failing to account for the existence of expansion
contexts. Ignoring the assertion failure, the functional effect of
this is that we would fail to detect incorrect local extern
declarations inside expansion contexts. The fix here is to make
sure that we use `getEnclosingNonExpansionStatementContext()` to
find the true DeclContext for the current scope.
The initial report only identified local extern function declarations
but the same bug occurred with extern var decls, but the path did
not lead to an assertion firing, just incorrect behaviour.
Thanks to Sirraide for explaining why this was going wrong, and
confirming this was the correct fix.
Also fixes #211912
(cherry picked from commit da798c26ae2d191863910035e07a3e2affeb21b5)
Added:
clang/test/SemaCXX/expansion-statements-local-extern-decls.cpp
Modified:
clang/lib/AST/Decl.cpp
clang/lib/Sema/SemaDecl.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 4eaef0d87f3e5..5a76a726cd1f1 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1566,7 +1566,9 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
// one such matching entity, the program is ill-formed. Otherwise,
// if no matching entity is found, the block scope entity receives
// external linkage.
- if (D->getDeclContext()->isFunctionOrMethod())
+ if (D->getDeclContext()
+ ->getEnclosingNonExpansionStatementContext()
+ ->isFunctionOrMethod())
return getLVForLocalDecl(D, computation);
// C++ [basic.link]p6:
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 9b2efd96cb62d..27fe259af3717 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -7506,7 +7506,7 @@ static bool hasParsedAttr(Scope *S, const Declarator &PD,
}
bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) {
- if (!DC->isFunctionOrMethod())
+ if (!DC->getEnclosingNonExpansionStatementContext()->isFunctionOrMethod())
return false;
// If this is a local extern function or variable declared within a function
diff --git a/clang/test/SemaCXX/expansion-statements-local-extern-decls.cpp b/clang/test/SemaCXX/expansion-statements-local-extern-decls.cpp
new file mode 100644
index 0000000000000..c00a9c400c24d
--- /dev/null
+++ b/clang/test/SemaCXX/expansion-statements-local-extern-decls.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 %s -I %S/Inputs -std=c++2c -fsyntax-only -verify
+
+int wibble(); // #wibble_decl
+
+void foo1() {
+ template for (auto x : {1}) { // #foo1_instantiation
+ void wibble();
+ // expected-error at -1 {{functions that
diff er only in their return type cannot be overloaded}}
+ // expected-note@#wibble_decl {{previous declaration is here}}
+ // expected-note@#foo1_instantiation {{in instantiation of expansion statement requested here}}
+ }
+}
+
+void foo2() {
+ template for (auto x : {1}) { // #foo2_instantiation
+ template for (auto x : {1}) {
+ void wibble();
+ // expected-error at -1 {{functions that
diff er only in their return type cannot be overloaded}}
+ // expected-note@#wibble_decl {{previous declaration is here}}
+ // expected-note@#foo2_instantiation {{in instantiation of expansion statement requested here}}
+ }
+ }
+}
+
+int woffle; // #woffle_decl
+
+void foo3() {
+ template for (auto x : {1}) { // #foo3_instantiation
+ extern double woffle;
+ // expected-error at -1 {{redeclaration of 'woffle' with a
diff erent type: 'double' vs 'int'}}
+ // expected-note@#woffle_decl {{previous definition is here}}
+ // expected-note@#foo3_instantiation {{in instantiation of expansion statement requested here}}
+ }
+}
+
+void foo4() {
+ template for (auto x : {1}) { // #foo4_instantiation
+ template for (auto x : {1}) {
+ extern double woffle;
+ // expected-error at -1 {{redeclaration of 'woffle' with a
diff erent type: 'double' vs 'int'}}
+ // expected-note@#woffle_decl {{previous definition is here}}
+ // expected-note@#foo4_instantiation {{in instantiation of expansion statement requested here}}
+ }
+ }
+}
+
+void foo5() {
+ template for (constexpr auto x : {1,2,3}) { // #foo5_instantiation
+ extern int duplicated_global_var_decl[x]; // #duplicate_global_var_decl
+ // expected-error@#duplicate_global_var_decl {{redeclaration of 'duplicated_global_var_decl' with a
diff erent type: 'int[2]' vs 'int[1]'}}
+ // expected-note@#foo5_instantiation {{in instantiation of expansion statement requested here}}
+ // expected-note@#duplicate_global_var_decl {{previous declaration is here}}
+
+ // expected-error@#duplicate_global_var_decl {{redeclaration of 'duplicated_global_var_decl' with a
diff erent type: 'int[3]' vs 'int[1]'}}
+ // expected-note@#foo5_instantiation {{in instantiation of expansion statement requested here}}
+ // expected-note@#duplicate_global_var_decl {{previous declaration is here}}
+ }
+}
+
+template <int n> struct StandinType {};
+
+void foo6() {
+ template for (constexpr auto x : {1,2,3}) { // #foo6_instantiation
+ extern StandinType<x> duplicated_global_function_decl(); // #duplicate_global_function_decl
+ // expected-error@#duplicate_global_function_decl {{functions that
diff er only in their return type cannot be overloaded}}
+ // expected-note@#foo6_instantiation {{in instantiation of expansion statement requested here}}
+ // expected-note@#duplicate_global_function_decl {{previous declaration is here}}
+
+ // expected-error@#duplicate_global_function_decl {{functions that
diff er only in their return type cannot be overloaded}}
+ // expected-note@#foo6_instantiation {{in instantiation of expansion statement requested here}}
+ // expected-note@#duplicate_global_function_decl {{previous declaration is here}}
+ }
+}
More information about the llvm-branch-commits
mailing list