Skip to content
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

Reject Metadata on Nested-Module-Definitions #3768

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

InsertCreativityHere
Copy link
Member

@InsertCreativityHere InsertCreativityHere commented Mar 24, 2025

This PR:

  1. Adds bool usesNestedSyntax to Module, which stores whether a module used nested-module syntax.
  2. Changes the MetadataValidator to reject all metadata that is applied to nested-module-definitions.
  3. Adds a getStatus method to Unit which returns an exit code based on whether any errors have been emitted.

Up until now, libSlice only emitted errors during parsing. So the slice2xxx compilers only checked for errors from parsing. Now that we emit an error during the validation phase, I updated all the slice2xxx compilers to also check for errors at the end of everything: parsing, validation, and code-gen.

Comment on lines 224 to +225

status |= p->getStatus();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After we've finished parsing, validation, and code-gen, we want to check if any errors were reported.
We use |= because we don't want to overwrite an EXIT_FAILURE with an EXIT_SUCCESS.

We also don't want to return because we're looping over a list of files to compile. One of them failing shouldn't stop compilation of all the others.

@@ -135,6 +135,11 @@ IceRuby_loadSlice(int argc, VALUE* argv, VALUE /*self*/)
//
out << "# encoding: utf-8\n";
generate(u, all, includePaths, out);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from the lines above:

if (!icecpp->close() || parseStatus == EXIT_FAILURE)
{
    u->destroy();
    throw RubyException(rb_eArgError, "Slice parsing failed for `%s'", cmd.c_str());
}

@@ -143,6 +143,12 @@ IcePy_loadSlice(PyObject* /*self*/, PyObject* args)
out.setUseTab(false);

generate(u, all, includePaths, out);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from the lines above:

if (!icecpp->close() || parseStatus == EXIT_FAILURE)
{
    PyErr_Format(PyExc_RuntimeError, "Slice parsing failed for `%s'", cmd);
    u->destroy();
    return nullptr;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed the old IllegalMetadata test to FileMetadataMustComeFirst, since it was specifically focused on that.

@bernardnormier
Copy link
Member

I find validating metadata as part of the code generation sub-optimal. The logic was not introduced by this PR but is made worse by this PR since this validation can now generate errors - not just warnings.

It would be nicer for "validate metadata" to be a separate step. And if this step fails (completes with an error), we don't generate any code. With this PR, I can get into the odd situation where my Slice compilation fails with an error and yet overwrites all my generated files.

@InsertCreativityHere
Copy link
Member Author

Yes, @externl had a similar thought.

I started fixing this, by moving validation out of the gen functions, and adding a new check for errors before code-gen, which if hit, skips code-gen.

But I think I'll ask you both to ignore this issue for now, and put all those changes in an immediate follow-up PR.
Much of the validateMetadata implementations are inside the Gen classes. So fixing it moves around code which has nothing to do with the this PR's focus.

@@ -1,7 +1,11 @@
// Copyright (c) ZeroC, Inc.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Suggestion:

Suggested change
// Copyright (c) ZeroC, Inc.
{ "hello":"there" }

// Ice:

{ "hello":"there" }

// JSON:

{ "hello":"there" }

// Slice:

{ "hello":"there" }

// Suggestion:

Suggested change
// Copyright (c) ZeroC, Inc.
{ "Copyright (c)":"ZeroC, Inc." }

// Ice:

{ "Copyright (c)":"ZeroC, Inc." }

// JSON:

{ "Copyright (c)":"ZeroC, Inc." }

// Slice:

{ "Copyright (c)":"ZeroC, Inc." }

Suggestion:

Suggested change
// Copyright (c) ZeroC, Inc.
// Copyright (c) ZeroC, Inc. hello

JSON:

// Copyright (c) ZeroC, Inc. hello

Ice:

// Copyright (c) ZeroC, Inc. hello

Slice:

// Copyright (c) ZeroC, Inc. hello

int
Slice::Unit::getStatus() const
{
return (_errors ? EXIT_FAILURE : EXIT_SUCCESS);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be _errors > 0 ? ....

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some obscure difference here?
Or are you saying for clarity's sake?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarity sake.

{
// Metadata cannot be applied to modules that used nested-module-syntax, since it's ambiguous in meaning.
// We issue an error, and clear the metadata, so that we're in a valid state for further validation.
p->unit()->error(p->file(), p->line(), "metadata cannot be applied to nested module definitions");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a confusing message. Here is a nested module definition:

module Outer
{
    module Nested {} // a nested module definition
}

I can certainly put metadata on Nested.

It would be clearer to emit:
"metadata cannot be applied to a module defined using the nested module syntax".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was using the wording C++uses

/tmp/SAClaD0ZbY/main.cpp:13:1: error: a nested namespace definition cannot have attributes
   13 | namespace [[deprecated]] Foo::Bar {}
      | ^~~~~~~~~

I'll switch it back to what I had originally,
but I don't like talking about the "syntax" here, and I think calling this thing a module defined using nested module syntax is verbose. We should come up with some better term for this thing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to
metadata cannot be applied to modules defined with nested module syntax
Same idea, but a little shorter at least.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be "with the nested module syntax".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants