diff mbox

[C++] PR 39970

Message ID 4F970FCB.7060308@oracle.com
State New
Headers show

Commit Message

Paolo Carlini April 24, 2012, 8:40 p.m. UTC
Hi,

I'm trying to resolve this rather old PR, where we don't reject uses of 
the dot operator in default template arguments, eg:

class blah { int member; };
blah global;

template<int param = global.member>
class template_blah;


I'm enforcing the check by adding to cp_parser a new 
in_template_default_argument_p which can be set in 
cp_parser_default_argument. Then it's just matter of reading it 
(together with integral_constant_expression_p, otherwise we can make 
mistakes in the argument of eg, sizeof or decltype) exactly when parsing 
. -> .* and ->* in order to have a precise location for the error. Is 
this the way we can fix this or we can do better?

Tested x86_64-linux.

Thanks,
Paolo.

//////////////////////////////
/cp
2012-04-24  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/39970
	* parser.h (cp_parser::in_template_default_argument_p): Add.
	* parser.c (cp_parser_new): Initialize the latter.
	(cp_parser_default_argument): Set the latter to true when parsing
	the default argument for a non-type template parameter. 
	(cp_parser_primary_expression): When in_template_default_argument_p
	&& integral_constant_expression_p reject pointer-to-member operators.
	(cp_parser_postfix_expression): Likewise for class member access
	operators.

/testsuite
2012-04-24  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/39970
	* g++.dg/parse/template27.C: New.
diff mbox

Patch

Index: testsuite/g++.dg/parse/template27.C
===================================================================
--- testsuite/g++.dg/parse/template27.C	(revision 0)
+++ testsuite/g++.dg/parse/template27.C	(revision 0)
@@ -0,0 +1,22 @@ 
+// PR c++/39970
+
+struct blah { int member; };
+blah global;
+blah* pglobal;
+
+template <int param = global.member>   // { dg-error "class member access operator" }
+class template1_blah;
+
+template <int* param = &global.member> // { dg-error "class member access operator" }
+class template2_blah;
+
+template <int param = pglobal->member> // { dg-error "class member access operator" }
+class template3_blah;
+
+int blah::* pm = &blah::member;
+
+template <int param = global.*pm>      // { dg-error "pointer-to-member operator" }
+class template4_blah;
+
+template <int param = pglobal->*pm>    // { dg-error "pointer-to-member operator" }
+class template5_blah;
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 186780)
+++ cp/parser.c	(working copy)
@@ -503,6 +503,8 @@  cp_debug_parser (FILE *file, cp_parser *parser)
   cp_debug_print_flag (file, "Local names and 'this' forbidden in "
 			      "current context",
 			      parser->local_variables_forbidden_p);
+  cp_debug_print_flag (file, "In template default argument",
+			      parser->in_template_default_argument_p);
   cp_debug_print_flag (file, "In unbraced linkage specification",
 			      parser->in_unbraced_linkage_specification_p);
   cp_debug_print_flag (file, "Parsing a declarator",
@@ -3278,6 +3280,10 @@  cp_parser_new (void)
   /* Local variable names are not forbidden.  */
   parser->local_variables_forbidden_p = false;
 
+  /* We are not processing the default argument for 
+     a non-type template parameter.  */
+  parser->in_template_default_argument_p = false;
+
   /* We are not processing an `extern "C"' declaration.  */
   parser->in_unbraced_linkage_specification_p = false;
 
@@ -4266,6 +4272,14 @@  cp_parser_primary_expression (cp_parser *parser,
 	  return error_mark_node;
 	id_expr_token = token;
 	token = cp_lexer_peek_token (parser->lexer);
+	if (parser->in_template_default_argument_p
+	    && parser->integral_constant_expression_p
+	    && (token->type == CPP_DOT_STAR || token->type == CPP_DEREF_STAR))
+	  {
+	    error_at (token->location,
+		      "pointer-to-member operator is not allowed here");
+	    return error_mark_node;
+	  }
 	done = (token->type != CPP_OPEN_SQUARE
 		&& token->type != CPP_OPEN_PAREN
 		&& token->type != CPP_DOT
@@ -5776,6 +5790,11 @@  cp_parser_postfix_expression (cp_parser *parser, b
 	     postfix-expression -> template [opt] id-expression
 	     postfix-expression -> pseudo-destructor-name */
 
+	  if (parser->in_template_default_argument_p
+	      && parser->integral_constant_expression_p)
+	    error_at (token->location,
+		      "class member access operator is not allowed here");
+
 	  /* Consume the `.' or `->' operator.  */
 	  cp_lexer_consume_token (parser->lexer);
 
@@ -17372,6 +17391,7 @@  cp_parser_default_argument (cp_parser *parser, boo
   tree default_argument = NULL_TREE;
   bool saved_greater_than_is_operator_p;
   bool saved_local_variables_forbidden_p;
+  bool saved_in_template_default_argument_p;
   bool non_constant_p, is_direct_init;
 
   /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
@@ -17382,6 +17402,12 @@  cp_parser_default_argument (cp_parser *parser, boo
      appear in a default argument.  */
   saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
   parser->local_variables_forbidden_p = true;
+  if (template_parm_p)
+    {
+      saved_in_template_default_argument_p
+       = parser->in_template_default_argument_p;
+      parser->in_template_default_argument_p = true;
+    }
   /* Parse the assignment-expression.  */
   if (template_parm_p)
     push_deferring_access_checks (dk_no_deferred);
@@ -17393,6 +17419,9 @@  cp_parser_default_argument (cp_parser *parser, boo
     pop_deferring_access_checks ();
   parser->greater_than_is_operator_p = saved_greater_than_is_operator_p;
   parser->local_variables_forbidden_p = saved_local_variables_forbidden_p;
+  if (template_parm_p)
+    parser->in_template_default_argument_p
+      = saved_in_template_default_argument_p;
 
   return default_argument;
 }
Index: cp/parser.h
===================================================================
--- cp/parser.h	(revision 186780)
+++ cp/parser.h	(working copy)
@@ -282,6 +282,10 @@  typedef struct GTY(()) cp_parser {
      current context.  */
   bool local_variables_forbidden_p;
 
+  /* TRUE if we are parsing the default argument for a non-type
+     template parameter.  */
+  bool in_template_default_argument_p;
+
   /* TRUE if the declaration we are parsing is part of a
      linkage-specification of the form `extern string-literal
      declaration'.  */