Hi Jason,

On 7 Feb 2025, at 23:10, Jason Merrill wrote:

> On 2/7/25 4:04 PM, Simon Martin wrote:
>> Hi Jason,
>>
>> On 7 Feb 2025, at 14:21, Jason Merrill wrote:
>>
>>> On 2/6/25 3:05 PM, Simon Martin wrote:
>>>> Hi Jason,
>>>>
>>>> On 6 Feb 2025, at 16:48, Jason Merrill wrote:
>>>>
>>>>> On 2/5/25 2:21 PM, Simon Martin wrote:
>>>>>> Hi Jason,
>>>>>>
>>>>>> On 4 Feb 2025, at 21:23, Jason Merrill wrote:
>>>>>>
>>>>>>> On 2/4/25 3:03 PM, Jason Merrill wrote:
>>>>>>>> On 2/4/25 11:45 AM, Simon Martin wrote:
>>>>>>>>> On 4 Feb 2025, at 17:17, Jason Merrill wrote:
>>>>>>>>>
>>>>>>>>>> On 2/4/25 10:56 AM, Simon Martin wrote:
>>>>>>>>>>> Hi Jason,
>>>>>>>>>>>
>>>>>>>>>>> On 4 Feb 2025, at 16:39, Jason Merrill wrote:
>>>>>>>>>>>
>>>>>>>>>>>> On 1/15/25 9:56 AM, Jason Merrill wrote:
>>>>>>>>>>>>> On 1/15/25 7:24 AM, Simon Martin wrote:
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 14 Jan 2025, at 23:31, Jason Merrill wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On 1/14/25 2:13 PM, Simon Martin wrote:
>>>>>>>>>>>>>>>> On 10 Jan 2025, at 19:10, Andrew Pinski wrote:
>>>>>>>>>>>>>>>>> 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, makes sense to add those. Done in the attached
>>>>>>>>>>>>>>>> updated
>>>>>>>>>>>>>>>> revision,
>>>>>>>>>>>>>>>> successfully tested on x86_64-pc-linux-gnu.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +/* 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,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> id_loc should be the same as declarator->id_loc?
>>>>>>>>>>>>>> You’re right.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>                            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 ? 
>>>>>>>>>>>>>>>> "*"
>>>>>>>>>>>>>>>> :
>>>>>>>>>>>>>>>> "&");
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> ...and id_loc isn't the location of the ptr-operator, 

>>>>>>>>>>>>>>> it's
>>
>>>>>>>>>>>>>>> the
>>>>>>
>>>>>>>>>>>>>>> location of the identifier, so this indicates the wrong
>>>>>>>>>>>>>>> column.
>>>>>>>>>>>>>>> I
>>>>>>>>>>>>>>> think using declarator->id_loc makes sense, just not
>>>>>>>>>>>>>>> pretending
>>>>>>>>>>>>>>> it's
>>>>>>>>>>>>>>> the location of the *.
>>>>>>>>>>>>>> Good catch, thanks.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Let's give diagnostics more like the others later in the

>>>>>>>>>>>>>>> function
>>>>>>>>>>>>>>> instead of trying to emulate cp_parser_error.
>>>>>>>>>>>>>> Makes sense. This is what the updated patch does,
>>>>>>>>>>>>>> successfully
>>>>>>>>>>>>>> tested on
>>>>>>>>>>>>>> x86_64-pc-linux-gnu. OK for GCC 16?
>>>>>>>>>>>>>
>>>>>>>>>>>>> OK.
>>>>>>>>>>>>
>>>>>>>>>>>> Does this also fix 118304?  If so, let's go ahead and 
>>>>>>>>>>>> apply
>>>>>>>>>>>> it
>>>>>>>>>>>> to
>>>>>>>>>>>> GCC
>>>>>>>>>>>> 15.
>>>>>>>>>>> I have checked just now, and we still ICE for 118304’s
>>
>>>>>>>>>>> testcase
>>>>>>>>>>> with
>>>>>>>>>>> that fix.
>>>>>>>>>>
>>>>>>>>>> Why doesn't the preeexisting
>>>>>>>>>>
>>>>>>>>>> type = void_type_node;
>>>>>>>>>>
>>>>>>>>>> in check_special_function_return_type fix the return type and

>>>>>>>>>> avoid
>>>>>>
>>>>>>>>>> the ICE?
>>>>>>>>
>>>>>>>>> We hit the gcc_assert at method.cc:3593, that Marek’s fix
>>>>>>
>>>>>>>>> bypasses.
>>>>>>>>
>>>>>>>> Yes, but why doesn't check_special_function_return_type prevent

>>>>>>>> that?
>>>>>>>
>>>>>>> Ah, because we call it before walking the declarator.  We need 
>>>>>>> to
>>>>>>> check again later, perhaps in grokfndecl, that the type is
>>>>>>> correct.
>>>>>>> Perhaps instead of your patch.
>>>>>> One “issue” with adding another check in or close to 
>>>>>> grokfndecl
>>>>>> is
>>>>>> that DECLARATOR will have “been moved to the ID”, and the 
>>>>>> fact
>>>>>> that
>>>>>> we had a CDK_POINTER kind is “lost”. We could obviously 
>>>>>> somehow
>>>>>> propagate this information, but there might be something easier.
>>>>>
>>>>> The information isn't lost: it's now reflected in the (wrong) 
>>>>> return
>>
>>>>> type.  One place it would make sense to check would be
>>>>>
>>>>>>               if (ctype && (sfk == sfk_constructor
>>>>>>                             || sfk == sfk_destructor))
>>>>>>                 {
>>>>>>                   /* We are within a class's scope. If our
>>>>>> declarator
>>>>>> name
>>>>>>                 is the same as the class name, and we are 
>>>>>> defining
>>>>>>                                                                          
>>>>>>       a
>>>>>> function, then it is a constructor/destructor, and
>>>>>>                                                                therefore
>>>>>> returns a void type.  */
>>>>>
>>>>> Here 'type' is still the return type, we haven't gotten to
>>>>> build_function_type yet.
>>>> That’s true. However, doesn’t it make sense to cram all the
>>>> checks
>>>> about the return type of special functions in
>>>> check_special_function_return_type, and return an error if that
>>>> return
>>>> type is invalid?
>>>
>>> This error seems easily recoverable since we know what the type 
>>> needs
>>> to be, there's no need for error return from grokdeclarator.
>> ACK.
>>
>>> However, an alternative to my suggestion above would be to build on
>>> your patch by making check_special_function_return_type actually 
>>> strip
>>> the invalid declarators, not just complain about them.
>
>> Thanks for the suggestion, I like that it keeps everything within
>> check_special_function_return_type. Hence the updated attached patch,

