On Fri, Jan 10, 2025 at 3:18 AM Simon Martin <si...@nasilyan.com> wrote:
>
> We currently accept the following invalid code (EDG and MSVC do as well)

clang does too: https://github.com/llvm/llvm-project/issues/121706 .

Note it might be useful if a testcase with multiply `*` is included too:
```
struct A {
  ****A ();
};
```


Thanks,
Andrew

>
> === cut here ===
> struct A {
>   *A ();
> };
> === cut here ===
>
> The problem is that we end up in grokdeclarator with a cp_declarator of
> kind cdk_pointer but no type, and we happily go through (if we have a
> reference instead we eventually error out trying to form a reference to
> void).
>
> This patch makes sure that grokdeclarator errors out when processing a
> constructor or a conversion operator with no return type specified but
> also a declarator representing a pointer or a reference type.
>
> Successfully tested on x86_64-pc-linux-gnu. OK for GCC 16?
>
>         PR c++/118306
>
> gcc/cp/ChangeLog:
>
>         * decl.cc (check_special_function_return_type): Take declarator
>         and location as input. Reject return type specifiers with only
>         a * or &.
>         (grokdeclarator): Update call to
>         check_special_function_return_type.
>
> gcc/testsuite/ChangeLog:
>
>         * g++.dg/parse/constructor4.C: New test.
>         * g++.dg/parse/conv_op2.C: New test.
>         * g++.dg/parse/default_to_int.C: New test.
>
> ---
>  gcc/cp/decl.cc                              | 21 +++++++++---
>  gcc/testsuite/g++.dg/parse/constructor4.C   | 36 +++++++++++++++++++++
>  gcc/testsuite/g++.dg/parse/conv_op2.C       |  8 +++++
>  gcc/testsuite/g++.dg/parse/default_to_int.C | 33 +++++++++++++++++++
>  4 files changed, 94 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/parse/constructor4.C
>  create mode 100644 gcc/testsuite/g++.dg/parse/conv_op2.C
>  create mode 100644 gcc/testsuite/g++.dg/parse/default_to_int.C
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 5c6a4996a89..b57df261e76 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -101,7 +101,8 @@ static void end_cleanup_fn (void);
>  static tree cp_make_fname_decl (location_t, tree, int);
>  static void initialize_predefined_identifiers (void);
>  static tree check_special_function_return_type
> -       (special_function_kind, tree, tree, int, const location_t*);
> +       (special_function_kind, tree, tree, int, const cp_declarator*,
> +       location_t, const location_t*);
>  static tree push_cp_library_fn (enum tree_code, tree, int);
>  static tree build_cp_library_fn (tree, enum tree_code, tree, int);
>  static void store_parm_decls (tree);
> @@ -12349,9 +12350,9 @@ smallest_type_location (const cp_decl_specifier_seq 
> *declspecs)
>    return smallest_type_location (type_quals, declspecs->locations);
>  }
>
> -/* Check that it's OK to declare a function with the indicated TYPE
> -   and TYPE_QUALS.  SFK indicates the kind of special function (if any)
> -   that this function is.  OPTYPE is the type given in a conversion
> +/* Check that it's OK to declare a function at ID_LOC with the indicated 
> TYPE,
> +   TYPE_QUALS and DECLARATOR.  SFK indicates the kind of special function (if
> +   any) that this function is.  OPTYPE is the type given in a conversion
>     operator declaration, or the class type for a constructor/destructor.
>     Returns the actual return type of the function; that may be different
>     than TYPE if an error occurs, or for certain special functions.  */
> @@ -12361,8 +12362,19 @@ check_special_function_return_type 
> (special_function_kind sfk,
>                                     tree type,
>                                     tree optype,
>                                     int type_quals,
> +                                   const cp_declarator *declarator,
> +                                   location_t id_loc,
>                                     const location_t* locations)
>  {
> +  /* If TYPE is unspecified, DECLARATOR, if set, should not represent a 
> pointer
> +     or a reference type.  */
> +  if (type == NULL_TREE
> +      && declarator
> +      && (declarator->kind == cdk_pointer
> +         || declarator->kind == cdk_reference))
> +    error_at (id_loc, "expected unqualified-id before %qs token",
> +             declarator->kind == cdk_pointer ? "*" : "&");
> +
>    switch (sfk)
>      {
>      case sfk_constructor:
> @@ -13089,6 +13101,7 @@ grokdeclarator (const cp_declarator *declarator,
>        type = check_special_function_return_type (sfk, type,
>                                                  ctor_return_type,
>                                                  type_quals,
> +                                                declarator, id_loc,
>                                                  declspecs->locations);
>        type_quals = TYPE_UNQUALIFIED;
>      }
> diff --git a/gcc/testsuite/g++.dg/parse/constructor4.C 
> b/gcc/testsuite/g++.dg/parse/constructor4.C
> new file mode 100644
> index 00000000000..7d5a8ecaa97
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/parse/constructor4.C
> @@ -0,0 +1,36 @@
> +// PR c++/118306
> +// { dg-do "compile" }
> +
> +// Constructors.
> +struct A {
> +  *A ();           // { dg-error "expected unqualified-id" }
> +};
> +struct B {
> +  &B ();           // { dg-error "expected unqualified-id|reference to" }
> +};
> +struct C {
> +  *C (const C&);    // { dg-error "expected unqualified-id" }
> +};
> +struct D {
> +  &D (const D&);    // { dg-error "expected unqualified-id|reference to" }
> +};
> +struct E {
> +  const E();       // { dg-error "expected unqualified-id" }
> +};
> +
> +// Destructors.
> +struct F {
> +  * ~F ();         // { dg-error "expected unqualified-id" }
> +};
> +struct G {
> +  & ~G ();         // { dg-error "expected unqualified-id|reference to" }
> +};
> +struct H {
> +  virtual * ~H ();  // { dg-error "expected unqualified-id" }
> +};
> +struct I {
> +  virtual & ~I ();  // { dg-error "expected unqualified-id|reference to" }
> +};
> +struct J {
> +  volatile ~J();    // { dg-error "qualifiers are not allowed" }
> +};
> diff --git a/gcc/testsuite/g++.dg/parse/conv_op2.C 
> b/gcc/testsuite/g++.dg/parse/conv_op2.C
> new file mode 100644
> index 00000000000..33477de6274
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/parse/conv_op2.C
> @@ -0,0 +1,8 @@
> +// PR c++/118306
> +// { dg-do "compile" }
> +
> +struct K {
> +  char operator int(); // { dg-error "return type specified for" }
> +  * operator short();  // { dg-error "expected unqualified-id" }
> +  & operator long();   // { dg-error "expected unqualified-id" }
> +};
> diff --git a/gcc/testsuite/g++.dg/parse/default_to_int.C 
> b/gcc/testsuite/g++.dg/parse/default_to_int.C
> new file mode 100644
> index 00000000000..5c3ec37e007
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/parse/default_to_int.C
> @@ -0,0 +1,33 @@
> +// PR c++/118306 - "Document" various behaviours wrt. defaulting types to 
> int.
> +// { dg-do "compile" }
> +// { dg-additional-options "-fpermissive" }
> +
> +// Members.
> +struct K {
> +  * mem1;          // { dg-warning "forbids declaration" }
> +  const * mem2;            // { dg-warning "forbids declaration" }
> +  & mem3;          // { dg-warning "forbids declaration" }
> +  volatile & mem4;  // { dg-warning "forbids declaration" }
> +
> +  void foo (const& permissive_fine,            // { dg-warning "forbids 
> declaration" }
> +           volatile* permissive_fine_as_well); // { dg-warning "forbids 
> declaration" }
> +
> +  * bar () { return 0; }  // { dg-warning "forbids declaration" }
> +  const& baz ();         // { dg-warning "forbids declaration" }
> +
> +  void bazz () {
> +    try {}
> +    catch (const *i) {}        // { dg-warning "forbids" }
> +    catch (const &i) {}        // { dg-warning "forbids" }
> +  }
> +};
> +
> +// Template parameters.
> +template<const *i, const &j>  // { dg-warning "forbids" }
> +void baz() {}
> +
> +// Functions.
> +foo(int) { return 42; }                  // { dg-warning "forbids 
> declaration" }
> +*bar(int) { return 0; }                  // { dg-warning "forbids 
> declaration" }
> +const bazz (int) { return 0; }   // { dg-warning "forbids declaration" }
> +const* bazzz (int) { return 0; }  // { dg-warning "forbids declaration" }
> --
> 2.44.0
>

Reply via email to