[C++ Patch] PR 61753

Paolo Carlini paolo.carlini@oracle.com
Mon Aug 31 15:23:00 GMT 2015


Hi,

this is about suboptimal error messages for the kind of code distilled 
by Jonathan in Comment #2:

class Rule {
     Rule(int e);
};

const Rule::Rule(int e) { }

that is, an error message of the type "error: prototype for 
‘Rule::Rule()’ does not match any in class ‘Rule’" and no mention of the 
fact that the const qualifier doesn't make sense.

In fact, however, in grokdeclarator we already emit sensible error 
messages for operators, thus the patch below mostly boils down to 
unifying the logic inside check_special_function_return_type. There is 
also a new smallest_type_quals_location helper function which computes 
an optimal location for the error message in case of multiple 
qualifiers, that is corresponding to the leftmost one.

Tested x86_64-linux.

Thanks,
Paolo.

////////////////////////


-------------- next part --------------
/cp
2015-08-31  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/61753
	* decl.c (smallest_type_quals_location): New.
	(check_special_function_return_type): Use the latter; add int and
	const location_t* parameters.
	(grokdeclarator): Adjust check_special_function_return_type call.

/testsuite
2015-08-31  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/61753
	* g++.dg/other/pr61753.C: New.
-------------- next part --------------
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 227335)
+++ cp/decl.c	(working copy)
@@ -113,7 +113,7 @@ 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);
+       (special_function_kind, tree, tree, int, 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);
@@ -8924,18 +8924,42 @@ create_array_type_for_decl (tree name, tree type,
   return build_cplus_array_type (type, itype);
 }
 
-/* Check that it's OK to declare a function with the indicated TYPE.
-   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.  */
+/* Returns the smallest location != UNKNOWN_LOCATION among the
+   three stored in LOCATIONS[ds_const], LOCATIONS[ds_volatile],
+   and LOCATIONS[ds_restrict].  */
 
