Template specialization: why drop attributes?

Hello,

I am working on a custom attribute for an experimental project. I’ve just finally tracked down a problem where explicit template specializations have their attributes removed by Clang. I’m suspicious of the following function:

/// \brief Strips various properties off an implicit instantiation

/// that has just been explicitly specialized.

static void StripImplicitInstantiation(NamedDecl *D) {

// FIXME: “make check” is clean if the call to dropAttrs() is commented out.

D->dropAttrs();

if (FunctionDecl *FD = dyn_cast(D)) {

FD->setInlineSpecified(false);

}

}

‘dropAttrs’ does exactly what you would expect: it removes the attributes from my explicit specialization. To me, this seems like incorrect behavior. Consider the following program:

template < int N >

int Test(int x) attribute((custom))

{

return x * N;

}

template < >

int Test < 1 > (int x) attribute((custom))

{

return x;

}

When I debug a call to Test < 1 >, it behaves as if the program was written like so:

template < int N >

int Test(int x) attribute((custom))

{

return x * N;

}

template < >

int Test < 1 > (int x) // custom attribute removed by StripImplicitInstantiation.

{

return x;

}

I was hoping to understand the reasoning for this before I commented out dropAttrs here. The comment above dropAttrs seems to imply that it might not be fully correct. What is “make check”?

Thank you for any insight into this issue!

This function is only called when the instantiation has already been implicitly requested. This makes sense for most attributes because the use at the site of instantiation has probably already been fixed to use the default behavior. Is there a reason you can't provide your explicit specialization before its uses?

Jordan

What you said makes sense. However, maybe there is a separate issue, because I don't think the function has already been implicitly instantiated. I see the issue I described with the following program:

template < int N >
int Test(int x) __attribute__((custom))
{
  return x * N;
}

template < >
int Test < 1 > (int x) __attribute__((custom))
{
  return x;
}

int Call(int x) __attribute__((custom))
{
  return Test < 1 > (x);
}

When I compile this, the call to Test < 1 > is to a FunctionDecl that doesn't have the custom attribute, and I can see it getting removed by StripImplicitInstantiation when debugging.

That is the entire program, so I don't think that the implicit specialization has actually been requested until after the explicit specialization is defined.

Thank you for your help!

Dillon

Hi,

What you said makes sense. However, maybe there is a separate issue, because I don't think the function has already been implicitly instantiated. I see the issue I described with the following program:

template < int N >
int Test(int x) __attribute__((custom))
{
return x * N;
}

template < >
int Test < 1 > (int x) __attribute__((custom))

When we see this declaration, we implicitly instantiate the base
template in order to check that the explicit specialization matches
it. So we implicitly instantiate a declaration:

int Test<1>(int) __attribute__((custom));

It's that declaration from which we should be stripping the
attributes. If this is also stripping attributes which were specified
on the explicit specialization, I believe that is simply a bug.