view dmd2/access.c @ 945:03d7c4aac654

SWITCHED TO LLVM 2.5 ! Applied patch from ticket #129 to compile against latest LLVM. Thanks Frits van Bommel. Fixed implicit return by asm block at the end of a function on x86-32. Other architectures will produce an error at the moment. Adding support for new targets is fairly simple. Fixed return calling convention for complex numbers, ST and ST(1) were switched around. Added some testcases. I've run a dstress test and there are no regressions. However, the runtime does not seem to compile with symbolic debug information. -O3 -release -inline works well and is what I used for the dstress run. Tango does not compile, a small workaround is needed in tango.io.digest.Digest.Digest.hexDigest. See ticket #206 .
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sun, 08 Feb 2009 05:26:54 +0100
parents f04dde6e882c
children 638d16625da2
line wrap: on
line source


// Copyright (c) 1999-2006 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "root.h"
#include "mem.h"

#include "enum.h"
#include "aggregate.h"
#include "init.h"
#include "attrib.h"
#include "scope.h"
#include "id.h"
#include "mtype.h"
#include "declaration.h"
#include "aggregate.h"
#include "expression.h"
#include "module.h"

#define LOG 0

/* Code to do access checks
 */

int hasPackageAccess(Scope *sc, Dsymbol *s);

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

enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
{
    return PROTpublic;
}

enum PROT StructDeclaration::getAccess(Dsymbol *smember)
{
    enum PROT access_ret = PROTnone;

#if LOG
    printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
	toChars(), smember->toChars());
#endif
    if (smember->toParent() == this)
    {
	access_ret = smember->prot();
    }
    else if (smember->isDeclaration()->isStatic())
    {
	access_ret = smember->prot();
    }
    return access_ret;
}

enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
{
    enum PROT access_ret = PROTnone;

#if LOG
    printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
	toChars(), smember->toChars());
#endif
    if (smember->toParent() == this)
    {
	access_ret = smember->prot();
    }
    else
    {
	enum PROT access;
	int i;

	if (smember->isDeclaration()->isStatic())
	{
	    access_ret = smember->prot();
	}

	for (i = 0; i < baseclasses.dim; i++)
	{   BaseClass *b = (BaseClass *)baseclasses.data[i];

	    access = b->base->getAccess(smember);
	    switch (access)
	    {
		case PROTnone:
		    break;

		case PROTprivate:
		    access = PROTnone;	// private members of base class not accessible
		    break;

		case PROTpackage:
		case PROTprotected:
		case PROTpublic:
		case PROTexport:
		    // If access is to be tightened
		    if (b->protection < access)
			access = b->protection;

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

		default:
		    assert(0);
	    }
	}
    }
#if LOG
    printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
	toChars(), smember->toChars(), access_ret);
#endif
    return access_ret;
}

/********************************************************
 * Helper function for ClassDeclaration::accessCheck()
 * Returns:
 *	0	no access
 * 	1	access
 */

static int accessCheckX(
	Dsymbol *smember,
	Dsymbol *sfunc,
	AggregateDeclaration *dthis,
	AggregateDeclaration *cdscope)
{
    assert(dthis);

#if 0
    printf("accessCheckX for %s.%s in function %s() in scope %s\n",
	dthis->toChars(), smember->toChars(),
	sfunc ? sfunc->toChars() : "NULL",
	cdscope ? cdscope->toChars() : "NULL");
#endif
    if (dthis->hasPrivateAccess(sfunc) ||
	dthis->isFriendOf(cdscope))
    {
	if (smember->toParent() == dthis)
	    return 1;
	else
	{
	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
	    if (cdthis)
	    {
		for (int i = 0; i < cdthis->baseclasses.dim; i++)
		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
		    enum PROT access;

		    access = b->base->getAccess(smember);
		    if (access >= PROTprotected ||
			accessCheckX(smember, sfunc, b->base, cdscope)
		       )
			return 1;

		}
	    }
	}
    }
    else
    {
	if (smember->toParent() != dthis)
	{
	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
	    if (cdthis)
	    {
		for (int i = 0; i < cdthis->baseclasses.dim; i++)
		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];

		    if (accessCheckX(smember, sfunc, b->base, cdscope))
			return 1;
		}
	    }
	}
    }
    return 0;
}

/*******************************
 * Do access check for member of this class, this class being the
 * type of the 'this' pointer used to access smember.
 */

void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
{
    int result;

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

#if LOG
    printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
	toChars(), smember->toChars(),
	f ? f->toChars() : NULL,
	cdscope ? cdscope->toChars() : NULL);
