-
-
Notifications
You must be signed in to change notification settings - Fork 610
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
Refactor mangle-only extern(C++, namespace) into an AttribDeclaration
#10021
Conversation
|
Thanks for your pull request, @Geod24! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub fetch digger
dub run digger -- build "master + dmd#10021" |
93cd57c to
28ab07a
Compare
1e6697b to
40ee34c
Compare
|
Can you split the first three commits as a separate PR please. |
40ee34c to
375324a
Compare
Sure thing: #10032 |
375324a to
3ff20df
Compare
|
Since this pass the full |
Originally, `extern(C++, ident)` was implemented as introducing a scope, importing C++ semantics into D, and was made a `ScopeDsymbol`. Introducing a scope turned out to be a behavior that was problematic, and users of `extern(C++)` just wanted to use D semantics and have the correct mangling. Later on, `extern(C++, "namespace")` was implemented, which removed the introduction of a scope. However, it was implemented within the existing `Nspace`, basically hacking around the fact that `ScopeDsymbol` introduces a scope and injecting the symbols in the parent scope. This commit implements a new AST node, `CPPNamespaceDeclaration`, which is an `AttributeDeclaration`. `AttributeDeclaration` are the way storage classes (e.g. `extern(C)` and `extern(C++, class|struct)` are implemented, as well as declarations that apply to a scope without introducing one, such as `DeprecatedDeclaration`. Since mangling is part of the function's external interface, CTFE on the message is run during the first semantic pass. Since `_scope` is set earlier than `semantic` is done on the attribute, the full `CPPNamespaceDeclaration` needs to be stored in the `Scope`, not just the resolved `Identifiers`. Moreover, a few tweaks are required to `cppmangle` to make it work with the new AST structure. Once the scoped version of `extern(C++, namespace)` is deprecated, the code can be greatly simplified.
3ff20df to
fd8a824
Compare
|
Rebased on master since #10032 got merged |
|
Why is this called "refactoring" when @SSoulaimane claims it introduces a scope? Where does it say that? Where's the documentation? |
Sorry, I meant this fixed the 'introduce a scope then discard it" i.e. no scope anymore. It's just a |
|
I surely do not understand how the code is better with this refactoring. |
| buf.writestring("N"); | ||
| if (!this.substitute(sym2)) | ||
| sym2.accept(this); | ||
| dg(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Geod24 duplicated call to dg(). and missing terminator "E" for "N".
It seems this branch isn't covered in the tests.
extern(C++, A) struct S(T){}
extern(C++) void fun(int i)(S!int);
pragma(msg, fun!0.mangleof);Prints _Z3funILi0EEvN1AIiE1SIiE. should be _Z3funILi0EEvN1A1SIiEE.
| sym2.accept(this); | ||
| dg(); | ||
| } | ||
| if (sym1 !is null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
redundant check. sym1 in never null here.
| const sident = se.toStringz(); | ||
| if (!sident.length || !Identifier.isValidIdentifier(sident)) | ||
| { | ||
| ns.exp.error("expected valid identifer for C++ namespace but got `%.*s`", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't the motive of this syntax that D identifiers don't exactly match C++? 15512.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's one of the motives, and very important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then checking the validity here defeats the point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code was adapted from what's existing. I also had a "Wait, what?" moment until I checked the code for isValidIdentifier. It does not check if the identifier is one of the reserved ones.
cppmangle: Follow up on #10021 merged-on-behalf-of: Nicholas Wilson <thewilsonator@users.noreply.github.com>
|
|
||
| extern(D) override const(char)[] toString() const | ||
| { | ||
| return "extern (C++, `namespace`)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should include the identifier or expression instead of "namespace".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nspace doesn't do that (and it allocates)
I was considering doing a refactor where toString takes a sink, but it has been put off so far.
| s.namespace, () { | ||
| this.writeIdentifier(ti.tempdecl.toAlias().ident); | ||
| template_args(ti); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
source_name isn't supposed to insert N..E but writeNamespace does.
extern(C++, "a", "b")
struct S
{
void func();
}
pragma(msg, S.func.mangleof);This is a regression. It prints _ZNN1a1b1SE4funcEv it used to be _ZN1a1b1S4funcEv.
| return null; | ||
| return parent.pastMixinAndNspace(); | ||
| } | ||
| alias pastMixinAndNspace = pastMixin; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This caused a regression (C++ headers weren't updated).
| @@ -1187,6 +1180,7 @@ extern (C++) class Dsymbol : ASTNode | |||
| inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; } | |||
| inout(AttribDeclaration) isAttribDeclaration() inout { return null; } | |||
| inout(AnonDeclaration) isAnonDeclaration() inout { return null; } | |||
| inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; } | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And another regression...
|
This also fixed https://issues.dlang.org/show_bug.cgi?id=19339 |
|
This seems to have caused a regression: https://issues.dlang.org/show_bug.cgi?id=24547 |
Over the past two weeks I tried two things:
extern(C++, namespace)After much trial and error, I came up with the explanation mentioned above.
This will fail the CI for now as I haven't tried it on Windows yet.
I can split a few changes in separate PRs, but the bulk of it is indissociable.
CC @TurkeyMan