Source file test/devirtualization_with_type_assertions_interleaved.go

     1  // errorcheck -0 -m
     2  
     3  // Copyright 2025 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package escape
     8  
     9  type hashIface interface {
    10  	Sum() []byte
    11  }
    12  
    13  type cloneableHashIface interface {
    14  	hashIface
    15  	Clone() hashIface
    16  }
    17  
    18  type hash struct{ state [32]byte }
    19  
    20  func (h *hash) Sum() []byte { // ERROR "can inline \(\*hash\).Sum$" "h does not escape$"
    21  	return make([]byte, 32) // ERROR "make\(\[\]byte, 32\) escapes to heap$"
    22  }
    23  
    24  func (h *hash) Clone() hashIface { // ERROR "can inline \(\*hash\).Clone$" "h does not escape$"
    25  	c := *h // ERROR "moved to heap: c$"
    26  	return &c
    27  }
    28  
    29  type hash2 struct{ state [32]byte }
    30  
    31  func (h *hash2) Sum() []byte { // ERROR "can inline \(\*hash2\).Sum$" "h does not escape$"
    32  	return make([]byte, 32) // ERROR "make\(\[\]byte, 32\) escapes to heap$"
    33  }
    34  
    35  func (h *hash2) Clone() hashIface { // ERROR "can inline \(\*hash2\).Clone$" "h does not escape$"
    36  	c := *h // ERROR "moved to heap: c$"
    37  	return &c
    38  }
    39  
    40  func newHash() hashIface { // ERROR "can inline newHash$"
    41  	return &hash{} // ERROR "&hash{} escapes to heap$"
    42  }
    43  
    44  func cloneHash1(h hashIface) hashIface { // ERROR "can inline cloneHash1$" "leaking param: h$"
    45  	if h, ok := h.(cloneableHashIface); ok {
    46  		return h.Clone()
    47  	}
    48  	return &hash{} // ERROR "&hash{} escapes to heap$"
    49  }
    50  
    51  func cloneHash2(h hashIface) hashIface { // ERROR "can inline cloneHash2$" "leaking param: h$"
    52  	if h, ok := h.(cloneableHashIface); ok {
    53  		return h.Clone()
    54  	}
    55  	return nil
    56  }
    57  
    58  func cloneHash3(h hashIface) hashIface { // ERROR "can inline cloneHash3$" "leaking param: h$"
    59  	if h, ok := h.(cloneableHashIface); ok {
    60  		return h.Clone()
    61  	}
    62  	return &hash2{} // ERROR "&hash2{} escapes to heap$"
    63  }
    64  
    65  func cloneHashWithBool1(h hashIface) (hashIface, bool) { // ERROR "can inline cloneHashWithBool1$" "leaking param: h$"
    66  	if h, ok := h.(cloneableHashIface); ok {
    67  		return h.Clone(), true
    68  	}
    69  	return &hash{}, false // ERROR "&hash{} escapes to heap$"
    70  }
    71  
    72  func cloneHashWithBool2(h hashIface) (hashIface, bool) { // ERROR "can inline cloneHashWithBool2$" "leaking param: h$"
    73  	if h, ok := h.(cloneableHashIface); ok {
    74  		return h.Clone(), true
    75  	}
    76  	return nil, false
    77  }
    78  
    79  func cloneHashWithBool3(h hashIface) (hashIface, bool) { // ERROR "can inline cloneHashWithBool3$" "leaking param: h$"
    80  	if h, ok := h.(cloneableHashIface); ok {
    81  		return h.Clone(), true
    82  	}
    83  	return &hash2{}, false // ERROR "&hash2{} escapes to heap$"
    84  }
    85  
    86  func interleavedWithTypeAssertions() {
    87  	h1 := newHash() // ERROR "&hash{} does not escape$" "inlining call to newHash"
    88  	_ = h1.Sum()    // ERROR "devirtualizing h1.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$"
    89  
    90  	h2 := cloneHash1(h1) // ERROR "&hash{} does not escape$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHash1"
    91  	_ = h2.Sum()         // ERROR "devirtualizing h2.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$"
    92  
    93  	h3 := cloneHash2(h1) // ERROR "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHash2"
    94  	_ = h3.Sum()         // ERROR "devirtualizing h3.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$"
    95  
    96  	h4 := cloneHash3(h1) // ERROR "&hash2{} escapes to heap$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHash3" "moved to heap: c$"
    97  	_ = h4.Sum()
    98  
    99  	h5, _ := cloneHashWithBool1(h1) // ERROR "&hash{} does not escape$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHashWithBool1"
   100  	_ = h5.Sum()                    // ERROR "devirtualizing h5.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$"
   101  
   102  	h6, _ := cloneHashWithBool2(h1) // ERROR "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHashWithBool2"
   103  	_ = h6.Sum()                    // ERROR "devirtualizing h6.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$"
   104  
   105  	h7, _ := cloneHashWithBool3(h1) // ERROR "&hash2{} escapes to heap$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHashWithBool3" "moved to heap: c$"
   106  	_ = h7.Sum()
   107  }
   108  
   109  type cloneableHashError interface {
   110  	hashIface
   111  	Clone() (hashIface, error)
   112  }
   113  
   114  type hash3 struct{ state [32]byte }
   115  
   116  func newHash3() hashIface { // ERROR "can inline newHash3$"
   117  	return &hash3{} // ERROR "&hash3{} escapes to heap$"
   118  }
   119  
   120  func (h *hash3) Sum() []byte { // ERROR "can inline \(\*hash3\).Sum$" "h does not escape$"
   121  	return make([]byte, 32) // ERROR "make\(\[\]byte, 32\) escapes to heap$"
   122  }
   123  
   124  func (h *hash3) Clone() (hashIface, error) { // ERROR "can inline \(\*hash3\).Clone$" "h does not escape$"
   125  	c := *h // ERROR "moved to heap: c$"
   126  	return &c, nil
   127  }
   128  
   129  func interleavedCloneableHashError() {
   130  	h1 := newHash3() // ERROR "&hash3{} does not escape$" "inlining call to newHash3"
   131  	_ = h1.Sum()     // ERROR "devirtualizing h1.Sum to \*hash3$" "inlining call to \(\*hash3\).Sum" "make\(\[\]byte, 32\) does not escape$"
   132  
   133  	if h1, ok := h1.(cloneableHashError); ok {
   134  		h2, err := h1.Clone() // ERROR "devirtualizing h1.Clone to \*hash3$" "inlining call to \(\*hash3\).Clone"
   135  		if err == nil {
   136  			_ = h2.Sum() // ERROR "devirtualizing h2.Sum to \*hash3$" "inlining call to \(\*hash3\).Sum" "make\(\[\]byte, 32\) does not escape$"
   137  		}
   138  	}
   139  }
   140  

View as plain text