>>
>> successfully tested on 86_64-pc-linux-gnu. OK for trunk?
>
>>      case sfk_constructor:
>>        if (type)
>>      error_at (smallest_type_location (type_quals, locations),
>>                "return type specification for constructor invalid");
>> +      else if (maybe_strip_indirect_ref (declarator))
>> +    error_at ((*declarator)->id_loc,
>> +              "return type specification for constructor invalid");
>>        else if (type_quals != TYPE_UNQUALIFIED)
>>      error_at (smallest_type_quals_location (type_quals, locations),
>>                "qualifiers are not allowed on constructor declaration");
>
> This looks like if someone writes e.g.
>
> int *A();
>
> then we'll complain about the 'int' but leave the * alone.
Argh you’re right, the return type is not fully groked at this
point, so check_special_function_return_type should check first
for indirect refs and then for type if needed. This is what the
updated attached patch does

Successfully tested on x86_64-pc-linux-gnu. OK for trunk?

Thanks, Simon
From 140bd5fa4f98fcb2ac32b99e4403dd4875afe9c5 Mon Sep 17 00:00:00 2001
From: Simon Martin <si...@nasilyan.com>
Date: Sun, 9 Feb 2025 20:38:43 +0100
Subject: [PATCH] c++: Reject cdtors and conversion operators with a single *
 as return type [PR118304, PR118306]

We currently accept the following constructor declaration (clang, EDG
and MSVC do as well), and ICE on the destructor declaration

=== cut here ===
struct A {
  *A ();
  ~A () = default;
};
=== 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 and strips the
invalid declarator when processing a cdtor (or a conversion operator
with no return type specified) with a declarator representing a pointer
or a reference type.

Successfully tested on x86_64-pc-linux-gnu.

        PR c++/118306
        PR c++/118304

gcc/cp/ChangeLog:

        * decl.cc (maybe_strip_indirect_ref): New.
        (check_special_function_return_type): Take declarator as input.
        Call maybe_strip_indirect_ref and error out if it returns true.
        (grokdeclarator): Update call to
        check_special_function_return_type.

gcc/testsuite/ChangeLog:

        * g++.old-deja/g++.jason/operator.C: Adjust bogus test
        expectation (char** vs char*).
        * g++.dg/parse/constructor4.C: New test.
        * g++.dg/parse/constructor5.C: New test.
        * g++.dg/parse/conv_op2.C: New test.
        * g++.dg/parse/default_to_int.C: New test.

