Skip to content

Commit 04cf7e9

Browse files
committed
Rework support for forward class declarations
Signed-off-by: Roberto Raggi <[email protected]>
1 parent 07c4c3b commit 04cf7e9

File tree

4 files changed

+208
-88
lines changed

4 files changed

+208
-88
lines changed

src/parser/cxx/parser.cc

Lines changed: 174 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -6658,43 +6658,69 @@ auto Parser::parse_elaborated_type_specifier_helper(
66586658
ast->classKey = unit->tokenKind(classLoc);
66596659
ast->isTemplateIntroduced = isTemplateIntroduced;
66606660

6661-
const auto loc = currentLocation();
6662-
6663-
if (lookat(TokenKind::T_IDENTIFIER, TokenKind::T_LESS)) {
6664-
if (SimpleTemplateIdAST* templateId = nullptr; parse_simple_template_id(
6665-
templateId, nestedNameSpecifier, isTemplateIntroduced)) {
6666-
ast->unqualifiedId = templateId;
6667-
} else {
6668-
parse_error(loc, "expected a template-id");
6669-
}
6670-
} else if (NameIdAST* nameId = nullptr; parse_name_id(nameId)) {
6671-
ast->unqualifiedId = nameId;
6661+
if (!parse_simple_template_or_name_id(ast->unqualifiedId,
6662+
ast->nestedNameSpecifier,
6663+
ast->isTemplateIntroduced)) {
6664+
parse_error("expected a name");
6665+
return false;
6666+
}
66726667

6673-
auto symbol = Lookup{scope_}(nestedNameSpecifier, nameId->identifier);
6668+
const auto loc = ast->unqualifiedId->firstSourceLocation();
66746669

6675-
if (ast->classKey == TokenKind::T_CLASS ||
6676-
ast->classKey == TokenKind::T_STRUCT ||
6677-
ast->classKey == TokenKind::T_UNION) {
6678-
for (auto symbol : SymbolChainView(symbol) | views::classes) {
6679-
ast->symbol = symbol;
6680-
specs.type = symbol->type();
6681-
break;
6682-
}
6683-
} else if (ast->classKey == TokenKind::T_ENUM) {
6684-
for (auto symbol :
6685-
SymbolChainView(symbol) | views::enum_or_scoped_enums) {
6686-
ast->symbol = symbol;
6687-
specs.type = symbol->type();
6688-
break;
6689-
}
6690-
}
6691-
} else {
6692-
parse_error(loc, "expected a name");
6670+
if (isClassKey(ast->classKey)) {
6671+
finish_elaborated_class_specifier(ast, templateDeclarations);
6672+
return true;
66936673
}
66946674

66956675
return true;
66966676
}
66976677

6678+
void Parser::finish_elaborated_class_specifier(
6679+
ElaboratedTypeSpecifierAST* elab,
6680+
const std::vector<TemplateDeclarationAST*>& templateDeclarations) {
6681+
auto className = getIdentifier(elab->unqualifiedId);
6682+
6683+
if (elab->nestedNameSpecifier) {
6684+
auto parent = getClassOrNamespace(elab->nestedNameSpecifier);
6685+
ClassSymbol* classSymbol = findClass(parent, className);
6686+
elab->symbol = classSymbol;
6687+
return;
6688+
}
6689+
6690+
const auto isForwardClassDeclaration = lookat(TokenKind::T_SEMICOLON);
6691+
6692+
auto declaringScope = currentDeclaringScope();
6693+
if (!declaringScope) {
6694+
cxx_runtime_error("no declaring scope");
6695+
}
6696+
6697+
auto parent = declaringScope->owner();
6698+
6699+
if (isForwardClassDeclaration && !parent->isClassOrNamespace()) {
6700+
parent = currentNamespace();
6701+
}
6702+
6703+
if (auto classSymbol = findClass(parent, className)) {
6704+
elab->symbol = classSymbol;
6705+
return;
6706+
}
6707+
6708+
const auto isUnion = elab->classKey == TokenKind::T_UNION;
6709+
6710+
// create a forward declaration
6711+
auto classSymbol = control_->newClassSymbol(
6712+
parent->scope(), elab->unqualifiedId->firstSourceLocation());
6713+
classSymbol->setName(className);
6714+
classSymbol->setIsUnion(isUnion);
6715+
6716+
auto templateParameters =
6717+
symbol_cast<TemplateParametersSymbol>(scope_->owner());
6718+
6719+
classSymbol->setTemplateParameters(templateParameters);
6720+
6721+
std::invoke(DeclareSymbol{this, parent->scope()}, classSymbol);
6722+
}
6723+
66986724
auto Parser::parse_elaborated_enum_specifier(ElaboratedTypeSpecifierAST*& yyast,
66996725
DeclSpecs& specs) -> bool {
67006726
SourceLocation enumLoc;
@@ -9207,87 +9233,67 @@ auto Parser::parse_class_head(ClassHead& classHead) -> bool {
92079233

92089234
parse_optional_attribute_specifier_seq(classHead.attributeList);
92099235

9210-
auto is_class_declaration = false;
9236+
bool isClassDeclaration = false;
9237+
bool isForwardClassDeclaration = false;
92119238

92129239
if (parse_class_head_name(classHead.nestedNameSpecifier, classHead.name)) {
92139240
if (parse_class_virt_specifier(classHead.finalLoc)) {
9214-
is_class_declaration = true;
9241+
isClassDeclaration = true;
92159242
}
92169243
}
92179244

9218-
if (LA().isOneOf(TokenKind::T_COLON, TokenKind::T_LBRACE)) {
9219-
is_class_declaration = true;
9245+
if (!isClassDeclaration) {
9246+
isClassDeclaration = LA().isOneOf(TokenKind::T_COLON, TokenKind::T_LBRACE);
9247+
}
9248+
9249+
if (!isClassDeclaration) {
9250+
return false;
92209251
}
92219252

9222-
auto is_template_declaration = !classHead.templateDeclarations.empty();
9253+
auto isTemplateDeclaration = !classHead.templateDeclarations.empty();
92239254

9224-
if (is_class_declaration && is_template_declaration &&
9225-
!classHead.nestedNameSpecifier) {
9255+
if (isTemplateDeclaration) {
92269256
mark_maybe_template_name(classHead.name);
92279257
}
92289258

9229-
if (classHead.nestedNameSpecifier) {
9230-
auto enclosingSymbol = classHead.nestedNameSpecifier->symbol;
9231-
if (!enclosingSymbol) {
9232-
if (config_.checkTypes) {
9233-
parse_error(classHead.nestedNameSpecifier->firstSourceLocation(),
9234-
"unresolved nested name specifier");
9235-
}
9236-
} else {
9237-
Scope* enclosingScope = nullptr;
9259+
auto templateId = ast_cast<SimpleTemplateIdAST>(classHead.name);
92389260

9239-
if (auto alias = symbol_cast<TypeAliasSymbol>(enclosingSymbol)) {
9240-
if (auto classTy = type_cast<ClassType>(alias->type())) {
9241-
enclosingScope = classTy->symbol()->scope();
9242-
}
9243-
} else if (auto enclosingClass =
9244-
symbol_cast<ClassSymbol>(enclosingSymbol)) {
9245-
enclosingScope = enclosingClass->scope();
9246-
} else if (auto enclosingNamespace =
9247-
symbol_cast<NamespaceSymbol>(enclosingSymbol)) {
9248-
enclosingScope = enclosingNamespace->scope();
9249-
}
9261+
const Identifier* identifier = getIdentifier(classHead.name);
92509262

9251-
if (enclosingScope) {
9252-
setScope(enclosingScope);
9253-
} else if (config_.checkTypes) {
9254-
parse_error(classHead.nestedNameSpecifier->firstSourceLocation(),
9255-
"unresolved nested name specifier");
9256-
}
9257-
}
9258-
}
9263+
SourceLocation location = currentLocation();
92599264

9260-
const Identifier* identifier = nullptr;
9261-
SourceLocation location;
9262-
bool isTemplateSpecialization = false;
9263-
if (const auto simpleName = ast_cast<NameIdAST>(classHead.name)) {
9264-
location = simpleName->identifierLoc;
9265-
identifier = simpleName->identifier;
9266-
} else if (const auto t = ast_cast<SimpleTemplateIdAST>(classHead.name)) {
9267-
location = t->firstSourceLocation();
9268-
isTemplateSpecialization = true;
9269-
identifier = t->identifier;
9270-
} else {
9271-
location = currentLocation();
9265+
if (classHead.name) {
9266+
location = classHead.name->firstSourceLocation();
92729267
}
92739268

92749269
ClassSymbol* classSymbol = nullptr;
92759270

92769271
if (identifier) {
9277-
if (!is_class_declaration && !lookat(TokenKind::T_SEMICOLON)) {
9278-
auto symbol = symbol_cast<ClassSymbol>(Lookup{scope_}(identifier));
9279-
classSymbol = symbol;
9280-
} else if (!isTemplateSpecialization) {
9281-
for (auto previousClass : scope_->find(identifier) | views::classes) {
9282-
if (previousClass->isComplete()) {
9283-
parse_error(classHead.name->firstSourceLocation(),
9284-
"class name already declared");
9285-
} else {
9286-
classSymbol = previousClass;
9272+
ScopedSymbol* parent = nullptr;
9273+
9274+
if (classHead.nestedNameSpecifier) {
9275+
if (auto ns = symbol_cast<NamespaceSymbol>(
9276+
classHead.nestedNameSpecifier->symbol)) {
9277+
parent = ns;
9278+
} else if (auto cls = symbol_cast<ClassSymbol>(
9279+
classHead.nestedNameSpecifier->symbol)) {
9280+
parent = cls;
9281+
} else {
9282+
if (config_.checkTypes) {
9283+
parse_error(classHead.nestedNameSpecifier->firstSourceLocation(),
9284+
"expected a namespace or class");
92879285
}
9288-
break;
92899286
}
92909287
}
9288+
9289+
if (!parent) {
9290+
parent = currentClassOrNamespace();
9291+
}
9292+
9293+
for (auto candidate : parent->scope()->find(identifier) | views::classes) {
9294+
classSymbol = candidate;
9295+
break;
9296+
}
92919297
}
92929298

92939299
if (!classSymbol) {
@@ -9296,6 +9302,8 @@ auto Parser::parse_class_head(ClassHead& classHead) -> bool {
92969302
classSymbol->setName(identifier);
92979303

92989304
std::invoke(DeclareSymbol{this, scope_}, classSymbol);
9305+
} else {
9306+
classSymbol->setLocation(location);
92999307
}
93009308

93019309
classHead.symbol = classSymbol;
@@ -11253,6 +11261,36 @@ void Parser::setScope(Scope* scope) { scope_ = scope; }
1125311261

1125411262
void Parser::setScope(ScopedSymbol* symbol) { setScope(symbol->scope()); }
1125511263

11264+
auto Parser::currentClassOrNamespace() const -> ScopedSymbol* {
11265+
for (auto scope = scope_; scope; scope = scope->parent()) {
11266+
if (auto ns = symbol_cast<NamespaceSymbol>(scope->owner())) {
11267+
return ns;
11268+
}
11269+
11270+
if (auto cls = symbol_cast<ClassSymbol>(scope->owner())) {
11271+
return cls;
11272+
}
11273+
}
11274+
11275+
return nullptr;
11276+
}
11277+
11278+
auto Parser::currentNamespace() const -> NamespaceSymbol* {
11279+
for (auto scope = scope_; scope; scope = scope->parent()) {
11280+
if (auto ns = symbol_cast<NamespaceSymbol>(scope->owner())) {
11281+
return ns;
11282+
}
11283+
}
11284+
11285+
return nullptr;
11286+
}
11287+
11288+
auto Parser::currentDeclaringScope() const -> Scope* {
11289+
auto scope = scope_;
11290+
while (scope && scope->isTransparent()) scope = scope->parent();
11291+
return scope;
11292+
}
11293+
1125611294
void Parser::completeFunctionDefinition(FunctionDefinitionAST* ast) {
1125711295
if (!ast->functionBody) return;
1125811296

@@ -11307,10 +11345,58 @@ void Parser::completeFunctionDefinition(FunctionDefinitionAST* ast) {
1130711345
rewind(saved);
1130811346
}
1130911347

11348+
auto Parser::isClassKey(TokenKind tk) const -> bool {
11349+
return tk == TokenKind::T_CLASS || tk == TokenKind::T_STRUCT ||
11350+
tk == TokenKind::T_UNION;
11351+
}
11352+
11353+
auto Parser::findClass(ScopedSymbol* parent, const Identifier* className) const
11354+
-> ClassSymbol* {
11355+
if (!parent) return nullptr;
11356+
11357+
return findClass(parent->scope(), className);
11358+
}
11359+
11360+
auto Parser::findClass(Scope* scope, const Identifier* className) const
11361+
-> ClassSymbol* {
11362+
if (!scope) return nullptr;
11363+
11364+
for (auto candidate : scope->find(className) | views::classes) {
11365+
return candidate;
11366+
}
11367+
11368+
return nullptr;
11369+
}
11370+
11371+
auto Parser::getClassOrNamespace(
11372+
NestedNameSpecifierAST* nestedNameSpecifier) const -> ScopedSymbol* {
11373+
if (auto ns = symbol_cast<NamespaceSymbol>(nestedNameSpecifier->symbol))
11374+
return ns;
11375+
11376+
if (auto classSymbol = symbol_cast<ClassSymbol>(nestedNameSpecifier->symbol))
11377+
return classSymbol;
11378+
11379+
return nullptr;
11380+
}
11381+
1131011382
auto Parser::convertName(UnqualifiedIdAST* id) -> const Name* {
1131111383
if (!id) return nullptr;
1131211384
return visit(ConvertToName{control_}, id);
1131311385
}
11386+
11387+
auto Parser::getIdentifier(UnqualifiedIdAST* unqualifiedId)
11388+
-> const Identifier* {
11389+
if (auto nameId = ast_cast<NameIdAST>(unqualifiedId)) {
11390+
return nameId->identifier;
11391+
}
11392+
11393+
if (auto templateId = ast_cast<SimpleTemplateIdAST>(unqualifiedId)) {
11394+
return templateId->identifier;
11395+
}
11396+
11397+
return nullptr;
11398+
}
11399+
1131411400
auto Parser::getFunction(Scope* scope, const Name* name, const Type* type)
1131511401
-> FunctionSymbol* {
1131611402
for (auto candidate : scope->find(name)) {

src/parser/cxx/parser.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,14 +458,22 @@ class Parser final {
458458
[[nodiscard]] auto parse_type_name(
459459
UnqualifiedIdAST*& yyast, NestedNameSpecifierAST* nestedNameSpecifier,
460460
bool isTemplateIntroduced) -> bool;
461+
461462
[[nodiscard]] auto parse_elaborated_type_specifier(
462463
SpecifierAST*& yyast, DeclSpecs& specs,
463464
const std::vector<TemplateDeclarationAST*>& templateDeclarations) -> bool;
465+
464466
[[nodiscard]] auto parse_elaborated_type_specifier_helper(
465467
ElaboratedTypeSpecifierAST*& yyast, DeclSpecs& specs,
466468
const std::vector<TemplateDeclarationAST*>& templateDeclarations) -> bool;
469+
467470
[[nodiscard]] auto parse_elaborated_enum_specifier(
468471
ElaboratedTypeSpecifierAST*& yyast, DeclSpecs& specs) -> bool;
472+
473+
void finish_elaborated_class_specifier(
474+
ElaboratedTypeSpecifierAST* elab,
475+
const std::vector<TemplateDeclarationAST*>& templateDeclarations);
476+
469477
[[nodiscard]] auto parse_decltype_specifier(DecltypeSpecifierAST*& yyast)
470478
-> bool;
471479
[[nodiscard]] auto parse_placeholder_type_specifier(SpecifierAST*& yyast,
@@ -785,9 +793,27 @@ class Parser final {
785793
void setScope(Scope* scope);
786794
void setScope(ScopedSymbol* symbol);
787795

796+
[[nodiscard]] auto currentNamespace() const -> NamespaceSymbol*;
797+
[[nodiscard]] auto currentClassOrNamespace() const -> ScopedSymbol*;
798+
[[nodiscard]] auto currentDeclaringScope() const -> Scope*;
799+
800+
[[nodiscard]] auto isClassKey(TokenKind tk) const -> bool;
801+
788802
// lookup
803+
[[nodiscard]] auto findClass(ScopedSymbol* scope,
804+
const Identifier* className) const
805+
-> ClassSymbol*;
806+
807+
[[nodiscard]] auto findClass(Scope* scope, const Identifier* className) const
808+
-> ClassSymbol*;
809+
810+
[[nodiscard]] auto getClassOrNamespace(
811+
NestedNameSpecifierAST* nestedNameSpecifier) const -> ScopedSymbol*;
812+
789813
[[nodiscard]] auto convertName(UnqualifiedIdAST* id) -> const Name*;
790814

815+
[[nodiscard]] auto getIdentifier(UnqualifiedIdAST* id) -> const Identifier*;
816+
791817
[[nodiscard]] auto getFunction(Scope* scope, const Name* name,
792818
const Type* type) -> FunctionSymbol*;
793819

src/parser/cxx/scope.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ Scope::Scope(Scope* parent) : parent_(parent) {}
7676

7777
Scope::~Scope() {}
7878

79+
auto Scope::isTransparent() const -> bool {
80+
if (!owner_) return true;
81+
if (owner_->isTemplateParameters()) return true;
82+
if (owner_->isFunctionParameters()) return true;
83+
return false;
84+
}
85+
7986
auto Scope::isEnumScope() const -> bool {
8087
return owner_ && (owner_->isEnum() || owner_->isScopedEnum());
8188
}

0 commit comments

Comments
 (0)