Skip to content

Commit db33af7

Browse files
committed
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 db33af7

File tree

8 files changed

+139
-13
lines changed

8 files changed

+139
-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: 87 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,19 @@ 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+
2662+
ast->type = control_->getSizeType();
2663+
26552664
return true;
26562665
}
26572666

@@ -5631,7 +5640,10 @@ auto Parser::parse_defining_type_specifier(
56315640
if (parse_enum_specifier(yyast, specs)) {
56325641
lookahead.commit();
56335642

5643+
auto enumSpec = ast_cast<EnumSpecifierAST>(yyast);
5644+
56345645
specs.setTypeSpecifier(yyast);
5646+
specs.type = enumSpec->symbol->type();
56355647

56365648
return true;
56375649
}
@@ -5641,6 +5653,7 @@ auto Parser::parse_defining_type_specifier(
56415653
lookahead.commit();
56425654

56435655
specs.setTypeSpecifier(classSpecifier);
5656+
specs.type = classSpecifier->symbol->type();
56445657
yyast = classSpecifier;
56455658

56465659
return true;
@@ -6867,6 +6880,7 @@ auto Parser::parse_elaborated_type_specifier(
68676880
}
68686881

68696882
ast->symbol = classSymbol;
6883+
specs.type = classSymbol->type();
68706884

68716885
return true;
68726886
}
@@ -7971,6 +7985,7 @@ auto Parser::parse_enum_specifier(SpecifierAST*& yyast, DeclSpecs& specs)
79717985
ast->colonLoc = colonLoc;
79727986
ast->typeSpecifierList = typeSpecifierList;
79737987
ast->lbraceLoc = lbraceLoc;
7988+
ast->symbol = symbol;
79747989

79757990
if (!match(TokenKind::T_RBRACE, ast->rbraceLoc)) {
79767991
parse_enumerator_list(ast->enumeratorList, symbol->type());
@@ -9416,7 +9431,69 @@ auto Parser::parse_class_specifier(
94169431
expect(TokenKind::T_RBRACE, ast->rbraceLoc);
94179432
}
94189433

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

94219498
return true;
94229499
}
@@ -9798,6 +9875,9 @@ auto Parser::declareField(DeclaratorAST* declarator, const Decl& decl)
97989875
applySpecifiers(fieldSymbol, decl.specs);
97999876
fieldSymbol->setName(name);
98009877
fieldSymbol->setType(type);
9878+
if (auto alignment = control_->memoryLayout()->alignmentOf(type)) {
9879+
fieldSymbol->setAlignment(alignment.value());
9880+
}
98019881
scope_->addSymbol(fieldSymbol);
98029882
return fieldSymbol;
98039883
}

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)