[Issue 10979] New: Add trait for function callgraph extraction, to allow "builtin attribute"-style UDA semantic checks

d-bugmail at puremagic.com d-bugmail at puremagic.com
Fri Sep 6 08:07:49 PDT 2013


http://d.puremagic.com/issues/show_bug.cgi?id=10979

           Summary: Add trait for function callgraph extraction, to allow
                    "builtin attribute"-style UDA semantic checks
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody at puremagic.com
        ReportedBy: andrej.mitrovich at gmail.com


--- Comment #0 from Andrej Mitrovic <andrej.mitrovich at gmail.com> 2013-09-06 08:07:47 PDT ---
Currently, attributes such as @safe work on the entire possible callgraph of a
function, meaning:

-----
void _safe(bool state) @safe
{
    if (state)
        foo();
    else
        bar(); // error, can't call system function 'bar'
}

void foo() @safe
{
}

void bar()
{
}
-----

However for user-defined types we currently cannot implement such semantic
checks, even if we used compile-time checking using traits and static asserts.

The user should be able to extract the entire possible callgraph tree of a
function, and then use this to implement his own semantic checks via a
template.

Here's an example use-case and some pseudo-code on how this might look:

-----
enum NoMalloc;  // UDA type

// this may or may not allocate and therefore breaks the @NoMalloc guarantee.
void func(bool state) @NoMalloc
{
    if (state)
        does_allocate();
    else
        does_not_allocate();
}

void does_not_allocate() @NoMalloc { }
void does_allocate() { }

/**
    Ensure that $(D func) defines the semantics of @NoMalloc:
    making sure it itself is marked with @NoMalloc, and that
    all the functions in the callgraph are @NoMalloc as well,
    and that none of the functions in the callgraph are the
    druntime function $(D malloc).
*/
template CheckNoMalloc(alias func)
{
    // pseudocode
    static assert(hasUDA!(func, NoMalloc));

    // pseudocode
    foreach (callfunc; getCallgraph!func)
    {
        // a more appropriate check could be made
        static assert(!is(callfunc == core.stdc.malloc) ||
                      hasUDA!(callfunc, NoMalloc));
    }
}

void main()
{
    // user-defined check (usually part of a constraint)
    CheckNoMalloc!func;
    func();
}
-----

The 'CheckNoMalloc' template can then be used in e.g. template constraints, to
verify that a function can only call other @NoMalloc functions, and that none
of these functions ever call the druntime function malloc (yes it's only an
extern(C) declaration, but any check could be made here).

This is just one example use-case, there could potentially be many more.

Of course, the downside of the malloc check is can't be 100% reliable, since
user-code could internally define an extern(C) function, or could use pointers
to get to a function that uses a function such as 'malloc'.

So that particular check may not be too reliable, but the benefit is the
ability to add semantic checking to UDAs based on the possible callgraph, so
you could implement pure/trusted-style UDAs that work recursively.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list