[REVISED PATCH][RFC] Fix PR c++/31923: Storage class with explicit template specialization

Simon Baldwin simonb@google.com
Fri Jun 15 18:19:00 GMT 2007


Attached is a revised version of a pending patch first distributed as

  http://gcc.gnu.org/ml/gcc-patches/2007-05/msg02033.html

The attached patch implements section 7.1.1-1 of the C++ standard by
preventing storage class specifiers on explicit specializations of templated
functions.  It also adjusts the linkage of such explicit specializations that
now cannot specify a storage class so that they meet the recommendations of
the C++ Core Language Working Group for Defect Report 605:

  http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#605

The patch includes two new tests, to verify parsing and linkage of explicit
specializations of templated functions.

Regression tested with the full g++ testsuite.


gcc/cp/ChangeLog
2007-06-15  Simon Baldwin <simonb@google.com>

	PR c++/31923
	* parser.c (cp_parser_single_declaration): Added check for storage
	class other than sc_none in parsed declaration, and a flag to indicate
	if the call is part of an explicit template specialization parse.
	* (cp_parser_explicit_specialization): Specialization check flag added
	to call to cp_parser_single_declaration(), set true.
	* (cp_parser_template_declaration_after_export): Specialization check
	flag added to call to cp_parser_single_declaration(), set false.
	* pt.c (check_explicit_specialization): Added code to copy visiblity
	and linkage from the templated function to the explicit specialization.

gcc/testsuite/ChangeLog
2007-06-15  Simon Baldwin <simonb@google.com>

	PR c++/31923
	* g++.dg/template/error25.C: New.
	* g++.dg/template/spec35.C: New.


diff -Nrcp3 gcc_orig/gcc/cp/parser.c gcc/gcc/cp/parser.c
*** gcc_orig/gcc/cp/parser.c	Tue Jun 12 10:21:25 2007
--- gcc/gcc/cp/parser.c	Fri Jun 15 09:45:58 2007
*************** static void cp_parser_template_declarati
*** 1913,1919 ****
  static void cp_parser_perform_template_parameter_access_checks
    (VEC (deferred_access_check,gc)*);
  static tree cp_parser_single_declaration
!   (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool *);
  static tree cp_parser_functional_cast
    (cp_parser *, tree);
  static tree cp_parser_save_member_function_body
--- 1913,1919 ----
  static void cp_parser_perform_template_parameter_access_checks
    (VEC (deferred_access_check,gc)*);
  static tree cp_parser_single_declaration
!   (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool, bool *);
  static tree cp_parser_functional_cast
    (cp_parser *, tree);
  static tree cp_parser_save_member_function_body
