Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Address of" operation on generic functions with type parameters #559

Open
Prabhuk opened this issue Sep 7, 2018 · 2 comments
Open

"Address of" operation on generic functions with type parameters #559

Prabhuk opened this issue Sep 7, 2018 · 2 comments
Labels
future work This labels issues that need further triaging and discussion.

Comments

@Prabhuk
Copy link
Collaborator

Prabhuk commented Sep 7, 2018

Generic functions in Checked C accept type parameters. There are two function specifiers that can be used for this.

  • _Itype_for_any (<COMMA_SEPARATED_TYPE_VARIABLES>)
  • _For_any(<COMMA_SEPARATED_TYPE_VARIABLES>)

e.g.
_Itype_for_any(T1, T2) void * myfunction(void * param1 : itype(_Ptr),
void * param2 : itype(_Ptr)
) : itype(_Ptr);

Currently, the "address of" operation can be performed on these functions without type parameters. This produces a value with generic function types.

e.g.
genericFunctionPointerVariable = &myfunction;

We must be able to supply concrete type parameters along with the address of operations.

e.g.
integerFunctionPointerVariable = &myfunction<int, int>

dtarditi added a commit that referenced this issue Oct 27, 2018
We implemented parsing of generic type applications as part of an intern
project.  The parsing code relied on detecting an occurrence of generic
function (or a function with a generic bounds-safe interface in a checked
scope). If either condition was met, the code assumed that a generic type
argument list must follow.  It tried to parse that type argument list to
create a type application.

Reimplement parsing of generic type applications so that it does not depend on
information from semantic checking.  Relying on information from semantic
checking is a potential sign that that grammer for ambiguous.

We treat generic type applications as postfix expression, with the
grammar production:

postfix-expression:
   postfix-expression < type argument list>

where type argument list consists of a comma separated list of zero
more type arguments.

This isn't ambiguous because the `<` operator cannot currently be
followed by a type name or '>'.  We just need to check the first token after
'<' to see if it is a type name or '>'.  Of course, there is an ambiguity in
the C grammar that an identifier could either by the name of a type or
the name of a variable.  We haven't made this worse.

Add a new diagnostic message for the case where a non-generic function
is applied to type arguments.  Before, there was just a parsing failure
of the form "expected expression".

This change partly addresses Github issue #559 (address of operator
on function with generic type parameters).  It now allows the address-of
operator to be applied to generic functions with type arguments.

Testing:
- Passes existing tests, except for these where a generic function
  is called without applying it to type arguments.
dtarditi added a commit that referenced this issue Oct 29, 2018
This change revises parsing and type substitution for generic functions.  Fix a number of bugs in the existing implementation.

The implementation of generic bounds-safe interfaces required that all calls involving checked arguments be supplied type arguments.  This increased the number of code changes required.  In unchecked or _Bounds_only contexts, allow the type arguments to be omitted and supply void as the omitted type arguments. This allows existing code to work "as is" (i.e. keep implicit casts to _Array_ptr<void>).  We may revisit this at some point

Details:

1. Parsing of generic type applications depended on detecting an  occurrence of a generic function to parse a type argument list.  Reimplement parsing of generic type  applications so that it does not depend on information from semantic checking.

   Treat generic type applications as postfix expressions, with the grammar production:

    postfix-expression:
      postfix-expression < type argument list>

   where type argument list consists of a comma separated list of zero or more type arguments.

   In C, this isn't ambiguous because the `<` operator cannot be followed by a type name or '>'.  We just need to check the first token after '<' to see if it is a type name or '>'.  Of course, there is an ambiguity in
the C grammar that an identifier could either by a type name or variable name.  We haven't made this worse,
      
   I don't believe this is ambiguous for C++ assuming that recognizing a template application has higher precedence. A handful of clang tests that check compiler diagnostics for C++ templates broke, so I've enabled this production only for Checked C for now.
   
   The parsing change partly addresses Github issue #559 (address of operator on function with generic type parameters).  We now allow the address-of operator to be applied to generic functions with type arguments.