---
 gcc/cp/decl.cc                                | 50 ++++++++++++-----
 gcc/testsuite/g++.dg/parse/constructor4.C     | 54 +++++++++++++++++++
 gcc/testsuite/g++.dg/parse/constructor5.C     | 48 +++++++++++++++++
 gcc/testsuite/g++.dg/parse/conv_op2.C         | 10 ++++
 gcc/testsuite/g++.dg/parse/default_to_int.C   | 37 +++++++++++++
 .../g++.old-deja/g++.jason/operator.C         |  2 +-
 6 files changed, 187 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/parse/constructor4.C
 create mode 100644 gcc/testsuite/g++.dg/parse/constructor5.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 84abc17ade0..552a7a2ec54 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**,
+       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);
@@ -12441,10 +12442,27 @@ 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
-   operator declaration, or the class type for a constructor/destructor.
+/* Returns whether DECLARATOR represented a pointer or a reference and if so,
+   strip out the pointer/reference declarator(s).  */
+
+static bool
+maybe_strip_indirect_ref (const cp_declarator** declarator)
+{
+  bool indirect_ref_p = false;
+  while (declarator && *declarator
+        && ((*declarator)->kind == cdk_pointer
+            || (*declarator)->kind == cdk_reference))
+    {
+      indirect_ref_p = true;
+      *declarator = (*declarator)->declarator;
+    }
+  return indirect_ref_p;
+}
+
+/* Check that it's OK to declare a function 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.  */
 
