gc: unsafe.Pointer is not a pointer

Change unsafe.Pointer to be its own kind of
type, instead of making it equivalent to *any.
The change complicates import and export
but avoids the need to find all the places that
operate on pointers but should not operate on
unsafe.Pointer.

Fixes #1566. (a different way)
Fixes #1582.

R=ken2
CC=golang-dev
https://golang.org/cl/4264050
This commit is contained in:
Russ Cox 2011-03-07 15:10:01 -05:00
parent 22c45c558b
commit 5c2666c18c
10 changed files with 48 additions and 22 deletions

View File

@ -172,6 +172,9 @@ dowidth(Type *t)
w = 8; w = 8;
checkwidth(t->type); checkwidth(t->type);
break; break;
case TUNSAFEPTR:
w = widthptr;
break;
case TINTER: // implemented as 2 pointers case TINTER: // implemented as 2 pointers
w = 2*widthptr; w = 2*widthptr;
t->align = widthptr; t->align = widthptr;
@ -400,6 +403,13 @@ typeinit(void)
types[TPTR64] = typ(TPTR64); types[TPTR64] = typ(TPTR64);
dowidth(types[TPTR64]); dowidth(types[TPTR64]);
t = typ(TUNSAFEPTR);
types[TUNSAFEPTR] = t;
t->sym = pkglookup("Pointer", unsafepkg);
t->sym->def = typenod(t);
dowidth(types[TUNSAFEPTR]);
tptr = TPTR32; tptr = TPTR32;
if(widthptr == 8) if(widthptr == 8)
@ -481,6 +491,7 @@ typeinit(void)
okforeq[TPTR32] = 1; okforeq[TPTR32] = 1;
okforeq[TPTR64] = 1; okforeq[TPTR64] = 1;
okforeq[TUNSAFEPTR] = 1;
okforeq[TINTER] = 1; okforeq[TINTER] = 1;
okforeq[TMAP] = 1; okforeq[TMAP] = 1;
okforeq[TCHAN] = 1; okforeq[TCHAN] = 1;
@ -570,6 +581,7 @@ typeinit(void)
simtype[TMAP] = tptr; simtype[TMAP] = tptr;
simtype[TCHAN] = tptr; simtype[TCHAN] = tptr;
simtype[TFUNC] = tptr; simtype[TFUNC] = tptr;
simtype[TUNSAFEPTR] = tptr;
/* pick up the backend typedefs */ /* pick up the backend typedefs */
for(i=0; typedefs[i].name; i++) { for(i=0; typedefs[i].name; i++) {

View File

@ -96,7 +96,7 @@ char *runtimeimport =
"$$\n"; "$$\n";
char *unsafeimport = char *unsafeimport =
"package unsafe\n" "package unsafe\n"
"type \"\".Pointer *any\n" "type \"\".Pointer uintptr\n"
"func \"\".Offsetof (? any) int\n" "func \"\".Offsetof (? any) int\n"
"func \"\".Sizeof (? any) int\n" "func \"\".Sizeof (? any) int\n"
"func \"\".Alignof (? any) int\n" "func \"\".Alignof (? any) int\n"

View File

@ -155,6 +155,7 @@ convlit1(Node **np, Type *t, int explicit)
case TMAP: case TMAP:
case TCHAN: case TCHAN:
case TFUNC: case TFUNC:
case TUNSAFEPTR:
break; break;
} }
break; break;

View File

