-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[clang] Improve nested name specifier AST representation #147835
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
Conversation
Can you please attach the crash reproducer which clang should have generated? Thanks. |
After this commit, the comment in
isn't accurate any more, there's no more |
clangd doesn't really have a preference here, we just surface one can repro the situation with where a.cc is: namespace N {
struct Foo {};
} // namespace N
void f() {
using namespace N;
Foo foo;
N::Foo x;
} pre this change output looks like:
emphasis on after thins change this is now reported as this was handled by https://github.com/llvm/llvm-project/blob/main/clang/lib/AST/TextNodeDumper.cpp#L909-L926, I am not sure if change is intended (i think we should still be able to detect & desugar) |
@mizvekov, anyway, it would be good to know if
However, I don't see where in the world QualifiedTypeLoc is created...
|
Thanks for reporting, I'll fix in a follow up patch.
Right, the difference here is that before this patch, if you print a fully desugared tag type (that's what the 'aka' in the diagnostic does), the type is printed fully qualified. That's because the name qualifiers were carried in the 'ElaboratedType' sugar node, and we used to handle this situation specially: we assumed a bare tag type only occurred because of canonicalization. With this patch the tag types themselves carry the name qualifier, so just removing the top level sugar doesn't make them lose name qualifier information. We still fully qualify canonical tag types when printing them though, but that now happens because a canonical tag type is a special value which is not identical to any other tag type for the same declaration. We may still want to fully qualify types for the 'aka' diagnostic, but I deferred that for a follow up patch in order to limit the amount of test churn. For clangd, I assume the same thing is happening here, for this arcana" field, you are fully desugaring the type before printing it.
The TraverseQualifier flag means, 'should I traverse NestedNameSpecifiers?' If you are simply customizing one of the Traverse* methods which take it, but still delegating to the base class Traverse method, you should just forward that flag along to the base method. If you are implementing your own Traverse method for a type from scratch, then if this flag is false, you should not traverse the nested name specifier for that type.
QualifiedTypeLoc is created implicitly for QualTypes which have top level qualifiers, and they represent the source locations for type qualifiers (not name qualifiers, different thing.) This assert here means that a top level type qualifier can't appear within a nested name specifier (but it could appear for example in the underlying type for a typedef). The C++ grammar doesn't allow you to write const / volatile in a way which applies to an entity in the name qualifier itself. While such a NestedNameSpecifier could still be produced as part of template argument deduction, we simply remove the top level qualifiers in that case, as the NestedNameSpecifier AST node itself still can't represent it. |
|
@mizvekov, thanks for the clarifying! In fact, it means that at least |
Yeah, it may only given false in the implementation of TraverseNestedNameSpecifier, which for out-of-tree users is only relevant if you are overriding that. If you mistakenly passed true instead, the name qualifiers would be traversed twice. |
I mean that I cannot do this: struct MyVisitor : RecursiveASTVisitor<MyVisitor> {
using Base = RecursiveASTVisitor<MyVisitor>;
bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = false) {
return Base::TraverseTypeLoc(TL, TraverseQualifier);
}
}; Calling |
llvm/llvm-project#147835 makes minor diagnostic changes. Accept the previous and new diagnostic messages. Bug: 437910658 Change-Id: Iec24f4e20944465fe12a87539822c095bb88979f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6842043 Reviewed-by: Nico Weber <[email protected]> Commit-Queue: Arthur Eubanks <[email protected]> Cr-Commit-Position: refs/heads/main@{#1500458}
Minimized this using C-Vise to 620 bytes: https://pastebin.com/yegBAfpe |
llvm/llvm-project#147835 makes minor diagnostic changes. Accept the previous and new diagnostic messages. Bug: 437910658 Change-Id: Iec24f4e20944465fe12a87539822c095bb88979f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6842043 Reviewed-by: Nico Weber <[email protected]> Commit-Queue: Arthur Eubanks <[email protected]> Cr-Commit-Position: refs/heads/main@{#1500458} NOKEYCHECK=True GitOrigin-RevId: 83aa2e61488debc4572256e81768123605224687
llvm/llvm-project#147835 makes minor diagnostic changes. Accept the previous and new diagnostic messages. Bug: 437910658 Change-Id: Iec24f4e20944465fe12a87539822c095bb88979f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6842043 Reviewed-by: Nico Weber <[email protected]> Commit-Queue: Arthur Eubanks <[email protected]> Cr-Commit-Position: refs/heads/main@{#1500458} NOKEYCHECK=True GitOrigin-RevId: 83aa2e61488debc4572256e81768123605224687
Upstream recently made sweeping changes to some AST representations (llvm/llvm-project#147835), so we need to update our plugin to match. Since it involves syntax/type changes, we need to check if we're building at head or not. Some tests have slightly different diagnostic messages (e.g. an extra `base::`). Since the test framework doesn't make it easy to have two golden files, just suppress these tests until we roll past this. Bug: 437910658 Change-Id: Icf3ffbb5eed6f3728cd267407eaf1821ea378845 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6842037 Auto-Submit: Arthur Eubanks <[email protected]> Reviewed-by: Devon Loehr <[email protected]> Reviewed-by: Nico Weber <[email protected]> Commit-Queue: Devon Loehr <[email protected]> Cr-Commit-Position: refs/heads/main@{#1500577}
…153344) This fixes a regression reported here #147835 (comment), where getTrivialTemplateArgumentLoc can't see through template name sugar when producing a trivial TemplateArgumentLoc for template template arguments. Since this regression was never released, there are no release notes.
Thanks, that has been fixed here: #153344 |
…e argument (#153344) This fixes a regression reported here llvm/llvm-project#147835 (comment), where getTrivialTemplateArgumentLoc can't see through template name sugar when producing a trivial TemplateArgumentLoc for template template arguments. Since this regression was never released, there are no release notes.
The following fails as well: struct MyVisitor : RecursiveASTVisitor<MyVisitor> {
} visitor;
visitor.TraverseTypeLoc(typeloc, false); if the given So you insist that |
If you want to avoid traversal of NNSes, why don't you just override TraverseNestedNameSpecifier{,Loc} with no-ops? |
They should be avoided not always but in certain circumstances, so there should be a new flag field in the visitor class. Not many new code, TBH, but using |
We can make it work, we could move the assert elsewhere. |
The assert doesn't hurt us, as I've said. I just asked if it is a "documented way" of working with the new visitor interface. If it is not to be avoided, then we will probably just proceed with the |
It would be hard for us to document this as an intended interface, but leave that assert in the way, even if you found yourself a way to avoid it. This wouldn't look very polished. |
@kimgr, what do you think? |
Summary: Clang recently made major changes to the AST representation of nested name specifiers in [llvm-project#147835](llvm/llvm-project#147835). While waiting for Bindgen to be updated to understand the new representation, this diff changes our Bindgen invocation on `folly::IOBuf` to disregard the nested name `folly::IOBuf::Iterator`, which is unused anyway in the Rust `IOBuf` binding. This unblocks staging builds for the LLVM Server Compiler team. This diff causes the following difference in the Bindgen-generated Rust binding observed through `buck2 build fbcode//mode/opt fbcode//folly/rust/iobuf:iobuf-sys-bindgen`: ```lang=diff @@ -571,8 +571,6 @@ pub const IOBuf_CombinedOption_SEPARATE: root::folly::IOBuf_CombinedOption = 2; pub type IOBuf_CombinedOption = ::std::os::raw::c_int; pub type IOBuf_value_type = root::folly::ByteRange; - pub type IOBuf_iterator = root::folly::IOBuf_Iterator; - pub type IOBuf_const_iterator = root::folly::IOBuf_Iterator; pub type IOBuf_FreeFunction = ::std::option::Option< unsafe extern "C" fn( buf: *mut ::std::os::raw::c_void, @@ -765,31 +763,6 @@ "Offset of field: IOBuf::sharedInfo_", ][::std::mem::offset_of!(IOBuf, sharedInfo_) - 48usize]; }; - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct IOBuf_Iterator { - pub pos_: *const root::folly::IOBuf, - pub end_: *const root::folly::IOBuf, - pub val_: root::folly::ByteRange, - } - #[allow(clippy::unnecessary_operation, clippy::identity_op)] - const _: () = { - [ - "Size of IOBuf_Iterator", - ][::std::mem::size_of::<IOBuf_Iterator>() - 32usize]; - [ - "Alignment of IOBuf_Iterator", - ][::std::mem::align_of::<IOBuf_Iterator>() - 8usize]; - [ - "Offset of field: IOBuf_Iterator::pos_", - ][::std::mem::offset_of!(IOBuf_Iterator, pos_) - 0usize]; - [ - "Offset of field: IOBuf_Iterator::end_", - ][::std::mem::offset_of!(IOBuf_Iterator, end_) - 8usize]; - [ - "Offset of field: IOBuf_Iterator::val_", - ][::std::mem::offset_of!(IOBuf_Iterator, val_) - 16usize]; - }; } pub mod facebook { #[allow(unused_imports)] ``` Bindgen issue: [bindgen#3264](rust-lang/rust-bindgen#3264) Reviewed By: HighW4y2H3ll Differential Revision: D80186965 fbshipit-source-id: 9f0546a2964b5d4e5c67e6bdd91b542e3e5f7b2c
This is a major change on how we represent nested name qualifications in the AST.
This patch offers a great performance benefit.
It greatly improves compilation time for stdexec. For one datapoint, for
test_on2.cpp
in that project, which is the slowest compiling test, this patch improves-c
compilation time by about 7.2%, with the-fsyntax-only
improvement being at ~12%.This has great results on compile-time-tracker as well:

This patch also further enables other optimziations in the future, and will reduce the performance impact of template specialization resugaring when that lands.
It has some other miscelaneous drive-by fixes.
About the review: Yes the patch is huge, sorry about that. Part of the reason is that I started by the nested name specifier part, before the ElaboratedType part, but that had a huge performance downside, as ElaboratedType is a big performance hog. I didn't have the steam to go back and change the patch after the fact.
There is also a lot of internal API changes, and it made sense to remove ElaboratedType in one go, versus removing it from one type at a time, as that would present much more churn to the users. Also, the nested name specifier having a different API avoids missing changes related to how prefixes work now, which could make existing code compile but not work.
How to review: The important changes are all in
clang/include/clang/AST
andclang/lib/AST
, with also important changes inclang/lib/Sema/TreeTransform.h
.The rest and bulk of the changes are mostly consequences of the changes in API.
PS: TagType::getDecl is renamed to
getOriginalDecl
in this patch, just for easier to rebasing. I plan to rename it back after this lands.Fixes #136624
Fixes #43179
Fixes #68670
Fixes #92757