*************** cp_parser_explicit_specialization (cp_pa
*** 10225,10230 ****
--- 10225,10231 ----
      cp_parser_single_declaration (parser,
  				  /*checks=*/NULL,
  				  /*member_p=*/false,
+                                   /*explicit_specialization_p=*/true,
  				  /*friend_p=*/NULL);
    /* We're done with the specialization.  */
    end_specialization ();
*************** cp_parser_template_declaration_after_exp
*** 16510,16515 ****
--- 16511,16517 ----
        decl = cp_parser_single_declaration (parser,
  					   checks,
  					   member_p,
+                                            /*explicit_specialization_p=*/false,
  					   &friend_p);
        pop_deferring_access_checks ();
  
*************** static tree
*** 16575,16580 ****
--- 16577,16583 ----
  cp_parser_single_declaration (cp_parser* parser,
  			      VEC (deferred_access_check,gc)* checks,
  			      bool member_p,
+                               bool explicit_specialization_p,
  			      bool* friend_p)
  {
    int declares_class_or_enum;
*************** cp_parser_single_declaration (cp_parser*
*** 16648,16660 ****
    if (!decl
        && (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
  	  || decl_specifiers.type != error_mark_node))
!     decl = cp_parser_init_declarator (parser,
! 				      &decl_specifiers,
! 				      checks,
! 				      /*function_definition_allowed_p=*/true,
! 				      member_p,
! 				      declares_class_or_enum,
! 				      &function_definition_p);
  
    pop_deferring_access_checks ();
  
--- 16651,16677 ----
    if (!decl
        && (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
  	  || decl_specifiers.type != error_mark_node))
!     {
!       decl = cp_parser_init_declarator (parser,
! 				        &decl_specifiers,
! 				        checks,
! 				        /*function_definition_allowed_p=*/true,
! 				        member_p,
! 				        declares_class_or_enum,
! 				        &function_definition_p);
! 
!     /* 7.1.1-1 [dcl.stc]
! 
!        A storage-class-specifier shall not be specified in an explicit
!        specialization...  */
!     if (decl
!         && explicit_specialization_p
!         && decl_specifiers.storage_class != sc_none)
!       {
!         error ("explicit template specialization cannot have a storage class");
!         decl = error_mark_node;
!       }
!     }
  
    pop_deferring_access_checks ();
  
diff -Nrcp3 gcc_orig/gcc/cp/pt.c gcc/gcc/cp/pt.c
*** gcc_orig/gcc/cp/pt.c	Tue Jun 12 10:21:25 2007
--- gcc/gcc/cp/pt.c	Fri Jun 15 10:40:03 2007
*************** check_explicit_specialization (tree decl
*** 2193,2198 ****
--- 2193,2227 ----
  	  TREE_PRIVATE (decl) = TREE_PRIVATE (gen_tmpl);
  	  TREE_PROTECTED (decl) = TREE_PROTECTED (gen_tmpl);
  
+           /* 7.1.1-1 [dcl.stc]
+ 
+              A storage-class-specifier shall not be specified in an
+              explicit specialization...
+ 
+              The parser rejects these, so unless action is taken here,
+              explicit function specializations will always appear with
+              global linkage.
+ 
+              The action recommended by the C++ CWG in response to C++
+              defect report 605 is to make the storage class and linkage
+              of the explicit specialization match the templated function:
+ 
+              http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#605
+            */
+           if (tsk == tsk_expl_spec
+               && TREE_CODE (decl) == FUNCTION_DECL
+               && DECL_TEMPLATE_INFO (decl) && DECL_USE_TEMPLATE (decl)
+               && DECL_FUNCTION_TEMPLATE_P (gen_tmpl))
+             {
+               tree tmpl_func = DECL_TEMPLATE_RESULT (gen_tmpl);
+               gcc_assert (TREE_CODE (tmpl_func) == FUNCTION_DECL);
+ 
+               /* This specialization has the same linkage and visiblity as
+                  the function template it specializes.  */
+               TREE_PUBLIC (decl) = TREE_PUBLIC (tmpl_func);
+               DECL_THIS_STATIC (decl) = DECL_THIS_STATIC (tmpl_func);
+             }
+ 
  	  /* If DECL is a friend declaration, declared using an
  	     unqualified name, the namespace associated with DECL may
  	     have been set incorrectly.  For example, in:
diff -Nrcp3 gcc_orig/gcc/testsuite/g++.dg/template/error25.C gcc/gcc/testsuite/g++.dg/template/error25.C
*** gcc_orig/gcc/testsuite/g++.dg/template/error25.C	Wed Dec 31 16:00:00 1969
--- gcc/gcc/testsuite/g++.dg/template/error25.C	Tue Jun 12 14:02:38 2007
***************
*** 0 ****
--- 1,16 ----
+ // PR c++/31923
+ 
+ template<class T>
+ static void f1 ();
+ 
+ template<>
+ static void f1<void> ();  // { dg-error "explicit template specialization cannot have a storage class" }
+ 
+ template<class T>
+ extern void f2 ();
+ 
+ template<>
+ extern void f2<void> ();  // { dg-error "explicit template specialization cannot have a storage class" }
+ 
+ export template<class T>  // { dg-warning "keyword 'export' not implemented" }
+ static void* f3 ();
diff -Nrcp3 gcc_orig/gcc/testsuite/g++.dg/template/spec35.C gcc/gcc/testsuite/g++.dg/template/spec35.C
*** gcc_orig/gcc/testsuite/g++.dg/template/spec35.C	Wed Dec 31 16:00:00 1969
--- gcc/gcc/testsuite/g++.dg/template/spec35.C	Fri Jun 15 10:35:33 2007
***************
*** 0 ****
--- 1,29 ----
+ // PR c++/31923
+ // C++ DR 605 -- "...the linkage of an explicit specialization must be that of
+ // the template."
+ 
+ // { dg-do compile { target i?86-*-* x86_64-*-* } }
+ // { dg-require-weak "" }
+ 
+ template<class T>
+ static void f1 (T) { }
+ 
+ // { dg-final { scan-assembler-not ".glob(a|)l\[\t \]*_Z2f1IfEvT_" } }
+ template<>
+ void f1<float> (float) { }  // Expected to have static linkage
+ 
+ template<class T>
+ void f2 (T) { }
+ 
+ // { dg-final { scan-assembler ".glob(a|)l\[\t \]*_Z2f2IfEvT_" } }
+ template<>
+ void f2<float> (float) { }  // Expected to have global linkage
+ 
+ void instantiator ()
+ {
+   // { dg-final { scan-assembler-not ".glob(a|)l\[\t \]*_Z2f1IiEvT_" } }
+   f1(0);  // Expected to have static linkage
+ 
+   // { dg-final { scan-assembler ".weak\[\t \]*_Z2f2IiEvT_" } }
+   f2(0);  // Expected to have weak global linkage
+ }



More information about the Gcc-patches mailing list