diff --git a/src/parser/cxx/ast.h b/src/parser/cxx/ast.h index b30b5824..bbcfab82 100644 --- a/src/parser/cxx/ast.h +++ b/src/parser/cxx/ast.h @@ -2334,6 +2334,7 @@ class UsingDeclaratorAST final : public AST { NestedNameSpecifierAST* nestedNameSpecifier = nullptr; UnqualifiedIdAST* unqualifiedId = nullptr; SourceLocation ellipsisLoc; + UsingDeclarationSymbol* symbol = nullptr; bool isPack = false; void accept(ASTVisitor* visitor) override { visitor->visit(this); } diff --git a/src/parser/cxx/control.cc b/src/parser/cxx/control.cc index cde6698b..fea603b3 100644 --- a/src/parser/cxx/control.cc +++ b/src/parser/cxx/control.cc @@ -149,6 +149,7 @@ struct Control::Private { std::forward_list constraintTypeParameterSymbols; std::forward_list enumeratorSymbols; + std::forward_list usingDeclarationSymbols; std::forward_list typeTraitIdentifierInfos; @@ -624,6 +625,14 @@ auto Control::newEnumeratorSymbol(Scope* enclosingScope, SourceLocation loc) return symbol; } +auto Control::newUsingDeclarationSymbol(Scope* enclosingScope, + SourceLocation loc) + -> UsingDeclarationSymbol* { + auto symbol = &d->usingDeclarationSymbols.emplace_front(enclosingScope); + symbol->setLocation(loc); + return symbol; +} + auto Control::is_void(const Type* type) -> bool { return d->traits.is_void(type); } diff --git a/src/parser/cxx/control.h b/src/parser/cxx/control.h index f9049787..68be55ce 100644 --- a/src/parser/cxx/control.h +++ b/src/parser/cxx/control.h @@ -217,6 +217,9 @@ class Control { [[nodiscard]] auto newEnumeratorSymbol(Scope* enclosingScope, SourceLocation sourceLocation) -> EnumeratorSymbol*; + [[nodiscard]] auto newUsingDeclarationSymbol(Scope* enclosingScope, + SourceLocation sourceLocation) + -> UsingDeclarationSymbol*; [[nodiscard]] auto instantiate(TranslationUnit* unit, Symbol* primaryTemplate, const std::vector& arguments) diff --git a/src/parser/cxx/external_name_encoder.cc b/src/parser/cxx/external_name_encoder.cc index 65dbd688..bded7dca 100644 --- a/src/parser/cxx/external_name_encoder.cc +++ b/src/parser/cxx/external_name_encoder.cc @@ -177,6 +177,8 @@ struct ExternalNameEncoder::SymbolVisitor { void operator()(OverloadSetSymbol* symbol) {} void operator()(BaseClassSymbol* symbol) {} + + void operator()(UsingDeclarationSymbol* symbol) {} }; ExternalNameEncoder::ExternalNameEncoder() {} diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index cdd37a7e..e8270194 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -8277,8 +8277,6 @@ auto Parser::parse_using_declarator_list(List*& yyast) if (!parse_using_declarator(declarator)) return false; - declarator->isPack = match(TokenKind::T_DOT_DOT_DOT, declarator->ellipsisLoc); - *it = make_list_node(pool_, declarator); it = &(*it)->next; @@ -8287,9 +8285,6 @@ auto Parser::parse_using_declarator_list(List*& yyast) while (match(TokenKind::T_COMMA, commaLoc)) { if (UsingDeclaratorAST* declarator = nullptr; parse_using_declarator(declarator)) { - declarator->isPack = - match(TokenKind::T_DOT_DOT_DOT, declarator->ellipsisLoc); - *it = make_list_node(pool_, declarator); it = &(*it)->next; } else { @@ -8316,10 +8311,30 @@ auto Parser::parse_using_declarator(UsingDeclaratorAST*& yyast) -> bool { /*inRequiresClause*/ false)) return false; + auto name = convertName(unqualifiedId); + + SourceLocation ellipsisLoc; + auto isPack = match(TokenKind::T_DOT_DOT_DOT, ellipsisLoc); + yyast = make_node(pool_); yyast->typenameLoc = typenameLoc; yyast->nestedNameSpecifier = nestedNameSpecifier; yyast->unqualifiedId = unqualifiedId; + yyast->ellipsisLoc = ellipsisLoc; + yyast->isPack = isPack; + + auto target = Lookup{scope_}.lookup(nestedNameSpecifier, name); + + auto symbol = control_->newUsingDeclarationSymbol( + scope_, unqualifiedId->firstSourceLocation()); + + yyast->symbol = symbol; + + symbol->setName(name); + symbol->setDeclarator(yyast); + symbol->setTarget(target); + + std::invoke(DeclareSymbol{this, scope_}, symbol); return true; } diff --git a/src/parser/cxx/symbol_instantiation.cc b/src/parser/cxx/symbol_instantiation.cc index 7775c48d..18424343 100644 --- a/src/parser/cxx/symbol_instantiation.cc +++ b/src/parser/cxx/symbol_instantiation.cc @@ -73,6 +73,7 @@ struct SymbolInstantiation::VisitSymbol { -> Symbol*; [[nodiscard]] auto operator()(OverloadSetSymbol* symbol) -> Symbol*; [[nodiscard]] auto operator()(BaseClassSymbol* symbol) -> Symbol*; + [[nodiscard]] auto operator()(UsingDeclarationSymbol* symbol) -> Symbol*; }; struct SymbolInstantiation::VisitType { @@ -373,6 +374,13 @@ auto SymbolInstantiation::VisitSymbol::operator()(BaseClassSymbol* symbol) return newSymbol; } +auto SymbolInstantiation::VisitSymbol::operator()( + UsingDeclarationSymbol* symbol) -> Symbol* { + auto newSymbol = self.replacement(symbol); + newSymbol->setTarget(self.instantiate(symbol->target())); + return newSymbol; +} + // types auto SymbolInstantiation::VisitType::operator()(const BuiltinVaListType* type) diff --git a/src/parser/cxx/symbol_printer.cc b/src/parser/cxx/symbol_printer.cc index 212dbb91..992f1455 100644 --- a/src/parser/cxx/symbol_printer.cc +++ b/src/parser/cxx/symbol_printer.cc @@ -104,7 +104,6 @@ struct DumpSymbols { } else { out << std::format("{} {}\n", classKey, to_string(symbol->name())); } - indent(); if (!symbol->constructors().empty()) { ++depth; for (auto constructor : symbol->constructors()) { @@ -308,6 +307,18 @@ struct DumpSymbols { out << std::format("enumerator {}\n", to_string(symbol->type(), symbol->name())); } + + void operator()(UsingDeclarationSymbol* symbol) { + indent(); + + if (auto target = symbol->target()) { + out << std::format("using {}\n", + to_string(target->type(), target->name())); + } else { + // unresolved symbol + out << std::format("using unresolved {}\n", to_string(symbol->name())); + } + } }; } // namespace diff --git a/src/parser/cxx/symbols.cc b/src/parser/cxx/symbols.cc index cdcff127..1b66738b 100644 --- a/src/parser/cxx/symbols.cc +++ b/src/parser/cxx/symbols.cc @@ -614,4 +614,21 @@ void EnumeratorSymbol::setValue(const std::optional& value) { value_ = value; } +UsingDeclarationSymbol::UsingDeclarationSymbol(Scope* enclosingScope) + : Symbol(Kind, enclosingScope) {} + +UsingDeclarationSymbol::~UsingDeclarationSymbol() {} + +auto UsingDeclarationSymbol::target() const -> Symbol* { return target_; } + +void UsingDeclarationSymbol::setTarget(Symbol* symbol) { target_ = symbol; } + +auto UsingDeclarationSymbol::declarator() const -> UsingDeclaratorAST* { + return declarator_; +} + +void UsingDeclarationSymbol::setDeclarator(UsingDeclaratorAST* declarator) { + declarator_ = declarator; +} + } // namespace cxx diff --git a/src/parser/cxx/symbols.h b/src/parser/cxx/symbols.h index 6880382c..f9b60c46 100644 --- a/src/parser/cxx/symbols.h +++ b/src/parser/cxx/symbols.h @@ -697,6 +697,24 @@ class EnumeratorSymbol final : public Symbol { std::optional value_; }; +class UsingDeclarationSymbol final : public Symbol { + public: + constexpr static auto Kind = SymbolKind::kUsingDeclaration; + + explicit UsingDeclarationSymbol(Scope* enclosingScope); + ~UsingDeclarationSymbol() override; + + [[nodiscard]] auto declarator() const -> UsingDeclaratorAST*; + void setDeclarator(UsingDeclaratorAST* declarator); + + [[nodiscard]] auto target() const -> Symbol*; + void setTarget(Symbol* symbol); + + private: + Symbol* target_ = nullptr; + UsingDeclaratorAST* declarator_ = nullptr; +}; + template auto visit(Visitor&& visitor, Symbol* symbol) { #define PROCESS_SYMBOL(S) \ diff --git a/src/parser/cxx/symbols_fwd.h b/src/parser/cxx/symbols_fwd.h index 4864c544..7129fbf6 100644 --- a/src/parser/cxx/symbols_fwd.h +++ b/src/parser/cxx/symbols_fwd.h @@ -45,7 +45,8 @@ namespace cxx { V(TemplateTypeParameter) \ V(ConstraintTypeParameter) \ V(OverloadSet) \ - V(BaseClass) + V(BaseClass) \ + V(UsingDeclaration) class Symbol; class ScopedSymbol; diff --git a/tests/unit_tests/sema/using_decl_01.cc b/tests/unit_tests/sema/using_decl_01.cc new file mode 100644 index 00000000..ae46f04e --- /dev/null +++ b/tests/unit_tests/sema/using_decl_01.cc @@ -0,0 +1,44 @@ +// RUN: %cxx -fcheck -dump-symbols %s | %filecheck %s + +int printf(const char*, ...); + +namespace std { +using ::printf; +} + +struct Base { + operator bool() const; + + void f(); +}; + +struct Derived : Base { + using Base::operator bool; + using Base::f; +}; + +namespace std { +using nullptr_t = decltype(nullptr); +} // namespace std + +auto main() -> int { + using std::nullptr_t; + return 0; +} + +// clang-format off +// CHECK:namespace +// CHECK-NEXT: function int printf(const char*...) +// CHECK-NEXT: namespace std +// CHECK-NEXT: using int printf(const char*...) +// CHECK-NEXT: typealias decltype(nullptr) nullptr_t +// CHECK-NEXT: class Base +// CHECK-NEXT: function operator bool() const +// CHECK-NEXT: function void f() +// CHECK-NEXT: class Derived +// CHECK-NEXT: using operator bool() const +// CHECK-NEXT: using void f() +// CHECK-NEXT: function int main() +// CHECK-NEXT: block +// CHECK-NEXT: using decltype(nullptr) nullptr_t +