Skip to content

Commit 2654b2a

Browse files
authored
Initial support for sizeof, alignof and builtin_offsetof
Also, add a test to parse and check a subset of the wasm32 system headers. Signed-off-by: GitHub <[email protected]>
1 parent 51d216d commit 2654b2a

File tree

8 files changed

+137
-13
lines changed

8 files changed

+137
-13
lines changed

src/parser/cxx/ast.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,7 @@ class BuiltinOffsetofExpressionAST final : public ExpressionAST {
16401640
SourceLocation commaLoc;
16411641
ExpressionAST* expression = nullptr;
16421642
SourceLocation rparenLoc;
1643+
FieldSymbol* symbol = nullptr;
16431644

16441645
void accept(ASTVisitor* visitor) override { visitor->visit(this); }
16451646

@@ -3156,6 +3157,7 @@ class EnumSpecifierAST final : public SpecifierAST {
31563157
SourceLocation commaLoc;
31573158
List<EnumeratorAST*>* enumeratorList = nullptr;
31583159
SourceLocation rbraceLoc;
3160+
Symbol* symbol = nullptr;
31593161

31603162
void accept(ASTVisitor* visitor) override { visitor->visit(this); }
31613163

src/parser/cxx/const_expression_evaluator.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <cxx/types.h>
3333

3434
#include <format>
35+
#include <optional>
3536

3637
namespace cxx {
3738

@@ -214,6 +215,7 @@ auto ConstExpressionEvaluator::operator()(BuiltinBitCastExpressionAST* ast)
214215

215216
auto ConstExpressionEvaluator::operator()(BuiltinOffsetofExpressionAST* ast)
216217
-> std::optional<ConstValue> {
218+
if (ast->symbol) return ast->symbol->offset();
217219
return std::nullopt;
218220
}
219221

src/parser/cxx/memory_layout.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,13 @@ struct SizeOf {
242242
struct AlignmentOf {
243243
const MemoryLayout& memoryLayout;
244244

245+
auto operator()(const ClassType* type) const -> std::optional<std::size_t> {
246+
return type->symbol()->alignment();
247+
}
248+
245249
auto operator()(auto type) const -> std::optional<std::size_t> {
246250
// ### TODO
251+
if (!type) return std::nullopt;
247252
return memoryLayout.sizeOf(type);
248253
}
249254
};
@@ -297,11 +302,13 @@ void MemoryLayout::setSizeOfLongDouble(std::size_t sizeOfLongDouble) {
297302

298303
auto MemoryLayout::sizeOf(const Type* type) const
299304
-> std::optional<std::size_t> {
305+
if (!type) return std::nullopt;
300306
return visit(SizeOf{*this}, type);
301307
}
302308

303309
auto MemoryLayout::alignmentOf(const Type* type) const
304310
-> std::optional<std::size_t> {
311+
if (!type) return std::nullopt;
305312
return visit(AlignmentOf{*this}, type);
306313
}
307314

src/parser/cxx/name_lookup.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ class Lookup {
4949
[[nodiscard]] auto lookupType(NestedNameSpecifierAST* nestedNameSpecifier,
5050
const Identifier* id) const -> Symbol*;
5151

52-
private:
53-
[[nodiscard]] auto unqualifiedLookup(const Name* name) const -> Symbol*;
54-
5552
[[nodiscard]] auto qualifiedLookup(Scope* scope, const Name* name) const
5653
-> Symbol*;
5754

55+
private:
56+
[[nodiscard]] auto unqualifiedLookup(const Name* name) const -> Symbol*;
57+
5858
[[nodiscard]] auto qualifiedLookup(Symbol* scopedSymbol,
5959
const Name* name) const -> Symbol*;
6060

src/parser/cxx/parser.cc

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <cxx/const_expression_evaluator.h>
2626
#include <cxx/control.h>
2727
#include <cxx/literals.h>
28+
#include <cxx/memory_layout.h>
2829
#include <cxx/name_lookup.h>
2930
#include <cxx/name_printer.h>
3031
#include <cxx/names.h>
@@ -34,6 +35,7 @@
3435
#include <cxx/token.h>
3536
#include <cxx/type_printer.h>
3637
#include <cxx/types.h>
38+
#include <cxx/util.h>
3739
#include <cxx/views/symbol_chain.h>
3840

3941
#include <algorithm>
@@ -42,12 +44,6 @@
4244
#include <ranges>
4345
#include <unordered_set>
4446

45-
#include "cxx/cxx_fwd.h"
46-
#include "cxx/parser_fwd.h"
47-
#include "cxx/source_location.h"
48-
#include "cxx/symbols_fwd.h"
49-
#include "cxx/token_fwd.h"
50-
5147
namespace cxx {
5248

5349
namespace {
@@ -2652,6 +2648,17 @@ auto Parser::parse_builtin_offsetof_expression(ExpressionAST*& yyast,
26522648
parse_expression(ast->expression, ctx);
26532649
expect(TokenKind::T_RPAREN, ast->rparenLoc);
26542650

2651+
auto classType = type_cast<ClassType>(ast->typeId->type);
2652+
auto id = ast_cast<IdExpressionAST>(ast->expression);
2653+
2654+
if (classType && id && !id->nestedNameSpecifier) {
2655+
auto symbol = classType->symbol();
2656+
auto name = convertName(id->unqualifiedId);
2657+
auto member = Lookup{scope_}.qualifiedLookup(symbol->scope(), name);
2658+
auto field = symbol_cast<FieldSymbol>(member);
2659+
ast->symbol = field;
2660+
}
2661+
26552662
return true;
26562663
}
26572664

@@ -5631,7 +5638,10 @@ auto Parser::parse_defining_type_specifier(
56315638
if (parse_enum_specifier(yyast, specs)) {
56325639
lookahead.commit();
56335640

5641+
auto enumSpec = ast_cast<EnumSpecifierAST>(yyast);
5642+
56345643
specs.setTypeSpecifier(yyast);
5644+
specs.type = enumSpec->symbol->type();
56355645

56365646
return true;
56375647
}
@@ -5641,6 +5651,7 @@ auto Parser::parse_defining_type_specifier(
56415651
lookahead.commit();
56425652

56435653
specs.setTypeSpecifier(classSpecifier);
5654+
specs.type = classSpecifier->symbol->type();
56445655
yyast = classSpecifier;
56455656

56465657
return true;
@@ -6867,6 +6878,7 @@ auto Parser::parse_elaborated_type_specifier(
68676878
}
68686879

68696880
ast->symbol = classSymbol;
6881+
specs.type = classSymbol->type();
68706882

68716883
return true;
68726884
}
@@ -7971,6 +7983,7 @@ auto Parser::parse_enum_specifier(SpecifierAST*& yyast, DeclSpecs& specs)
79717983
ast->colonLoc = colonLoc;
79727984
ast->typeSpecifierList = typeSpecifierList;
79737985
ast->lbraceLoc = lbraceLoc;
7986+
ast->symbol = symbol;
79747987

79757988
if (!match(TokenKind::T_RBRACE, ast->rbraceLoc)) {
79767989
parse_enumerator_list(ast->enumeratorList, symbol->type());
@@ -9416,7 +9429,69 @@ auto Parser::parse_class_specifier(
94169429
expect(TokenKind::T_RBRACE, ast->rbraceLoc);
94179430
}
94189431

9419-
ast->symbol->setComplete(true);
9432+
if (!is_template(classSymbol)) {
9433+
int offset = 0;
9434+
int alignment = 1;
9435+
9436+
for (auto base : classSymbol->baseClasses()) {
9437+
auto baseClassSymbol = symbol_cast<ClassSymbol>(base->symbol());
9438+
9439+
if (!baseClassSymbol) {
9440+
if (config_.checkTypes) {
9441+
parse_error(base->location(), std::format("base class '{}' not found",
9442+
to_string(base->name())));
9443+
}
9444+
continue;
9445+
}
9446+
9447+
offset = align_to(offset, baseClassSymbol->alignment());
9448+
offset += baseClassSymbol->sizeInBytes();
9449+
alignment = std::max(alignment, baseClassSymbol->alignment());
9450+
}
9451+
9452+
for (auto member : classSymbol->scope()->symbols()) {
9453+
auto field = symbol_cast<FieldSymbol>(member);
9454+
if (!field) continue;
9455+
if (field->isStatic()) continue;
9456+
9457+
if (!field->alignment()) {
9458+
if (config_.checkTypes) {
9459+
parse_error(field->location(),
9460+
std::format("alignment of incomplete type '{}'",
9461+
to_string(field->type(), field->name())));
9462+
}
9463+
continue;
9464+
}
9465+
9466+
auto size = control_->memoryLayout()->sizeOf(field->type());
9467+
9468+
if (!size.has_value()) {
9469+
if (config_.checkTypes) {
9470+
parse_error(field->location(),
9471+
std::format("size of incomplete type '{}'",
9472+
to_string(field->type(), field->name())));
9473+
}
9474+
continue;
9475+
}
9476+
9477+
if (classSymbol->isUnion()) {
9478+
offset = std::max(offset, int(size.value()));
9479+
} else {
9480+
offset = align_to(offset, field->alignment());
9481+
field->setOffset(offset);
9482+
offset += size.value();
9483+
}
9484+
9485+
alignment = std::max(alignment, field->alignment());
9486+
}
9487+
9488+
offset = align_to(offset, alignment);
9489+
9490+
classSymbol->setAlignment(alignment);
9491+
classSymbol->setSizeInBytes(offset);
9492+
}
9493+
9494+
classSymbol->setComplete(true);
94209495

94219496
return true;
94229497
}
@@ -9798,6 +9873,9 @@ auto Parser::declareField(DeclaratorAST* declarator, const Decl& decl)
97989873
applySpecifiers(fieldSymbol, decl.specs);
97999874
fieldSymbol->setName(name);
98009875
fieldSymbol->setType(type);
9876+
if (auto alignment = control_->memoryLayout()->alignmentOf(type)) {
9877+
fieldSymbol->setAlignment(alignment.value());
9878+
}
98019879
scope_->addSymbol(fieldSymbol);
98029880
return fieldSymbol;
98039881
}

src/parser/cxx/symbols.cc

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,15 @@ auto ClassSymbol::isComplete() const -> bool { return isComplete_; }
178178

179179
void ClassSymbol::setComplete(bool isComplete) { isComplete_ = isComplete; }
180180

181-
auto ClassSymbol::sizeInBytes() const -> std::size_t { return sizeInBytes_; }
181+
auto ClassSymbol::sizeInBytes() const -> int { return sizeInBytes_; }
182+
183+
void ClassSymbol::setSizeInBytes(int sizeInBytes) {
184+
sizeInBytes_ = sizeInBytes;
185+
}
186+
187+
auto ClassSymbol::alignment() const -> int { return alignment_; }
188+
189+
void ClassSymbol::setAlignment(int alignment) { alignment_ = alignment; }
182190

183191
auto ClassSymbol::hasBaseClass(Symbol* symbol) const -> bool {
184192
std::unordered_set<const ClassSymbol*> processed;
@@ -493,6 +501,14 @@ auto FieldSymbol::isInline() const -> bool { return isInline_; }
493501

494502
void FieldSymbol::setInline(bool isInline) { isInline_ = isInline; }
495503

504+
auto FieldSymbol::offset() const -> int { return offset_; }
505+
506+
void FieldSymbol::setOffset(int offset) { offset_ = offset; }
507+
508+
auto FieldSymbol::alignment() const -> int { return alignment_; }
509+
510+
void FieldSymbol::setAlignment(int alignment) { alignment_ = alignment; }
511+
496512
ParameterSymbol::ParameterSymbol(Scope* enclosingScope)
497513
: Symbol(Kind, enclosingScope) {}
498514

src/parser/cxx/symbols.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,11 @@ class ClassSymbol final : public ScopedSymbol {
251251
[[nodiscard]] auto isComplete() const -> bool;
252252
void setComplete(bool isComplete);
253253

254-
[[nodiscard]] auto sizeInBytes() const -> std::size_t;
254+
[[nodiscard]] auto sizeInBytes() const -> int;
255+
void setSizeInBytes(int sizeInBytes);
256+
257+
[[nodiscard]] auto alignment() const -> int;
258+
void setAlignment(int alignment);
255259

256260
[[nodiscard]] auto hasBaseClass(Symbol* symbol) const -> bool;
257261

@@ -305,7 +309,8 @@ class ClassSymbol final : public ScopedSymbol {
305309
std::unique_ptr<TemplateInfo<ClassSymbol>> templateInfo_;
306310
ClassSymbol* templateClass_ = nullptr;
307311
std::size_t templateSepcializationIndex_ = 0;
308-
std::size_t sizeInBytes_ = 0;
312+
int sizeInBytes_ = 0;
313+
int alignment_ = 0;
309314
union {
310315
std::uint32_t flags_{};
311316
struct {
@@ -566,6 +571,12 @@ class FieldSymbol final : public Symbol {
566571
[[nodiscard]] auto isInline() const -> bool;
567572
void setInline(bool isInline);
568573

574+
[[nodiscard]] auto offset() const -> int;
575+
void setOffset(int offset);
576+
577+
[[nodiscard]] auto alignment() const -> int;
578+
void setAlignment(int alignment);
579+
569580
private:
570581
union {
571582
std::uint32_t flags_{};
@@ -577,6 +588,8 @@ class FieldSymbol final : public Symbol {
577588
std::uint32_t isInline_ : 1;
578589
};
579590
};
591+
int offset_{};
592+
int alignment_{};
580593
};
581594

582595
class ParameterSymbol final : public Symbol {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %cxx -toolchain wasm32 -ftemplates -fcheck %s
2+
3+
#include <cctype>
4+
#include <cstdio>
5+
#include <cstdlib>
6+
#include <cstring>

0 commit comments

Comments
 (0)