#endif

    Dsymbol *smemberparent = smember->toParent();
    if (!smemberparent || !smemberparent->isAggregateDeclaration())
    {
#if LOG
	printf("not an aggregate member\n");
#endif
	return;				// then it is accessible
    }

    // BUG: should enable this check
    //assert(smember->parent->isBaseOf(this, NULL));

    if (smemberparent == this)
    {	enum PROT access = smember->prot();

	result = access >= PROTpublic ||
		hasPrivateAccess(f) ||
		isFriendOf(cdscope) ||
		(access == PROTpackage && hasPackageAccess(sc, this));
#if LOG
	printf("result1 = %d\n", result);
#endif
    }
    else if ((access = this->getAccess(smember)) >= PROTpublic)
    {
	result = 1;
#if LOG
	printf("result2 = %d\n", result);
#endif
    }
    else if (access == PROTpackage && hasPackageAccess(sc, this))
    {
	result = 1;
#if LOG
	printf("result3 = %d\n", result);
#endif
    }
    else
    {
	result = accessCheckX(smember, f, this, cdscope);
#if LOG
	printf("result4 = %d\n", result);
#endif
    }
    if (!result)
    {
	error(loc, "member %s is not accessible", smember->toChars());
halt();
    }
}

/****************************************   
 * Determine if this is the same or friend of cd.
 */

int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
{
#if LOG
    printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
#endif
    if (this == cd)
	return 1;

    // Friends if both are in the same module
    //if (toParent() == cd->toParent())
    if (cd && getModule() == cd->getModule())
    {
#if LOG
	printf("\tin same module\n");
#endif
	return 1;
    }

#if LOG
    printf("\tnot friend\n");
#endif
    return 0;
}

/****************************************
 * Determine if scope sc has package level access to s.
 */

int hasPackageAccess(Scope *sc, Dsymbol *s)
{
#if LOG
    printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
#endif

    for (; s; s = s->parent)
    {
	if (s->isPackage() && !s->isModule())
	    break;
    }
#if LOG
    if (s)
	printf("\tthis is in package '%s'\n", s->toChars());
#endif

    if (s && s == sc->module->parent)
    {
#if LOG
	printf("\ts is in same package as sc\n");
#endif
	return 1;
    }


#if LOG
    printf("\tno package access\n");
#endif
    return 0;
}

/**********************************
 * Determine if smember has access to private members of this declaration.
 */

int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
{
    if (smember)
    {	AggregateDeclaration *cd = NULL;
	Dsymbol *smemberparent = smember->toParent();
	if (smemberparent)
	    cd = smemberparent->isAggregateDeclaration();

#if LOG
	printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
		toChars(), smember->toChars());
#endif

	if (this == cd)		// smember is a member of this class
	{
#if LOG
	    printf("\tyes 1\n");
#endif
	    return 1;		// so we get private access
	}

	// If both are members of the same module, grant access
	while (1)
	{   Dsymbol *sp = smember->toParent();
	    if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
		smember = sp;
	    else
		break;
	}
	if (!cd && toParent() == smember->toParent())
	{
#if LOG
	    printf("\tyes 2\n");
#endif
	    return 1;
	}
	if (!cd && getModule() == smember->getModule())
	{
#if LOG
	    printf("\tyes 3\n");
#endif
	    return 1;
	}
    }
#if LOG
    printf("\tno\n");
#endif
    return 0;
}

/****************************************
 * Check access to d for expression e.d
 */

void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
{
#if LOG
    if (e)
    {	printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
	printf("\te->type = %s\n", e->type->toChars());
    }
    else
    {
	//printf("accessCheck(%s)\n", d->toChars());
    }
#endif
    if (!e)
    {
	if (d->prot() == PROTprivate && d->getModule() != sc->module ||
	    d->prot() == PROTpackage && !hasPackageAccess(sc, d))

	    error(loc, "%s %s.%s is not accessible from %s",
		d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars());
    }
    else if (e->type->ty == Tclass)
    {   // Do access check
	ClassDeclaration *cd;

	cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
#if 1
	if (e->op == TOKsuper)
	{   ClassDeclaration *cd2;

	    cd2 = sc->func->toParent()->isClassDeclaration();
	    if (cd2)
		cd = cd2;
	}
#endif
	cd->accessCheck(loc, sc, d);
    }
    else if (e->type->ty == Tstruct)
    {   // Do access check
	StructDeclaration *cd;

	cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
	cd->accessCheck(loc, sc, d);
    }
}