This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH for c++/19407 (attributes on template parms)


It's nice to have all these PRs with different testcases, as it means I have to keep refining my code to make it deal with the different situations. I wasn't very happy with my first pass, but I'm quite pleased with the code now.

This patch deals with the problem that we didn't know how to deal with applying attributes to template type parms: now we can just defer all of them until instantiation time.

Tested x86_64-pc-linux-gnu, applied to trunk.

2007-09-22  Jason Merrill  <jason@redhat.com>

	PR c++/19407
	* cp/cp-tree.h (ATTR_IS_DEPENDENT): New macro.
	(MAYBE_TAGGED_TYPE_P): Remove.
	* cp/pt.c (apply_late_template_attributes): Check ATTR_IS_DEPENDENT
	instead of calling is_late_template_attribute again.
	(tsubst_decl) [TYPE_DECL]: Just check if the name is the tag.
	(tsubst): A typedef is a TYPE_NAME != TYPE_MAIN_DECL.
	Don't crash on typedefs from non-template classes.
	* cp/decl2.c (grokfield): Don't sorry about attrs on template parms.
	(is_late_template_attribute): All attributes applied to template
	parms or typename types are dependent.  Static, take decl.
	(splice_template_attributes): Pass decl through.
	(save_template_attributes): Likewise.
	* attribs.c (lookup_attribute_spec): Split out...
	(decl_attributes): From here.
	* tree.h: Declare it.

Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h	(revision 128669)
--- cp/cp-tree.h	(working copy)
*************** struct diagnostic_context;
*** 58,63 ****
--- 58,64 ----
        TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR)
        TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX)
        TYPE_REF_IS_RVALUE (in REFERENCE_TYPE)
+       ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
     1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
*************** enum languages { lang_c, lang_cplusplus,
*** 988,997 ****
    ((T) == RECORD_TYPE || (T) == UNION_TYPE)
  #define TAGGED_TYPE_P(T) \
    (CLASS_TYPE_P (T) || TREE_CODE (T) == ENUMERAL_TYPE)
- /* A tagged type or a dependent type that might be a tagged type when
-    instantiated.  Like IS_AGGR_TYPE, but include enums as well.  */
- #define MAYBE_TAGGED_TYPE_P(T) \
-   (IS_AGGR_TYPE(T) || TREE_CODE (T) == ENUMERAL_TYPE)
  #define IS_OVERLOAD_TYPE(T) TAGGED_TYPE_P (T)
  
  /* True if this a "Java" type, defined in 'extern "Java"'.  */
--- 989,994 ----
*************** struct lang_decl GTY(())
*** 2134,2139 ****
--- 2131,2140 ----
     directives  */
  #define TREE_INDIRECT_USING(NODE) (TREE_LIST_CHECK (NODE)->base.lang_flag_0)
  
+ /* In a TREE_LIST in an attribute list, indicates that the attribute
+    must be applied at instantiation time.  */
+ #define ATTR_IS_DEPENDENT(NODE) (TREE_LIST_CHECK (NODE)->base.lang_flag_0)
+ 
  extern tree decl_shadowed_for_var_lookup (tree);
  extern void decl_shadowed_for_var_insert (tree, tree);
  
*************** extern tree grokfield (const cp_declarat
*** 4280,4286 ****
  		       tree, bool, tree, tree);
  extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *,
  			  tree);
- extern bool is_late_template_attribute		(tree);
  extern void cplus_decl_attributes		(tree *, tree, int);
  extern void finish_anon_union			(tree);
  extern void cp_write_global_declarations	(void);
--- 4281,4286 ----
Index: cp/pt.c
===================================================================
*** cp/pt.c	(revision 128669)
--- cp/pt.c	(working copy)
*************** apply_late_template_attributes (tree *de
*** 6494,6513 ****
    else
      TYPE_ATTRIBUTES (*decl_p) = attributes;
  
-   /* Set processing_template_decl so we can check for dependent
-      expressions.  */
-   ++processing_template_decl;
- 
    for (t = attributes; t; t = TREE_CHAIN (t))
!     if (is_late_template_attribute (t))
        late_attrs = tree_cons
  	(TREE_PURPOSE (t),
  	 tsubst_expr (TREE_VALUE (t), args, complain, in_decl,
  		      /*integral_constant_expression_p=*/false),
  	 late_attrs);
  
-   --processing_template_decl;
- 
    cplus_decl_attributes (decl_p, late_attrs, attr_flags);
  }
  
