Skip to content

Commit

Permalink
[Clang][Sema] Fix crash when using name of UnresolvedUsingValueDecl w…
Browse files Browse the repository at this point in the history
…ith template arguments (#83842)

The following snippet causes a crash:
```
template<typename T>
struct A : T {
  using T::f;
  void f();

  void g() {
    f<int>(); // crash here
  }
};
```
This happens because we cast the result of `getAsTemplateNameDecl` as a
`TemplateDecl` in `Sema::ClassifyName`, which we cannot do for an
`UnresolvedUsingValueDecl`. This patch fixes the crash by considering a name
to be that of a template if _any_ function declaration is found per [temp.names] p3.3.
  • Loading branch information
sdkrystian authored Mar 5, 2024
1 parent 894f52f commit a642eb8
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 5 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ Bug Fixes to C++ Support
our attention by an attempt to fix in (#GH77703). Fixes (#GH83385).
- Fix evaluation of some immediate calls in default arguments.
Fixes (#GH80630)
- Fix a crash when an explicit template argument list is used with a name for which lookup
finds a non-template function and a dependent using declarator.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,9 @@ 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;
Expand All @@ -1120,6 +1122,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
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));
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
30 changes: 30 additions & 0 deletions clang/test/SemaTemplate/unqual-unresolved-using-value.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s

template<typename T>
struct A : T {
using T::f;
using T::g;
using T::h;

void f();
void g();

void i() {
f<int>();
g<int>(); // expected-error{{no member named 'g' in 'A<B>'}}
h<int>(); // expected-error{{expected '(' for function-style cast or type construction}}
// expected-error@-1{{expected expression}}
}
};

struct B {
template<typename T>
void f();

void g();

template<typename T>
void h();
};

template struct A<B>; // expected-note{{in instantiation of member function 'A<B>::i' requested here}}

0 comments on commit a642eb8

Please sign in to comment.