Skip to content

Commit

Permalink
fix: Parse of template member expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
robertoraggi committed Oct 3, 2023
1 parent bc4d32f commit 6e43b5b
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 37 deletions.
11 changes: 2 additions & 9 deletions packages/cxx-frontend/src/AST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3831,19 +3831,12 @@ export class MemberExpressionAST extends ExpressionAST {
return Token.from(cxx.getASTSlot(this.getHandle(), 1), this.parser);
}

/**
* Returns the location of the template token in this node
*/
getTemplateToken(): Token | undefined {
return Token.from(cxx.getASTSlot(this.getHandle(), 2), this.parser);
}

/**
* Returns the memberId of this node
*/
getMemberId(): IdExpressionAST | undefined {
return AST.from<IdExpressionAST>(
cxx.getASTSlot(this.getHandle(), 3),
cxx.getASTSlot(this.getHandle(), 2),
this.parser,
);
}
Expand All @@ -3852,7 +3845,7 @@ export class MemberExpressionAST extends ExpressionAST {
* Returns the accessOp attribute of this node
*/
getAccessOp(): TokenKind {
return cxx.getASTSlot(this.getHandle(), 4);
return cxx.getASTSlot(this.getHandle(), 3);
}
}

Expand Down
2 changes: 0 additions & 2 deletions src/parser/cxx/ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1103,14 +1103,12 @@ auto SubscriptExpressionAST::lastSourceLocation() -> SourceLocation {
auto MemberExpressionAST::firstSourceLocation() -> SourceLocation {
if (auto loc = cxx::firstSourceLocation(baseExpression)) return loc;
if (auto loc = cxx::firstSourceLocation(accessLoc)) return loc;
if (auto loc = cxx::firstSourceLocation(templateLoc)) return loc;
if (auto loc = cxx::firstSourceLocation(memberId)) return loc;
return {};
}

auto MemberExpressionAST::lastSourceLocation() -> SourceLocation {
if (auto loc = cxx::lastSourceLocation(memberId)) return loc;
if (auto loc = cxx::lastSourceLocation(templateLoc)) return loc;
if (auto loc = cxx::lastSourceLocation(accessLoc)) return loc;
if (auto loc = cxx::lastSourceLocation(baseExpression)) return loc;
return {};
Expand Down
1 change: 0 additions & 1 deletion src/parser/cxx/ast.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,6 @@ table MemberExpression /* ExpressionAST */ {
member_id: IdExpression;
access_op: uint32;
access_loc: SourceLocation;
template_loc: SourceLocation;
}

table PostIncrExpression /* ExpressionAST */ {
Expand Down
1 change: 0 additions & 1 deletion src/parser/cxx/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1451,7 +1451,6 @@ class MemberExpressionAST final : public ExpressionAST {

ExpressionAST* baseExpression = nullptr;
SourceLocation accessLoc;
SourceLocation templateLoc;
IdExpressionAST* memberId = nullptr;
TokenKind accessOp = TokenKind::T_EOF_SYMBOL;

Expand Down
2 changes: 0 additions & 2 deletions src/parser/cxx/ast_cloner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1444,8 +1444,6 @@ void ASTCloner::visit(MemberExpressionAST* ast) {

copy->accessLoc = ast->accessLoc;

copy->templateLoc = ast->templateLoc;

copy->memberId = accept(ast->memberId);

copy->accessOp = ast->accessOp;
Expand Down
3 changes: 0 additions & 3 deletions src/parser/cxx/ast_encoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2200,16 +2200,13 @@ void ASTEncoder::visit(MemberExpressionAST* ast) {

auto accessLoc = encodeSourceLocation(ast->accessLoc);

auto templateLoc = encodeSourceLocation(ast->templateLoc);

const auto memberId = accept(ast->memberId);

io::MemberExpression::Builder builder{fbb_};
builder.add_base_expression(baseExpression);
builder.add_base_expression_type(
static_cast<io::Expression>(baseExpressionType));
builder.add_access_loc(accessLoc.o);
builder.add_template_loc(templateLoc.o);
builder.add_member_id(memberId.o);
builder.add_access_op(static_cast<std::uint32_t>(ast->accessOp));

Expand Down
11 changes: 3 additions & 8 deletions src/parser/cxx/ast_slot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2140,24 +2140,19 @@ void ASTSlot::visit(MemberExpressionAST* ast) {
slotKind_ = ASTSlotKind::kToken;
slotNameIndex_ = SlotNameIndex{0};
break;
case 2: // templateLoc
value_ = ast->templateLoc.index();
slotKind_ = ASTSlotKind::kToken;
slotNameIndex_ = SlotNameIndex{190};
break;
case 3: // memberId
case 2: // memberId
value_ = reinterpret_cast<std::intptr_t>(ast->memberId);
slotKind_ = ASTSlotKind::kNode;
slotNameIndex_ = SlotNameIndex{129};
break;
case 4: // accessOp
case 3: // accessOp
value_ = intptr_t(ast->accessOp);
slotKind_ = ASTSlotKind::kIntAttribute;
slotNameIndex_ = SlotNameIndex{1};
break;
} // switch

slotCount_ = 5;
slotCount_ = 4;
}

void ASTSlot::visit(PostIncrExpressionAST* ast) {
Expand Down
17 changes: 9 additions & 8 deletions src/parser/cxx/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -653,8 +653,8 @@ auto Parser::parse_id_expression(IdExpressionAST*& yyast, bool inRequiresClause)
const auto isTemplateIntroduced = match(TokenKind::T_TEMPLATE, templateLoc);

UnqualifiedIdAST* unqualifiedId = nullptr;
if (!parse_unqualified_id(unqualifiedId,
/*isTemplateIntroduced*/ false, inRequiresClause))
if (!parse_unqualified_id(unqualifiedId, isTemplateIntroduced,
inRequiresClause))
return false;

lookahead.commit();
Expand All @@ -671,10 +671,11 @@ auto Parser::parse_id_expression(IdExpressionAST*& yyast, bool inRequiresClause)
}

auto Parser::parse_maybe_template_id(UnqualifiedIdAST*& yyast,
bool isTemplateIntroduced,
bool inRequiresClause) -> bool {
LookaheadParser lookahead{this};

auto template_id = parse_template_id(yyast);
auto template_id = parse_template_id(yyast, isTemplateIntroduced);

if (!template_id) return false;

Expand Down Expand Up @@ -722,7 +723,8 @@ auto Parser::parse_unqualified_id(UnqualifiedIdAST*& yyast,
bool inRequiresClause) -> bool {
const auto start = currentLocation();

if (parse_maybe_template_id(yyast, inRequiresClause)) return true;
if (parse_maybe_template_id(yyast, isTemplateIntroduced, inRequiresClause))
return true;

rewind(start);

Expand Down Expand Up @@ -1590,8 +1592,6 @@ auto Parser::parse_member_expression(ExpressionAST*& yyast) -> bool {

yyast = ast;

// match(TokenKind::T_TEMPLATE, ast->templateLoc);

if (!parse_id_expression(ast->memberId))
parse_error("expected a member name");

Expand Down Expand Up @@ -8349,7 +8349,8 @@ auto Parser::parse_function_operator_template_id(
return true;
}

auto Parser::parse_template_id(UnqualifiedIdAST*& yyast) -> bool {
auto Parser::parse_template_id(UnqualifiedIdAST*& yyast,
bool isTemplateIntroduced) -> bool {
if (LiteralOperatorTemplateIdAST* templateName = nullptr;
parse_literal_operator_template_id(templateName)) {
yyast = templateName;
Expand All @@ -8359,7 +8360,7 @@ auto Parser::parse_template_id(UnqualifiedIdAST*& yyast) -> bool {
yyast = templateName;
return true;
} else if (SimpleTemplateIdAST* templateName = nullptr;
parse_simple_template_id(templateName)) {
parse_simple_template_id(templateName, isTemplateIntroduced)) {
yyast = templateName;
return true;
} else {
Expand Down
7 changes: 4 additions & 3 deletions src/parser/cxx/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ class Parser final {
[[nodiscard]] auto parse_id_expression(IdExpressionAST*& yyast,
bool inRequiresClause = false) -> bool;
[[nodiscard]] auto parse_maybe_template_id(UnqualifiedIdAST*& yyast,
bool inRequiresClause = false)
-> bool;
bool isTemplateIntroduced,
bool inRequiresClause) -> bool;
[[nodiscard]] auto parse_unqualified_id(UnqualifiedIdAST*& yyast,
bool isTemplateIntroduced,
bool inRequiresClause) -> bool;
Expand Down Expand Up @@ -601,7 +601,8 @@ class Parser final {
LiteralOperatorTemplateIdAST*& yyast) -> bool;
[[nodiscard]] auto parse_function_operator_template_id(
OperatorFunctionTemplateIdAST*& yyast) -> bool;
[[nodiscard]] auto parse_template_id(UnqualifiedIdAST*& yyast) -> bool;
[[nodiscard]] auto parse_template_id(UnqualifiedIdAST*& yyast,
bool isTemplateIntroduced) -> bool;
[[nodiscard]] auto parse_template_argument_list(
List<TemplateArgumentAST*>*& yyast) -> bool;
[[nodiscard]] auto parse_template_argument(TemplateArgumentAST*& yyast)
Expand Down
114 changes: 114 additions & 0 deletions tests/unit_tests/ast/template_member_expression_01.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// RUN: %cxx -verify -ast-dump %s | %filecheck %s --match-full-lines

struct Allocator {
template <typename T>
auto Allocate(int) -> T * {
return nullptr;
}
};

auto copy(Allocator &A) -> void * { return A.template Allocate<char>(128); }
// clang-format off
// CHECK:translation-unit
// CHECK-NEXT: declaration-list
// CHECK-NEXT: simple-declaration
// CHECK-NEXT: decl-specifier-list
// CHECK-NEXT: class-specifier
// CHECK-NEXT: class-key: struct
// CHECK-NEXT: unqualified-id: name-id
// CHECK-NEXT: identifier: Allocator
// CHECK-NEXT: declaration-list
// CHECK-NEXT: template-declaration
// CHECK-NEXT: template-parameter-list
// CHECK-NEXT: typename-type-parameter
// CHECK-NEXT: identifier: T
// CHECK-NEXT: declaration: function-definition
// CHECK-NEXT: decl-specifier-list
// CHECK-NEXT: auto-type-specifier
// CHECK-NEXT: declarator: declarator
// CHECK-NEXT: core-declarator: id-declarator
// CHECK-NEXT: declarator-id: id-expression
// CHECK-NEXT: unqualified-id: name-id
// CHECK-NEXT: identifier: Allocate
// CHECK-NEXT: declarator-chunk-list
// CHECK-NEXT: function-declarator-chunk
// CHECK-NEXT: parameters-and-qualifiers: parameters-and-qualifiers
// CHECK-NEXT: parameter-declaration-clause: parameter-declaration-clause
// CHECK-NEXT: parameter-declaration-list
// CHECK-NEXT: parameter-declaration
// CHECK-NEXT: type-specifier-list
// CHECK-NEXT: integral-type-specifier
// CHECK-NEXT: specifier: int
// CHECK-NEXT: declarator: declarator
// CHECK-NEXT: trailing-return-type: trailing-return-type
// CHECK-NEXT: type-id: type-id
// CHECK-NEXT: type-specifier-list
// CHECK-NEXT: named-type-specifier
// CHECK-NEXT: unqualified-id: name-id
// CHECK-NEXT: identifier: T
// CHECK-NEXT: declarator: declarator
// CHECK-NEXT: ptr-op-list
// CHECK-NEXT: pointer-operator
// CHECK-NEXT: function-body: compound-statement-function-body
// CHECK-NEXT: statement: compound-statement
// CHECK-NEXT: statement-list
// CHECK-NEXT: return-statement
// CHECK-NEXT: expression: nullptr-literal-expression
// CHECK-NEXT: literal: nullptr
// CHECK-NEXT: function-definition
// CHECK-NEXT: decl-specifier-list
// CHECK-NEXT: auto-type-specifier
// CHECK-NEXT: declarator: declarator
// CHECK-NEXT: core-declarator: id-declarator
// CHECK-NEXT: declarator-id: id-expression
// CHECK-NEXT: unqualified-id: name-id
// CHECK-NEXT: identifier: copy
// CHECK-NEXT: declarator-chunk-list
// CHECK-NEXT: function-declarator-chunk
// CHECK-NEXT: parameters-and-qualifiers: parameters-and-qualifiers
// CHECK-NEXT: parameter-declaration-clause: parameter-declaration-clause
// CHECK-NEXT: parameter-declaration-list
// CHECK-NEXT: parameter-declaration
// CHECK-NEXT: type-specifier-list
// CHECK-NEXT: named-type-specifier
// CHECK-NEXT: unqualified-id: name-id
// CHECK-NEXT: identifier: Allocator
// CHECK-NEXT: declarator: declarator
// CHECK-NEXT: ptr-op-list
// CHECK-NEXT: reference-operator
// CHECK-NEXT: ref-op: &
// CHECK-NEXT: core-declarator: id-declarator
// CHECK-NEXT: declarator-id: id-expression
// CHECK-NEXT: unqualified-id: name-id
// CHECK-NEXT: identifier: A
// CHECK-NEXT: trailing-return-type: trailing-return-type
// CHECK-NEXT: type-id: type-id
// CHECK-NEXT: type-specifier-list
// CHECK-NEXT: void-type-specifier
// CHECK-NEXT: declarator: declarator
// CHECK-NEXT: ptr-op-list
// CHECK-NEXT: pointer-operator
// CHECK-NEXT: function-body: compound-statement-function-body
// CHECK-NEXT: statement: compound-statement
// CHECK-NEXT: statement-list
// CHECK-NEXT: return-statement
// CHECK-NEXT: expression: call-expression
// CHECK-NEXT: base-expression: member-expression
// CHECK-NEXT: access-op: .
// CHECK-NEXT: base-expression: id-expression
// CHECK-NEXT: unqualified-id: name-id
// CHECK-NEXT: identifier: A
// CHECK-NEXT: member-id: id-expression
// CHECK-NEXT: is-template-introduced: true
// CHECK-NEXT: unqualified-id: simple-template-id
// CHECK-NEXT: identifier: Allocate
// CHECK-NEXT: template-argument-list
// CHECK-NEXT: type-template-argument
// CHECK-NEXT: type-id: type-id
// CHECK-NEXT: type-specifier-list
// CHECK-NEXT: integral-type-specifier
// CHECK-NEXT: specifier: char
// CHECK-NEXT: declarator: declarator
// CHECK-NEXT: expression-list
// CHECK-NEXT: int-literal-expression
// CHECK-NEXT: literal: 128

0 comments on commit 6e43b5b

Please sign in to comment.