Skip to content

Commit

Permalink
[clang][Sema] Fix a crash when instantiating a non-type template argu…
Browse files Browse the repository at this point in the history
…ment in a dependent scope.

The type alias template is not diagnosed when instantiating an expected non-type template argument in a dependent scope, causing ICE.

Besides that, the diagnostic message has been updated to account for the fact that the function template  is not the only non-type template.

Fixes #62533

Reviewed By: #clang-language-wg, erichkeane

Differential Revision: https://reviews.llvm.org/D151062
  • Loading branch information
0x59616e committed May 24, 2023
1 parent 2f6eba7 commit cde1390
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 12 deletions.
3 changes: 2 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,8 @@ Bug Fixes in This Version
``__builtin_dynamic_object_size`` on structs containing flexible array
members.
(`#62789 <https://github.com/llvm/llvm-project/issues/62789>`_).

- Fix a crash when instantiating a non-type template argument in a dependent scope.
(`#62533 <https://github.com/llvm/llvm-project/issues/62533>`_).
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5490,10 +5490,10 @@ def note_template_kw_refers_to_non_template : Note<
def err_template_kw_refers_to_dependent_non_template : Error<
"%0%select{| following the 'template' keyword}1 "
"cannot refer to a dependent template">;
def err_template_kw_refers_to_class_template : Error<
"'%0%1' instantiated to a class template, not a function template">;
def note_referenced_class_template : Note<
"class template declared here">;
def err_template_kw_refers_to_type_template : Error<
"'%0%1' is expected to be a non-type template, but instantiated to a %select{class|type alias}2 template">;
def note_referenced_type_template : Note<
"%select{class|type alias}0 template declared here">;
def err_template_kw_missing : Error<
"missing 'template' keyword prior to dependent template name '%0%1'">;
def ext_template_outside_of_template : ExtWarn<
Expand Down
19 changes: 13 additions & 6 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5001,13 +5001,20 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
return ExprError();
}

if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) {
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_class_template)
<< SS.getScopeRep()
<< NameInfo.getName().getAsString() << SS.getRange();
Diag(Temp->getLocation(), diag::note_referenced_class_template);
auto DiagnoseTypeTemplateDecl = [&](TemplateDecl *Temp,
bool isTypeAliasTemplateDecl) {
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
<< SS.getScopeRep() << NameInfo.getName().getAsString() << SS.getRange()
<< isTypeAliasTemplateDecl;
Diag(Temp->getLocation(), diag::note_referenced_type_template) << 0;
return ExprError();
}
};

if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>())
return DiagnoseTypeTemplateDecl(Temp, false);

if (TypeAliasTemplateDecl *Temp = R.getAsSingle<TypeAliasTemplateDecl>())
return DiagnoseTypeTemplateDecl(Temp, true);

return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs);
}
Expand Down
33 changes: 33 additions & 0 deletions clang/test/SemaCXX/PR62533.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

template<typename T>
struct test {
template<typename> using fun_diff = char; // expected-note 2{{class 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}}
}
2 changes: 1 addition & 1 deletion clang/test/SemaTemplate/ms-sizeof-missing-typename.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ template struct Foo<Bar>; // expected-note-re {{in instantiation {{.*}} requeste
}

namespace ambiguous_missing_parens {
// expected-error@+1 {{'Q::U' instantiated to a class template, not a function template}}
// expected-error@+1 {{'Q::U' is expected to be a non-type template, but instantiated to a class template}}
template <typename T> void f() { int a = sizeof T::template U<0> + 4; }
struct Q {
// expected-note@+1 {{class template declared here}}
Expand Down

0 comments on commit cde1390

Please sign in to comment.