2. Refactor the code for applying a generic function type to type arguments. The implementation of type substitution was buggy and didn't substitute type arguments into bounds expressions.

   Move the substitution code from Parse into Sema so that we have access to TreeTransform. Also move the semantic checking for type applications to Sema.

   Use TreeTransform-based transformation to do type substitution for type applications so that it is correct for bounds expression (so that bounds expressions are rewritten).

   When checking call expressions, we expand count/byte_count bounds expressions to standard forms after doing substitution.  In the case where the interface type for a parameter is used to construct the
parameter bounds expression, we need to cast the argument to the interface type before expansion.  Otherwise we end up with arithmetic on void pointers when generic bounds-safe interfaces are used.

3.  Improve diagnostics:
   Add diagnostics for the different ways redeclarations of functions  can be incompatible due generic quantifiers.
      - The quantifiers can be mismatched.
      - The number of type variables can be mismatched.
      - One type can be declared as generic and the other type as
     non-generic.
    
    Add a new diagnostic message for the case where a non-generic function is applied to type arguments.

4. Fix bugs in the existing implementation:
   1. The calculation of nesting depths of type variables (the number   of generic quantifiers enclosing a type variable) was wrong.   All type variables were being assigned a depth of 0, which would cause substitution in types involving higher-order polymorphic functions to go wrong.
   2. Fix type compatibility for generic, itype generic, and non-generic  function types.
   - Generic types are compatible with generic types.
   - Non-generic types are compatible with non-generic types.
   - Itype generic types are compatible with other itype generic types or non-generic types.
   - All other combinations of generic, itype generics, and non-generic functions are incompatible.
   Also, merging of function types wasn't working properly for itype generic functions.
   3.  Dumping of itype generic functions differed from generic functions.
   4. Scope handling of scopes created for generic and itype generic functions was often wrong.  In particular, we weren't always exiting the scope in some cases.  I fixed all the spots I could find, but the   handling of this remains brittle and bug prone.  The issue is that we treat the quantifier as being part of the decl spec, so we introduce  the new scope during parsing of decl specifiers.  That means we have to be sure to exit the scope when we are done with the declaration.
   5. When adding function declarations to scopes, we didn't properly go to the enclosing scope when the function was an `itype forall`.
   6. The Profile function for type variables wasn't including whether the type variable is for a bounds-safe interface. This caused  `_Itype_for_any` type variables and `_For_any type` variables to become confused with each other, which led to test failures.

Testing:
- Add more tests of AST construction for generic functions, including new tests for higher-order generic functions (generic functions that take other generic functions as arguments).
- Add tests of AST construction for type applications of generic functions, where type arguments are substited for type parameters.
- In the Checked C repo, add tests of new diagnostics for types that are incompatible due properties of generic types.
- Update existing tests of AST dumping of type variables.
- Passed automated testing for update Checked C, Checked C clang, and and clang tests on Linux.  Passed testing on Windows x64 locally.
@dtarditi
Copy link
Contributor

We can express this syntactically now with PR #581. We can take the address of generic functions and generic function instantiations. We still need to test this further.

When we implement type variables with representation information, we need to implement restrictions on taking the addresses of generic function instantiations. For parameter/return types, we have to make sure that the instantiated argument/return types have the same calling convention as the argument/return types using the representation type instead.

For example, suppose we have a functionforany(T).f(T arg that has a type parameter T that uses 4-byte integers as the representation for T. It might be OK to call f<float> because at calls, we can convert floats to the 4-byte integer representation. On some architectures floating point numbers are passed differently than integers. But taking the address of f might not be OK, because we would not know to do the conversion at indirect calls.

@lenary
Copy link
Collaborator

lenary commented Jan 14, 2019

I believe we need these (calling convention-related) restrictions on all instantiations though, rather than solely for the address-of operator. The caveat is I have potentially failed to consider a point in the design space, please do correct me if I’m wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
future work This labels issues that need further triaging and discussion.
Projects
None yet
Development

No branches or pull requests

4 participants