Wrong DeclRefExpr for PackIndexingExpr
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
https://godbolt.org/z/M5qYzKrKW
```c++
template
int templated_fn() {
struct S { int a; };
auto [... members] = S{12};
return members...[0];
}
void repro() {
templated_fn();
}
```
In the AST, there is the primary template for the function. That is followed by the `T=void` instantiation. Finally the function named `repro`.
Notice that the `DeclRefExpr` of the `PackIndexingExpr` of the template instantiation has the same `BindingDecl` pointer as is present in the primary template decl.
This seems to be a bug, as otherwise what would be the purpose of the `BindingDecl` inside the template instantiation?
Here is the AST part from the template instantiation:
```
| |-DeclStmt 0x1d142688
| | `-DecompositionDecl 0x1d1421d8 col:10 used 'S' cinit
| | |-CXXFunctionalCastExpr 0x1d142450 'S' functional cast to S
| | | `-InitListExpr 0x1d1422d0 'S'
| | | `-IntegerLiteral 0x1d11cd30 'int' 12
| | `-BindingDecl 0x1d142188 col:15 referenced members '...'
| | `-FunctionParmPackExpr 0x1d142610 '...' lvalue
| `-ReturnStmt 0x1d142740
| `-ImplicitCastExpr 0x1d142728 'int'
| `-PackIndexingExpr 0x1d1426f8 'int' lvalue
| |-DeclRefExpr 0x1d11ce08 '' lvalue Binding 0x1d11cc18 'members' '...' <--- this should be 0x1d142188
| `-ConstantExpr 0x1d1426d8 '__size_t':'unsigned long'
```
Here is the full AST dump from compiler explorer:
```
|-FunctionTemplateDecl 0x1d11c7e0 <:1:1, line:6:1> line:2:5 templated_fn
| |-TemplateTypeParmDecl 0x1d11c5e0 col:17 class depth 0 index 0
| | `-TemplateArgument type 'void'
| | `-BuiltinType 0x1d0c3fe0 'void'
| |-FunctionDecl 0x1d11c730 line:2:5 templated_fn 'int ()'
| | `-CompoundStmt 0x1d11ceb8
| | |-DeclStmt 0x1d11cb78
| | | `-CXXRecordDecl 0x1d11c910 col:12 referenced struct S definition
| | | |-DefinitionData aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor
| | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
| | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | | | |-MoveConstructor exists simple trivial needs_implicit
| | | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| | | | |-MoveAssignment exists simple trivial needs_implicit
| | | | `-Destructor simple irrelevant trivial constexpr needs_implicit
| | | |-CXXRecordDecl 0x1d11ca28 col:12 implicit struct S
| | | `-FieldDecl 0x1d11caf0 col:20 a 'int'
| | |-DeclStmt 0x1d11cdf0
| | | `-DecompositionDecl 0x1d11cc68 col:10 'auto' cinit
| | | |-CXXUnresolvedConstructExpr 0x1d11cd98 'S' 'S' list
| | | | `-InitListExpr 0x1d11cd50 'void'
| | | | `-IntegerLiteral 0x1d11cd30 'int' 12
| | | `-BindingDecl 0x1d11cc18 col:15 referenced members '...'
| | `-ReturnStmt 0x1d11cea8
| | `-PackIndexingExpr 0x1d11ce80 '' lvalue
| | |-DeclRefExpr 0x1d11ce08 '' lvalue Binding 0x1d11cc18 'members' '...'
| | `-ConstantExpr 0x1d11ce60 '__size_t':'unsigned long'
| | |-value: Int 0
| | `-ImplicitCastExpr 0x1d11ce48 '__size_t':'unsigned long'
| | `-IntegerLiteral 0x1d11ce28 'int' 0
| `-FunctionDecl 0x1d11d0a8 line:2:5 used templated_fn 'int ()' implicit_instantiation instantiated_from 0x1d11c730
| |-TemplateArgument type 'void'
| | `-BuiltinType 0x1d0c3fe0 'void'
| `-CompoundStmt 0x1d142750
| |-DeclStmt 0x1d142168
| | `-CXXRecordDecl 0x1d11d290 col:12 struct S definition instantiated_from 0x1d11c910
| | |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor
| | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
| | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveConstructor exists simple trivial needs_implicit
| | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveAssignment exists simple trivial needs_implicit
| | | `-Destructor simple irrelevant trivial constexpr
| | |-CXXRecordDecl 0x1d142028 col:12 implicit struct S
| | |-FieldDecl 0x1d1420d8 col:20 referenced a 'int'
| | `-CXXDestructorDecl 0x1d142320 col:12 implicit referenced constexpr ~S 'void () noexcept' inline default trivial
| |-DeclStmt 0x1d142688
| | `-DecompositionDecl 0x1d1421d8 col:10 used 'S' cinit
| | |-CXXFunctionalCastExpr 0x1d142450 'S' functional cast to S
| | | `-InitListExpr 0x1d1422d0 'S'
| | | `-IntegerLiteral 0x1d11cd30 'int' 12
| | `-BindingDecl 0x1d142188 col:15 referenced members '...'
| | `-FunctionParmPackExpr 0x1d142610 '...' lvalue
| `-ReturnStmt 0x1d142740
| `-ImplicitCastExpr 0x1d142728 'int'
| `-PackIndexingExpr 0x1d1426f8 'int' lvalue
| |-DeclRefExpr 0x1d11ce08 '' lvalue Binding 0x1d11cc18 'members' '...'
| `-ConstantExpr 0x1d1426d8 '__size_t':'unsigned long'
| |-value: Int 0
| `-ImplicitCastExpr 0x1d1426c0 '__size_t':'unsigned long'
| `-IntegerLiteral 0x1d11ce28 'int' 0
`-FunctionDecl 0x1d11cf58 line:8:6 repro 'void ()'
`-CompoundStmt 0x1d11d270
`-CallExpr 0x1d11d248 'int'
`-ImplicitCastExpr 0x1d11d230 'int (*)()'
`-DeclRefExpr 0x1d11d1d0 'int ()' lvalue Function 0x1d11d0a8 'templated_fn' 'int ()' (FunctionTemplate 0x1d11c7e0 'templated_fn')
```
PS: I've noticed this while implementing structured binding pack indexing for the Clang Static Analyzer.
Contributor guide
Research direction
Start with the Compiler Explorer reproducer and compare the AST for the primary template with its T=void instantiation. Trace how PackIndexingExpr and DeclRefExpr refer to the structured-binding BindingDecl during template instantiation. Done means the instantiated PackIndexingExpr references the instantiated BindingDecl rather than the primary template's declaration, with the AST dump confirming the corrected pointer.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100