Skip to content

Commit d54a7fd

Browse files
committed
Build the class layout for the instantiated symbols
Signed-off-by: GitHub <[email protected]>
1 parent db33af7 commit d54a7fd

File tree

7 files changed

+184
-79
lines changed

7 files changed

+184
-79
lines changed

src/parser/cxx/name_lookup.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,40 @@ auto Lookup::qualifiedLookup(Symbol* scopedSymbol, const Name* name) const
5353
case SymbolKind::kNamespace:
5454
return qualifiedLookup(
5555
symbol_cast<NamespaceSymbol>(scopedSymbol)->scope(), name);
56+
5657
case SymbolKind::kClass:
5758
return qualifiedLookup(symbol_cast<ClassSymbol>(scopedSymbol)->scope(),
5859
name);
60+
5961
case SymbolKind::kEnum:
6062
return qualifiedLookup(symbol_cast<EnumSymbol>(scopedSymbol)->scope(),
6163
name);
64+
6265
case SymbolKind::kScopedEnum:
6366
return qualifiedLookup(
6467
symbol_cast<ScopedEnumSymbol>(scopedSymbol)->scope(), name);
68+
69+
case SymbolKind::kTypeAlias: {
70+
auto alias = symbol_cast<TypeAliasSymbol>(scopedSymbol);
71+
72+
if (auto classType = type_cast<ClassType>(alias->type())) {
73+
auto classSymbol = classType->symbol();
74+
return qualifiedLookup(classSymbol->scope(), name);
75+
}
76+
77+
if (auto enumType = type_cast<EnumType>(alias->type())) {
78+
auto enumSymbol = enumType->symbol();
79+
return qualifiedLookup(enumSymbol->scope(), name);
80+
}
81+
82+
if (auto scopedEnumType = type_cast<ScopedEnumType>(alias->type())) {
83+
auto scopedEnumSymbol = scopedEnumType->symbol();
84+
return qualifiedLookup(scopedEnumSymbol->scope(), name);
85+
}
86+
87+
return nullptr;
88+
}
89+
6590
default:
6691
return nullptr;
6792
} // switch

src/parser/cxx/parser.cc

