[clang] [clang][Sema] fix Crash when lookup finds UnresolvedUsingValueDecl followed by '<' (PR #190322)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 3 01:21:56 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: firstmoonlight
<details>
<summary>Changes</summary>
The code in Sema::ClassifyName (or relevant template lookup logic) used a hard `cast<TemplateDecl>`, which caused a crash when encountering an `UnresolvedUsingValueDecl` (e.g., a `using` declaration pointing to a dependent base class member).
This patch:
1. Replaces the unsafe `cast` with `dyn_cast_or_null`.
2. Adds a fallback path to construct an `AssumedTemplateName` or
`DependentTemplateName` when a concrete `TemplateDecl` is not
immediately available.
Fixes: https://github.com/llvm/llvm-project/issues/174951
---
Full diff: https://github.com/llvm/llvm-project/pull/190322.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaDecl.cpp (+25-19)
- (added) clang/test/SemaTemplate/lookup-dependent-using.cpp (+33)
``````````diff
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a479ff68c35c5..bb867ef192bab 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1157,26 +1157,32 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
IsFunctionTemplate = true;
Template = Context.getOverloadedTemplateName(Result.begin(),
Result.end());
- } else if (!Result.empty()) {
- auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(
- *Result.begin(), /*AllowFunctionTemplates=*/true,
- /*AllowDependent=*/false));
- IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
- IsVarTemplate = isa<VarTemplateDecl>(TD);
-
- UsingShadowDecl *FoundUsingShadow =
- dyn_cast<UsingShadowDecl>(*Result.begin());
- assert(!FoundUsingShadow ||
- TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
- Template = Context.getQualifiedTemplateName(
- SS.getScopeRep(),
- /*TemplateKeyword=*/false,
- FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
} else {
- // All results were non-template functions. This is a function template
- // name.
- IsFunctionTemplate = true;
- Template = Context.getAssumedTemplateName(NameInfo.getName());
+ TemplateDecl *TD = nullptr;
+ if (!Result.empty()) {
+ TD = dyn_cast_or_null<TemplateDecl>(getAsTemplateNameDecl(
+ *Result.begin(), /*AllowFunctionTemplates=*/true,
+ /*AllowDependent=*/false));
+ }
+
+ if (TD) {
+ IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
+ IsVarTemplate = isa<VarTemplateDecl>(TD);
+
+ UsingShadowDecl *FoundUsingShadow =
+ dyn_cast<UsingShadowDecl>(*Result.begin());
+ assert(!FoundUsingShadow ||
+ TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
+ Template = Context.getQualifiedTemplateName(
+ SS.getScopeRep(),
+ /*TemplateKeyword=*/false,
+ FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
+ } else {
+ // All results were non-template functions. This is a function template
+ // name.
+ IsFunctionTemplate = true;
+ Template = Context.getAssumedTemplateName(NameInfo.getName());
+ }
}
if (IsFunctionTemplate) {
diff --git a/clang/test/SemaTemplate/lookup-dependent-using.cpp b/clang/test/SemaTemplate/lookup-dependent-using.cpp
new file mode 100644
index 0000000000000..1dc0ba7ad29f3
--- /dev/null
+++ b/clang/test/SemaTemplate/lookup-dependent-using.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+// expected-no-diagnostics
+
+// This is a regression test that verifies handling a mix of using-declarations
+// from dependent and non-dependent base classes does not cause name lookup
+// to crash when a dependent entity cannot be converted to a TemplateDecl.
+
+template<typename A>
+class X {
+public:
+ template<typename T>
+ void execute(int a) {}
+};
+
+class Y {
+public:
+ void execute(int a) {}
+};
+
+template<typename A>
+class Exec : public X<A>, public Y {
+public:
+ using X<A>::execute;
+ using Y::execute;
+
+ void validate() {
+ // In C++20 the 'execute' here is followed by '<'.
+ // The lookup result will include an UnresolvedUsingValueDecl (from X<A>)
+ // and a UsingShadowDecl (from Y).
+ execute<int>(42);
+ execute(42);
+ }
+};
``````````
</details>
https://github.com/llvm/llvm-project/pull/190322
More information about the cfe-commits
mailing list