+static location_t
+smallest_type_quals_location (int type_quals, const location_t* locations)
+{
+  location_t loc = UNKNOWN_LOCATION;
+
+  if (type_quals & TYPE_QUAL_CONST)
+    loc = locations[ds_const];
+
+  if ((type_quals & TYPE_QUAL_VOLATILE)
+      && (loc == UNKNOWN_LOCATION || locations[ds_volatile] < loc))
+    loc = locations[ds_volatile];
+
+  if ((type_quals & TYPE_QUAL_RESTRICT)
+      && (loc == UNKNOWN_LOCATION || locations[ds_restrict] < loc))
+    loc = locations[ds_restrict];
+
+  return loc;
+}
+
+/* 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 the actual return type of the function; that may be different
+   than TYPE if an error occurs, or for certain special functions.  */
+
 static tree
 check_special_function_return_type (special_function_kind sfk,
 				    tree type,
-				    tree optype)
+				    tree optype,
+				    int type_quals,
+				    const location_t* locations)
 {
   switch (sfk)
     {
@@ -8942,6 +8966,9 @@ check_special_function_return_type (special_functi
     case sfk_constructor:
       if (type)
 	error ("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");
 
       if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (optype))
 	type = build_pointer_type (optype);
@@ -8952,6 +8979,10 @@ check_special_function_return_type (special_functi
     case sfk_destructor:
       if (type)
 	error ("return type specification for destructor invalid");
+      else if (type_quals != TYPE_UNQUALIFIED)
+	error_at (smallest_type_quals_location (type_quals, locations),
+		  "qualifiers are not allowed on destructor declaration");
+
       /* We can't use the proper return type here because we run into
 	 problems with ambiguous bases and covariant returns.
 	 Java classes are left unchanged because (void *) isn't a valid
@@ -8964,7 +8995,12 @@ check_special_function_return_type (special_functi
 
     case sfk_conversion:
       if (type)
-	error ("return type specified for %<operator %T%>",  optype);
+	error ("return type specified for %<operator %T%>", optype);
+      else if (type_quals != TYPE_UNQUALIFIED)
+	error_at (smallest_type_quals_location (type_quals, locations),
+		  "qualifiers are not allowed on declaration of "
+		  "%<operator %T%>", optype);
+
       type = optype;
       break;
 
@@ -9090,7 +9126,7 @@ grokdeclarator (const cp_declarator *declarator,
      a member function.  */
   cp_ref_qualifier rqual = REF_QUAL_NONE;
   /* cv-qualifiers that apply to the type specified by the DECLSPECS.  */
-  int type_quals;
+  int type_quals = TYPE_UNQUALIFIED;
   tree raises = NULL_TREE;
   int template_count = 0;
   tree returned_attrs = NULL_TREE;
@@ -9137,6 +9173,13 @@ grokdeclarator (const cp_declarator *declarator,
   if (concept_p)
     constexpr_p = true;
 
+  if (decl_spec_seq_has_spec_p (declspecs, ds_const))
+    type_quals |= TYPE_QUAL_CONST;
+  if (decl_spec_seq_has_spec_p (declspecs, ds_volatile))
+    type_quals |= TYPE_QUAL_VOLATILE;
+  if (decl_spec_seq_has_spec_p (declspecs, ds_restrict))
+    type_quals |= TYPE_QUAL_RESTRICT;
+
   if (decl_context == FUNCDEF)
     funcdef_flag = true, decl_context = NORMAL;
   else if (decl_context == MEMFUNCDEF)
@@ -9462,8 +9505,13 @@ grokdeclarator (const cp_declarator *declarator,
     ctor_return_type = ctype;
 
   if (sfk != sfk_none)
-    type = check_special_function_return_type (sfk, type,
-					       ctor_return_type);
+    {
+      type = check_special_function_return_type (sfk, type,
+						 ctor_return_type,
+						 type_quals,
+						 declspecs->locations);
+      type_quals = TYPE_UNQUALIFIED;
+    }
   else if (type == NULL_TREE)
     {
       int is_main;
@@ -9648,17 +9696,6 @@ grokdeclarator (const cp_declarator *declarator,
 	type = build_complex_type (type);
     }
 
-  type_quals = TYPE_UNQUALIFIED;
-  if (decl_spec_seq_has_spec_p (declspecs, ds_const))
-    type_quals |= TYPE_QUAL_CONST;
-  if (decl_spec_seq_has_spec_p (declspecs, ds_volatile))
-    type_quals |= TYPE_QUAL_VOLATILE;
-  if (decl_spec_seq_has_spec_p (declspecs, ds_restrict))
-    type_quals |= TYPE_QUAL_RESTRICT;
-  if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED)
-    error ("qualifiers are not allowed on declaration of %<operator %T%>",
-	   ctor_return_type);
-
   /* If we're using the injected-class-name to form a compound type or a
      declaration, replace it with the underlying class so we don't get
      redundant typedefs in the debug output.  But if we are returning the
Index: testsuite/g++.dg/other/pr61753.C
===================================================================
--- testsuite/g++.dg/other/pr61753.C	(revision 0)
+++ testsuite/g++.dg/other/pr61753.C	(working copy)
@@ -0,0 +1,31 @@
+// PR c++/61753
+
+class Rulec {
+  Rulec();
+};
+
+const Rulec::Rulec() { }      // { dg-error "1:qualifiers" }
+
+class Rulev {
+  Rulev();
+};
+
+volatile Rulev::Rulev() { }   // { dg-error "1:qualifiers" }
+
+class Ruler {
+  Ruler();
+};
+
+__restrict Ruler::Ruler() { }  // { dg-error "1:qualifiers" }
+
+class Rulecvr {
+  Rulecvr();
+};
+
+const volatile __restrict Rulecvr::Rulecvr() { }  // { dg-error "1:qualifiers" }
+
+class Rulervc {
+  Rulervc();
+};
+
+__restrict volatile const Rulervc::Rulervc() { }  // { dg-error "1:qualifiers" }


More information about the Gcc-patches mailing list