Lines changed: 38 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5272,29 +5272,33 @@ auto Parser::parse_static_assert_declaration(DeclarationAST*& yyast) -> bool {
52725272

52735273
expect(TokenKind::T_SEMICOLON, ast->semicolonLoc);
52745274

5275-
bool value = false;
5275+
if (!inTemplate_) {
5276+
// not in a template context
52765277

5277-
if (constValue.has_value()) {
5278-
value = visit(to_bool, *constValue);
5279-
}
5278+
bool value = false;
52805279

5281-
if (!value && config_.staticAssert) {
5282-
SourceLocation loc = ast->firstSourceLocation();
5280+
if (constValue.has_value()) {
5281+
value = visit(to_bool, *constValue);
5282+
}
52835283

5284-
if (!ast->expression || !constValue.has_value()) {
5285-
parse_error(
5286-
loc,
5287-
"static assertion expression is not an integral constant expression");
5288-
} else {
5289-
if (ast->literalLoc)
5290-
loc = ast->literalLoc;
5291-
else if (ast->expression)
5292-
ast->expression->firstSourceLocation();
5284+
if (!value && config_.staticAssert) {
5285+
SourceLocation loc = ast->firstSourceLocation();
5286+
5287+
if (!ast->expression || !constValue.has_value()) {
5288+
parse_error(loc,
5289+
"static assertion expression is not an integral constant "
5290+
"expression");
5291+
} else {
5292+
if (ast->literalLoc)
5293+
loc = ast->literalLoc;
5294+
else if (ast->expression)
5295+
ast->expression->firstSourceLocation();
52935296

5294-
std::string message =
5295-
ast->literal ? ast->literal->value() : "static assert failed";
5297+
std::string message =
5298+
ast->literal ? ast->literal->value() : "static assert failed";
52965299

5297-
unit->error(loc, std::move(message));
5300+
unit->error(loc, std::move(message));
5301+
}
52985302
}
52995303
}
53005304

@@ -9431,66 +9435,11 @@ auto Parser::parse_class_specifier(
94319435
expect(TokenKind::T_RBRACE, ast->rbraceLoc);
94329436
}
94339437

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());
9438+
if (!inTemplate_) {
9439+
auto status = classSymbol->buildClassLayout(control_);
9440+
if (!status.has_value() && config_.checkTypes) {
9441+
parse_error(classSymbol->location(), status.error());
94889442
}
9489-
9490-
offset = align_to(offset, alignment);
9491-
9492-
classSymbol->setAlignment(alignment);
9493-
classSymbol->setSizeInBytes(offset);
94949443
}
94959444

94969445
classSymbol->setComplete(true);
@@ -11506,7 +11455,18 @@ void Parser::completePendingFunctionDefinitions() {
1150611455
}
1150711456
}
1150811457

11509-
void Parser::setScope(Scope* scope) { scope_ = scope; }
11458+
void Parser::setScope(Scope* scope) {
11459+
scope_ = scope;
11460+
11461+
inTemplate_ = false;
11462+
11463+
for (auto current = scope_; current; current = current->parent()) {
11464+
if (current->isTemplateParametersScope()) {
11465+
inTemplate_ = true;
11466+
break;
11467+
}
11468+
}
11469+
}
1151011470

1151111471
void Parser::setScope(ScopedSymbol* symbol) { setScope(symbol->scope()); }
1151211472

src/parser/cxx/parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ class Parser final {
911911
int templateParameterCount_ = 0;
912912
bool didAcceptCompletionToken_ = false;
913913
std::vector<FunctionDefinitionAST*> pendingFunctionDefinitions_;
914+
bool inTemplate_ = false;
914915

915916
template <typename T>
916917
class CachedAST {

src/parser/cxx/symbol_instantiation.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
// cxx
2424
#include <cxx/ast.h>
2525
#include <cxx/control.h>
26+
#include <cxx/memory_layout.h>
27+
#include <cxx/name_printer.h>
2628
#include <cxx/scope.h>
2729
#include <cxx/symbols.h>
2830
#include <cxx/translation_unit.h>
31+
#include <cxx/type_printer.h>
2932
#include <cxx/types.h>
3033

3134
#include <format>
@@ -185,9 +188,19 @@ auto SymbolInstantiation::findOrCreateReplacement(Symbol* symbol) -> Symbol* {
185188
replacements_[symbol] = newSymbol;
186189

187190
auto enclosingSymbol = replacement(symbol->enclosingSymbol());
191+
188192
newSymbol->setEnclosingScope(enclosingSymbol->scope());
193+
189194
if (symbol->type()) {
190195
newSymbol->setType(visit(VisitType{*this}, symbol->type()));
196+
197+
auto field = symbol_cast<FieldSymbol>(newSymbol);
198+
199+
if (field) {
200+
auto memoryLayout = control()->memoryLayout();
201+
auto alignment = memoryLayout->alignmentOf(newSymbol->type());
202+
field->setAlignment(alignment.value_or(0));
203+
}
191204
}
192205

193206
newSymbol->setName(symbol->name());
@@ -217,6 +230,10 @@ auto SymbolInstantiation::VisitSymbol::operator()(ClassSymbol* symbol)
217230
auto newSymbol = self.replacement(symbol);
218231
newSymbol->setFlags(symbol->flags());
219232

233+
if (symbol->isComplete()) {
234+
newSymbol->setComplete(true);
235+
}
236+
220237
if (symbol != self.current_) {
221238
newSymbol->setTemplateParameters(
222239
self.instantiate(symbol->templateParameters()));
@@ -226,14 +243,19 @@ auto SymbolInstantiation::VisitSymbol::operator()(ClassSymbol* symbol)
226243
auto newBaseClass = self.instantiate(baseClass);
227244
newSymbol->addBaseClass(newBaseClass);
228245
}
246+
229247
for (auto ctor : symbol->constructors()) {
230248
auto newCtor = self.instantiate(ctor);
231249
newSymbol->addConstructor(newCtor);
232250
}
251+
233252
for (auto member : views::members(symbol)) {
234253
auto newMember = self.instantiate(member);
235254
newSymbol->addMember(newMember);
236255
}
256+
257+
auto status = newSymbol->buildClassLayout(self.control());
258+
237259
return newSymbol;
238260
}
239261

src/parser/cxx/symbols.cc

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,15 @@
2222

2323
// cxx
2424
#include <cxx/ast.h>
25+
#include <cxx/control.h>
26+
#include <cxx/memory_layout.h>
27+
#include <cxx/name_printer.h>
2528
#include <cxx/scope.h>
29+
#include <cxx/type_printer.h>
2630
#include <cxx/types.h>
31+
#include <cxx/util.h>
32+
33+
#include <format>
2734

2835
namespace cxx {
2936

@@ -184,7 +191,7 @@ void ClassSymbol::setSizeInBytes(int sizeInBytes) {
184191
sizeInBytes_ = sizeInBytes;
185192
}
186193

187-
auto ClassSymbol::alignment() const -> int { return alignment_; }
194+
auto ClassSymbol::alignment() const -> int { return std::max(alignment_, 1); }
188195

189196
void ClassSymbol::setAlignment(int alignment) { alignment_ = alignment; }
190197

@@ -241,6 +248,64 @@ void ClassSymbol::addSpecialization(std::vector<TemplateArgument> arguments,
241248
templateInfo_->addSpecialization(std::move(arguments), specialization);
242249
}
243250

251+
auto ClassSymbol::buildClassLayout(Control* control)
252+
-> std::expected<bool, std::string> {
253+
int offset = 0;
254+
int alignment = 1;
255+
256+
auto memoryLayout = control->memoryLayout();
257+
258+
for (auto base : baseClasses()) {
259+
auto baseClassSymbol = symbol_cast<ClassSymbol>(base->symbol());
260+
261+
if (!baseClassSymbol) {
262+
return std::unexpected(
263+
std::format("base class '{}' not found", to_string(base->name())));
264+
}
265+
266+
offset = align_to(offset, baseClassSymbol->alignment());
267+
offset += baseClassSymbol->sizeInBytes();
268+
alignment = std::max(alignment, baseClassSymbol->alignment());
269+
}
270+
271+
for (auto member : scope()->symbols()) {
272+
auto field = symbol_cast<FieldSymbol>(member);
273+
if (!field) continue;
274+
if (field->isStatic()) continue;
275+
276+
if (!field->alignment()) {
277+
return std::unexpected(
278+
std::format("alignment of incomplete type '{}'",
279+
to_string(field->type(), field->name())));
280+
}
281+
282+
auto size = memoryLayout->sizeOf(field->type());
283+
284+
if (!size.has_value()) {
285+
return std::unexpected(
286+
std::format("size of incomplete type '{}'",
287+
to_string(field->type(), field->name())));
288+
}
289+
290+
if (isUnion()) {
291+
offset = std::max(offset, int(size.value()));
292+
} else {
293+
offset = align_to(offset, field->alignment());
294+
field->setOffset(offset);
295+
offset += size.value();
296+
}
297+
298+
alignment = std::max(alignment, field->alignment());
299+
}
300+
301+
offset = align_to(offset, alignment);
302+
303+
setAlignment(alignment);
304+
setSizeInBytes(offset);
305+
306+
return true;
307+
}
308+
244309
EnumSymbol::EnumSymbol(Scope* enclosingScope)
245310
: ScopedSymbol(Kind, enclosingScope) {}
246311

src/parser/cxx/symbols.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <cxx/symbols_fwd.h>
2828
#include <cxx/types_fwd.h>
2929

30+
#include <expected>
3031
#include <memory>
3132
#include <optional>
3233
#include <ranges>
@@ -298,6 +299,9 @@ class ClassSymbol final : public ScopedSymbol {
298299
return templateSepcializationIndex_;
299300
}
300301

302+
[[nodiscard]] auto buildClassLayout(Control* control)
303+
-> std::expected<bool, std::string>;
304+
301305
private:
302306
[[nodiscard]] auto hasBaseClass(Symbol* symbol,
303307
std::unordered_set<const ClassSymbol*>&) const
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %cxx -verify -ftemplates -fcheck %s
2+
3+
template <typename Key, typename Value>
4+
struct X {
5+
Key key;
6+
Value value;
7+
8+
void check() { static_assert(sizeof(*this)); }
9+
};
10+
11+
auto main() -> int {
12+
using U = X<char, int>;
13+
U u;
14+
15+
static_assert(sizeof(U) == 8);
16+
static_assert(sizeof(u) == 8);
17+
18+
static_assert(__builtin_offsetof(U, key) == 0);
19+
static_assert(__builtin_offsetof(U, value) == 4);
20+
21+
static_assert(sizeof(X<char, int>::key) == 1);
22+
static_assert(sizeof(X<char, int>::value) == 4);
23+
24+
static_assert(sizeof(U::key) == 1);
25+
static_assert(sizeof(U::value) == 4);
26+
27+
return 0;
28+
}

0 commit comments

Comments
 (0)