From 605d1f8042cf25ddaf92c2000eaf813197207657 Mon Sep 17 00:00:00 2001 From: ykiko Date: Wed, 4 Sep 2024 23:22:14 +0800 Subject: [PATCH] update Resolver. --- .vscode/launch.json | 23 +--- CMakeLists.txt | 11 +- include/AST/Resolver.h | 301 ++++++++++++++++++++++++++++------------- src/AST/Directive.cpp | 6 +- tests/test.cpp | 81 +++++------ 5 files changed, 260 insertions(+), 162 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d121d769..5d947f75 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,32 +4,19 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - //{ - // "type": "lldb", - // "request": "launch", - // "name": "Launch", - // "program": "${workspaceFolder}/build/clice_test", - // "args": [], - // "cwd": "${workspaceFolder}" - //}, { "type": "lldb", "request": "launch", "name": "ASTVisitor", "program": "${workspaceFolder}/build/bin/clice", - "args": [ - "/home/ykiko/C++/clice/test.cpp", - ], "cwd": "${workspaceFolder}" }, - ], - "compounds": [ { - "name": "Select and Launch", - "configurations": [ - "ASTVisitor", - "Preprocessor" - ] + "type": "lldb", + "request": "launch", + "name": "DependentNameResolver", + "program": "${workspaceFolder}/build/bin/test", + "cwd": "${workspaceFolder}" } ] } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index cba5bd89..b0a8dcb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(CLICE) set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -w") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -w -fno-rtti -O0") set(LLVM_INSTALL_PATH "${CMAKE_SOURCE_DIR}/deps/llvm/build-install") @@ -59,10 +59,8 @@ add_executable(clice) target_clang(clice) -file(GLOB_RECURSE SRC_FILES "${CMAKE_SOURCE_DIR}/src/*.cpp") -target_sources(clice PRIVATE ${SRC_FILES}) - -target_compile_options(clice PRIVATE -fno-rtti -O0) +file(GLOB_RECURSE SRC_FILES "${CMAKE_SOURCE_DIR}/src/*/*.cpp") +target_sources(clice PRIVATE ${SRC_FILES} "${CMAKE_SOURCE_DIR}/src/main.cpp") target_include_directories(clice PRIVATE ${CMAKE_SOURCE_DIR}/deps/libuv/include @@ -75,5 +73,6 @@ target_link_libraries(clice PRIVATE uv spdlog::spdlog) if(CLICE_ENABLE_TEST) add_executable(test) target_clang(test) - target_sources(test PRIVATE ${CMAKE_SOURCE_DIR}/tests/test.cpp) + file(GLOB_RECURSE AST_SRC_FILES "${CMAKE_SOURCE_DIR}/src/AST/*.cpp") + target_sources(test PRIVATE ${AST_SRC_FILES} "${CMAKE_SOURCE_DIR}/tests/test.cpp") endif() diff --git a/include/AST/Resolver.h b/include/AST/Resolver.h index c8461327..f7d702a6 100644 --- a/include/AST/Resolver.h +++ b/include/AST/Resolver.h @@ -2,6 +2,8 @@ #include "ParsedAST.h" #include +#include +#include namespace clice { @@ -14,129 +16,234 @@ class DependentNameResolver { public: DependentNameResolver(clang::Sema& sema, clang::ASTContext& context) : sema(sema), context(context) {} - clang::QualType simplify(clang::DependentNameType type); - - clang::QualType simplify(clang::DependentTemplateSpecializationType type); - - clang::ExprResult simplify(clang::DependentScopeDeclRefExpr* expr); - - clang::ExprResult simplify(clang::CXXDependentScopeMemberExpr* expr); - - clang::ExprResult simplify(clang::UnresolvedLookupExpr* expr); - - clang::DeclResult simplify(clang::UnresolvedUsingValueDecl* decl); - - clang::DeclResult simplify(clang::UnresolvedUsingTypenameDecl* decl); - - clang::ExprResult simplify(clang::CXXUnresolvedConstructExpr* expr); - -private: - clang::Type* lookup(const clang::CXXRecordDecl* CRD, const clang::IdentifierInfo* II) { - auto reuslt = CRD->lookup(II); - - // FIXME: currently, we assume there are no member template specialization - // that is the size of the partial specialization is 1, - for(auto member: reuslt) { - if(auto type = simplify(member)) { - return type; + std::vector resolve(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()); + continue; + } + } } + result.push_back(arg); } - - for(auto base: CRD->bases()) { - if(auto type = simplify(base.getType())) { - return type; - } - } - - return nullptr; + return result; } - void simplify(clang::NestedNameSpecifier* NNS, clang::IdentifierInfo* II) { + clang::QualType dealias(clang::QualType type) { + if(auto DNT = type->getAs()) { + return clang::QualType(DNT, 0); + } else if(auto DTST = type->getAs()) { + auto NNS = clang::NestedNameSpecifier::Create( + context, + nullptr, + false, + dealias(clang::QualType(DTST->getQualifier()->getAsType(), 0)).getTypePtr()); + return context.getDependentTemplateSpecializationType(DTST->getKeyword(), + NNS, + DTST->getIdentifier(), + resolve(DTST->template_arguments())); + } else { + return type; + } + } + + clang::QualType resolve(clang::QualType type) { + while(true) { + // llvm::outs() << + // "--------------------------------------------------------------------\n"; + // type.dump(); + + clang::MultiLevelTemplateArgumentList list; + if(auto DNT = type->getAs()) { + type = resolve(resolve(DNT->getQualifier(), DNT->getIdentifier())); + for(auto begin = arguments.rbegin(), end = arguments.rend(); begin != end; ++begin) { + list.addOuterTemplateArguments((*begin)->first, (*begin)->second, true); + } + type = sema.SubstType(dealias(type), list, {}, {}); + arguments.clear(); + + } else if(auto DTST = type->getAs()) { + auto ND = resolve(DTST->getQualifier(), DTST->getIdentifier()); + if(auto TATD = llvm::dyn_cast(ND)) { + auto args = resolve(DTST->template_arguments()); + + clang::Sema::CodeSynthesisContext context; + context.Entity = TATD; + context.Kind = clang::Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation; + context.TemplateArgs = args.data(); + sema.pushCodeSynthesisContext(context); + + list.addOuterTemplateArguments(TATD, args, true); + for(auto begin = arguments.rbegin(), end = arguments.rend(); begin != end; ++begin) { + list.addOuterTemplateArguments((*begin)->first, (*begin)->second, true); + } + + // llvm::outs() << "before: + // ----------------------------------------------------------------\n"; + // TATD->getTemplatedDecl()->getUnderlyingType().dump(); + type = dealias(TATD->getTemplatedDecl()->getUnderlyingType()); + // llvm::outs() << "arguments: + // -------------------------------------------------------------\n"; + // list.dump(); + type = sema.SubstType(type, list, {}, {}); + // type.dump(); + arguments.clear(); + + } else { + ND->dump(); + std::terminate(); + } + // return resolve(DTST); + } else if(auto LRT = type->getAs()) { + type = context.getLValueReferenceType(resolve(LRT->getPointeeType())); + } else { + return type; + } + } + } + + clang::QualType resolve(clang::NamedDecl* ND) { + if(auto TD = llvm::dyn_cast(ND)) { + return TD->getUnderlyingType(); + } else if(auto TAD = llvm::dyn_cast(ND)) { + return TAD->getUnderlyingType(); + } else { + ND->dump(); + std::terminate(); + } + } + + clang::NamedDecl* resolve(const clang::NestedNameSpecifier* NNS, const clang::IdentifierInfo* II) { switch(NNS->getKind()) { - // when NNS is a type, e.g., `std::vector::` or `T::` - case clang::NestedNameSpecifier::TypeSpec: { - auto type = NNS->getAsType(); - - if(auto TST = type->getAs()) { - auto TD = TST->getTemplateName().getAsTemplateDecl(); - clang::QualType type; - if(auto CTD = llvm::dyn_cast(TD)) { - // `std::vector::` - } else if(auto TATD = llvm::dyn_cast(TD)) { - // template - // using Vector = std::vector::value_type; - // `Vector::` - } else if(auto TTPD = llvm::dyn_cast(TD)) { - // template typename List> - // using X = List::value_type; - // `List::` - } - - } else if(auto TTPT = type->getAs()) { - // `T::` - } - } - case clang::NestedNameSpecifier::TypeSpecWithTemplate: { - // TODO: + // prefix is an identifier, e.g. <...>::name:: + case clang::NestedNameSpecifier::SpecifierKind::Identifier: { + return lookup(resolve(resolve(NNS->getPrefix(), NNS->getAsIdentifier())), II); } - // when NNS is still a dependent name, e.g., `std::vector::value_type::` - case clang::NestedNameSpecifier::Identifier: { - // TODO: - { - auto prefix = NNS->getPrefix(); - auto name = NNS->getAsIdentifier(); - } + // prefix is a type, e.g. <...>::typename name:: + case clang::NestedNameSpecifier::SpecifierKind::TypeSpec: + case clang::NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: { + return lookup(clang::QualType(NNS->getAsType(), 0), II); + } + + default: { + NNS->dump(); + std::terminate(); } } } - clang::Type* simplify(clang::QualType); + clang::NamedDecl* lookup(clang::QualType Type, const clang::IdentifierInfo* Name) { + clang::NamedDecl* TemplateDecl; + clang::ArrayRef arguments; - clang::Type* simplify(const clang::NamedDecl* ND) {} + // llvm::outs() << "--------------------------------------------------------------------\n"; - clang::Type* simplify(const clang::TemplateSpecializationType* TST, const clang::IdentifierInfo* II) { - auto TD = TST->getTemplateName().getAsTemplateDecl(); - auto arguments = TST->template_arguments(); + if(auto TTPT = Type->getAs()) { + Type->dump(); + std::terminate(); + } else if(auto TST = Type->getAs()) { + auto TemplateName = TST->getTemplateName(); + TemplateDecl = TemplateName.getAsTemplateDecl(); + arguments = TST->template_arguments(); + } else if(auto DTST = Type->getAs()) { + TemplateDecl = resolve(DTST->getQualifier(), DTST->getIdentifier()); + arguments = DTST->template_arguments(); + } else if(auto RT = Type->getAs()) { + return RT->getDecl()->lookup(Name).front(); + } else { + Type->dump(); + std::terminate(); + } - if(auto CTD = llvm::dyn_cast(TD)) { - // `std::vector::` + clang::NamedDecl* result; + clang::Sema::CodeSynthesisContext context; - // iterate all partial specializations - llvm::SmallVector partials; - CTD->getPartialSpecializations(partials); + if(auto CTD = llvm::dyn_cast(TemplateDecl)) { + // always we check main template first + result = CTD->getTemplatedDecl()->lookup(Name).front(); + if(result) { + this->arguments.push_back(new std::pair>{ + TemplateDecl, + resolve(arguments), + }); + context.Entity = TemplateDecl; + context.Kind = clang::Sema::CodeSynthesisContext::TemplateInstantiation; + context.TemplateArgs = this->arguments.back()->second.data(); + sema.pushCodeSynthesisContext(context); + } else { + llvm::SmallVector paritals; + CTD->getPartialSpecializations(paritals); - clang::sema::TemplateDeductionInfo Info(CTD->getLocation()); - for(auto partial: partials) { - if(auto error = sema.DeduceTemplateArguments(partial, arguments, Info); - error == clang::TemplateDeductionResult::Success) { - if(auto result = lookup(partial, II)) { - return result; + clang::sema::TemplateDeductionInfo info(CTD->getLocation()); + for(auto partial: paritals) { + auto deduction = sema.DeduceTemplateArguments(partial, arguments, info); + if(deduction == clang::TemplateDeductionResult::Success) { + auto decl = partial->lookup(Name).front(); + if(decl) { + result = decl; + + // TODO: fix resugar + // std::vector arguments; + auto arguments = info.takeSugared(); + for(auto& arg: arguments->asArray()) { + arg.dump(); + // if(arg.getKind() == clang::TemplateArgument::ArgKind::Type) { + // auto type = arg.getAsType(); + // type->dump(); + // if(type.isCanonical()) { + // auto TemplateDecl = + // llvm::dyn_cast(this->arguments.back()->first); + // auto params = TemplateDecl->getTemplateParameters(); + // auto TTPT = type->getAs(); + // unsigned Depth = TTPT->getDepth(); + // unsigned Index = TTPT->getIndex(); + // auto* TTPD = dyn_cast(params->getParam(Index)); + // arguments.push_back( + // clang::TemplateArgument(this->context.getTypeDeclType(TTPD))); + // } else { + // arguments.push_back(arg); + // } + // } else { + // arguments.push_back(arg); + // } + } + + this->arguments.push_back(new std::pair>{ + partial, + arguments->asArray(), + }); + context.Entity = partial; + context.Kind = clang::Sema::CodeSynthesisContext::TemplateInstantiation; + context.TemplateArgs = this->arguments.back()->second.data(); + sema.pushCodeSynthesisContext(context); + break; + } } } } - // fallback to main template - if(auto result = lookup(CTD->getTemplatedDecl(), II)) { - return result; - } - - } else if(auto TATD = llvm::dyn_cast(TD)) { - // template - // using Vector = std::vector::value_type; - // `Vector::` - } else if(auto TTPD = llvm::dyn_cast(TD)) { - // template typename List> - // using X = List::value_type; - // `List::` + } else if(auto TATD = llvm::dyn_cast(TemplateDecl)) { + result = lookup(TATD->getTemplatedDecl()->getUnderlyingType(), Name); } + + if(result == nullptr) { + Type.dump(); + std::terminate(); + } + + return result; } private: clang::Sema& sema; clang::ASTContext& context; - std::stack templateStack; - std::stack> argumentsStack; + std::vector>*> arguments; }; } // namespace clice diff --git a/src/AST/Directive.cpp b/src/AST/Directive.cpp index 7e65bb65..be97dd48 100644 --- a/src/AST/Directive.cpp +++ b/src/AST/Directive.cpp @@ -29,9 +29,9 @@ struct PPCallback : clang::PPCallbacks { namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; llvm::SmallVector RealPath; - fs::make_absolute(SearchPath + "/" + RelativePath, RealPath); - path::remove_dots(RealPath, /*remove_dot_dot=*/true); - llvm::outs() << RealPath << "\n"; + // fs::make_absolute(SearchPath + "/" + RelativePath, RealPath); + // path::remove_dots(RealPath, /*remove_dot_dot=*/true); + // llvm::outs() << RealPath << "\n"; } // virtual void diff --git a/tests/test.cpp b/tests/test.cpp index 4d40f163..785ff85a 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1,51 +1,56 @@ #include +using namespace clice; + +const char* code = R"( +#include + template -using void_t = void; +struct X {}; + +template typename List> +struct X> { + using type = std::vector; +}; template -struct replace_first_arg; - -template