add dealias for Resolver.

This commit is contained in:
ykiko
2024-09-07 11:11:41 +08:00
parent 76b33d1f7c
commit 4e331bc8a2
3 changed files with 83 additions and 14 deletions

View File

@@ -40,8 +40,14 @@ public:
const clang::IdentifierInfo* II,
llvm::ArrayRef<clang::TemplateArgument> arguments);
// replace the template arguments in the type, using the arguments in the frame
clang::Decl* substitute(clang::Decl* decl);
/// we use `Sema::SubstType` to substitute the template arguments in dependent type.
/// but it doesn't substitute the template arguments in alias type.
/// i.e. `typename base::type`, when base is `std::vector<T>`, it will ignore the `T`.
/// so before actually substituting the type, we need to dealias the type.
clang::QualType dealias(clang::QualType type);
/// replace the template arguments in the type, using the arguments in the frame
clang::QualType substitute(clang::QualType type);
private:
struct Frame {

View File

@@ -3,11 +3,10 @@
namespace clice {
clang::QualType DependentNameResolver::resolve(clang::NamedDecl* ND) {
auto decl = substitute(ND);
if(auto TAD = llvm::dyn_cast<clang::TypeAliasDecl>(decl)) {
return resolve(TAD->getUnderlyingType());
} else if(auto TND = llvm::dyn_cast<clang::TypedefNameDecl>(decl)) {
return resolve(TND->getUnderlyingType());
if(auto TAD = llvm::dyn_cast<clang::TypeAliasDecl>(ND)) {
return resolve(substitute(TAD->getUnderlyingType()));
} else if(auto TND = llvm::dyn_cast<clang::TypedefNameDecl>(ND)) {
return resolve(substitute(TND->getUnderlyingType()));
} else {
std::terminate();
}
@@ -127,7 +126,40 @@ bool DependentNameResolver::lookup(llvm::SmallVector<clang::NamedDecl*>& result,
return false;
}
clang::Decl* DependentNameResolver::substitute(clang::Decl* decl) {
// FIXME: handle more case
static bool isalias(clang::QualType type) {
if(!type->isDependentType()) {
return false;
}
if(auto TAT = type->getAs<clang::TypedefType>()) {
return true;
} else if(auto DNT = type->getAs<clang::TemplateSpecializationType>()) {
return false;
} else if(auto DNT = type->getAs<clang::DependentNameType>()) {
return isalias(clang::QualType(DNT->getQualifier()->getAsType(), 0));
} else {
std::terminate();
}
}
clang::QualType DependentNameResolver::dealias(clang::QualType type) {
if(!isalias(type)) {
return type;
}
if(auto TAT = type->getAs<clang::TypedefType>()) {
return dealias(TAT->getDecl()->getUnderlyingType());
} else if(auto DNT = type->getAs<clang::DependentNameType>()) {
auto type = dealias(clang::QualType(DNT->getQualifier()->getAsType(), 0));
auto prefix = clang::NestedNameSpecifier::Create(context, nullptr, false, type.getTypePtr());
return context.getDependentNameType(DNT->getKeyword(), prefix, DNT->getIdentifier());
} else {
std::terminate();
}
}
clang::QualType DependentNameResolver::substitute(clang::QualType type) {
clang::MultiLevelTemplateArgumentList list;
for(auto begin = frames.rbegin(), end = frames.rend(); begin != end; ++begin) {
list.addOuterTemplateArguments(begin->decl, begin->arguments, true);
@@ -141,10 +173,7 @@ clang::Decl* DependentNameResolver::substitute(clang::Decl* decl) {
sema.pushCodeSynthesisContext(context);
}
// FIXME: use global TU may result misunderstanding result
// create some fake namespace to avoid this
auto result = sema.SubstDecl(decl, context.getTranslationUnitDecl(), list);
auto result = sema.SubstType(dealias(type), list, {}, {});
frames.clear();
return result;

View File

@@ -97,7 +97,6 @@ template <typename X>
struct test {
using result = typename C<X>::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
@@ -129,7 +128,6 @@ template <typename X>
struct test {
using result = typename A<X>::self::self::self::self::self::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
@@ -146,5 +144,41 @@ struct test {
ASSERT_EQ(T->getDecl()->getName(), "X");
}
TEST(DependentNameResolver, alias_dependent_name) {
const char* code = R"(
template <typename ...Ts>
struct type_list {};
template <typename T1>
struct A {
using type = type_list<T1>;
};
template <typename T2>
struct B {
using base = A<T2>;
using type = typename base::type;
};
template <typename X>
struct test {
using result = typename B<X>::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
// result->dump();
auto TST = result->getAs<clang::TemplateSpecializationType>();
ASSERT_TRUE(TST);
ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list");
auto args = TST->template_arguments();
ASSERT_EQ(args.size(), 1);
auto T = llvm::dyn_cast<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
}
} // namespace