--- 6494,6507 ----
    else
      TYPE_ATTRIBUTES (*decl_p) = attributes;
  
    for (t = attributes; t; t = TREE_CHAIN (t))
!     if (ATTR_IS_DEPENDENT (t))
        late_attrs = tree_cons
  	(TREE_PURPOSE (t),
  	 tsubst_expr (TREE_VALUE (t), args, complain, in_decl,
  		      /*integral_constant_expression_p=*/false),
  	 late_attrs);
  
    cplus_decl_attributes (decl_p, late_attrs, attr_flags);
  }
  
*************** tsubst_decl (tree t, tree args, tsubst_f
*** 8085,8104 ****
  	bool local_p;
  
  	if (TREE_CODE (t) == TYPE_DECL
! 	    && MAYBE_TAGGED_TYPE_P (TREE_TYPE (t)))
  	  {
  	    type = tsubst (TREE_TYPE (t), args, complain, in_decl);
! 	    if (TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
! 		|| t == TYPE_MAIN_DECL (TREE_TYPE (t)))
! 	      {
! 		/* If this is the canonical decl, we don't have to
! 		   mess with instantiations, and often we can't (for
! 		   typename, template type parms and such).  Note that
! 		   TYPE_NAME is not correct for the above test if
! 		   we've copied the type for a typedef.  */
! 		r = TYPE_NAME (type);
! 		break;
! 	      }
  	  }
  
  	/* Check to see if we already have the specialization we
--- 8079,8094 ----
  	bool local_p;
  
  	if (TREE_CODE (t) == TYPE_DECL
! 	    && t == TYPE_MAIN_DECL (TREE_TYPE (t)))
  	  {
+ 	    /* If this is the canonical decl, we don't have to
+ 	       mess with instantiations, and often we can't (for
+ 	       typename, template type parms and such).  Note that
+ 	       TYPE_NAME is not correct for the above test if
+ 	       we've copied the type for a typedef.  */
  	    type = tsubst (TREE_TYPE (t), args, complain, in_decl);
! 	    r = TYPE_NAME (type);
! 	    break;
  	  }
  
  	/* Check to see if we already have the specialization we
*************** tsubst (tree t, tree args, tsubst_flags_
*** 8555,8570 ****
    gcc_assert (type != unknown_type_node);
  
    /* Reuse typedefs.  We need to do this to handle dependent attributes,
!      specifically attribute aligned.  */
    if (TYPE_P (t)
        && TYPE_NAME (t)
!       && !MAYBE_TAGGED_TYPE_P (t)
!       && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM
!       && TREE_CODE (t) != UNBOUND_CLASS_TEMPLATE)
      {
        tree decl = TYPE_NAME (t);
        
!       if (DECL_CLASS_SCOPE_P (decl))
  	{
  	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
  	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
--- 8545,8559 ----
    gcc_assert (type != unknown_type_node);
  
    /* Reuse typedefs.  We need to do this to handle dependent attributes,
!      such as attribute aligned.  */
    if (TYPE_P (t)
        && TYPE_NAME (t)
!       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
      {
        tree decl = TYPE_NAME (t);
        
!       if (DECL_CLASS_SCOPE_P (decl)
! 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl)))
  	{
  	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
  	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
Index: cp/decl2.c
===================================================================
*** cp/decl2.c	(revision 128669)
--- cp/decl2.c	(working copy)
*************** grokfield (const cp_declarator *declarat
*** 800,815 ****
  	value = push_template_decl (value);
  
        if (attrlist)
! 	{
! 	  /* Avoid storing attributes in template parameters:
! 	     tsubst is not ready to handle them.  */
! 	  tree type = TREE_TYPE (value);
! 	  if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
! 	      || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
! 	    sorry ("applying attributes to template parameters is not implemented");
! 	  else
! 	    cplus_decl_attributes (&value, attrlist, 0);
! 	}
  
        return value;
      }
--- 800,806 ----
  	value = push_template_decl (value);
  
        if (attrlist)
! 	cplus_decl_attributes (&value, attrlist, 0);
  
        return value;
      }
*************** grokbitfield (const cp_declarator *decla
*** 988,1011 ****
  /* Returns true iff ATTR is an attribute which needs to be applied at
     instantiation time rather than template definition time.  */
  
! bool
! is_late_template_attribute (tree attr)
  {
    tree name = TREE_PURPOSE (attr);
    tree args = TREE_VALUE (attr);
    if (is_attribute_p ("aligned", name)
        && args
        && value_dependent_expression_p (TREE_VALUE (args)))
      return true;
    else
      return false;
  }
  
  /* ATTR_P is a list of attributes.  Remove any attributes which need to be
!    applied at instantiation time and return them.  */
  
  static tree
! splice_template_attributes (tree *attr_p)
  {
    tree *p = attr_p;
    tree late_attrs = NULL_TREE;
--- 979,1021 ----
  /* Returns true iff ATTR is an attribute which needs to be applied at
     instantiation time rather than template definition time.  */
  
! static bool
! is_late_template_attribute (tree attr, tree decl)
  {
    tree name = TREE_PURPOSE (attr);
    tree args = TREE_VALUE (attr);
+   const struct attribute_spec *spec = lookup_attribute_spec (name);
+ 
    if (is_attribute_p ("aligned", name)
        && args
        && value_dependent_expression_p (TREE_VALUE (args)))
+     /* Can't apply this until we know the desired alignment.  */
      return true;
+   else if (TREE_CODE (decl) == TYPE_DECL || spec->type_required)
+     {
+       tree type = TYPE_P (decl) ? decl : TREE_TYPE (decl);
+ 
+       /* We can't apply any attributes to a completely unknown type until
+ 	 instantiation time.  */
+       enum tree_code code = TREE_CODE (type);
+       if (code == TEMPLATE_TYPE_PARM
+ 	  || code == BOUND_TEMPLATE_TEMPLATE_PARM
+ 	  || code == TYPENAME_TYPE)
+ 	return true;
+       else
+ 	return false;
+     }
    else
      return false;
  }
  
  /* ATTR_P is a list of attributes.  Remove any attributes which need to be
!    applied at instantiation time and return them.  If IS_DEPENDENT is true,
!    the declaration itself is dependent, so all attributes should be applied
!    at instantiation time.  */
  
  static tree
! splice_template_attributes (tree *attr_p, tree decl)
  {
    tree *p = attr_p;
    tree late_attrs = NULL_TREE;
*************** splice_template_attributes (tree *attr_p
*** 1016,1023 ****
  
    for (; *p; )
      {
!       if (is_late_template_attribute (*p))
  	{
  	  *q = *p;
  	  *p = TREE_CHAIN (*p);
  	  q = &TREE_CHAIN (*q);
--- 1026,1034 ----
  
    for (; *p; )
      {
!       if (is_late_template_attribute (*p, decl))
  	{
+ 	  ATTR_IS_DEPENDENT (*p) = 1;
  	  *q = *p;
  	  *p = TREE_CHAIN (*p);
  	  q = &TREE_CHAIN (*q);
*************** splice_template_attributes (tree *attr_p
*** 1036,1042 ****
  static void
  save_template_attributes (tree *attr_p, tree *decl_p)
  {
!   tree late_attrs = splice_template_attributes (attr_p);
    tree *q;
  
    if (!late_attrs)
--- 1047,1053 ----
  static void
  save_template_attributes (tree *attr_p, tree *decl_p)
  {
!   tree late_attrs = splice_template_attributes (attr_p, *decl_p);
    tree *q;
  
    if (!late_attrs)
Index: attribs.c
===================================================================
*** attribs.c	(revision 128669)
--- attribs.c	(working copy)
*************** init_attributes (void)
*** 195,200 ****
--- 195,214 ----
        }
    attributes_initialized = true;
  }
+ 
+ /* Return the spec for the attribute named NAME.  */
+ 
+ const struct attribute_spec *
+ lookup_attribute_spec (tree name)
+ {
+   struct substring attr;
+ 
+   attr.str = IDENTIFIER_POINTER (name);
+   attr.length = IDENTIFIER_LENGTH (name);
+   extract_attribute_substring (&attr);
+   return htab_find_with_hash (attribute_hash, &attr,
+ 			      substring_hash (attr.str, attr.length));
+ }
  
  /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
     which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
*************** decl_attributes (tree *node, tree attrib
*** 221,236 ****
        tree name = TREE_PURPOSE (a);
        tree args = TREE_VALUE (a);
        tree *anode = node;
!       const struct attribute_spec *spec = NULL;
        bool no_add_attrs = 0;
        tree fn_ptr_tmp = NULL_TREE;
-       struct substring attr;
- 
-       attr.str = IDENTIFIER_POINTER (name);
-       attr.length = IDENTIFIER_LENGTH (name);
-       extract_attribute_substring (&attr);
-       spec = htab_find_with_hash (attribute_hash, &attr,
- 				  substring_hash (attr.str, attr.length));
  
        if (spec == NULL)
  	{
--- 235,243 ----
        tree name = TREE_PURPOSE (a);
        tree args = TREE_VALUE (a);
        tree *anode = node;
!       const struct attribute_spec *spec = lookup_attribute_spec (name);
        bool no_add_attrs = 0;
        tree fn_ptr_tmp = NULL_TREE;
  
        if (spec == NULL)
  	{
Index: tree.h
===================================================================
*** tree.h	(revision 128669)
--- tree.h	(working copy)
*************** extern bool must_pass_in_stack_var_size_
*** 5002,5007 ****
--- 5002,5009 ----
  
  /* In attribs.c.  */
  
+ extern const struct attribute_spec *lookup_attribute_spec (tree);
+ 
  /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
     which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
     it should be modified in place; if a TYPE, a copy should be created
Index: testsuite/g++.dg/ext/attrib20.C
===================================================================
*** testsuite/g++.dg/ext/attrib20.C	(revision 128669)
--- testsuite/g++.dg/ext/attrib20.C	(working copy)
*************** template <typename T>
*** 7,14 ****
  struct BVector
  {
    typedef T T2;
!   typedef T value_type __attribute__ ((aligned(8)));    // { dg-bogus "attribute" "attribute" { xfail *-*-* } }
!   typedef T2 value_type2 __attribute__ ((aligned(8)));  // { dg-bogus "attribute" "attribute" { xfail *-*-* } }
    value_type v;
  };
  BVector<int> m;
--- 7,14 ----
  struct BVector
  {
    typedef T T2;
!   typedef T value_type __attribute__ ((aligned(8)));    // { dg-bogus "attribute" "attribute" }
!   typedef T2 value_type2 __attribute__ ((aligned(8)));  // { dg-bogus "attribute" "attribute" }
    value_type v;
  };
  BVector<int> m;
*************** BVector<int> m;
*** 16,22 ****
  template <template <class> class T>
  struct BV2
  {
!   typedef T<float> value_type __attribute__((aligned(8))); // { dg-bogus "attribute" "attribute" { xfail *-*-* } }
    value_type v;
  };
  BV2<BVector> m2;
--- 16,22 ----
  template <template <class> class T>
  struct BV2
  {
!   typedef T<float> value_type __attribute__((aligned(8))); // { dg-bogus "attribute" "attribute" }
    value_type v;
  };
  BV2<BVector> m2;
Index: testsuite/g++.dg/ext/tmplattr5.C
===================================================================
*** testsuite/g++.dg/ext/tmplattr5.C	(revision 0)
--- testsuite/g++.dg/ext/tmplattr5.C	(revision 0)
***************
*** 0 ****
--- 1,33 ----
+ // PR c++/19407
+ // { dg-do run }
+ 
+ typedef float global_vector_type __attribute__((vector_size(16)));
+ 
+ template <class T> struct A
+ {
+   typedef T type;
+ };
+ 
+ template < typename Val > struct S
+ {
+   typedef typename A<Val>::type vector_type __attribute__((vector_size(16)));
+   typedef Val vector_type2 __attribute__((vector_size(16)));
+   int pr_size() { return sizeof(vector_type); }
+   int pr_size2() { return sizeof(vector_type2); }
+ };
+ 
+ int main()
+ {
+   if (sizeof (S<float>::vector_type) != sizeof (global_vector_type))
+     return 1;
+   if (sizeof (S<float>::vector_type2) != sizeof (global_vector_type))
+     return 2;
+ 
+   S<float> x;
+   if (x.pr_size() != sizeof (global_vector_type))
+     return 3;
+   if (x.pr_size2() != sizeof (global_vector_type))
+     return 4;
+   
+   return 0;
+ }
Index: testsuite/g++.dg/template/typedef7.C
===================================================================
*** testsuite/g++.dg/template/typedef7.C	(revision 0)
--- testsuite/g++.dg/template/typedef7.C	(revision 0)
***************
*** 0 ****
--- 1,15 ----
+ // An intermediate version of the fix for c++/19407 broke this example.
+ 
+ struct A
+ {
+   typedef struct { int i; } S;
+ };
+ 
+ template <class T>
+ struct B: public A
+ {
+   template <class U>
+   static S f ();
+ };
+ 
+ template struct B<int>;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]