Patchwork [C++] PR 18747

login
register
mail settings
Submitter Paolo Carlini
Date Aug. 23, 2012, 2:04 p.m.
Message ID <50363851.9070205@oracle.com>
Download mbox | patch
Permalink /patch/179659/
State New
Headers show

Comments

Paolo Carlini - Aug. 23, 2012, 2:04 p.m.
Hi,

here we want to reject meaningless things like:

template<> int i;   // { dg-error "template" }

struct A
{
};

template<> A j;     // { dg-error "template" }

It seems to me that a good place to do that is toward the end of 
cp_parser_single_declaration, where we have only to be careful with 
static data members (otherwise, eg, debug/static1.C regresses 
immediately). I'm not sure about the error message...

The below bootstraps and tests fine on x86_64-linux.

Thanks,
Paolo.

/////////////////////
/cp
2012-08-23  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/18747
	* parser.c (cp_parser_single_declaration): When trying for template
	functions, reject VAR_DECLs (besides static data members).

/testsuite
2012-08-23  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/18747
	* g++.dg/parse/error50.C: New.
Jason Merrill - Aug. 23, 2012, 3:24 p.m.
On 08/23/2012 10:04 AM, Paolo Carlini wrote:
> +    if (decl
> +	&& TREE_CODE (decl) == VAR_DECL
> +	&& ! TYPE_P (CP_DECL_CONTEXT (decl)))
> +      {
> +	error_at (decl_spec_token_start->location,
> +		  "%qT is not a template type", TREE_TYPE (decl));
> +	decl = error_mark_node;
> +      }

Can we just check whether decl has DECL_TEMPLATE_INFO at this point?

Jason
Paolo Carlini - Aug. 23, 2012, 3:53 p.m.
On 08/23/2012 05:24 PM, Jason Merrill wrote:
> On 08/23/2012 10:04 AM, Paolo Carlini wrote:
>> +    if (decl
>> +    && TREE_CODE (decl) == VAR_DECL
>> +    && ! TYPE_P (CP_DECL_CONTEXT (decl)))
>> +      {
>> +    error_at (decl_spec_token_start->location,
>> +          "%qT is not a template type", TREE_TYPE (decl));
>> +    decl = error_mark_node;
>> +      }
>
> Can we just check whether decl has DECL_TEMPLATE_INFO at this point?
I tried, possibly together with a preliminary DECL_LANG_SPECIFIC check 
and maybe a check that decl isn't already error_mark_node, but anyway 
apparently the idea has issues with friends, testcases like 
template/friend17.C (gave me already headaches earlier today, that's why 
I'm so quick at replying ;)

template <class T>
struct X {
   template <class U> void operator+=(U);

   template <class V>
   template <class U>
   friend void X<V>::operator+=(U);
};

int main() {
   X<int>() += 1.0;
}

when we parse the friend declaration, DECL_TEMPLATE_INFO is not set.

Paolo.
Paolo Carlini - Aug. 24, 2012, 12:08 a.m.
Hi again,

On 08/23/2012 05:53 PM, Paolo Carlini wrote:
> On 08/23/2012 05:24 PM, Jason Merrill wrote:
>> On 08/23/2012 10:04 AM, Paolo Carlini wrote:
>>> +    if (decl
>>> +    && TREE_CODE (decl) == VAR_DECL
>>> +    && ! TYPE_P (CP_DECL_CONTEXT (decl)))
>>> +      {
>>> +    error_at (decl_spec_token_start->location,
>>> +          "%qT is not a template type", TREE_TYPE (decl));
>>> +    decl = error_mark_node;
>>> +      }
>>
>> Can we just check whether decl has DECL_TEMPLATE_INFO at this point?
> I tried, possibly together with a preliminary DECL_LANG_SPECIFIC check 
> and maybe a check that decl isn't already error_mark_node, but anyway 
> apparently the idea has issues with friends, testcases like 
> template/friend17.C (gave me already headaches earlier today, that's 
> why I'm so quick at replying ;)
>
> template <class T>
> struct X {
>   template <class U> void operator+=(U);
>
>   template <class V>
>   template <class U>
>   friend void X<V>::operator+=(U);
> };
>
> int main() {
>   X<int>() += 1.0;
> }
>
> when we parse the friend declaration, DECL_TEMPLATE_INFO is not set.
I looked somewhat more into this and I haven't been able to find a 
simple way to just use DECL_TEMPLATE_INFO. If I arrange to cope with 
friend17.C by explicitly excluding TEMPLATE_DECLs like in:

       else if (decl != error_mark_node
            && TREE_CODE (decl) != TEMPLATE_DECL
            && (!DECL_LANG_SPECIFIC (decl)
                || !DECL_TEMPLATE_INFO (decl)))
         {
           error_at (decl_spec_token_start->location,
             "%qT is not a template type", TREE_TYPE (decl));
           decl = error_mark_node;
         }

then we regress eg, g++.dg/cpp0x/temp_default4.C, because in that case, 
again involving friends, we have:

lass X {
   template<typename T = int> friend void f(X) { }
   template<typename T> friend void g(X); // { dg-error "previously 
declared here" }
   template<typename T = int> friend void h(X); // { dg-error "function 
template friend" }
};

template<typename T = int> void g(X) // { dg-error "default template 
argument" }
{
}

and the out of class g is a FUNCTION_DECL with again DECL_TEMPLATE_INFO 
not set.

Do you have in mind something more specific?

Ah, just in case you wondered (like me ;) we do *not* have an issue with 
things like:

template<> int i(int);

which obviously aren't VAR_DECLs, because those are handled already by 
check_explicit_specialization.

What about adding a comment about the latter point?

Thanks,
Paolo.

Patch

Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 190618)
+++ cp/parser.c	(working copy)
@@ -21429,6 +21429,15 @@  cp_parser_single_declaration (cp_parser* parser,
 		  "explicit template specialization cannot have a storage class");
         decl = error_mark_node;
       }
+
+    if (decl
+	&& TREE_CODE (decl) == VAR_DECL
+	&& ! TYPE_P (CP_DECL_CONTEXT (decl)))
+      {
+	error_at (decl_spec_token_start->location,
+		  "%qT is not a template type", TREE_TYPE (decl));
+	decl = error_mark_node;
+      }
     }
 
   /* Look for a trailing `;' after the declaration.  */
Index: testsuite/g++.dg/parse/error50.C
===================================================================
--- testsuite/g++.dg/parse/error50.C	(revision 0)
+++ testsuite/g++.dg/parse/error50.C	(revision 0)
@@ -0,0 +1,9 @@ 
+// PR c++/18747
+
+template<> int i;   // { dg-error "template" }
+
+struct A
+{
+};
+
+template<> A j;     // { dg-error "template" }