@ -656,10 +656,19 @@ typedcl2(Type *pt, Type *t)
{ {
Node *n; Node *n;
// override declaration in unsafe.go for Pointer.
// there is no way in Go code to define unsafe.Pointer
// so we have to supply it.
if(incannedimport &&
strcmp(importpkg->name, "unsafe") == 0 &&
strcmp(pt->nod->sym->name, "Pointer") == 0) {
t = types[TUNSAFEPTR];
}
if(pt->etype == TFORW) if(pt->etype == TFORW)
goto ok; goto ok;
if(!eqtype(pt->orig, t)) if(!eqtype(pt->orig, t))
yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t); yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
return; return;
ok: ok:

View File

@ -459,9 +459,10 @@ enum
TFIELD, TFIELD,
TANY, TANY,
TSTRING, TSTRING,
TUNSAFEPTR,
// pseudo-types for literals // pseudo-types for literals
TIDEAL, // 32 TIDEAL, // 33
TNIL, TNIL,
TBLANK, TBLANK,

View File

@ -466,6 +466,7 @@ kinds[] =
[TFUNC] = KindFunc, [TFUNC] = KindFunc,
[TCOMPLEX64] = KindComplex64, [TCOMPLEX64] = KindComplex64,
[TCOMPLEX128] = KindComplex128, [TCOMPLEX128] = KindComplex128,
[TUNSAFEPTR] = KindUnsafePointer,
}; };
static char* static char*
@ -488,6 +489,7 @@ structnames[] =
[TFLOAT64] = "*runtime.FloatType", [TFLOAT64] = "*runtime.FloatType",
[TBOOL] = "*runtime.BoolType", [TBOOL] = "*runtime.BoolType",
[TSTRING] = "*runtime.StringType", [TSTRING] = "*runtime.StringType",
[TUNSAFEPTR] = "*runtime.UnsafePointerType",
[TPTR32] = "*runtime.PtrType", [TPTR32] = "*runtime.PtrType",
[TPTR64] = "*runtime.PtrType", [TPTR64] = "*runtime.PtrType",
@ -514,9 +516,6 @@ typestruct(Type *t)
if(isslice(t)) if(isslice(t))
name = "*runtime.SliceType"; name = "*runtime.SliceType";
if(isptr[et] && t->type->etype == TANY)
name = "*runtime.UnsafePointerType";
return pkglookup(name, typepkg); return pkglookup(name, typepkg);
} }
@ -553,6 +552,7 @@ haspointers(Type *t)
case TSTRING: case TSTRING:
case TPTR32: case TPTR32:
case TPTR64: case TPTR64:
case TUNSAFEPTR:
case TINTER: case TINTER:
case TCHAN: case TCHAN:
case TMAP: case TMAP:
@ -612,8 +612,6 @@ dcommontype(Sym *s, int ot, Type *t)
i = kinds[t->etype]; i = kinds[t->etype];
if(t->etype == TARRAY && t->bound < 0) if(t->etype == TARRAY && t->bound < 0)
i = KindSlice; i = KindSlice;
if(isptr[t->etype] && t->type->etype == TANY)
i = KindUnsafePointer;
if(!haspointers(t)) if(!haspointers(t))
i |= KindNoPointers; i |= KindNoPointers;
ot = duint8(s, ot, i); // kind ot = duint8(s, ot, i); // kind
@ -714,12 +712,8 @@ dtypesym(Type *t)
tbase = t->type; tbase = t->type;
dupok = tbase->sym == S; dupok = tbase->sym == S;
if(compiling_runtime) { if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc
if(tbase == types[tbase->etype]) // int, float, etc goto ok;
goto ok;
if(tbase->etype == tptr && tbase->type->etype == TANY) // unsafe.Pointer
goto ok;
}
// named types from other files are defined only by those files // named types from other files are defined only by those files
if(tbase->sym && !tbase->local) if(tbase->sym && !tbase->local)
@ -908,7 +902,7 @@ dumptypestructs(void)
for(i=1; i<=TBOOL; i++) for(i=1; i<=TBOOL; i++)
dtypesym(ptrto(types[i])); dtypesym(ptrto(types[i]));
dtypesym(ptrto(types[TSTRING])); dtypesym(ptrto(types[TSTRING]));
dtypesym(ptrto(pkglookup("Pointer", unsafepkg)->def->type)); dtypesym(ptrto(types[TUNSAFEPTR]));
// add paths for runtime and main, which 6l imports implicitly. // add paths for runtime and main, which 6l imports implicitly.
dimportpath(runtimepkg); dimportpath(runtimepkg);

View File

