PR21216 and non-type template parameters of reference type

So I’m looking at addressing PR21216 and I’ve come across a few hiccups:

  • I can fix the bug as filed by using TemplateArgument’s isDeclForReferenceParameter to either create a reference or a pointer type for the argument

  • But this doesn’t include const-ness. How would I differentiate the types of the arguments to these template parameters: “template<const int&, int&>” ?

  • This also doesn’t include rvalue ref-ness. How would I differentiate the types of the arguments to these template parameters: “template<int &, int&&>” ?

  • Clang prints the desugared name (which we use in the debug info, but can also appear in diagnostics) somewhat strange/incorrectly:

int i;
template<int& I, int *J, int&& K, const int &L>
struct foo {
};

foo<i, &i, i, i> f;

void f1(int);

template
void f2(T t) {
f1(t);
}

int main() {
f1(f);
f2(f);
}

Clang produces (just cutting to the notes in question):

templ.cpp:16:3: error: no matching function for call to ‘f1’
f1(f);
^~
templ.cpp:8:6: note: candidate function not viable: no known conversion from ‘foo<i, &i, i, i>’ to ‘int’ for 1st argument
void f1(int);
^
templ.cpp:12:3: error: no matching function for call to ‘f1’
f1(t);
^~
templ.cpp:17:3: note: in instantiation of function template specialization ‘f2<foo<&i, &i, &i, &i> >’ requested here
f2(f);
^
templ.cpp:8:6: note: candidate function not viable: no known conversion from ‘foo<&i, &i, &i, &i>’ to ‘int’ for 1st argument
void f1(int);
^

Note the desugaring of the template adds ‘&’ to all the parameters, even the reference parameters.

GCC gets something that looks ugly but probably correct:

templ.cpp: In function ‘int main()’:
templ.cpp:16:7: error: cannot convert ‘foo<(* & i), (& i), (* & i), ((const int&)(& i))>’ to ‘int’ for argument ‘1’ to ‘void f1(int)’
f1(f);
^

Though, weirdly, GCC doesn’t reject the call to f2… which is weird.

Anyway: where should I get the right type for my non-type template arguments? Do I have to go spelunking through the template parameters (can I get to them from the template arguments) & try to stitch the type together? That’s probably not ideal…

& what can we do about the type printing for non-type template parameters? (I haven’t spent too long searching for where those extra ‘&’ are coming from yet - but pointers would be appreciated)

Thanks,

  • David

Sorry, PR21246.

So I'm looking at addressing PR21216

Are you sure that's the right bug number?

and I've come across a few hiccups:

* I can fix the bug as filed by using TemplateArgument's
isDeclForReferenceParameter to either create a reference or a pointer type
for the argument

* But this doesn't include const-ness. How would I differentiate the types
of the arguments to these template parameters: "template<const int&, int&>"
?

* This also doesn't include rvalue ref-ness. How would I differentiate the
types of the arguments to these template parameters: "template<int &,
int&&>" ?

* Clang prints the desugared name (which we use in the debug info, but can
also appear in diagnostics) somewhat strange/incorrectly:

int i;
template<int& I, int *J, int&& K, const int &L>
struct foo {
};

foo<i, &i, i, i> f;

void f1(int);

template<typename T>
void f2(T t) {
  f1(t);
}

int main() {
  f1(f);
  f2(f);
}

Clang produces (just cutting to the notes in question):
templ.cpp:16:3: error: no matching function for call to 'f1'
  f1(f);
  ^~
templ.cpp:8:6: note: candidate function not viable: no known conversion
from 'foo<i, &i, i, i>' to 'int' for 1st argument
void f1(int);
     ^
templ.cpp:12:3: error: no matching function for call to 'f1'
  f1(t);
  ^~
templ.cpp:17:3: note: in instantiation of function template specialization
'f2<foo<&i, &i, &i, &i> >' requested here
  f2(f);
  ^
templ.cpp:8:6: note: candidate function not viable: no known conversion
from 'foo<&i, &i, &i, &i>' to 'int' for 1st argument
void f1(int);
     ^

