Skip to content

Commit

Permalink
Merge pull request #3651 from Dicebot/package-protection
Browse files Browse the repository at this point in the history
Fix #2529: explicit protection package
  • Loading branch information
WalterBright committed Aug 26, 2014
2 parents 39d3dc6 + 9873073 commit a41dccc
Show file tree
Hide file tree
Showing 39 changed files with 517 additions and 133 deletions.
81 changes: 45 additions & 36 deletions src/access.c
Expand Up @@ -37,12 +37,12 @@ bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember);
bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd);

/****************************************
* Return PROT access for Dsymbol smember in this declaration.
* Return Prot access for Dsymbol smember in this declaration.
*/

PROT getAccess(AggregateDeclaration *ad, Dsymbol *smember)
Prot getAccess(AggregateDeclaration *ad, Dsymbol *smember)
{
PROT access_ret = PROTnone;
Prot access_ret = PROTnone;

#if LOG
printf("+AggregateDeclaration::getAccess(this = '%s', smember = '%s')\n",
Expand All @@ -64,8 +64,8 @@ PROT getAccess(AggregateDeclaration *ad, Dsymbol *smember)
{
BaseClass *b = (*cd->baseclasses)[i];

PROT access = getAccess(b->base, smember);
switch (access)
Prot access = getAccess(b->base, smember);
switch (access.kind)
{
case PROTnone:
break;
Expand All @@ -79,11 +79,11 @@ PROT getAccess(AggregateDeclaration *ad, Dsymbol *smember)
case PROTpublic:
case PROTexport:
// If access is to be tightened
if (b->protection < access)
if (b->protection.isMoreRestrictiveThan(access))
access = b->protection;

// Pick path with loosest access
if (access > access_ret)
if (access_ret.isMoreRestrictiveThan(access))
access_ret = access;
break;

Expand Down Expand Up @@ -133,8 +133,8 @@ static int accessCheckX(
{
for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
{ BaseClass *b = (*cdthis->baseclasses)[i];
PROT access = getAccess(b->base, smember);
if (access >= PROTprotected ||
Prot access = getAccess(b->base, smember);
if (access.kind >= PROTprotected ||
accessCheckX(smember, sfunc, b->base, cdscope)
)
return 1;
Expand Down Expand Up @@ -173,7 +173,7 @@ void accessCheck(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)

FuncDeclaration *f = sc->func;
AggregateDeclaration *cdscope = sc->getStructClassScope();
PROT access;
Prot access;

#if LOG
printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
Expand All @@ -196,24 +196,24 @@ void accessCheck(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)

if (smemberparent == ad)
{
PROT access2 = smember->prot();
result = access2 >= PROTpublic ||
Prot access2 = smember->prot();
result = access2.kind >= PROTpublic ||
hasPrivateAccess(ad, f) ||
isFriendOf(ad, cdscope) ||
(access2 == PROTpackage && hasPackageAccess(sc, ad)) ||
(access2.kind == PROTpackage && hasPackageAccess(sc, ad)) ||
ad->getAccessModule() == sc->module;
#if LOG
printf("result1 = %d\n", result);
#endif
}
else if ((access = getAccess(ad, smember)) >= PROTpublic)
else if ((access = getAccess(ad, smember)).kind >= PROTpublic)
{
result = 1;
#if LOG
printf("result2 = %d\n", result);
#endif
}
else if (access == PROTpackage && hasPackageAccess(sc, ad))
else if (access.kind == PROTpackage && hasPackageAccess(sc, ad))
{
result = 1;
#if LOG
Expand Down Expand Up @@ -270,39 +270,48 @@ bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd)
bool hasPackageAccess(Scope *sc, Dsymbol *s)
{
#if LOG
printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
printf("hasPackageAccess(s = '%s', sc = '%p', s->protection.pkg = '%s')\n",
s->toChars(), sc,
s->prot().pkg ? s->prot().pkg->toChars() : "NULL");
#endif

Package *pkg = NULL;
for (; s; s = s->parent)

if (s->prot().pkg)
pkg = s->prot().pkg;
else
{
if (Module *m = s->isModule())
// no explicit package for protection, inferring most qualified one
for (; s; s = s->parent)
{
DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL);
assert(dst);
Dsymbol *s2 = dst->lookup(m->ident);
assert(s2);
Package *p = s2->isPackage();
if (p && p->isPackageMod())
if (Module *m = s->isModule())
{
pkg = p;
break;
DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL);
assert(dst);
Dsymbol *s2 = dst->lookup(m->ident);
assert(s2);
Package *p = s2->isPackage();
if (p && p->isPackageMod())
{
pkg = p;
break;
}
}
else if ((pkg = s->isPackage()) != NULL)
break;
}
else if ((pkg = s->isPackage()) != NULL)
break;
}
#if LOG
if (pkg)
printf("\tthis is in package '%s'\n", pkg->toChars());
printf("\tsymbol access binds to package '%s'\n", pkg->toChars());
#endif

if (pkg)
{
if (pkg == sc->module->parent)
{
#if LOG
printf("\ts is in same package as sc\n");
printf("\tsc is in permitted package for s\n");
#endif
return true;
}
Expand All @@ -313,13 +322,13 @@ bool hasPackageAccess(Scope *sc, Dsymbol *s)
#endif
return true;
}
s = sc->module->parent;
for (; s; s = s->parent)
Dsymbol* ancestor = sc->module->parent;
for (; ancestor; ancestor = ancestor->parent)
{
if (s == pkg)
if (ancestor == pkg)
{
#if LOG
printf("\ts is in ancestor package of sc\n");
printf("\tsc is in permitted ancestor package for s\n");
#endif
return true;
}
Expand Down Expand Up @@ -415,8 +424,8 @@ void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
}
if (!e)
{
if (d->prot() == PROTprivate && d->getAccessModule() != sc->module ||
d->prot() == PROTpackage && !hasPackageAccess(sc, d))
if (d->prot().kind == PROTprivate && d->getAccessModule() != sc->module ||
d->prot().kind == PROTpackage && !hasPackageAccess(sc, d))
{
error(loc, "%s %s is not accessible from module %s",
d->kind(), d->toPrettyChars(), sc->module->toChars());
Expand Down
8 changes: 4 additions & 4 deletions src/aggregate.h
Expand Up @@ -67,7 +67,7 @@ class AggregateDeclaration : public ScopeDsymbol
public:
Type *type;
StorageClass storage_class;
PROT protection;
Prot protection;
unsigned structsize; // size of struct
unsigned alignsize; // size of struct for alignment purposes
VarDeclarations fields; // VarDeclaration fields
Expand Down Expand Up @@ -118,7 +118,7 @@ class AggregateDeclaration : public ScopeDsymbol
bool isExport();
Dsymbol *searchCtor();

PROT prot();
Prot prot();

Type *handleType() { return type; } // 'this' type

Expand Down Expand Up @@ -194,7 +194,7 @@ class UnionDeclaration : public StructDeclaration
struct BaseClass
{
Type *type; // (before semantic processing)
PROT protection; // protection for the base interface
Prot protection; // protection for the base interface

ClassDeclaration *base;
unsigned offset; // 'this' pointer offset
Expand All @@ -207,7 +207,7 @@ struct BaseClass
BaseClass *baseInterfaces;

BaseClass();
BaseClass(Type *type, PROT protection);
BaseClass(Type *type, Prot protection);

bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
void copyBaseInterfaces(BaseClasses *);
Expand Down
95 changes: 90 additions & 5 deletions src/attrib.c
Expand Up @@ -70,13 +70,13 @@ int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param)
* the scope after it used.
*/
Scope *AttribDeclaration::createNewScope(Scope *sc,
StorageClass stc, LINK linkage, PROT protection, int explicitProtection,
StorageClass stc, LINK linkage, Prot protection, int explicitProtection,
structalign_t structalign)
{
Scope *sc2 = sc;
if (stc != sc->stc ||
linkage != sc->linkage ||
protection != sc->protection ||
!protection.isSubsetOf(sc->protection) ||
explicitProtection != sc->explicitProtection ||
structalign != sc->structalign)
{
Expand Down Expand Up @@ -540,24 +540,109 @@ char *LinkDeclaration::toChars()

/********************************* ProtDeclaration ****************************/

ProtDeclaration::ProtDeclaration(PROT p, Dsymbols *decl)
/**
* Params:
* loc = source location of attribute token
* p = protection attribute data
* decl = declarations which are affected by this protection attribute
*/
ProtDeclaration::ProtDeclaration(Loc loc, Prot p, Dsymbols *decl)
: AttribDeclaration(decl)
{
protection = p;
this->loc = loc;
this->protection = p;
this->pkg_identifiers = NULL;
//printf("decl = %p\n", decl);
}

/**
* Params:
* loc = source location of attribute token
* pkg_identifiers = list of identifiers for a qualified package name
* decl = declarations which are affected by this protection attribute
*/
ProtDeclaration::ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl)
: AttribDeclaration(decl)
{
this->loc = loc;
this->protection.kind = PROTpackage;
this->protection.pkg = NULL;
this->pkg_identifiers = pkg_identifiers;
}

Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
{
assert(!s);
return new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl));
if (protection.kind == PROTpackage)
return new ProtDeclaration(this->loc, pkg_identifiers, Dsymbol::arraySyntaxCopy(decl));
else
return new ProtDeclaration(this->loc, protection, Dsymbol::arraySyntaxCopy(decl));
}

Scope *ProtDeclaration::newScope(Scope *sc)
{
if (pkg_identifiers)
semantic(sc);
return createNewScope(sc, sc->stc, sc->linkage, this->protection, 1, sc->structalign);
}

void ProtDeclaration::semantic(Scope* sc)
{
if (pkg_identifiers)
{
Dsymbol* tmp;
Package::resolve(pkg_identifiers, &tmp, NULL);
protection.pkg = tmp ? tmp->isPackage() : NULL;
pkg_identifiers = NULL;
}

AttribDeclaration::semantic(sc);

if ((protection.kind == PROTpackage) && (protection.pkg != NULL) && sc->module)
{
Package* pkg = sc->module->parent->isPackage();
assert(pkg);
if (pkg && !protection.pkg->isAncestorPackageOf(pkg))
error("does not bind to one of ancestor packages of module '%s'",
sc->module->toPrettyChars(true));
}
}


const char *ProtDeclaration::kind()
{
return "protection attribute";
}

const char *ProtDeclaration::toPrettyChars(bool unused)
{
assert(protection.kind > PROTundefined);

const char* kind = protectionToChars(this->protection);

OutBuffer buffer;

if ((protection.kind == PROTpackage) && protection.pkg)
{
// 'package(name)'
const char* name = protection.pkg->toPrettyChars(true);
buffer.writestring("'");
buffer.writestring(kind);
buffer.writestring("(");
buffer.writestring(name);
buffer.writestring(")'");
return buffer.extractString();
}
else
{
// 'attrkind'
buffer.writestring("'");
buffer.writestring(kind);
buffer.writestring("'");
return buffer.extractString();
}
}

/********************************* AlignDeclaration ****************************/

AlignDeclaration::AlignDeclaration(unsigned sa, Dsymbols *decl)
Expand Down
12 changes: 9 additions & 3 deletions src/attrib.h
Expand Up @@ -36,7 +36,7 @@ class AttribDeclaration : public Dsymbol
virtual Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
int apply(Dsymbol_apply_ft_t fp, void *param);
static Scope *createNewScope(Scope *sc,
StorageClass newstc, LINK linkage, PROT protection, int explictProtection,
StorageClass newstc, LINK linkage, Prot protection, int explictProtection,
structalign_t structalign);
virtual Scope *newScope(Scope *sc);
int addMember(Scope *sc, ScopeDsymbol *sds, int memnum);
Expand Down Expand Up @@ -100,11 +100,17 @@ class LinkDeclaration : public AttribDeclaration
class ProtDeclaration : public AttribDeclaration
{
public:
PROT protection;
Prot protection;
Identifiers* pkg_identifiers;

ProtDeclaration(Loc loc, Prot p, Dsymbols *decl);
ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl);

ProtDeclaration(PROT p, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
const char *kind();
const char *toPrettyChars(bool unused);
void semantic(Scope* sc);
void accept(Visitor *v) { v->visit(this); }
};

Expand Down

0 comments on commit a41dccc

Please sign in to comment.