Title
Restrictions on declarators with late-specified return types
Status
cd1
Section
9.3.4.6 [dcl.fct]
Submitter
Mike Miller

Created on 2008-03-10.00:00:00 last changed 196 months ago

Messages

Date: 2008-09-15.00:00:00

[Voted into the WP at the September, 2008 meeting as part of paper N2757.]

Date: 2008-06-15.00:00:00

Proposed resolution (June, 2008):

  1. Change the grammar in 9.3 [dcl.decl] paragraph 4 as follows:

    • declarator:
        direct-declarator
        ptr-operator declarator

        ptr-declarator
        noptr-declarator parameters-and-qualifiers -> type-id

      ptr-declarator:
        noptr-declarator
        ptr-operator ptr-declarator

      direct-declarator:
      noptr-declarator:
        declarator-id
        direct-declarator ( parameter-declaration-clause )
          cv-qualifier-seqopt ref-qualifieropt exception-specificationopt
        direct-declarator( parameter-declaration-clause )
          cv-qualifier-seqopt ref-qualifieropt exception-specificationopt -> type-id
        direct-declarator [ constant-expressionopt ]
        noptr-declarator parameters-and-qualifiers
        noptr-declarator [ constant-expressionopt ]

        ( ptr-declarator )

      parameters-and-qualifiers:
        ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt
      ...
  2. Change the grammar in 9.3.2 [dcl.name] paragraph 1 as follows:

    • ...
      abstract-declarator:
        ptr-operator abstract-declaratoropt
        direct-abstract-declarator

        ptr-abstract-declarator
        noptr-abstract-declaratoropt parameters-and-qualifiers -> type-id

        ...

      ptr-abstract-declarator:
        noptr-abstract-declarator
        ptr-operator ptr-abstract-declaratoropt

      direct-abstract-declarator:
        direct-abstract-declaratoropt ( parameter-declaration-clause )
          cv-qualifier-seqopt ref-qualifieropt exception-specificationopt
        direct-abstract-declaratoropt ( parameter-declaration-clause )
          cv-qualifier-seqopt ref-qualifieropt exception-specificationopt -> type-id
        direct-abstract-declaratoropt [ constant-expressionopt ]

      noptr-abstract-declarator:
        noptr-abstract-declaratoropt parameters-and-qualifiers
        noptr-abstract-declaratoropt [ constant-expressionopt ]

        ( ptr-abstract-declarator )
  3. Change 9.3.4.6 [dcl.fct] paragraph 2 as follows:

  4. ... T shall be the single type-specifier auto and the derived-declarator-type-list shall be empty. Then the type...
  5. Change all occurrences of direct-new-declarator in 7.6.2.8 [expr.new] to noptr-new-declarator. These changes appear in the grammar in paragraph 1 and in the text of paragraphs 6-8, as follows:

    • ...
      new-declarator:
        ptr-operator new-declaratoropt
        direct-noptr-new-declarator

      direct-noptr-new-declarator:
        [ expression ]
        direct-noptr-new-declarator [ constant-expression ]
      ...

    When the allocated object is an array (that is, the direct-noptr-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array. [Note: both new int and new int[10] have type int* and the type of new int[i][10] is int (*)[10]end note]

    Every constant-expression in a direct-noptr-new-declarator shall be an integral constant expression (7.7 [expr.const]) and evaluate to a strictly positive value. The expression in a direct-noptr-new-declarator shall be of integral type, enumeration type, or a class type for which a single non-explicit conversion function to integral or enumeration type exists (11.4.8 [class.conv]). If the expression is of class type, the expression is converted by calling that conversion function, and the result of the conversion is used in place of the original expression. If the value of the expression is negative, the behavior is undefined. [Example: given the definition int n = 42, new float[n][5] is well-formed (because n is the expression of a direct-noptr-new-declarator), but new float[5][n] is ill-formed (because n is not a constant expression). If n is negative, the effect of new float[n][5] is undefined. —end example]

    When the value of the expression in a direct-noptr-new-declarator is zero, the allocation function is called to allocate an array with no elements.

Date: 2008-10-05.00:00:00

The wording added to 9.3.4.6 [dcl.fct] for declarators with late-specified return types says,

In a declaration T D where D has the form

    D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt -> type-id

and the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T,” T shall be the single type-specifier auto and the derived-declarator-type-list shall be empty.

These restrictions were intended to ensure that the return type of the function is exactly the specified type-id following the ->, not modified by declarator operators and cv-qualification.

Unfortunately, the requirement for an empty derived-declarator-type-list does not achieve this goal but instead forbids declarations like

    auto (*fp)() -> int;    // pointer to function returning int

while allowing declarations like

    auto *f() -> int;       // function returning pointer to int

The reason for this is that, according to the grammar in 9.3 [dcl.decl] paragraph 4, the declarator *f() -> int is parsed as a ptr-operator applied to the direct-declarator f() -> int; that is, the declarator D1 seen in 9.3.4.6 [dcl.fct] is just f, and the derived-declarator-type-list is thus empty.

By contrast, the declarator (*fp)() -> int is parsed as the direct-declarator (*fp) followed by the parameter-declaration-clause, etc. In this case, D1 in 9.3.4.6 [dcl.fct] is (*fp) and the derived-declarator-type-list is “pointer to,” i.e., not empty.

My personal view is that there is no reason to forbid the (*fp)() -> int form, and that doing so is problematic. For example, this restriction would require users desiring the late-specified return type syntax to write function parameters as function types and rely on parameter type transformations rather than writing them as pointer-to-function types, as they will actually turn out to be:

    void f(auto (*fp)() -> int);  // ill-formed
    void f(auto fp() -> int);     // OK (but icky)

It may be helpful in deciding whether to allow this form to consider the example of a function returning a pointer to a function. With the current restriction, only one of the three plausible forms is allowed:

    auto (*f())() -> int;           // Disallowed
    auto f() -> int (*)();          // Allowed
    auto f() -> auto (*)() -> int;  // Disallowed
Suggested resolution:
  1. Delete the words “and the derived-declarator-type-list shall be empty” from 9.3.4.6 [dcl.fct] paragraph 2.

  2. Add a new paragraph following 9.3 [dcl.decl] paragraph 4:

  3. A ptr-operator shall not be applied, directly or indirectly, to a function declarator with a late-specified return type (9.3.4.6 [dcl.fct]).
History
Date User Action Args
2008-10-05 00:00:00adminsetmessages: + msg1822
2008-10-05 00:00:00adminsetstatus: review -> cd1
2008-06-29 00:00:00adminsetmessages: + msg1701
2008-06-29 00:00:00adminsetstatus: open -> review
2008-03-10 00:00:00admincreate