mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			Fix C++17 template placeholder for template template parm.
* parser.c (cp_parser_simple_type_specifier): Allow placeholder for template template parameter. (cp_parser_type_id_1): Improve diagnostic. * decl.c (grokdeclarator): Handle class deduction diagnostics here. * pt.c (splice_late_return_type): Not here. (tsubst) [TEMPLATE_TYPE_PARM]: Substitute into placeholder template. (do_class_deduction): Handle non-class templates. From-SVN: r242018
This commit is contained in:
		
							parent
							
								
									4a826ca6fe
								
							
						
					
					
						commit
						e922b25690
					
				|  | @ -1,5 +1,13 @@ | ||||||
| 2016-11-09  Jason Merrill  <jason@redhat.com> | 2016-11-09  Jason Merrill  <jason@redhat.com> | ||||||
| 
 | 
 | ||||||
|  | 	* parser.c (cp_parser_simple_type_specifier): Allow placeholder | ||||||
|  | 	for template template parameter. | ||||||
|  | 	(cp_parser_type_id_1): Improve diagnostic. | ||||||
|  | 	* decl.c (grokdeclarator): Handle class deduction diagnostics here. | ||||||
|  | 	* pt.c (splice_late_return_type): Not here. | ||||||
|  | 	(tsubst) [TEMPLATE_TYPE_PARM]: Substitute into placeholder template. | ||||||
|  | 	(do_class_deduction): Handle non-class templates. | ||||||
|  | 
 | ||||||
