diff mbox

[c++-concepts] Constrained scope bugfix

Message ID CANq5SyuTtD-RxtRkCcg8Oy9gK+wF30eoXLRmtqnYgW-hzeD7hw@mail.gmail.com
State New
Headers show

Commit Message

Andrew Sutton Oct. 30, 2013, 1:49 p.m. UTC
Partially fixing a bug that caused lookup errors in valid programs. For example:

template<Int T, Float U>
  pair<T, U>::type void f(T, U); // Error, no such pair

When entering a template scope, we tried to match the template to one
having the same constraints. Obviously pair doesn't have Int and Float
constraints, and it probably doesn't have a partial specialization
with those constraints either.

I relaxed the fixup_template_type function so that it would just
return the looked-up type without emitting a diagnostic. This fix
makes the following a legal, however:

template<typename T>
  struct S { void f(); }

template<Int T>
  void S<T>::f() { } // Should be an error

The right solution seems to be to diagnose the error only when
defining an out-of-class member by verifying that each template scope
in the qualified name matches a declaration with the same constraints.

2013-10-30  Andrew Sutton  <andrew.n.sutton@gmail.com>
        * gcc/cp/semantics.c (fixup_template_type): Don't emit errors when
        no templates can be found with matching constraints.
diff mbox

Patch

Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 203626)
+++ gcc/cp/semantics.c	(working copy)
@@ -2847,8 +2847,35 @@  finish_template_decl (tree parms)
 
 // Returns the template type of the class scope being entered. If we're
 // entering a constrained class scope. TYPE is the class template
-// scope being entered. If TYPE is not a class-type (e.g. a typename type),
-// then no fixup is needed.
+// scope being entered and we may need to match the intended type with
+// a constrained specialization. For example:
+//
+//    template<Object T>
+//      struct S { void f(); }; #1
+//
+//    template<Object T>
+//      void S<T>::f() { }      #2
+//
+// We check, in #2, that S<T> refers precisely to the type declared by
+// #1 (i.e., that the constraints match). Note that the following should
+// be an error since there is no specialization of S<T> that is 
+// unconstrained, but this is not diagnosed here.
+//
+//    template<typename T>
+//      void S<T>::f() { }
+//
+// We cannot diagnose this problem here since this function also matches
+// qualified template names that are not part of a definition. For example:
+//
+//    template<Integral T, Floating_point U>
+//      typename pair<T, U>::first_type void f(T, U);
+//
+// Here, it is unlikely that there is a partial specialization of
+// pair constrained for for Integral and Floating_point arguments.
+//
+// The general rule is: if a constrained specialization with matching
+// constraints is found return that type. Alos note that if TYPE is not a 
+// class-type (e.g. a typename type), then no fixup is needed.
 static tree
 fixup_template_type (tree type)
 {
@@ -2866,14 +2893,8 @@  fixup_template_type (tree type)
     return type;
   tree cur_constr = TEMPLATE_PARMS_CONSTRAINTS (parms);
 
-  // Do the constraints match those of the most general template? 
-  // If the constraints are NULL_TREE, this will match the most general
-  // template iff it is unconstrained.
+  // Search for a specialization whose constraints match.
   tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
-  if (equivalent_constraints (cur_constr, DECL_CONSTRAINTS (tmpl)))
-    return type;
-
-  // Can we find a specialization that matches?
   tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
   while (specs)
     {
@@ -2883,10 +2904,8 @@  fixup_template_type (tree type)
       specs = TREE_CHAIN (specs);
     }
 
-  // Emit an error, but return the type to allow processing to continue.
-  // TODO: We should emit candidates since we've just scanned the 
-  // list of template constraints.
-  error ("type %qT does not match any declarations", type);
+  // If no specialization matches, then must return the type
+  // previously found.
   return type;
 }
 
@@ -2904,7 +2923,7 @@  finish_template_type (tree name, tree ar
   type = lookup_template_class (name, args,
 				NULL_TREE, NULL_TREE, entering_scope,
 				tf_warning_or_error | tf_user);
-  
+
   // If entering a scope, correct the lookup to account for constraints.
   if (entering_scope)
     type = fixup_template_type (type);