Skip to content

Commit

Permalink
Fix @struct closes #426, and lay more groundwork for generative met…
Browse files Browse the repository at this point in the history
…afunctions

Fix `@struct` to generate a type that's actually usable as a struct, by providing a metafunction a way to disable all member function generation

Make member initialization diagnostics clearer and more actionable, with better source location attribution

Lay more groundwork for generative metafunctions like `enum` and `flag_enum` that replace the entire type's contents, including to move more semantic checks to `sema.h` where they belong and will run later
  • Loading branch information
hsutter committed Jun 17, 2023
1 parent 8345c2f commit 379ae03
Show file tree
Hide file tree
Showing 10 changed files with 530 additions and 208 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Microsoft (R) C/C++ Optimizing Compiler Version 19.35.32217.1 for x86
Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32534 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,6 @@ public: [[nodiscard]] auto operator<=>(person_in_family_tree const& that) const

class mystruct {
public: int val {0};
public: mystruct(mystruct const& that);

public: auto operator=(mystruct const& that) -> mystruct& ;
public: mystruct(mystruct&& that) noexcept;
public: auto operator=(mystruct&& that) noexcept -> mystruct& ;
public: explicit mystruct();

#line 19 "pure2-types-ordering-via-meta-functions.cpp2"
};

auto main() -> int;
Expand Down Expand Up @@ -123,18 +115,6 @@ auto main() -> int;
}


mystruct::mystruct(mystruct const& that)
: val{ that.val }{}

auto mystruct::operator=(mystruct const& that) -> mystruct& {
val = that.val;
return *this;}
mystruct::mystruct(mystruct&& that) noexcept
: val{ std::move(that).val }{}
auto mystruct::operator=(mystruct&& that) noexcept -> mystruct& {
val = std::move(that).val;
return *this;}
mystruct::mystruct(){}
#line 21 "pure2-types-ordering-via-meta-functions.cpp2"
auto main() -> int{
my_integer a {1};
Expand Down
2 changes: 1 addition & 1 deletion regression-tests/test-results/version
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

cppfront compiler v0.2.1 Build 8613:1951
cppfront compiler v0.2.1 Build 8617:0816
Copyright(c) Herb Sutter All rights reserved

SPDX-License-Identifier: CC-BY-NC-ND-4.0
Expand Down
2 changes: 1 addition & 1 deletion source/build.info
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"8613:1951"
"8617:0816"
9 changes: 9 additions & 0 deletions source/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,15 @@ auto contains(
!= range.end();
}

auto contains(
std::string const& s,
auto const& value
)
-> bool
{
return s.find(value);

This comment has been minimized.

Copy link
@JohelEGP

JohelEGP Jun 17, 2023

Contributor

This needs != s.npos, like the contains member function (since C++23): https://eel.is/c++draft/string.view#lib:contains,basic_string_view.

}


//-----------------------------------------------------------------------
//
Expand Down
57 changes: 40 additions & 17 deletions source/cppfront.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4488,7 +4488,8 @@ class cppfront

// We'll use this common guidance in several errors,
// so write it once to keep the guidance consistent
auto error_msg = "an operator= body must start with a series of 'member = value;' initialization statements for each of the type-scope objects in the same order they are declared";
assert (n.parent_declaration && n.parent_declaration->name());
auto error_msg = "an operator= body must start with a series of 'member = value;' initialization statements for each of the type-scope objects in the same order they are declared, or the member must have a default initializer (in type '" + n.parent_declaration->name()->to_string(true) + "')";

// If this constructor's type has data members, handle their initialization
// - objects is the list of this type's declarations
Expand Down Expand Up @@ -4519,6 +4520,9 @@ class cppfront
{
assert (*statement);
stmt_pos = (*statement)->position();
if (stmt_pos.lineno < 0) {
stmt_pos = n.position();
}

auto lhs = std::string{};
auto rhs = std::string{};
Expand Down Expand Up @@ -4615,7 +4619,15 @@ class cppfront
{
errors.emplace_back(
stmt_pos,
"expected '" + object_name + " = ...' initialization statement - " + error_msg
"in operator=, expected '" + object_name + " = ...' initialization statement (because type scope object '" + object_name + "' does not have a default initializer)"
);
errors.emplace_back(
(*object)->position(),
"see declaration for '" + object_name + "' here"
);
errors.emplace_back(
stmt_pos,
error_msg
);
return;
}
Expand Down Expand Up @@ -4731,7 +4743,15 @@ class cppfront
{
errors.emplace_back(
(*object)->position(),
canonize_object_name(*object) + " was not initialized - " + error_msg
canonize_object_name(*object) + " was not initialized - did you forget to write a default initializer, or assign to it in the operator= body?"
);
errors.emplace_back(
(*object)->position(),
"see declaration for '" + canonize_object_name(*object) + "' here"
);
errors.emplace_back(
(*object)->position(),
error_msg
);
return;
}
Expand Down Expand Up @@ -4776,7 +4796,7 @@ class cppfront
// Declarations are handled in multiple passes,
// but we only want to do the sema checks once
if (
printer.get_phase() == printer.phase1_type_defs_func_decls
printer.get_phase() == printer.phase2_func_defs
&& !sema.check(n)
)
{
Expand Down Expand Up @@ -5191,21 +5211,24 @@ class cppfront
);
auto prefix = "\n" + std::string( indent, ' ' ) + "public: ";

// If no constructor was defined, there should only be
// a default constructor, so generate that
if (!found_constructor) {
printer.print_extra( prefix + id + "() = default;" );
}
if (n.member_function_generation)
{
// If no constructor was defined, there should only be
// a default constructor, so generate that
if (!found_constructor) {
printer.print_extra( prefix + id + "() = default;" );
}

// If no 'that' constructor was defined, disable copy/move
// so that Cpp1 doesn't silently generate it anyway
if (!found_that_constructor) {
printer.print_extra( prefix + id + "(" + id + " const&) = delete; /* No 'that' constructor, suppress copy */" );
printer.print_extra( prefix + "auto operator=(" + id + " const&) -> void = delete;" );
}
// If no 'that' constructor was defined, disable copy/move
// so that Cpp1 doesn't silently generate it anyway
if (!found_that_constructor) {
printer.print_extra( prefix + id + "(" + id + " const&) = delete; /* No 'that' constructor, suppress copy */" );
printer.print_extra( prefix + "auto operator=(" + id + " const&) -> void = delete;" );
}

if (!found_constructor || !found_that_constructor) {
printer.print_extra( "\n" );
if (!found_constructor || !found_that_constructor) {
printer.print_extra( "\n" );
}
}

printer.print_cpp2("};\n", compound_stmt->close_brace);
Expand Down
Loading

0 comments on commit 379ae03

Please sign in to comment.