| 	Implement P0127R2, Declaring non-type parameters with auto. | 	Implement P0127R2, Declaring non-type parameters with auto. | ||||||
| 	* cp-tree.h (enum auto_deduction_context): Add adc_unify. | 	* cp-tree.h (enum auto_deduction_context): Add adc_unify. | ||||||
| 	* decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type | 	* decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type | ||||||
|  |  | ||||||
|  | @ -9490,6 +9490,11 @@ grokdeclarator (const cp_declarator *declarator, | ||||||
|   if (initialized > 1) |   if (initialized > 1) | ||||||
|     funcdef_flag = true; |     funcdef_flag = true; | ||||||
| 
 | 
 | ||||||
|  |   location_t typespec_loc = smallest_type_quals_location (type_quals, | ||||||
|  | 						      declspecs->locations); | ||||||
|  |   if (typespec_loc == UNKNOWN_LOCATION) | ||||||
|  |     typespec_loc = declspecs->locations[ds_type_spec]; | ||||||
|  | 
 | ||||||
|   /* Look inside a declarator for the name being declared
 |   /* Look inside a declarator for the name being declared
 | ||||||
|      and get it as a string, for an error message.  */ |      and get it as a string, for an error message.  */ | ||||||
|   for (id_declarator = declarator; |   for (id_declarator = declarator; | ||||||
|  | @ -10011,6 +10016,16 @@ grokdeclarator (const cp_declarator *declarator, | ||||||
|   /* We might have ignored or rejected some of the qualifiers.  */ |   /* We might have ignored or rejected some of the qualifiers.  */ | ||||||
|   type_quals = cp_type_quals (type); |   type_quals = cp_type_quals (type); | ||||||
| 
 | 
 | ||||||
|  |   if (cxx_dialect >= cxx1z && type && is_auto (type) | ||||||
|  |       && innermost_code != cdk_function | ||||||
|  |       && id_declarator && declarator != id_declarator) | ||||||
|  |     if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type)) | ||||||
|  |     { | ||||||
|  |       error_at (typespec_loc, "template placeholder type %qT must be followed " | ||||||
|  | 		"by a simple declarator-id", type); | ||||||
|  |       inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", tmpl); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|   staticp = 0; |   staticp = 0; | ||||||
|   inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline); |   inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline); | ||||||
|   virtualp =  decl_spec_seq_has_spec_p (declspecs, ds_virtual); |   virtualp =  decl_spec_seq_has_spec_p (declspecs, ds_virtual); | ||||||
|  | @ -10247,12 +10262,7 @@ grokdeclarator (const cp_declarator *declarator, | ||||||
| 	      { | 	      { | ||||||
| 		if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) | 		if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) | ||||||
| 		  { | 		  { | ||||||
| 		    location_t loc; | 		    warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " | ||||||
| 		    loc = smallest_type_quals_location (type_quals, |  | ||||||
| 							declspecs->locations); |  | ||||||
| 		    if (loc == UNKNOWN_LOCATION) |  | ||||||
| 		      loc = declspecs->locations[ds_type_spec]; |  | ||||||
| 		    warning_at (loc, OPT_Wignored_qualifiers, "type " |  | ||||||
| 				"qualifiers ignored on function return type"); | 				"qualifiers ignored on function return type"); | ||||||
| 		  } | 		  } | ||||||
| 		/* We now know that the TYPE_QUALS don't apply to the
 | 		/* We now know that the TYPE_QUALS don't apply to the
 | ||||||
|  | @ -10301,11 +10311,12 @@ grokdeclarator (const cp_declarator *declarator, | ||||||
| 	    funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id; | 	    funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id; | ||||||
| 
 | 
 | ||||||
| 	    /* Handle a late-specified return type.  */ | 	    /* Handle a late-specified return type.  */ | ||||||
|  | 	    tree late_return_type = declarator->u.function.late_return_type; | ||||||
| 	    if (funcdecl_p) | 	    if (funcdecl_p) | ||||||
| 	      { | 	      { | ||||||
| 		if (type_uses_auto (type)) | 		if (tree auto_node = type_uses_auto (type)) | ||||||
| 		  { | 		  { | ||||||
| 		    if (!declarator->u.function.late_return_type) | 		    if (!late_return_type) | ||||||
| 		      { | 		      { | ||||||
| 			if (current_class_type | 			if (current_class_type | ||||||
| 			    && LAMBDA_TYPE_P (current_class_type)) | 			    && LAMBDA_TYPE_P (current_class_type)) | ||||||
|  | @ -10333,8 +10344,32 @@ grokdeclarator (const cp_declarator *declarator, | ||||||
| 			       name, type); | 			       name, type); | ||||||
| 			return error_mark_node; | 			return error_mark_node; | ||||||
| 		      } | 		      } | ||||||
|  | 		    if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) | ||||||
|  | 		      { | ||||||
|  | 			if (!late_return_type) | ||||||
|  | 			  { | ||||||
|  | 			    if (dguide_name_p (unqualified_id)) | ||||||
|  | 			      error_at (typespec_loc, "deduction guide for " | ||||||
|  | 					"%qT must have trailing return type", | ||||||
|  | 					TREE_TYPE (tmpl)); | ||||||
|  | 			    else | ||||||
|  | 			      error_at (typespec_loc, "deduced class type %qT " | ||||||
|  | 					"in function return type", type); | ||||||
|  | 			    inform (DECL_SOURCE_LOCATION (tmpl), | ||||||
|  | 				    "%qD declared here", tmpl); | ||||||
| 			  } | 			  } | ||||||
| 		else if (declarator->u.function.late_return_type | 			else if (CLASS_TYPE_P (late_return_type) | ||||||
|  | 				 && CLASSTYPE_TEMPLATE_INFO (late_return_type) | ||||||
|  | 				 && (CLASSTYPE_TI_TEMPLATE (late_return_type) | ||||||
|  | 				     == tmpl)) | ||||||
|  | 			  /* OK */; | ||||||
|  | 			else | ||||||
|  | 			  error ("trailing return type %qT of deduction guide " | ||||||
|  | 				 "is not a specialization of %qT", | ||||||
|  | 				 late_return_type, TREE_TYPE (tmpl)); | ||||||
|  | 		      } | ||||||
|  | 		  } | ||||||
|  | 		else if (late_return_type | ||||||
| 			 && sfk != sfk_conversion) | 			 && sfk != sfk_conversion) | ||||||
| 		  { | 		  { | ||||||
| 		    if (cxx_dialect < cxx11) | 		    if (cxx_dialect < cxx11) | ||||||
|  | @ -10348,12 +10383,11 @@ grokdeclarator (const cp_declarator *declarator, | ||||||
| 		    return error_mark_node; | 		    return error_mark_node; | ||||||
| 		  } | 		  } | ||||||
| 	      } | 	      } | ||||||
| 	    type = splice_late_return_type | 	    type = splice_late_return_type (type, late_return_type); | ||||||
| 	      (type, declarator->u.function.late_return_type); |  | ||||||
| 	    if (type == error_mark_node) | 	    if (type == error_mark_node) | ||||||
| 	      return error_mark_node; | 	      return error_mark_node; | ||||||
| 
 | 
 | ||||||
| 	    if (declarator->u.function.late_return_type) | 	    if (late_return_type) | ||||||
| 	      late_return_type_p = true; | 	      late_return_type_p = true; | ||||||
| 
 | 
 | ||||||
