Skip to content

Commit 7f36cfc

Browse files
committed
Disallow nested structs and enums in C mode
Fixes #565 Signed-off-by: Roberto Raggi <[email protected]>
1 parent 18e16d5 commit 7f36cfc

File tree

6 files changed

+67
-9
lines changed

6 files changed

+67
-9
lines changed

src/parser/cxx/parser.cc

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5206,11 +5206,6 @@ auto Parser::parse_elaborated_enum_specifier(SpecifierAST*& yyast,
52065206
SourceLocation enumLoc;
52075207
if (!match(TokenKind::T_ENUM, enumLoc)) return false;
52085208

5209-
auto globalScopeGuard = Binder::ScopeGuard{&binder_};
5210-
if (is_parsing_c()) {
5211-
setScope(globalScope_);
5212-
}
5213-
52145209
NestedNameSpecifierAST* nestedNameSpecifier = nullptr;
52155210
parse_optional_nested_name_specifier(
52165211
nestedNameSpecifier, NestedNameSpecifierContext::kDeclarative);
@@ -5251,8 +5246,9 @@ auto Parser::parse_elaborated_type_specifier(SpecifierAST*& yyast,
52515246
if (!parse_class_key(classLoc)) return false;
52525247

52535248
auto globalScopeGuard = Binder::ScopeGuard{&binder_};
5249+
52545250
if (is_parsing_c()) {
5255-
setScope(globalScope_);
5251+
setScope(getCurrentNonClassScope());
52565252
}
52575253

52585254
List<AttributeSpecifierAST*>* attributes = nullptr;
@@ -6408,8 +6404,9 @@ auto Parser::parse_enum_specifier(SpecifierAST*& yyast, DeclSpecs& specs)
64086404
if (!parse_enum_key(enumLoc, classLoc)) return false;
64096405

64106406
auto globalScopeGuard = Binder::ScopeGuard{&binder_};
6407+
64116408
if (is_parsing_c()) {
6412-
setScope(globalScope_);
6409+
setScope(getCurrentNonClassScope());
64136410
}
64146411

64156412
List<AttributeSpecifierAST*>* attributes = nullptr;
@@ -7700,8 +7697,9 @@ auto Parser::parse_class_specifier(ClassSpecifierAST*& yyast, DeclSpecs& specs)
77007697
if (!parse_class_key(classLoc)) return false;
77017698

77027699
auto globalScopeGuard = Binder::ScopeGuard{&binder_};
7700+
77037701
if (is_parsing_c()) {
7704-
setScope(globalScope_);
7702+
setScope(getCurrentNonClassScope());
77057703
}
77067704

77077705
List<AttributeSpecifierAST*>* attributeList = nullptr;
@@ -9634,6 +9632,15 @@ void Parser::completePendingFunctionDefinitions() {
96349632
}
96359633
}
96369634

9635+
auto Parser::getCurrentNonClassScope() const -> Scope* {
9636+
for (auto current = scope(); current; current = current->parent()) {
9637+
if (current->isClassOrNamespaceScope()) continue;
9638+
return current;
9639+
}
9640+
9641+
return globalScope_;
9642+
}
9643+
96379644
auto Parser::scope() const -> Scope* { return binder_.scope(); }
96389645

96399646
void Parser::setScope(Scope* scope) { binder_.setScope(scope); }

src/parser/cxx/parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,8 @@ class Parser final {
780780
void completePendingFunctionDefinitions();
781781
void completeFunctionDefinition(FunctionDefinitionAST* ast);
782782

783+
[[nodiscard]] auto getCurrentNonClassScope() const -> Scope*;
784+
783785
[[nodiscard]] auto scope() const -> Scope*;
784786
void setScope(Scope* scope);
785787
void setScope(ScopedSymbol* symbol);

src/parser/cxx/scope.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ auto Scope::isTemplateParametersScope() const -> bool {
7474
return owner_ && owner_->isTemplateParameters();
7575
}
7676

77+
auto Scope::isFunctionParametersScope() const -> bool {
78+
return owner_ && owner_->isFunctionParameters();
79+
}
80+
7781
auto Scope::enclosingNamespaceScope() const -> Scope* {
7882
for (auto scope = parent_; scope; scope = scope->parent()) {
7983
if (scope->isNamespaceScope()) {

src/parser/cxx/scope.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Scope {
4646
[[nodiscard]] auto isBlockScope() const -> bool;
4747
[[nodiscard]] auto isEnumScope() const -> bool;
4848
[[nodiscard]] auto isTemplateParametersScope() const -> bool;
49+
[[nodiscard]] auto isFunctionParametersScope() const -> bool;
4950

5051
[[nodiscard]] auto enclosingNamespaceScope() const -> Scope*;
5152
[[nodiscard]] auto enclosingNonTemplateParametersScope() const -> Scope*;

src/parser/cxx/symbol_printer.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ struct DumpSymbols {
7070

7171
void operator()(NamespaceSymbol* symbol) {
7272
indent();
73-
out << std::format("namespace {}\n", to_string(symbol->name()));
73+
out << "namespace";
74+
if (symbol->name())
75+
out << std::format(" {}", to_string(symbol->name()));
76+
out << "\n";
7477
dumpScope(symbol->scope());
7578
}
7679

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %cxx -fcheck -dump-symbols -xc %s | %filecheck %s --match-full-lines
2+
3+
enum E {
4+
v,
5+
};
6+
7+
struct A {
8+
enum E e;
9+
int x;
10+
};
11+
12+
int main() {
13+
enum K {
14+
w,
15+
};
16+
17+
struct B {
18+
enum K k;
19+
enum E e;
20+
int y;
21+
};
22+
23+
struct M;
24+
}
25+
26+
// clang-format off
27+
// CHECK:namespace
28+
// CHECK-NEXT: enum E : int
29+
// CHECK-NEXT: enumerator E v
30+
// CHECK-NEXT: class A
31+
// CHECK-NEXT: field E e
32+
// CHECK-NEXT: field int x
33+
// CHECK-NEXT: function int main()
34+
// CHECK-NEXT: block
35+
// CHECK-NEXT: enum K : int
36+
// CHECK-NEXT: enumerator K w
37+
// CHECK-NEXT: class B
38+
// CHECK-NEXT: field K k
39+
// CHECK-NEXT: field E e
40+
// CHECK-NEXT: field int y
41+
// CHECK-NEXT: class M

0 commit comments

Comments
 (0)