Skip to content

Commit 0294712

Browse files
demangle: parse C++20 subobjects in expressions
1 parent b3c4bb3 commit 0294712

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

ast.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,79 @@ func (f *Fold) goString(indent int, field string) string {
24762476
}
24772477
}
24782478

2479+
// Subobject is a a reference to an offset in an expression. This is
2480+
// used for C++20 manglings of class types used as the type of
2481+
// non-type template arguments.
2482+
//
2483+
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
2484+
type Subobject struct {
2485+
Type AST
2486+
SubExpr AST
2487+
Offset int
2488+
Selectors []int
2489+
PastEnd bool
2490+
}
2491+
2492+
func (so *Subobject) print(ps *printState) {
2493+
ps.print(so.SubExpr)
2494+
ps.writeString(".<")
2495+
ps.print(so.Type)
2496+
ps.writeString(fmt.Sprintf(" at offset %d>", so.Offset))
2497+
}
2498+
2499+
func (so *Subobject) Traverse(fn func(AST) bool) {
2500+
if fn(so) {
2501+
so.Type.Traverse(fn)
2502+
so.SubExpr.Traverse(fn)
2503+
}
2504+
}
2505+
2506+
func (so *Subobject) Copy(fn func(AST) AST, skip func(AST) bool) AST {
2507+
if skip(so) {
2508+
return nil
2509+
}
2510+
typ := so.Type.Copy(fn, skip)
2511+
subExpr := so.SubExpr.Copy(fn, skip)
2512+
if typ == nil && subExpr == nil {
2513+
return nil
2514+
}
2515+
if typ == nil {
2516+
typ = so.Type
2517+
}
2518+
if subExpr == nil {
2519+
subExpr = so.SubExpr
2520+
}
2521+
so = &Subobject {
2522+
Type: typ,
2523+
SubExpr: subExpr,
2524+
Offset: so.Offset,
2525+
Selectors: so.Selectors,
2526+
PastEnd: so.PastEnd,
2527+
}
2528+
if r := fn(so); r != nil {
2529+
return r
2530+
}
2531+
return so
2532+
}
2533+
2534+
func (so *Subobject) GoString() string {
2535+
return so.goString(0, "")
2536+
}
2537+
2538+
func (so *Subobject) goString(indent int, field string) string {
2539+
var selectors string
2540+
for _, s := range so.Selectors {
2541+
selectors += fmt.Sprintf(" %d", s)
2542+
}
2543+
return fmt.Sprintf("%*s%sSubobject:\n%s\n%s\n%*sOffset: %d\n%*sSelectors:%s\n%*sPastEnd: %t",
2544+
indent, "", field,
2545+
so.Type.goString(indent+2, "Type: "),
2546+
so.SubExpr.goString(indent+2, "SubExpr: "),
2547+
indent+2, "", so.Offset,
2548+
indent+2, "", selectors,
2549+
indent+2, "", so.PastEnd)
2550+
}
2551+
24792552
// New is a use of operator new in an expression.
24802553
type New struct {
24812554
Op AST

cases_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30177,10 +30177,7 @@ var casesExpectedFailures = map[string]bool{
3017730177
"_ZN1XIZ1fIiEvOT_EUlS2_DpT0_E_EclIJEEEvDpT_": true,
3017830178
"_ZZZZN6abcdef9abcdefghi29abcdefabcdefabcdefabcefabcdef27xxxxxxxxxxxxxxxxxxxxxxxxxxxEN4absl8DurationERKNSt3__u12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPNS1_19yyyyyyyyyyyyyyyyyyyEENK3$_5clEvENKUlvE_clEvE6zzzzzz": true,
3017930179
"_Z1fIXtl1BadsoiL_Z6nestedE_EEEEvv": true,
30180-
"_Z1fIXtl1BadsoiL_Z6nestedE16_0pEEEEvv": true,
30181-
"_Z1fIXtl2BRsoiL_Z7derivedE4EEEEvv": true,
3018230180
"_Z1fIXtl1BcvPiplcvPcadL_Z7derivedELl16EEEEvv": true,
30183-
"_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv": true,
3018430181
"_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv": true,
3018530182
"_Z1fIXtl1Edi1nLi42EEEEvv": true,
3018630183
"_Z1h1XIJZ1fIiEDaOT_E1AZ1gIdEDaS2_E1BEE": true,

demangle.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,7 @@ func (st *state) exprList(stop byte) AST {
19711971
// ::= rc <type> <expression>
19721972
// ::= ti <type>
19731973
// ::= te <expression>
1974+
// ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
19741975
// ::= st <type>
19751976
// ::= sz <expression>
19761977
// ::= at <type>
@@ -2013,6 +2014,9 @@ func (st *state) expression() AST {
20132014
return st.exprPrimary()
20142015
} else if st.str[0] == 'T' {
20152016
return st.templateParam()
2017+
} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'o' {
2018+
st.advance(2)
2019+
return st.subobject()
20162020
} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'r' {
20172021
return st.unresolvedName()
20182022
} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' {
@@ -2185,6 +2189,39 @@ func (st *state) expression() AST {
21852189
}
21862190
}
21872191

2192+
// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
2193+
// <union-selector> ::= _ [<number>]
2194+
func (st *state) subobject() AST {
2195+
typ := st.demangleType(false)
2196+
expr := st.expression()
2197+
offset := 0
2198+
if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) {
2199+
offset = st.number()
2200+
}
2201+
var selectors []int
2202+
for len(st.str) > 0 && st.str[0] == '_' {
2203+
st.advance(1)
2204+
selector := st.number()
2205+
selectors = append(selectors, selector)
2206+
}
2207+
pastEnd := false
2208+
if len(st.str) > 0 && st.str[0] == 'p' {
2209+
st.advance(1)
2210+
pastEnd = true
2211+
}
2212+
if len(st.str) == 0 || st.str[0] != 'E' {
2213+
st.fail("expected E after subobject")
2214+
}
2215+
st.advance(1)
2216+
return &Subobject{
2217+
Type: typ,
2218+
SubExpr: expr,
2219+
Offset: offset,
2220+
Selectors: selectors,
2221+
PastEnd: pastEnd,
2222+
}
2223+
}
2224+
21882225
// <unresolved-name> ::= [gs] <base-unresolved-name>
21892226
// ::= sr <unresolved-type> <base-unresolved-name>
21902227
// ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>

0 commit comments

Comments
 (0)