| 	    if (ctype == NULL_TREE | 	    if (ctype == NULL_TREE | ||||||
|  |  | ||||||
|  | @ -16596,7 +16596,8 @@ cp_parser_simple_type_specifier (cp_parser* parser, | ||||||
| 						 /*ambiguous_decls=*/NULL, | 						 /*ambiguous_decls=*/NULL, | ||||||
| 						 token->location); | 						 token->location); | ||||||
| 	      if (tmpl && tmpl != error_mark_node | 	      if (tmpl && tmpl != error_mark_node | ||||||
| 		  && DECL_CLASS_TEMPLATE_P (tmpl)) | 		  && (DECL_CLASS_TEMPLATE_P (tmpl) | ||||||
|  | 		      || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) | ||||||
| 		type = make_template_placeholder (tmpl); | 		type = make_template_placeholder (tmpl); | ||||||
| 	      else | 	      else | ||||||
| 		{ | 		{ | ||||||
|  | @ -20311,8 +20312,8 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, | ||||||
|       && (!flag_concepts || parser->in_type_id_in_expr_p) |       && (!flag_concepts || parser->in_type_id_in_expr_p) | ||||||
|       /* None of the valid uses of 'auto' in C++14 involve the type-id
 |       /* None of the valid uses of 'auto' in C++14 involve the type-id
 | ||||||
| 	 nonterminal, but it is valid in a trailing-return-type.  */ | 	 nonterminal, but it is valid in a trailing-return-type.  */ | ||||||
|       && !(cxx_dialect >= cxx14 && is_trailing_return) |       && !(cxx_dialect >= cxx14 && is_trailing_return)) | ||||||
|       && type_uses_auto (type_specifier_seq.type)) |     if (tree auto_node = type_uses_auto (type_specifier_seq.type)) | ||||||
|       { |       { | ||||||
| 	/* A type-id with type 'auto' is only ok if the abstract declarator
 | 	/* A type-id with type 'auto' is only ok if the abstract declarator
 | ||||||
| 	   is a function declarator with a late-specified return type. | 	   is a function declarator with a late-specified return type. | ||||||
|  | @ -20327,7 +20328,16 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, | ||||||
| 	  /* OK */; | 	  /* OK */; | ||||||
| 	else | 	else | ||||||
| 	  { | 	  { | ||||||
| 	  error ("invalid use of %<auto%>"); | 	    location_t loc = type_specifier_seq.locations[ds_type_spec]; | ||||||
|  | 	    if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) | ||||||
|  | 	      { | ||||||
|  | 		error_at (loc, "missing template arguments after %qT", | ||||||
|  | 			  auto_node); | ||||||
|  | 		inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", | ||||||
|  | 			tmpl); | ||||||
|  | 	      } | ||||||
|  | 	    else | ||||||
|  | 	      error_at (loc, "invalid use of %qT", auto_node); | ||||||
| 	    return error_mark_node; | 	    return error_mark_node; | ||||||
| 	  } | 	  } | ||||||
|       } |       } | ||||||
|  |  | ||||||
							
								
								
									
										38
									
								
								gcc/cp/pt.c
								
								
								
								
							
							
						
						
									
										38
									
								
								gcc/cp/pt.c
								
								
								
								
							|  | @ -13314,8 +13314,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) | ||||||
| 		      PLACEHOLDER_TYPE_CONSTRAINTS (r) | 		      PLACEHOLDER_TYPE_CONSTRAINTS (r) | ||||||
| 			= tsubst_constraint (constr, args, complain, in_decl); | 			= tsubst_constraint (constr, args, complain, in_decl); | ||||||
| 		    else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t)) | 		    else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t)) | ||||||
|  | 		      { | ||||||
|  | 			if (DECL_TEMPLATE_TEMPLATE_PARM_P (pl)) | ||||||
|  | 			  pl = tsubst (pl, args, complain, in_decl); | ||||||
| 			CLASS_PLACEHOLDER_TEMPLATE (r) = pl; | 			CLASS_PLACEHOLDER_TEMPLATE (r) = pl; | ||||||
| 		      } | 		      } | ||||||
|  | 		  } | ||||||
| 
 | 
 | ||||||
| 		if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM) | 		if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM) | ||||||
| 		  /* We have reduced the level of the template
 | 		  /* We have reduced the level of the template
 | ||||||
|  | @ -24625,13 +24629,23 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) | ||||||
|   return ded_tmpl; |   return ded_tmpl; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Deduce template arguments for the class template TMPL based on the
 | /* Deduce template arguments for the class template placeholder PTYPE for
 | ||||||
|    initializer INIT, and return the resulting type.  */ |    template TMPL based on the initializer INIT, and return the resulting | ||||||
|  |    type.  */ | ||||||
| 
 | 
 | ||||||
