This patch revolves around the misuse of UnresolvedLookupExpr in
BuildTemplateIdExpr.
Basically, we build up an UnresolvedLookupExpr not only for function
overloads but for "unresolved" templates wherever we need an expression
for template decls. For example, a dependent VarTemplateDecl can be
wrapped with such an expression before template instantiation. (See
617007240c)
Also, one important thing is that UnresolvedLookupExpr uses a
"canonical"
QualType to describe the containing unresolved decls: a DependentTy is
for dependent expressions and an OverloadTy otherwise. Therefore, this
modeling for non-dependent templates leaves a problem in that the
expression
is marked and perceived as if describing overload functions. The
consumer then
expects functions for every such expression, although the fact is the
reverse.
Hence, we run into crashes.
As to the patch, I added a new canonical type "UnresolvedTemplateTy" to
model these cases. Given that we have been using this model
(intentionally or
accidentally) and it is pretty baked in throughout the code, I think
extending the role of UnresolvedLookupExpr is reasonable. Further, I
added
some diagnostics for the direct occurrence of these expressions, which
are supposed to be ill-formed.
As a bonus, this patch also fixes some typos in the diagnostics and
creates
RecoveryExprs rather than nothing in the hope of a better error-recovery
for clangd.
Fixes https://github.com/llvm/llvm-project/issues/88832
Fixes https://github.com/llvm/llvm-project/issues/63243
Fixes https://github.com/llvm/llvm-project/issues/48673
34 lines
1.3 KiB
C++
34 lines
1.3 KiB
C++
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
|
|
|
template<typename T>
|
|
struct test {
|
|
template<typename> using fun_diff = char; // expected-note 2{{type alias template declared here}}
|
|
};
|
|
|
|
template<typename T, typename V>
|
|
decltype(T::template fun_diff<V>) foo1() {}
|
|
// expected-note@-1 {{candidate template ignored: substitution failure [with T = test<int>, V = int]: 'test<int>::fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
|
|
|
|
template<typename T>
|
|
void foo2() {
|
|
// expected-error@+1 {{test<int>::fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
|
|
int a = test<T>::template fun_diff<int>;
|
|
}
|
|
|
|
template<typename T, typename V>
|
|
struct has_fun_diff {
|
|
using type = double;
|
|
};
|
|
|
|
template<typename T>
|
|
struct has_fun_diff<T, int> {
|
|
// expected-error@+1 {{'test<int>::fun_diff' is expected to be a non-type template, but instantiated to a type alias template}}
|
|
using type = decltype(T::template fun_diff<int>);
|
|
};
|
|
|
|
void bar() {
|
|
foo1<test<int>, int>(); // expected-error {{no matching function for call to 'foo1'}}
|
|
foo2<int>(); // expected-note {{in instantiation of function template specialization}}
|
|
has_fun_diff<test<int>, int>::type a; // expected-note {{in instantiation of template class}}
|
|
}
|