From 053fd3511ac270324f4202c561cc21b95c33e7ff Mon Sep 17 00:00:00 2001 From: ykiko Date: Sat, 7 Sep 2024 19:07:07 +0800 Subject: [PATCH] Resolver can handle `std::vector` now !!!! --- include/AST/Resolver.h | 2 + src/AST/Resolver.cpp | 105 +++++++++++++++++++++++++++++++++++++---- tests/Resolver.cpp | 104 ++++++++++++++++++++++++++++++++++------ 3 files changed, 186 insertions(+), 25 deletions(-) diff --git a/include/AST/Resolver.h b/include/AST/Resolver.h index 5d339a42..92504f7d 100644 --- a/include/AST/Resolver.h +++ b/include/AST/Resolver.h @@ -42,6 +42,8 @@ public: const clang::IdentifierInfo* II, llvm::ArrayRef arguments); + std::vector resugar(llvm::ArrayRef arguments); + /// 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`, it will ignore the `T`. diff --git a/src/AST/Resolver.cpp b/src/AST/Resolver.cpp index b39457fe..bc29d795 100644 --- a/src/AST/Resolver.cpp +++ b/src/AST/Resolver.cpp @@ -19,10 +19,22 @@ clang::QualType DependentNameResolver::resolve(clang::QualType type) { type = type.getDesugaredType(context); - if(auto DNT = llvm::dyn_cast(type)) { + if(auto TST = type->getAs()) { + std::vector args; + for(auto arg: TST->template_arguments()) { + if(arg.getKind() == clang::TemplateArgument::ArgKind::Type) { + args.push_back(resolve(arg.getAsType())); + } else { + args.push_back(arg); + } + } + return context.getTemplateSpecializationType(TST->getTemplateName(), args); + } else if(auto DNT = llvm::dyn_cast(type)) { return resolve(DNT); } else if(auto DTST = llvm::dyn_cast(type)) { return resolve(DTST); + } else if(auto LVRT = llvm::dyn_cast(type)) { + return context.getLValueReferenceType(resolve(LVRT->getPointeeType())); } else { return type; } @@ -42,7 +54,7 @@ clang::QualType DependentNameResolver::resolve(const clang::DependentTemplateSpe llvm::SmallVector result; if(lookup(result, DTST->getQualifier(), DTST->getIdentifier()) && result.size() == 1) { if(auto TATD = llvm::dyn_cast(result.front())) { - frames.emplace_back(TATD, DTST->template_arguments()); + frames.emplace_back(TATD, resugar(DTST->template_arguments())); return resolve(substitute(TATD->getTemplatedDecl()->getUnderlyingType())); } } @@ -68,7 +80,9 @@ bool DependentNameResolver::lookup(llvm::SmallVector& result, } // prefix is a type, e.g. <...>::typename name:: - case clang::NestedNameSpecifier::SpecifierKind::TypeSpec: + case clang::NestedNameSpecifier::SpecifierKind::TypeSpec: { + return lookup(result, clang::QualType(NNS->getAsType(), 0), II); + } case clang::NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: { return lookup(result, clang::QualType(NNS->getAsType(), 0), II); } @@ -83,18 +97,21 @@ bool DependentNameResolver::lookup(llvm::SmallVector& result, bool DependentNameResolver::lookup(llvm::SmallVector& result, const clang::QualType type, const clang::IdentifierInfo* II) { + if(auto DNT = type->getAs()) { + return lookup(result, resolve(DNT), II); + } clang::TemplateDecl* TD; - llvm::ArrayRef args; + std::vector args; // FIXME: consider default arguments if(auto TST = type->getAs()) { TD = TST->getTemplateName().getAsTemplateDecl(); - args = TST->template_arguments(); + args = resugar(TST->template_arguments()); } else if(auto DTST = type->getAs()) { if(lookup(result, DTST->getQualifier(), DTST->getIdentifier()) && result.size() == 1) { TD = llvm::dyn_cast(result.front()); - args = DTST->template_arguments(); + args = resugar(DTST->template_arguments()); result.clear(); } else { return false; @@ -108,6 +125,8 @@ bool DependentNameResolver::lookup(llvm::SmallVector& result, return lookup(result, resolve(substitute(TATD->getTemplatedDecl()->getUnderlyingType())), II); } + type->dump(); + llvm::outs() << II->getName() << "\n"; std::terminate(); } @@ -128,6 +147,20 @@ bool DependentNameResolver::lookup(llvm::SmallVector& result, return true; } + for(auto base: CTD->getTemplatedDecl()->bases()) { + // store the current state + auto copy = frames; + + // try to find the member in the base class + frames.emplace_back(CTD, arguments); + if(lookup(result, substitute(base.getType()), II)) { + return true; + } + + // if failed, restore the state + frames = std::move(copy); + } + // if failed, try partial specializations llvm::SmallVector partials; CTD->getPartialSpecializations(partials); @@ -158,6 +191,27 @@ bool DependentNameResolver::lookup(llvm::SmallVector& result, return false; } +/// FIXME: handle more cese +std::vector DependentNameResolver::resugar(llvm::ArrayRef arguments) { + std::vector result; + for(auto arg: arguments) { + if(arg.getKind() == clang::TemplateArgument::ArgKind::Type) { + // check whether it is a TemplateTypeParmType. + if(auto type = llvm::dyn_cast(arg.getAsType())) { + const clang::TemplateTypeParmDecl* param = type->getDecl(); + if(param && param->hasDefaultArgument()) { + result.push_back(param->getDefaultArgument().getArgument()); + } else { + result.emplace_back(resolve(arg.getAsType())); + } + continue; + } + } + result.push_back(arg); + } + return result; +} + // FIXME: handle more case static bool isalias(clang::QualType type) { if(!type->isDependentType()) { @@ -167,14 +221,24 @@ static bool isalias(clang::QualType type) { if(auto TAT = type->getAs()) { return true; } else if(auto DNT = type->getAs()) { + for(auto arg: DNT->template_arguments()) { + if(arg.getKind() == clang::TemplateArgument::ArgKind::Type) { + if(isalias(arg.getAsType())) { + return true; + } + } + } return false; } else if(auto DNT = type->getAs()) { return isalias(clang::QualType(DNT->getQualifier()->getAsType(), 0)); + } else if(auto DTST = type->getAs()) { + return isalias(clang::QualType(DTST->getQualifier()->getAsType(), 0)); } else if(auto LVRT = type->getAs()) { return isalias(LVRT->getPointeeType()); + } else if(auto TTPT = type->getAs()) { + return false; } else { - type.dump(); - std::terminate(); + return false; } } @@ -185,14 +249,32 @@ clang::QualType DependentNameResolver::dealias(clang::QualType type) { if(auto TAT = type->getAs()) { return dealias(TAT->getDecl()->getUnderlyingType()); - } else if(auto DNT = type->getAs()) { + } else if(auto DNT = type->getAs()) { + llvm::SmallVector args; + for(auto arg: DNT->template_arguments()) { + if(arg.getKind() == clang::TemplateArgument::ArgKind::Type) { + args.push_back(dealias(arg.getAsType())); + } else { + args.push_back(arg); + } + } + return context.getTemplateSpecializationType(DNT->getTemplateName(), args); + } + + else if(auto DNT = type->getAs()) { 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 if(auto DTST = type->getAs()) { + auto type = dealias(clang::QualType(DTST->getQualifier()->getAsType(), 0)); + auto NNS = clang::NestedNameSpecifier::Create(context, nullptr, false, type.getTypePtr()); + auto keyword = DTST->getKeyword(); + auto identifier = DTST->getIdentifier(); + return context.getDependentTemplateSpecializationType(keyword, NNS, identifier, DTST->template_arguments()); } else if(auto LVRT = type->getAs()) { return context.getLValueReferenceType(dealias(LVRT->getPointeeType())); } else { - std::terminate(); + return type; } } @@ -210,7 +292,10 @@ clang::QualType DependentNameResolver::substitute(clang::QualType type) { sema.pushCodeSynthesisContext(context); } + // type->dump(); auto result = sema.SubstType(dealias(type), list, {}, {}); + // result->dump(); + // llvm::outs() << "\n--------------------------------------------------\n"; frames.clear(); return result; diff --git a/tests/Resolver.cpp b/tests/Resolver.cpp index 837ab390..7e89cb8e 100644 --- a/tests/Resolver.cpp +++ b/tests/Resolver.cpp @@ -180,6 +180,42 @@ struct test { ASSERT_EQ(T->getDecl()->getName(), "X"); } +TEST(DependentNameResolver, alias_template_dependent_name) { + const char* code = R"( +template +struct type_list {}; + +template +struct A { + using type = T1; +}; + +template +struct B { + using base = A; + using type = type_list; +}; + +template +struct test { + using result = typename B::type; +}; +)"; + Visitor visitor(code); + clang::QualType result = visitor.test(); + + auto TST = result->getAs(); + 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(args[0].getAsType()); + ASSERT_TRUE(T); + ASSERT_EQ(T->getDecl()->getName(), "X"); +} + TEST(DependentNameResolver, template_alias_dependent_name) { const char* code = R"( template @@ -310,6 +346,59 @@ template struct test { using result = typename B>::type; }; +)"; + + Visitor visitor(code); + clang::QualType result = visitor.test(); + + // FIXME: resugar the result +} + +TEST(DependentNameResolver, dependent_base_name) { + const char* code = R"( +template +struct type_list {}; + +template +struct A { + using type = type_list; +}; + +template +struct B : A {}; + +template +struct test { + using result = typename B::type; +}; +)"; + + Visitor visitor(code); + auto result = visitor.test(); + + auto TST = result->getAs(); + 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(args[0].getAsType()); + ASSERT_TRUE(T); + ASSERT_EQ(T->getDecl()->getName(), "X"); +} + +TEST(DependentNameResolver, std_vector) { + const char* code = R"( +#include + +template +struct A {}; + +template +struct test { + using result = typename std::vector>::reference; +}; )"; Visitor visitor(code); @@ -317,20 +406,5 @@ struct test { result->dump(); } -// TEST(DependentNameResolver, std_vector) { -// const char* code = R"( -// #include -// -// template -// struct test { -// using result = typename std::vector>::reference; -// }; -//)"; -// -// Visitor visitor(code); -// clang::QualType result = visitor.test(); -// result->dump(); -// } - } // namespace