Skip to content

Commit 96c4126

Browse files
committed
Disallow shadowing type scope names
Require that a type's implementation may not declare a name that is the same as (i.e., shadows) a type scope name - for example, a type scope function's local variable may not have the same as one of the type's members" Also allow all data members to use their declared default initializers - removed spurious error check
1 parent 482bac8 commit 96c4126

File tree

2 files changed

+86
-14
lines changed

2 files changed

+86
-14
lines changed

source/common.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ struct error
116116
: where{w}, msg{m}, internal{i}
117117
{ }
118118

119+
auto operator==(error const& that)
120+
-> bool
121+
{
122+
return
123+
where == that.where
124+
&& msg == that.msg
125+
;
126+
}
127+
119128
auto print(auto& o, std::string const& file) const
120129
-> void;
121130
};

source/cppfront.cpp

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ class cppfront
837837
};
838838
std::vector<function_info> current_function_info = { {} };
839839

840-
std::vector<declaration_node const*> current_declaration = { {} };
840+
std::vector<declaration_node const*> current_declarations = { {} };
841841

842842
// For lowering
843843
//
@@ -3245,11 +3245,11 @@ class cppfront
32453245
auto is_template_parameter_name = false;
32463246
if (
32473247
unqid
3248-
&& current_declaration.back()
3249-
&& current_declaration.back()->template_parameters
3248+
&& current_declarations.back()
3249+
&& current_declarations.back()->template_parameters
32503250
)
32513251
{
3252-
for (auto& tparam : current_declaration.back()->template_parameters->parameters)
3252+
for (auto& tparam : current_declarations.back()->template_parameters->parameters)
32533253
{
32543254
assert(tparam);
32553255
if (
@@ -3595,6 +3595,49 @@ class cppfront
35953595
}
35963596

35973597

3598+
//-----------------------------------------------------------------------
3599+
//
3600+
auto is_name_declared_in_current_type_scope(std::string_view s)
3601+
-> bool
3602+
{
3603+
if (!s.empty())
3604+
{
3605+
// Navigate to the enclosing type, if there is one...
3606+
for (auto parent = current_declarations.rbegin();
3607+
parent != current_declarations.rend();
3608+
++parent
3609+
)
3610+
{
3611+
if (
3612+
*parent
3613+
&& (*parent)->is_namespace()
3614+
)
3615+
{
3616+
break;
3617+
}
3618+
// ... and here it is, so...
3619+
if (
3620+
*parent
3621+
&& (*parent)->is_type()
3622+
)
3623+
{
3624+
// ... for each of its type scope decls...
3625+
for (auto const& decl : (*parent)->get_type_scope_declarations())
3626+
{
3627+
// ... check the name
3628+
if (decl->has_name(s))
3629+
{
3630+
return true;
3631+
}
3632+
}
3633+
break;
3634+
}
3635+
}
3636+
}
3637+
return false;
3638+
}
3639+
3640+
35983641
//-----------------------------------------------------------------------
35993642
//
36003643
auto emit(
@@ -3612,8 +3655,25 @@ class cppfront
36123655
;
36133656
auto is_in_type = n.parent_is_type();
36143657

3615-
current_declaration.push_back(&n);
3616-
auto guard = finally([&]{ current_declaration.pop_back(); });
3658+
// In a type scope function, disallow declaring a name that is
3659+
// the same as (i.e., shadows) a type scope name... this is a
3660+
// convenient place to check because we have the decls stack
3661+
if (
3662+
n.has_name() // this is a named declaration
3663+
&& !n.parent_is_type() // where the type isn't the direct parent
3664+
&& is_name_declared_in_current_type_scope(*n.name()) // and it shadows a name
3665+
&& !emit_constructor_as_assignment // (don't emit the error twice if this is the
3666+
) // second time we're 're handling this function)
3667+
{
3668+
errors.emplace_back(
3669+
n.position(),
3670+
"a type's implementation may not declare a name that is the same as (i.e., shadows) a type scope name - for example, a type scope function's local variable may not have the same as one of the type's members"
3671+
);
3672+
return;
3673+
}
3674+
3675+
current_declarations.push_back(&n);
3676+
auto guard = finally([&]{ current_declarations.pop_back(); });
36173677

36183678
// If this is a function that has multiple return values,
36193679
// first we need to emit the struct that contains the returns
@@ -3863,13 +3923,6 @@ class cppfront
38633923
{
38643924
assert((*object)->has_name());
38653925

3866-
// The ctor body can't have other statements until it
3867-
// has initialized all the data members
3868-
if (!(*statement)->is_expression()) {
3869-
errors.emplace_back( (*statement)->position(), error_msg );
3870-
return;
3871-
}
3872-
38733926
// Check that this is an assignment to *object
38743927
auto exprs = (*statement)->get_lhs_rhs_if_simple_assignment();
38753928

@@ -4236,8 +4289,18 @@ class cppfront
42364289
printer.abandon();
42374290
}
42384291

4292+
error const* prev = nullptr;
42394293
for (auto&& error : errors) {
4240-
error.print(std::cerr, strip_path(sourcefile));
4294+
// Suppress adjacent duplicates (e.g., can arise when we
4295+
// reenter operator= to emit it as an assignment operator)
4296+
if (
4297+
!prev
4298+
|| error != *prev
4299+
)
4300+
{
4301+
error.print(std::cerr, strip_path(sourcefile));
4302+
}
4303+
prev = &error;
42414304
}
42424305
if (violates_lifetime_safety) {
42434306
std::cerr << " ==> program violates lifetime safety guarantee - see previous errors\n";

0 commit comments

Comments
 (0)