| tree | tree | ||||||
| do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain) | do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain) | ||||||
| { | { | ||||||
|   gcc_assert (DECL_CLASS_TEMPLATE_P (tmpl)); |   if (!DECL_CLASS_TEMPLATE_P (tmpl)) | ||||||
|  |     { | ||||||
|  |       /* We should have handled this in the caller.  */ | ||||||
|  |       if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)) | ||||||
|  | 	return ptype; | ||||||
|  |       if (complain & tf_error) | ||||||
|  | 	error ("non-class template %qT used without template arguments", tmpl); | ||||||
|  |       return error_mark_node; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|   tree type = TREE_TYPE (tmpl); |   tree type = TREE_TYPE (tmpl); | ||||||
| 
 | 
 | ||||||
|   vec<tree,va_gc> *args; |   vec<tree,va_gc> *args; | ||||||
|  | @ -24733,7 +24747,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, | ||||||
| 
 | 
 | ||||||
|   if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) |   if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) | ||||||
|     /* C++17 class template argument deduction.  */ |     /* C++17 class template argument deduction.  */ | ||||||
|     return do_class_deduction (tmpl, init, complain); |     return do_class_deduction (type, tmpl, init, complain); | ||||||
| 
 | 
 | ||||||
|   /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto
 |   /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto
 | ||||||
|      with either a new invented type template parameter U or, if the |      with either a new invented type template parameter U or, if the | ||||||
|  | @ -24881,20 +24895,6 @@ splice_late_return_type (tree type, tree late_return_type) | ||||||
| { | { | ||||||
|   if (is_auto (type)) |   if (is_auto (type)) | ||||||
|     { |     { | ||||||
|       if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type)) |  | ||||||
| 	{ |  | ||||||
| 	  if (!late_return_type) |  | ||||||
| 	    error ("deduction guide must have trailing return type"); |  | ||||||
| 	  else if (CLASS_TYPE_P (late_return_type) |  | ||||||
| 		   && CLASSTYPE_TEMPLATE_INFO (late_return_type) |  | ||||||
| 		   && CLASSTYPE_TI_TEMPLATE (late_return_type) == tmpl) |  | ||||||
| 	    /* OK */; |  | ||||||
| 	  else |  | ||||||
| 	    error ("trailing return type %qT of deduction guide is not " |  | ||||||
| 		   "a specialization of %qT", |  | ||||||
| 		   late_return_type, TREE_TYPE (tmpl)); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|       if (late_return_type) |       if (late_return_type) | ||||||
| 	return late_return_type; | 	return late_return_type; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| // { dg-do compile { target c++11 } }
 | // { dg-do compile { target c++11 } }
 | ||||||
| template<typename ... Elements> class Tuple; | template<typename ... Elements> class Tuple; | ||||||
| Tuple<>* t; // OK: Elements is empty
 | Tuple<>* t; // OK: Elements is empty
 | ||||||
| Tuple* u; // { dg-error "template-name" }
 | Tuple* u; // { dg-error "" }
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | // { dg-options -std=c++1z }
 | ||||||
|  | 
 | ||||||
|  | template<class T, class D = int> | ||||||
|  | struct S { T t; }; | ||||||
|  | template<class U> | ||||||
|  | S(U) -> S<typename U::type>; | ||||||
|  | 
 | ||||||
|  | struct A { | ||||||
|  |   using type = short; | ||||||
|  |   operator type(); | ||||||
|  | }; | ||||||
|  | S s{A()};			// OK
 | ||||||
|  | S x(A());			// { dg-error "return type" }
 | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | // { dg-options -std=c++1z }
 | ||||||
|  | 
 | ||||||
|  | template <template <class> class T> | ||||||
|  | void f() | ||||||
|  | { | ||||||
|  |   T t = 42;			// { dg-error "B" }
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template <class T> | ||||||
|  | struct A | ||||||
|  | { | ||||||
|  |   A(T); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template <class T> using B = T; | ||||||
|  | 
 | ||||||
|  | int main() | ||||||
|  | { | ||||||
|  |   f<A>(); | ||||||
|  |   f<B>();			// { dg-message "here" }
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,10 @@ | ||||||
|  | // { dg-options -std=c++1z }
 | ||||||
|  | 
 | ||||||
|  | template <class T> | ||||||
|  | struct A | ||||||
|  | { | ||||||
|  |   A(T); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | A a = 42; | ||||||
|  | A *ap = &a;			// { dg-error "placeholder" }
 | ||||||
|  | @ -20,7 +20,7 @@ template<template<class> class D,class E> class C | ||||||
| 
 | 
 | ||||||
| template<template<class> class D,class E> int C<D,E>::f() | template<template<class> class D,class E> int C<D,E>::f() | ||||||
| { | { | ||||||
| 	return d.f();			// { dg-error "" } d not properly declared
 | 	return d.f();			// { dg-prune-output "was not declared" }
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int main() | int main() | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jason Merrill
						Jason Merrill