[clang] [Clang][Sema] Fix crash when using name of UnresolvedUsingValueDecl with template arguments (PR #83842)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 4 09:08:07 PST 2024


https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/83842

>From aeeb445a9e52a8011a008a5ee3438709f835034c Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 4 Mar 2024 08:10:35 -0500
Subject: [PATCH 1/2] [Clang][Sema] Fix crash when using name of
 UnresolvedUsingValueDecl with template arguments

---
 clang/lib/AST/ASTContext.cpp                  |  3 ++-
 clang/lib/Sema/SemaDecl.cpp                   |  3 ++-
 .../unqual-unresolved-using-value.cpp         | 24 +++++++++++++++++++
 3 files changed, 28 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/SemaTemplate/unqual-unresolved-using-value.cpp

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 5a8fae76a43a4d..28dd69b8e45758 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -9200,7 +9200,8 @@ TemplateName
 ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
                                       UnresolvedSetIterator End) const {
   unsigned size = End - Begin;
-  assert(size > 1 && "set is not overloaded!");
+  assert((size == 1 && isa<UnresolvedUsingValueDecl>(*Begin)) ||
+         size > 1 && "set is not overloaded!");
 
   void *memory = Allocate(sizeof(OverloadedTemplateStorage) +
                           size * sizeof(FunctionTemplateDecl*));
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 9fdd8eb236d1ee..c62e4ce7d0f9c4 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1115,7 +1115,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
     bool IsFunctionTemplate;
     bool IsVarTemplate;
     TemplateName Template;
-    if (Result.end() - Result.begin() > 1) {
+
+    if ((Result.end() - Result.begin() > 1) || Result.isUnresolvableResult()) {
       IsFunctionTemplate = true;
       Template = Context.getOverloadedTemplateName(Result.begin(),
                                                    Result.end());
diff --git a/clang/test/SemaTemplate/unqual-unresolved-using-value.cpp b/clang/test/SemaTemplate/unqual-unresolved-using-value.cpp
new file mode 100644
index 00000000000000..7c45342adce783
--- /dev/null
+++ b/clang/test/SemaTemplate/unqual-unresolved-using-value.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+template<typename T>
+struct A : T {
+  using T::f;
+  using T::g;
+
+  void f();
+  void g();
+
+  void h() {
+    f<int>();
+    g<int>(); // expected-error{{no member named 'g' in 'A<B>'}}
+  }
+};
+
+struct B {
+  template<typename T>
+  void f();
+
+  void g();
+};
+
+template struct A<B>; // expected-note{{in instantiation of member function 'A<B>::h' requested here}}

>From de29206a4c1881acc4ed31fdd59ebed75f4388ca Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 4 Mar 2024 11:58:17 -0500
Subject: [PATCH 2/2] [FOLD] assume names is template when any function is
 found

---
 clang/lib/AST/ASTContext.cpp    |  3 +--
 clang/lib/Sema/SemaDecl.cpp     |  7 +++++--
 clang/lib/Sema/SemaTemplate.cpp | 10 ++++++----
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 28dd69b8e45758..5a8fae76a43a4d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -9200,8 +9200,7 @@ TemplateName
 ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
                                       UnresolvedSetIterator End) const {
   unsigned size = End - Begin;
-  assert((size == 1 && isa<UnresolvedUsingValueDecl>(*Begin)) ||
-         size > 1 && "set is not overloaded!");
+  assert(size > 1 && "set is not overloaded!");
 
   void *memory = Allocate(sizeof(OverloadedTemplateStorage) +
                           size * sizeof(FunctionTemplateDecl*));
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 9fc7765dc8ec27..4b46b357aca93a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1110,17 +1110,20 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
     //   unqualified-id followed by a < and name lookup finds either one
     //   or more functions or finds nothing.
     if (!IsFilteredTemplateName)
-      FilterAcceptableTemplateNames(Result);
+      FilterAcceptableTemplateNames(Result,
+                                    /*AllowFunctionTemplates=*/true,
+                                    /*AllowDependent=*/true);
 
     bool IsFunctionTemplate;
     bool IsVarTemplate;
     TemplateName Template;
 
-    if ((Result.end() - Result.begin() > 1) || Result.isUnresolvableResult()) {
+    if (Result.end() - Result.begin() > 1) {
       IsFunctionTemplate = true;
       Template = Context.getOverloadedTemplateName(Result.begin(),
                                                    Result.end());
     } else if (!Result.empty()) {
+      assert(!Result.isUnresolvableResult());
       auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(
           *Result.begin(), /*AllowFunctionTemplates=*/true,
           /*AllowDependent=*/false));
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 873ea10ebe0660..3b41a9dfbe0e52 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -491,18 +491,20 @@ bool Sema::LookupTemplateName(LookupResult &Found,
     // To keep our behavior consistent, we apply the "finds nothing" part in
     // all language modes, and diagnose the empty lookup in ActOnCallExpr if we
     // successfully form a call to an undeclared template-id.
-    bool AllFunctions =
-        getLangOpts().CPlusPlus20 && llvm::all_of(Found, [](NamedDecl *ND) {
+    bool AnyFunctions =
+        getLangOpts().CPlusPlus20 && llvm::any_of(Found, [](NamedDecl *ND) {
           return isa<FunctionDecl>(ND->getUnderlyingDecl());
         });
-    if (AllFunctions || (Found.empty() && !IsDependent)) {
+    if (AnyFunctions || (Found.empty() && !IsDependent)) {
       // If lookup found any functions, or if this is a name that can only be
       // used for a function, then strongly assume this is a function
       // template-id.
       *ATK = (Found.empty() && Found.getLookupName().isIdentifier())
                  ? AssumedTemplateKind::FoundNothing
                  : AssumedTemplateKind::FoundFunctions;
-      Found.clear();
+      FilterAcceptableTemplateNames(Found,
+                                    /*AllowFunctionTemplates*/true,
+                                    /*AllowDependent*/true);
       return false;
     }
   }



More information about the cfe-commits mailing list