Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Do you also want to update LangOpts.td to make the default for the langopt equal to CPlusPlus?
(I saw other opts doing that, not sure exactly what it affects, may be voodoo cargo cult stuff)
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp | ||
---|---|---|
1198–1200 | Why did the original test start failing? Is this a regression? (This certainly seems OK to regress and fix later, but there may be other consequences?) |
ah, I missed that.
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp | ||
---|---|---|
1198–1200 | yes, but I didn't dig into it, it is likely a regression, added a FIXME (looking at other cases in this test, they just use 10 as the parameter). |
We found an odd case in our downstream fork after this patch landed. We have a diagnostic in CheckVariableDeclarationType that checks for automatic variables that are too large for the stack address space, and it chokes on the testcase Parser/objcxx11-invalid-lambda.cpp:
void foo() { // expected-note {{to match this '{'}} int bar; auto baz = [ bar( // expected-note {{to match this '('}} expected-note {{to match this '('}} foo_undeclared() // expected-error{{use of undeclared identifier 'foo_undeclared'}} /* ) */ ] () { }; // expected-error{{expected ')'}} } // expected-error{{expected ')'}} expected-error {{expected ',' or ']'}} expected-error{{expected ';' at end of declaration}} expected-error{{expected '}'}}
When the lambda is parsed, the parsing of the initializer expression of the 'bar' capture fails since the paren is unbalanced, so it will build:
ParenListExpr 0xc592ce8 'NULL TYPE' contains-errors `-RecoveryExpr 0xc592cc0 '<dependent type>' contains-errors lvalue `-UnresolvedLookupExpr 0xc592c38 '<overloaded function type>' lvalue (ADL) = 'foo_undeclared' empty
Then, when building the lambda closure type, it will be given an auto member for bar with its type deduced to AutoType 0xc592d40 'auto' dependent:
CXXRecordDecl 0xdfeb798 <...> col:14 implicit class definition |-DefinitionData lambda pass_in_registers standard_layout trivially_copyable can_const_default_init | |-DefaultConstructor | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param | |-MoveConstructor exists simple trivial needs_implicit | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param | |-MoveAssignment | `-Destructor simple irrelevant trivial |-CXXMethodDecl 0xdfeb8d0 <line:10:8, col:12> line:5:14 operator() 'void () const' inline | `-CompoundStmt 0xdfeba20 <line:10:10, col:12> |-FieldDecl 0xdfeba58 <line:6:7> col:7 implicit 'auto' `-CXXDestructorDecl 0xdfebb08 <line:5:14> col:14 implicit referenced ~ 'void () noexcept' inline default trivial
However, this just means that baz has a very odd type; it's a variable of closure type that contains a dependent member that will never be resolved. Our diagnostic breaks, since the variable's type isn't dependent, but it has a member which is, and we can't take the size of that.
Is the lambda parser really supposed to build this kind of odd type when faced with RecoveryExpr?
Interesting. Simply turning this off for lambdas isn't enough. The following crashes clang for me:
class X { decltype(unresolved()) foo; }; constexpr int s = sizeof(X);
@hokein I think we need to revert until we find a solution for this. I suspect this is going to mean adding the error bit to type and... dropping members that have it set? Or marking them as invalid?
Thanks for the test case. Reverted in https://github.com/llvm/llvm-project/commit/62dea6e9be31b100962f9ad41c1b79467a53f6cd for now. Adding the error-bit to type looks like a right direction.
We have also encountered crashes in downstream testing caused by this using just the vanilla source from trunk. When there is a proposed fix, please let us know so we can test. Thanks.
@ebevhan Thanks again for the testcase. I've added a reduced version in 47e7bdb10732e6f140adce39a1bc34e3ee2a6ea6 to ensure this is fixed on re-land.
This particular case can be fixed by marking the decl as invalid I think, I'm curious how this generalizes.
We can try but it would be very useful to have details, no idea whether it's going to be the same issue and the more we know about the easier it is to improve the design.
Can you describe the case at all? Any chance of a minimal example? Ideally we'd check it in.
We can try but it would be very useful to have details, no idea whether it's going to be the same issue and the more we know about the easier it is to improve the design.
Can you describe the case at all? Any chance of a minimal example? Ideally we'd check it in.
All of them appear to have unresolved names in constexpr evaluation. It is likely to be the same issue.
The general scheme is probably common: unresolved expr -> ??? -> an expression is dependent but not marked as such -> constant evaluation crashes.
But the ??? matters, as that's where the fix is.
In the case above: expr is used in a member of X, and X is not a dependent type, so sizeof(X) is not considered dependent
The context, if I understand correctly for the cases I am seeing, boil down to:
- Value of a member initializer for a constexpr constructor
- Bitfield width
struct X { int Y; constexpr X() : Y(foo()) {] };
This will need a different fix I think. Maybe just isPotentialConstantExpr needs to bail out if there are errors.
- Bitfield width
struct X { int Y : foo(); }; constexpr int Z = sizeof(X);
I think this one is just another case of marking the fielddecl as invalid.
Why did the original test start failing? Is this a regression?
(This certainly seems OK to regress and fix later, but there may be other consequences?)