Skip to content

Commit

Permalink
facts: fix purity detection for allocations
Browse files Browse the repository at this point in the history
Neither make nor new should have ever been considered pure. They
allocate memory and different invocations return different addresses.

The ir.UnOp case has never handled allocations correctly (there was no
'&' UnOp), and loads were broken when we introduced the Load
instruction.
  • Loading branch information
dominikh committed Dec 2, 2019
1 parent 32de78d commit 6cdd070
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 6 deletions.
14 changes: 8 additions & 6 deletions facts/purity.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package facts

import (
"go/token"
"go/types"
"reflect"

Expand Down Expand Up @@ -100,11 +99,14 @@ func purity(pass *analysis.Pass) (interface{}, error) {
}

for _, param := range fn.Params {
// TODO(dh): this may not be strictly correct. pure code
// can, to an extent, operate on non-basic types.
if _, ok := param.Type().Underlying().(*types.Basic); !ok {
return false
}
}

// Don't consider external functions pure.
if fn.Blocks == nil {
return false
}
Expand All @@ -124,7 +126,7 @@ func purity(pass *analysis.Pass) (interface{}, error) {
}
} else {
switch builtin.Name() {
case "len", "cap", "make", "new":
case "len", "cap":
default:
return false
}
Expand Down Expand Up @@ -154,10 +156,10 @@ func purity(pass *analysis.Pass) (interface{}, error) {
return false
case *ir.FieldAddr:
return false
case *ir.UnOp:
if ins.Op == token.MUL || ins.Op == token.AND {
return false
}
case *ir.Alloc:
return false
case *ir.Load:
return false
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions facts/testdata/src/Purity/CheckPureFunctions.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ func fn3() {
stubPointer()
stubInt()
}

func ptr1() *int { return new(int) }
func ptr2() *int { var x int; return &x }
func lit() []int { return []int{} }

var X int

func load() int { _ = X; return 0 }
func assign(x int) int { _ = x; return 0 } // want assign:"is pure"

0 comments on commit 6cdd070

Please sign in to comment.