Valid-dirdeclor
Validate a direct declarator.
- Signature
(valid-dirdeclor dirdeclor fundef-params-p type table ienv)
→
(mv erp new-dirdeclor new-fundef-params-p
new-type ident return-types new-table)
- Arguments
- dirdeclor — Guard (dirdeclorp dirdeclor).
- fundef-params-p — Guard (booleanp fundef-params-p).
- type — Guard (typep type).
- table — Guard (valid-tablep table).
- ienv — Guard (ienvp ienv).
- Returns
- new-dirdeclor — Type (dirdeclorp new-dirdeclor).
- new-fundef-params-p — Type (booleanp new-fundef-params-p).
- new-type — Type (typep new-type).
- ident — Type (identp ident).
- return-types — Type (type-setp return-types).
- new-table — Type (valid-tablep new-table).
The type passed as input is the one resulting from the validation of
the list of declaration specifiers
or the list of specifiers and qualifiers
that precedes the declarator of which the direct declarator is part.
This type is refined according to the direct declarator,
and we return the refined type,
along with the declared identifier.
The meaning of the fundef-params-p flag passed as input is
the same as in valid-declor: see that function's documentation.
If the direct declarator is just an identifier,
the type is not further refined by this direct declarator.
If the direct declarator is a parenthesized declarator,
we recursively validate the declarator.
If the direct declarator is one of the array kinds,
we refine the type to the array type [C:6.7.6.2/3]
(so in our currently approximate type system
the input type is effectively ignored),
and we recursively validate the enclosed direct declarator.
Then we validate the index expression (if present),
ensuring that it has integer type.
For now we do not check that, if these expressions are constant,
their values are greater than 0 [C:6.7.6.2/1].
Currently we do not need to do anything
with type qualifiers and attributes.
The fundef-params-p flag is threaded through.
If the direct declarator is one of the function kinds,
we ensure that the input type, which is the function return type,
is not a function or array type [C:6.7.6.3/1].
We refine the input type to a function type
(which in our current type system means we override it),
and we validate the declarator.
Then things differ between the kinds of function declarators.
In a function declarator with a parameter type list,
we push a new scope for the parameters,
and we validate the parameters (which adds them to the new scope),
passing the fundef-params-p resulting from
the recursive validation of the enclosed direct declarator.
This resulting flag is t if
the parameters of the function being defined
have not been validated yet,
which means that the parameters of the current direct declarator
are in fact the ones of the function.
So we return nil as the new-fundef-params-p result,
so that any outer function declarator
is not treated as the one
whose parameters are for the function definition,
if we are validating one.
To make things clearer, consider a function definition
void (*f(int x, int y))(int z) { ... }
which defines a function f with parameters x and y,
which returns a pointer to a function
that has a parameter z and returns void.
When we validate the full declarator of this function definition,
fundef-params-p is t.
When we encounter the outer function declarator,
first we recursively process the inner function declarator,
whose input fundef-params-p is still t,
and whose output new-fundef-params-p is nil.
That way, when we continue validating the outer function declarator,
we do not treat z as a parameter of the function definition.
In any case, when the current function declarator
is the one whose parameters are for the function definition,
i.e. when fundef-params-p is t,
after validating the parameters, which pushes a new scope with them,
we return the validation table as such,
so that when we later validate the function body,
we already have the top-level scope for the body.
If instead fundef-params-p is nil,
the parameters form a function prototype scope [C:6.2.1/4],
which is therefore popped.
For the function declarator with a parameter type list,
we handle the special case of a single void [C:6.7.6.3/10]
before calling a separate function to validate the parameters.
A function declarator with a non-empty name list can only occur
as the parameters of a function being defined [C:6.7.6.3/3]
Thus, unless the list is empty,
we raise an error unless fundef-params-p is t,
i.e. unless we are validating the parameters of a defined function.
Note that the value of fundef-params-p is the one
after validating the inner direct declarator.
If we are not validating the declarator of a function definition
(i.e. if fundef-params-p is nil),
in which case as just mentioned the list must be empty,
there is nothing left to do, and we return;
note that there is no function prototype scope here.
Otherwise, we ensure that the names have no duplicates,
and we push a new scope for the parameters and the function body,
but we do not add the parameters to the new scope,
because their types are specified by the declarations
that must occur between the end of the whole function declarator
and the beginning of the defined function's body.