@@ -12453,13 +12471,18 @@ check_special_function_return_type 
(special_function_kind sfk,
                                    tree type,
                                    tree optype,
                                    int type_quals,
+                                   const cp_declarator** declarator,
                                    const location_t* locations)
 {
+  gcc_assert (declarator);
+  location_t rettype_loc = (type
+                           ? smallest_type_location (type_quals, locations)
+                           : (*declarator)->id_loc);
   switch (sfk)
     {
     case sfk_constructor:
-      if (type)
-       error_at (smallest_type_location (type_quals, locations),
+      if (maybe_strip_indirect_ref (declarator) || type)
+       error_at (rettype_loc,
                  "return type specification for constructor invalid");
       else if (type_quals != TYPE_UNQUALIFIED)
        error_at (smallest_type_quals_location (type_quals, locations),
@@ -12472,8 +12495,8 @@ check_special_function_return_type 
(special_function_kind sfk,
       break;
 
     case sfk_destructor:
-      if (type)
-       error_at (smallest_type_location (type_quals, locations),
+      if (maybe_strip_indirect_ref (declarator) || type)
+       error_at (rettype_loc,
                  "return type specification for destructor invalid");
       else if (type_quals != TYPE_UNQUALIFIED)
        error_at (smallest_type_quals_location (type_quals, locations),
@@ -12488,8 +12511,8 @@ check_special_function_return_type 
(special_function_kind sfk,
       break;
 
     case sfk_conversion:
-      if (type)
-       error_at (smallest_type_location (type_quals, locations),
+      if (maybe_strip_indirect_ref (declarator) || type)
+       error_at (rettype_loc,
                  "return type specified for %<operator %T%>", optype);
       else if (type_quals != TYPE_UNQUALIFIED)
        error_at (smallest_type_quals_location (type_quals, locations),
@@ -12500,8 +12523,8 @@ check_special_function_return_type 
(special_function_kind sfk,
       break;
 
     case sfk_deduction_guide:
-      if (type)
-       error_at (smallest_type_location (type_quals, locations),
+      if (maybe_strip_indirect_ref (declarator) || type)
+       error_at (rettype_loc,
                  "return type specified for deduction guide");
       else if (type_quals != TYPE_UNQUALIFIED)
        error_at (smallest_type_quals_location (type_quals, locations),
@@ -13181,6 +13204,7 @@ grokdeclarator (const cp_declarator *declarator,
       type = check_special_function_return_type (sfk, type,
                                                 ctor_return_type,
                                                 type_quals,
+                                                &declarator,
                                                 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..f7e4cace451
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/constructor4.C
@@ -0,0 +1,54 @@
+// PR c++/118306
+// { dg-do "compile" }
+
+// Constructors.
+struct A {
+  *A ();           // { dg-error "return type specification" }
+};
+struct B {
+  **B ();          // { dg-error "return type specification" }
+};
+struct C {
+  ***C ();         // { dg-error "return type specification" }
+};
+struct D {
+  &D ();           // { dg-error "return type specification|reference to" }
+};
+struct E {
+  *&E ();          // { dg-error "return type specification|reference to" }
+};
+struct F {
+  **&F ();         // { dg-error "return type specification|reference to" }
+};
+struct G {
+  *G (const G&);    // { dg-error "return type specification" }
+};
+struct H {
+  **H (const H&);    // { dg-error "return type specification" }
+};
+struct I {
+  &I (const I&);    // { dg-error "return type specification|reference to" }
+};
+struct J {
+  const J();       // { dg-error "expected unqualified-id" }
+};
+
+// Destructors.
+struct K {
+  * ~K ();         // { dg-error "return type specification" }
+};
+struct L {
+  ** ~L ();        // { dg-error "return type specification" }
+};
+struct M {
+  & ~M ();         // { dg-error "return type specification|reference to" }
+};
+struct N {
+  virtual * ~N ();  // { dg-error "return type specification" }
+};
+struct O {
+  virtual & ~O ();  // { dg-error "return type specification|reference to" }
+};
+struct P {
+  volatile ~P();    // { dg-error "qualifiers are not allowed" }
+};
diff --git a/gcc/testsuite/g++.dg/parse/constructor5.C 
b/gcc/testsuite/g++.dg/parse/constructor5.C
new file mode 100644
index 00000000000..5c86fe721a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/constructor5.C
@@ -0,0 +1,48 @@
+// PR c++/118304
+// { dg-do "compile" { target c++11 } }
+
+// Constructors.
+struct A {
+  *A () = default;           // { dg-error "return type specification" }
+};
+struct B {
+  int* B () = default;       // { dg-error "return type specification" }
+};
+struct C {
+  const int& C () = default;  // { dg-error "return type specification" }
+};
+struct D {
+  **D () = default;          // { dg-error "return type specification" }
+};
+struct E {
+  &E () = default;           // { dg-error "return type 
specification|reference to" }
+};
+struct F {
+  *&F () = default;          // { dg-error "return type 
specification|reference to" }
+};
+struct G {
+  **&G () = default;         // { dg-error "return type 
specification|reference to" }
+};
+struct H {
+  *H (const H&) = default;    // { dg-error "return type specification" }
+};
+struct I {
+  **I (const I&) = default;    // { dg-error "return type specification" }
+};
+struct J {
+  &J (const J&) = default;     // { dg-error "return type 
specification|reference to" }
+};
+struct K {
+  const K() = default;         // { dg-error "expected unqualified-id" }
+};
+
+// Destructors.
+struct L {
+  * ~L () = default;           // { dg-error "return type specification" }
+};
+struct M {
+  ** ~M () = default;          // { dg-error "return type specification" }
+};
+struct N {
+  & ~N () = default;           // { dg-error "return type 
specification|reference to" }
+};
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..f2719135e00
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/conv_op2.C
@@ -0,0 +1,10 @@
+// PR c++/118306
+// { dg-do "compile" }
+
+struct K {
+  char operator int(); // { dg-error "return type specified for" }
+  * operator short();  // { dg-error "return type specified for" }
+  ** operator float(); // { dg-error "return type specified for" }
+  &* operator double();        // { dg-error "return type specified 
for|pointer to 'double&'" }
+  & operator long();   // { dg-error "return type specified for" }
+};
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..681298ce634
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/default_to_int.C
@@ -0,0 +1,37 @@
+// 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" }
+  * mem2;          // { dg-warning "forbids declaration" }
+  const * mem3;            // { dg-warning "forbids declaration" }
+  const ** mem4;    // { dg-warning "forbids declaration" }
+  & mem5;          // { dg-warning "forbids declaration" }
+  volatile & mem6;  // { 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" }
+**bazz(int) { return 0; }          // { dg-warning "forbids declaration" }
+*&bazzz(int) { return 0; }         // { dg-warning "forbids declaration|bind 
non-const" }
+const bazzzz (int) { return 0; }    // { dg-warning "forbids declaration" }
+const* bazzzzz (int) { return 0; }  // { dg-warning "forbids declaration" }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/operator.C 
b/gcc/testsuite/g++.old-deja/g++.jason/operator.C
index c18790190b5..542f305942c 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/operator.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/operator.C
@@ -29,4 +29,4 @@ void * operator new (A a);    // { dg-error ".operator new. 
takes type .size_t." }
 void operator delete (A a);    // { dg-error ".operator delete. takes type 
.void\\*. as first parameter" }
 
 char * operator char * (int);  // { dg-error "return type" "ret" }
-// { dg-error "8:.operator char\\*\\*\\(int\\). must be a non-static member 
function" "mem" { target *-*-* } .-1 }
+// { dg-error "8:.operator char\\*\\(int\\). must be a non-static member 
function" "mem" { target *-*-* } .-1 }
-- 
2.44.0

Reply via email to