Skip to content

Commit c74e7f6

Browse files
committed
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. 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.
1 parent e8c5013 commit c74e7f6

File tree

6 files changed

+187
-14
lines changed

6 files changed

+187
-14
lines changed

gcc/cp/decl.cc

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ static void end_cleanup_fn (void);
101101
static tree cp_make_fname_decl (location_t, tree, int);
102102
static void initialize_predefined_identifiers (void);
103103
static tree check_special_function_return_type
104-
(special_function_kind, tree, tree, int, const location_t*);
104+
(special_function_kind, tree, tree, int, const cp_declarator**,
105+
const location_t*);
105106
static tree push_cp_library_fn (enum tree_code, tree, int);
106107
static tree build_cp_library_fn (tree, enum tree_code, tree, int);
107108
static void store_parm_decls (tree);
@@ -12441,10 +12442,27 @@ smallest_type_location (const cp_decl_specifier_seq *declspecs)
1244112442
return smallest_type_location (type_quals, declspecs->locations);
1244212443
}
1244312444

12444-
/* Check that it's OK to declare a function with the indicated TYPE
12445-
and TYPE_QUALS. SFK indicates the kind of special function (if any)
12446-
that this function is. OPTYPE is the type given in a conversion
12447-
operator declaration, or the class type for a constructor/destructor.
12445+
/* Returns whether DECLARATOR represented a pointer or a reference and if so,
12446+
strip out the pointer/reference declarator(s). */
12447+
12448+
static bool
12449+
maybe_strip_indirect_ref (const cp_declarator** declarator)
12450+
{
12451+
bool indirect_ref_p = false;
12452+
while (declarator && *declarator
12453+
&& ((*declarator)->kind == cdk_pointer
12454+
|| (*declarator)->kind == cdk_reference))
12455+
{
12456+
indirect_ref_p = true;
12457+
*declarator = (*declarator)->declarator;
12458+
}
12459+
return indirect_ref_p;
12460+
}
12461+
12462+
/* Check that it's OK to declare a function with the indicated TYPE, TYPE_QUALS
12463+
and DECLARATOR. SFK indicates the kind of special function (if any) that
12464+
this function is. OPTYPE is the type given in a conversion operator
12465+
declaration, or the class type for a constructor/destructor.
1244812466
Returns the actual return type of the function; that may be different
1244912467
than TYPE if an error occurs, or for certain special functions. */
1245012468