Note the desugaring of the template adds '&' to all the parameters, even
the reference parameters.

GCC gets something that looks ugly but probably correct:
templ.cpp: In function ‘int main()’:
templ.cpp:16:7: error: cannot convert ‘foo<(* & i), (& i), (* & i),
((const int&)(& i))>’ to ‘int’ for argument ‘1’ to ‘void f1(int)’
   f1(f);
       ^

Though, weirdly, GCC doesn't reject the call to f2... which is weird.

Anyway: where should I get the right type for my non-type template
arguments? Do I have to go spelunking through the template parameters (can
I get to them from the template arguments) & try to stitch the type
together? That's probably not ideal...

Right now, I think you need the template parameters.

So I'm looking at addressing PR21216

Are you sure that's the right bug number?

Nope, sorry about that. Actually PR21246:
http://llvm.org/bugs/show_bug.cgi?id=21246

and I've come across a few hiccups:

* I can fix the bug as filed by using TemplateArgument's
isDeclForReferenceParameter to either create a reference or a pointer type
for the argument

* But this doesn't include const-ness. How would I differentiate the
types of the arguments to these template parameters: "template<const int&,
int&>" ?

* This also doesn't include rvalue ref-ness. How would I differentiate
the types of the arguments to these template parameters: "template<int &,
int&&>" ?

* Clang prints the desugared name (which we use in the debug info, but
can also appear in diagnostics) somewhat strange/incorrectly:

int i;
template<int& I, int *J, int&& K, const int &L>
struct foo {
};

foo<i, &i, i, i> f;

void f1(int);

template<typename T>
void f2(T t) {
  f1(t);
}

int main() {
  f1(f);
  f2(f);
}

Clang produces (just cutting to the notes in question):
templ.cpp:16:3: error: no matching function for call to 'f1'
  f1(f);
  ^~
templ.cpp:8:6: note: candidate function not viable: no known conversion
from 'foo<i, &i, i, i>' to 'int' for 1st argument
void f1(int);
     ^
templ.cpp:12:3: error: no matching function for call to 'f1'
  f1(t);
  ^~
templ.cpp:17:3: note: in instantiation of function template
specialization 'f2<foo<&i, &i, &i, &i> >' requested here
  f2(f);
  ^
templ.cpp:8:6: note: candidate function not viable: no known conversion
from 'foo<&i, &i, &i, &i>' to 'int' for 1st argument
void f1(int);
     ^

Note the desugaring of the template adds '&' to all the parameters, even
the reference parameters.

GCC gets something that looks ugly but probably correct:
templ.cpp: In function ‘int main()’:
templ.cpp:16:7: error: cannot convert ‘foo<(* & i), (& i), (* & i),
((const int&)(& i))>’ to ‘int’ for argument ‘1’ to ‘void f1(int)’
   f1(f);
       ^

Though, weirdly, GCC doesn't reject the call to f2... which is weird.

Anyway: where should I get the right type for my non-type template
arguments? Do I have to go spelunking through the template parameters (can
I get to them from the template arguments) & try to stitch the type
together? That's probably not ideal...

Right now, I think you need the template parameters.

Hrm. I'm a bit concerned about trying to make this work with complex
dependent types...

template<typename T, typename T::foo F> struct foo { };
struct outer { typedef const int &foo; };
int i;
foo<outer, i> f;

is that going to be easier than I'm thinking? I'm a bit concerned about
figuring out the instantiation of T::foo from the template parameter
description...

This is a problem; we don't preserve enough information here.

Right you are, and as suggested offline it seems we had enough space to
store the whole QualType (TemplateArgument::Integer is the long pole, with
two 32 bit ints and two pointer sized elements - so
TemplateArgument::Declaration is only that big (one 32 bit int and two
pointer sized elements, plus alignment) on 64 bit, and smaller on 32 bit)
so I've done that and implemented the full debug info support in r219900.

I didn't look into/figure out where the weird type printing is coming from
as yet, and there were some other oddities I've called out in the commit
message.

- David