@ -1144,7 +1144,7 @@ Tpretty(Fmt *fp, Type *t)
&& t->sym != S && t->sym != S
&& !(fp->flags&FmtLong)) { && !(fp->flags&FmtLong)) {
s = t->sym; s = t->sym;
if(t == types[t->etype]) if(t == types[t->etype] && t->etype != TUNSAFEPTR)
return fmtprint(fp, "%s", s->name); return fmtprint(fp, "%s", s->name);
if(exporting) { if(exporting) {
if(fp->flags & FmtShort) if(fp->flags & FmtShort)
@ -1304,6 +1304,11 @@ Tpretty(Fmt *fp, Type *t)
if(t->sym) if(t->sym)
return fmtprint(fp, "undefined %S", t->sym); return fmtprint(fp, "undefined %S", t->sym);
return fmtprint(fp, "undefined"); return fmtprint(fp, "undefined");
case TUNSAFEPTR:
if(exporting)
return fmtprint(fp, "\"unsafe\".Pointer");
return fmtprint(fp, "unsafe.Pointer");
} }
// Don't know how to handle - fall back to detailed prints. // Don't know how to handle - fall back to detailed prints.
@ -1346,6 +1351,9 @@ Tconv(Fmt *fp)
} }
} }
if(sharp || exporting)
fatal("missing %E case during export", t->etype);
et = t->etype; et = t->etype;
fmtprint(fp, "%E ", et); fmtprint(fp, "%E ", et);
if(t->sym != S) if(t->sym != S)
@ -1864,7 +1872,7 @@ assignop(Type *src, Type *dst, char **why)
if(why != nil) if(why != nil)
*why = ""; *why = "";
if(safemode && (isptrto(src, TANY) || isptrto(dst, TANY))) { if(safemode && src != T && src->etype == TUNSAFEPTR) {
yyerror("cannot use unsafe.Pointer"); yyerror("cannot use unsafe.Pointer");
errorexit(); errorexit();
} }
@ -2028,11 +2036,11 @@ convertop(Type *src, Type *dst, char **why)
} }
// 8. src is a pointer or uintptr and dst is unsafe.Pointer. // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
if((isptr[src->etype] || src->etype == TUINTPTR) && isptrto(dst, TANY)) if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR)
return OCONVNOP; return OCONVNOP;
// 9. src is unsafe.Pointer and dst is a pointer or uintptr. // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
if(isptrto(src, TANY) && (isptr[dst->etype] || dst->etype == TUINTPTR)) if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR))
return OCONVNOP; return OCONVNOP;
return 0; return 0;

View File

@ -318,7 +318,7 @@ reswitch:
n->left = N; n->left = N;
goto ret; goto ret;
} }
if(!isptr[t->etype] || (t->type != T && t->type->etype == TANY) /* unsafe.Pointer */) { if(!isptr[t->etype]) {
yyerror("invalid indirect of %+N", n->left); yyerror("invalid indirect of %+N", n->left);
goto error; goto error;
} }
@ -1316,7 +1316,7 @@ ret:
// TODO(rsc): should not need to check importpkg, // TODO(rsc): should not need to check importpkg,
// but reflect mentions unsafe.Pointer. // but reflect mentions unsafe.Pointer.
if(safemode && !incannedimport && !importpkg && isptrto(t, TANY)) if(safemode && !incannedimport && !importpkg && t->etype == TUNSAFEPTR)
yyerror("cannot use unsafe.Pointer"); yyerror("cannot use unsafe.Pointer");
evconst(n); evconst(n);

View File

@ -8,7 +8,7 @@
package PACKAGE package PACKAGE
type Pointer *any type Pointer uintptr // not really; filled in by compiler
func Offsetof(any) int func Offsetof(any) int
func Sizeof(any) int func Sizeof(any) int

View File

@ -11,4 +11,5 @@ import "unsafe"
func main() { func main() {
var x unsafe.Pointer var x unsafe.Pointer
println(*x) // ERROR "invalid indirect.*unsafe.Pointer" println(*x) // ERROR "invalid indirect.*unsafe.Pointer"
var _ = (unsafe.Pointer)(nil).foo // ERROR "no field or method foo"
} }