Skip to content

Commit

Permalink
chore: Expand unresolved type references during template instantiation
Browse files Browse the repository at this point in the history
  • Loading branch information
robertoraggi authored Feb 27, 2024
1 parent bb3b80c commit 9f537a3
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 6 deletions.
5 changes: 2 additions & 3 deletions src/parser/cxx/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5554,12 +5554,11 @@ auto Parser::instantiate(SimpleTemplateIdAST* templateId) -> Symbol* {

auto needsInstantiation = [&]() -> bool {
if (args.empty()) return true;
for (std::size_t i = 0; i < args.size(); ++i) {
auto typeArgument = std::get_if<const Type*>(&args[i]);
for (auto arg : args) {
auto typeArgument = std::get_if<const Type*>(&arg);
if (!typeArgument) return true;
auto ty = type_cast<TypeParameterType>(*typeArgument);
if (!ty) return true;
if (ty->symbol()->index() != i) return true;
}
return false;
};
Expand Down
15 changes: 15 additions & 0 deletions src/parser/cxx/symbol_instantiation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,21 @@ auto SymbolInstantiation::VisitType::operator()(const UnresolvedNameType* type)
args.push_back(substitute(arg->typeId->type));
}
}

auto needsInstantiation = [&]() -> bool {
if (args.empty()) return true;

for (auto arg : args) {
auto typeArgument = std::get_if<const Type*>(&arg);
if (!typeArgument) return true;
auto ty = type_cast<TypeParameterType>(*typeArgument);
if (!ty) return true;
}
return false;
};

if (!needsInstantiation()) return type;

auto symbol = self.control()->instantiate(type->translationUnit(),
templateId->primaryTemplateSymbol,
std::move(args));
Expand Down
9 changes: 6 additions & 3 deletions src/parser/cxx/symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -717,17 +717,20 @@ auto symbol_cast(Symbol* symbol) -> T* {
struct GetTemplateParameters {
auto operator()(Symbol* symbol) const -> TemplateParametersSymbol* {
if (!symbol) return nullptr;
return visit(Visitor{*this}, symbol);
return visit(Visitor{}, symbol);
}

private:
struct Visitor {
const GetTemplateParameters& getTemplateParameters;

auto operator()(ConceptSymbol* symbol) const -> TemplateParametersSymbol* {
return symbol->templateParameters();
}

auto operator()(TemplateTypeParameterSymbol* symbol) const
-> TemplateParametersSymbol* {
return symbol->templateParameters();
}

auto operator()(ClassSymbol* symbol) const -> TemplateParametersSymbol* {
return symbol->templateParameters();
}
Expand Down
45 changes: 45 additions & 0 deletions tests/unit_tests/sema/template_class_03.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: %cxx -verify -fcheck -ftemplates -dump-symbols %s | %filecheck %s

namespace std {
using size_t = decltype(sizeof(0));

template <typename T>
struct allocator {
template <typename U>
struct rebind {
typedef allocator<U> other;
};

auto allocate(size_t n) -> T*;
void deallocate(T* p, size_t n);
};
} // namespace std

std::allocator<int>::rebind<char> alloc8;
std::allocator<int>::rebind<short> alloc16;

// clang-format off
// CHECK:namespace
// CHECK-NEXT: namespace std
// CHECK-NEXT: typealias unsigned long size_t
// CHECK-NEXT: template class allocator
// CHECK-NEXT: parameter typename<0, 0> T
// CHECK-NEXT: template class rebind
// CHECK-NEXT: parameter typename<0, 1> U
// CHECK-NEXT: typealias allocator<U> other
// CHECK-NEXT: function T* allocate(unsigned long)
// CHECK-NEXT: function void deallocate(T*, unsigned long)
// CHECK-NEXT: [specializations]
// CHECK-NEXT: class allocator<int>
// CHECK-NEXT: template class rebind
// CHECK-NEXT: parameter typename<0, 1> U
// CHECK-NEXT: typealias allocator<U> other
// CHECK-NEXT: [specializations]
// CHECK-NEXT: class rebind<char>
// CHECK-NEXT: typealias allocator<U> other
// CHECK-NEXT: class rebind<short>
// CHECK-NEXT: typealias allocator<U> other
// CHECK-NEXT: function int* allocate(unsigned long)
// CHECK-NEXT: function void deallocate(int*, unsigned long)
// CHECK-NEXT: variable std::allocator<int>::rebind<char> alloc8
// CHECK-NEXT: variable std::allocator<int>::rebind<short> alloc16

0 comments on commit 9f537a3

Please sign in to comment.