@@ -12453,13 +12471,18 @@ check_special_function_return_type (special_function_kind sfk,
1245312471
tree type,
1245412472
tree optype,
1245512473
int type_quals,
12474+
const cp_declarator** declarator,
1245612475
const location_t* locations)
1245712476
{
12477+
gcc_assert (declarator);
12478+
location_t rettype_loc = (type
12479+
? smallest_type_location (type_quals, locations)
12480+
: (*declarator)->id_loc);
1245812481
switch (sfk)
1245912482
{
1246012483
case sfk_constructor:
12461-
if (type)
12462-
error_at (smallest_type_location (type_quals, locations),
12484+
if (maybe_strip_indirect_ref (declarator) || type)
12485+
error_at (rettype_loc,
1246312486
"return type specification for constructor invalid");
1246412487
else if (type_quals != TYPE_UNQUALIFIED)
1246512488
error_at (smallest_type_quals_location (type_quals, locations),
@@ -12472,8 +12495,8 @@ check_special_function_return_type (special_function_kind sfk,
1247212495
break;
1247312496

1247412497
case sfk_destructor:
12475-
if (type)
12476-
error_at (smallest_type_location (type_quals, locations),
12498+
if (maybe_strip_indirect_ref (declarator) || type)
12499+
error_at (rettype_loc,
1247712500
"return type specification for destructor invalid");
1247812501
else if (type_quals != TYPE_UNQUALIFIED)
1247912502
error_at (smallest_type_quals_location (type_quals, locations),
@@ -12488,8 +12511,8 @@ check_special_function_return_type (special_function_kind sfk,
1248812511
break;
1248912512

1249012513
case sfk_conversion:
12491-
if (type)
12492-
error_at (smallest_type_location (type_quals, locations),
12514+
if (maybe_strip_indirect_ref (declarator) || type)
12515+
error_at (rettype_loc,
1249312516
"return type specified for %<operator %T%>", optype);
1249412517
else if (type_quals != TYPE_UNQUALIFIED)
1249512518
error_at (smallest_type_quals_location (type_quals, locations),
@@ -12500,8 +12523,8 @@ check_special_function_return_type (special_function_kind sfk,
1250012523
break;
1250112524

1250212525
case sfk_deduction_guide:
12503-
if (type)
12504-
error_at (smallest_type_location (type_quals, locations),
12526+
if (maybe_strip_indirect_ref (declarator) || type)
12527+
error_at (rettype_loc,
1250512528
"return type specified for deduction guide");
1250612529
else if (type_quals != TYPE_UNQUALIFIED)
1250712530
error_at (smallest_type_quals_location (type_quals, locations),
@@ -13181,6 +13204,7 @@ grokdeclarator (const cp_declarator *declarator,
1318113204
type = check_special_function_return_type (sfk, type,
1318213205
ctor_return_type,
1318313206
type_quals,
13207+
&declarator,
1318413208
declspecs->locations);
1318513209
type_quals = TYPE_UNQUALIFIED;
1318613210
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// PR c++/118306
2+
// { dg-do "compile" }
3+
4+
// Constructors.
5+
struct A {
6+
*A (); // { dg-error "return type specification" }
7+
};
8+
struct B {
9+
**B (); // { dg-error "return type specification" }
10+
};
11+
struct C {
12+
***C (); // { dg-error "return type specification" }
13+
};
14+
struct D {
15+
&D (); // { dg-error "return type specification|reference to" }
16+
};
17+
struct E {
18+
*&E (); // { dg-error "return type specification|reference to" }
19+
};
20+
struct F {
21+
**&F (); // { dg-error "return type specification|reference to" }
22+
};
23+
struct G {
24+
*G (const G&); // { dg-error "return type specification" }
25+
};
26+
struct H {
27+
**H (const H&); // { dg-error "return type specification" }
28+
};
29+
struct I {
30+
&I (const I&); // { dg-error "return type specification|reference to" }
31+
};
32+
struct J {
33+
const J(); // { dg-error "expected unqualified-id" }
34+
};
35+
36+
// Destructors.
37+
struct K {
38+
* ~K (); // { dg-error "return type specification" }
39+
};
40+
struct L {
41+
** ~L (); // { dg-error "return type specification" }
42+
};
43+
struct M {
44+
& ~M (); // { dg-error "return type specification|reference to" }
45+
};
46+
struct N {
47+
virtual * ~N (); // { dg-error "return type specification" }
48+
};
49+
struct O {
50+
virtual & ~O (); // { dg-error "return type specification|reference to" }
51+
};
52+
struct P {
53+
volatile ~P(); // { dg-error "qualifiers are not allowed" }
54+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// PR c++/118304
2+
// { dg-do "compile" { target c++11 } }
3+
4+
// Constructors.
5+
struct A {
6+
*A () = default; // { dg-error "return type specification" }
7+
};
8+
struct B {
9+
int* B () = default; // { dg-error "return type specification" }
10+
};
11+
struct C {
12+
const int& C () = default; // { dg-error "return type specification" }
13+
};
14+
struct D {
15+
**D () = default; // { dg-error "return type specification" }
16+
};
17+
struct E {
18+
&E () = default; // { dg-error "return type specification|reference to" }
19+
};
20+
struct F {
21+
*&F () = default; // { dg-error "return type specification|reference to" }
22+
};
23+
struct G {
24+
**&G () = default; // { dg-error "return type specification|reference to" }
25+
};
26+
struct H {
27+
*H (const H&) = default; // { dg-error "return type specification" }
28+
};
29+
struct I {
30+
**I (const I&) = default; // { dg-error "return type specification" }
31+
};
32+
struct J {
33+
&J (const J&) = default; // { dg-error "return type specification|reference to" }
34+
};
35+
struct K {
36+
const K() = default; // { dg-error "expected unqualified-id" }
37+
};
38+
39+
// Destructors.
40+
struct L {
41+
* ~L () = default; // { dg-error "return type specification" }
42+
};
43+
struct M {
44+
** ~M () = default; // { dg-error "return type specification" }
45+
};
46+
struct N {
47+
& ~N () = default; // { dg-error "return type specification|reference to" }
48+
};

gcc/testsuite/g++.dg/parse/conv_op2.C

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// PR c++/118306
2+
// { dg-do "compile" }
3+
4+
struct K {
5+
char operator int(); // { dg-error "return type specified for" }
6+
* operator short(); // { dg-error "return type specified for" }
7+
** operator float(); // { dg-error "return type specified for" }
8+
&* operator double(); // { dg-error "return type specified for|pointer to 'double&'" }
9+
& operator long(); // { dg-error "return type specified for" }
10+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// PR c++/118306 - "Document" various behaviours wrt. defaulting types to int.
2+
// { dg-do "compile" }
3+
// { dg-additional-options "-fpermissive" }
4+
5+
// Members.
6+
struct K {
7+
* mem1; // { dg-warning "forbids declaration" }
8+
* mem2; // { dg-warning "forbids declaration" }
9+
const * mem3; // { dg-warning "forbids declaration" }
10+
const ** mem4; // { dg-warning "forbids declaration" }
11+
& mem5; // { dg-warning "forbids declaration" }
12+
volatile & mem6; // { dg-warning "forbids declaration" }
13+
14+
void foo (const& permissive_fine, // { dg-warning "forbids declaration" }
15+
volatile* permissive_fine_as_well); // { dg-warning "forbids declaration" }
16+
17+
* bar () { return 0; } // { dg-warning "forbids declaration" }
18+
const& baz (); // { dg-warning "forbids declaration" }
19+
20+
void bazz () {
21+
try {}
22+
catch (const *i) {} // { dg-warning "forbids" }
23+
catch (const &i) {} // { dg-warning "forbids" }
24+
}
25+
};
26+
27+
// Template parameters.
28+
template<const *i, const &j> // { dg-warning "forbids" }
29+
void baz() {}
30+
31+
// Functions.
32+
foo(int) { return 42; } // { dg-warning "forbids declaration" }
33+
*bar(int) { return 0; } // { dg-warning "forbids declaration" }
34+
**bazz(int) { return 0; } // { dg-warning "forbids declaration" }
35+
*&bazzz(int) { return 0; } // { dg-warning "forbids declaration|bind non-const" }
36+
const bazzzz (int) { return 0; } // { dg-warning "forbids declaration" }
37+
const* bazzzzz (int) { return 0; } // { dg-warning "forbids declaration" }

gcc/testsuite/g++.old-deja/g++.jason/operator.C

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ void * operator new (A a); // { dg-error ".operator new. takes type .size_t." }
2929
void operator delete (A a); // { dg-error ".operator delete. takes type .void\\*. as first parameter" }
3030

3131
char * operator char * (int); // { dg-error "return type" "ret" }
32-
// { dg-error "8:.operator char\\*\\*\\(int\\). must be a non-static member function" "mem" { target *-*-* } .-1 }
32+
// { dg-error "8:.operator char\\*\\(int\\). must be a non-static member function" "mem" { target *-*-* } .-1 }

0 commit comments

Comments
 (0)