" literal operator template %qD", newdecl, olddecl);
}
+ /* True to merge attributes between the declarations, false to
+ set OLDDECL's attributes to those of NEWDECL (for template
+ explicit specializations that specify their own attributes
+ independent of those specified for the primary template). */
+ const bool merge_attr = (TREE_CODE (newdecl) != FUNCTION_DECL
+ || !DECL_TEMPLATE_SPECIALIZATION (newdecl)
+ || DECL_TEMPLATE_SPECIALIZATION (olddecl));
+
if (DECL_P (olddecl)
&& TREE_CODE (newdecl) == FUNCTION_DECL
&& TREE_CODE (olddecl) == FUNCTION_DECL
+ && merge_attr
&& diagnose_mismatched_attributes (olddecl, newdecl))
{
if (DECL_INITIAL (olddecl))
DECL_ORIGINAL_TYPE (newdecl) = DECL_ORIGINAL_TYPE (olddecl);
}
- /* Copy all the DECL_... slots specified in the new decl
- except for any that we copy here from the old type. */
- DECL_ATTRIBUTES (newdecl)
- = (*targetm.merge_decl_attributes) (olddecl, newdecl);
+ /* Copy all the DECL_... slots specified in the new decl except for
+ any that we copy here from the old type. */
+ if (merge_attr)
+ DECL_ATTRIBUTES (newdecl)
+ = (*targetm.merge_decl_attributes) (olddecl, newdecl);
+ else
+ DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
if (DECL_DECLARES_FUNCTION_P (olddecl) && DECL_DECLARES_FUNCTION_P (newdecl))
{
}
}
}
- else
- /* Merge the data types specified in the two decls. */
+ else if (merge_attr)
newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+ else
+ newtype = TREE_TYPE (newdecl);
if (VAR_P (newdecl))
{
&& !(processing_template_decl && uses_template_parms (newdecl)))
layout_decl (newdecl, 0);
- /* Merge the type qualifiers. */
- if (TREE_READONLY (newdecl))
- TREE_READONLY (olddecl) = 1;
- if (TREE_THIS_VOLATILE (newdecl))
- TREE_THIS_VOLATILE (olddecl) = 1;
- if (TREE_NOTHROW (newdecl))
- TREE_NOTHROW (olddecl) = 1;
-
/* Merge deprecatedness. */
if (TREE_DEPRECATED (newdecl))
TREE_DEPRECATED (olddecl) = 1;
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)
= DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl);
}
+ else
+ {
+ /* Merge the const type qualifier. */
+ if (TREE_READONLY (newdecl))
+ TREE_READONLY (olddecl) = 1;
+ /* Merge the volatile type qualifier. */
+ if (TREE_THIS_VOLATILE (newdecl))
+ TREE_THIS_VOLATILE (olddecl) = 1;
+ }
/* Merge the initialization information. */
if (DECL_INITIAL (newdecl) == NULL_TREE
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
|= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
- TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
- TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
- DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
- DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
- TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
- DECL_LOOPING_CONST_OR_PURE_P (newdecl)
+ DECL_LOOPING_CONST_OR_PURE_P (newdecl)
|= DECL_LOOPING_CONST_OR_PURE_P (olddecl);
+
+ if (merge_attr)
+ {
+ TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+ TREE_THIS_VOLATILE (olddecl) |= TREE_THIS_VOLATILE (newdecl);
+ TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
+ TREE_NOTHROW (olddecl) |= TREE_NOTHROW (newdecl);
+ TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+ DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
+ DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
+ }
+ else
+ {
+ /* Merge the noreturn bit. */
+ TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
+ TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
+ TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl);
+ DECL_IS_MALLOC (olddecl) = DECL_IS_MALLOC (newdecl);
+ DECL_PURE_P (olddecl) = DECL_PURE_P (newdecl);
+ }
/* Keep the old RTL. */
COPY_DECL_RTL (olddecl, newdecl);
}
/* [temp.expl.spec/14] We don't inline explicit specialization
just because the primary template says so. */
- /* But still keep DECL_DISREGARD_INLINE_LIMITS in sync with
- the always_inline attribute. */
- if (DECL_DISREGARD_INLINE_LIMITS (olddecl)
- && !DECL_DISREGARD_INLINE_LIMITS (newdecl))
+ if (merge_attr)
{
- if (DECL_DECLARED_INLINE_P (newdecl))
- DECL_DISREGARD_INLINE_LIMITS (newdecl) = true;
- else
- DECL_ATTRIBUTES (newdecl)
- = remove_attribute ("always_inline",
- DECL_ATTRIBUTES (newdecl));
+ /* But still keep DECL_DISREGARD_INLINE_LIMITS in sync with
+ the always_inline attribute. */
+ if (DECL_DISREGARD_INLINE_LIMITS (olddecl)
+ && !DECL_DISREGARD_INLINE_LIMITS (newdecl))
+ {
+ if (DECL_DECLARED_INLINE_P (newdecl))
+ DECL_DISREGARD_INLINE_LIMITS (newdecl) = true;
+ else
+ DECL_ATTRIBUTES (newdecl)
+ = remove_attribute ("always_inline",
+ DECL_ATTRIBUTES (newdecl));
+ }
+ }
+ else
+ {
+ DECL_DECLARED_INLINE_P (olddecl)
+ = DECL_DECLARED_INLINE_P (newdecl);
+
+ DECL_DISREGARD_INLINE_LIMITS (olddecl)
+ = DECL_DISREGARD_INLINE_LIMITS (newdecl);
+
+ DECL_UNINLINABLE (olddecl) = DECL_UNINLINABLE (newdecl);
}
}
else if (new_defines_function && DECL_INITIAL (olddecl))
template_count,
2 * funcdef_flag +
4 * (friendp != 0) +
- 8 * concept_p);
+ 8 * concept_p,
+ *attrlist);
if (decl == error_mark_node)
return NULL_TREE;