Skip to content

[FIX] Add support for multi-level pointers #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ auto null_from_cpp1() -> int* { return nullptr; }

auto try_pointer_stuff() -> void;
#line 21 "mixed-lifetime-safety-and-null-contracts.cpp2"
auto call_my_framework(cpp2::in<const char *> msg) -> void;
auto call_my_framework(cpp2::in<const char*> msg) -> void;

//=== Cpp2 definitions ==========================================================

Expand All @@ -29,12 +29,12 @@ auto call_my_framework(cpp2::in<const char *> msg) -> void;
#line 14 "mixed-lifetime-safety-and-null-contracts.cpp2"

auto try_pointer_stuff() -> void{
int* p { null_from_cpp1() };
int * p { null_from_cpp1() };
*p = 42; // deliberate null dereference
// to show -n
}

auto call_my_framework(cpp2::in<const char *> msg) -> void {
auto call_my_framework(cpp2::in<const char*> msg) -> void {
std::cout
<< "sending error to my framework... ["
<< msg << "]\n"; }
2 changes: 1 addition & 1 deletion regression-tests/test-results/mixed-type-safety-1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ auto print(cpp2::in<std::string> msg, cpp2::in<bool> b) -> void
print( "1 is int? ", cpp2::is<int>(1));

auto c { cpp2_new<Circle>() }; // safe by construction
Shape* s { CPP2_UFCS_0(get, c) }; // safe by Lifetime
Shape * s { CPP2_UFCS_0(get, c) }; // safe by Lifetime
print("\ns* is Shape? ", cpp2::is<Shape>(*s));
print( "s* is Circle? ", cpp2::is<Circle>(*s));
print( "s* is Square? ", cpp2::is<Square>(*s));
Expand Down
27 changes: 17 additions & 10 deletions source/cppfront.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,10 @@ class cppfront
assert(n.identifier);
emit(*n.identifier);

for (auto _ : n.pointer_declarators) {
printer.print_cpp2("*", n.position());
}

if (!n.template_args.empty()) {
printer.print_cpp2("<", n.open_angle);
auto first = true;
Expand Down Expand Up @@ -1572,9 +1576,19 @@ class cppfront
auto& unqual = std::get<id_expression_node::unqualified>(id->id);
assert(unqual);
auto decl = sema.get_local_declaration_of(*unqual->identifier);
// TODO: Generalize this -- for now we detect only cases of the form "p: *int = ...;"
// We don't recognize pointer types that are deduced, multi-level, or from Cpp1
if (decl && decl->declaration && decl->declaration->pointer_declarator) {

bool is_pointer = false;
if (decl && decl->declaration) {
if (auto* obj_id_expr = std::get_if<declaration_node::object>(&decl->declaration->type)) {
if (auto* unqual = std::get_if<id_expression_node::unqualified>(&(*obj_id_expr)->id)){
is_pointer = !(*unqual)->pointer_declarators.empty();
}
}
}

// TODO: Generalize this -- for now we detect only multi-level cases of the form "p: ***int = ...;"
// We don't recognize pointer types that are deduced or from Cpp1
if (!unqual->pointer_declarators.empty() || is_pointer) {
if (n.ops.empty()) {
last_postfix_expr_was_pointer = true;
}
Expand Down Expand Up @@ -2155,10 +2169,6 @@ class cppfront
}
else {
emit( id_expr );
if (n.declaration->pointer_declarator) {
printer.print_cpp2(" ", n.declaration->pointer_declarator->position());
emit(*n.declaration->pointer_declarator);
}
}

// Then any suffix
Expand Down Expand Up @@ -2538,9 +2548,6 @@ class cppfront
}
printer.preempt_position(n.position());
emit( *type );
if (n.pointer_declarator) {
printer.print_cpp2("*", n.position());
}
// one pointer is enough for now, pointer-to-function fun can be later
if (!n.initializer) {
printer.print_cpp2( ">", n.position() );
Expand Down
28 changes: 13 additions & 15 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ struct unqualified_id_node
{
token const* const_qualifier = {}; // optional
token const* identifier = {}; // required
std::vector<token const*> pointer_declarators = {}; // optional

enum active { empty=0, expression, id_expression };

Expand Down Expand Up @@ -846,8 +847,6 @@ struct declaration_node
source_position pos;
std::unique_ptr<unqualified_id_node> identifier;

token const* pointer_declarator = nullptr;

enum active { function, object };
std::variant<
std::unique_ptr<function_type_node>,
Expand Down Expand Up @@ -1771,13 +1770,19 @@ class parser
{
// Handle the identifier
if (curr().type() != lexeme::Identifier &&
curr().type() != lexeme::Keyword) // 'const', and fundamental types that are keywords
curr().type() != lexeme::Keyword && // 'const', and fundamental types that are keywords
curr().type() != lexeme::Multiply ) // pointer declarators
{
return {};
}

auto n = std::make_unique<unqualified_id_node>();

while (curr().type() == lexeme::Multiply) {
n->pointer_declarators.push_back(&curr());
next();
}

if (curr().type() == lexeme::Keyword && curr() == "const") {
n->const_qualifier = &curr();
next();
Expand Down Expand Up @@ -2784,6 +2789,7 @@ class parser
auto unnamed_declaration(source_position pos, bool semicolon_required = true, bool captures_allowed = false) -> std::unique_ptr<declaration_node>
{
auto deduced_type = false;
auto pointer_declaration = false;

// The next token must be :
if (curr().type() != lexeme::Colon) {
Expand All @@ -2809,19 +2815,11 @@ class parser
n->type = std::move(t);
assert (n->type.index() == declaration_node::function);
}

// Or a pointer to a type, declaring a pointer object
else if (curr().type() == lexeme::Multiply) {
n->pointer_declarator = &curr();
next();
if (auto t = id_expression()) {
n->type = std::move(t);
assert (n->type.index() == declaration_node::object);
}
}

// Or just a type, declaring a non-pointer object
else if (auto t = id_expression()) {
if(auto* unqual = std::get_if<id_expression_node::unqualified>(&t->id)) {
pointer_declaration = !(*unqual)->pointer_declarators.empty();
}
n->type = std::move(t);
assert (n->type.index() == declaration_node::object);
}
Expand Down Expand Up @@ -2866,7 +2864,7 @@ class parser
n->equal_sign = curr().position();
next();

if (n->pointer_declarator) {
if (pointer_declaration) {
if (curr() == "nullptr" ||
isdigit(std::string_view(curr())[0]) ||
(curr() == "(" && peek(1) && *peek(1) == ")")
Expand Down