Using clang-tool to Exact type names in template specification arguments

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
    ...
}
int main() {
    ...
    func<vector32_t>(...);
    ...
}

I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t". 

Any thoughts on how I can extract the type alias name "vector32_t" in my above example? 

Thanks,
Oliver

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:

>
> Hi,
>
> I'm using clang-tool to extract type names in template arguments. For example,
>
>> typedef unsigned int vectors32_t[32];
>> template <typename T>
>> func(T *const vec) {
>>     ...
>> }
>> int main() {
>>     ...
>>     func<vector32_t>(...);
>>     ...
>> }
>
>
> I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".
>
> Any thoughts on how I can extract the type alias name "vector32_t" in my above example?
>
> Thanks,
> Oliver
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.  

You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in  

Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)


For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.

Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):

I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.

- Dave

On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:

Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:

Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
   ...
}
int main() {
   ...
   func<vector32_t>(...);
   ...
}


I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".

Any thoughts on how I can extract the type alias name "vector32_t" in my above example?

Thanks,
Oliver
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
Correction: I did not notice that was a typename parameter, not a non-type template parameter as Pratyush addressed — so the issue is broader.  Perhaps CheckTemplateArgument(TemplateTypeParmDecl *, …) needs to be addressed too, e.g. perhaps in this line the original type should be used instead of the canonical type:

https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6126

That fix, or one like it, would probably solve Oliver’s issue.

More generally there is no reason to be replacing types with their canonical types anywhere in the AST, I believe.

- Dave

On Aug 13, 2020, at 10:13 AM, David Rector <[hidden email]> wrote:

Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.  

You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in  

Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)


For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.

Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):

I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.

- Dave

On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:

Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:

Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
   ...
}
int main() {
   ...
   func<vector32_t>(...);
   ...
}


I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".

Any thoughts on how I can extract the type alias name "vector32_t" in my above example?

Thanks,
Oliver
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
On Thu, Aug 13, 2020 at 7:45 AM David Rector <[hidden email]> wrote:
>
> Correction: I did not notice that was a typename parameter, not a non-type template parameter as Pratyush addressed — so the issue is broader.  Perhaps CheckTemplateArgument(TemplateTypeParmDecl *, …) needs to be addressed too, e.g. perhaps in this line the original type should be used instead of the canonical type:
>
> https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6126
>
> That fix, or one like it, would probably solve Oliver’s issue.
>
> More generally there is no reason to be replacing types with their canonical types anywhere in the AST, I believe.

I believe there is - ultimately there's only one implicit
specialization of 'f1' (f1<int>, specifically) in code like this:

template<typename T> void f1() { }
int main() {
  using x = int;
  using y = int;
  f1<x>();
  f1<y>();
}

So the FunctionDecl for 'f1' can't refer to x or y, it has to refer to
'int', right?

>
> - Dave
>
> On Aug 13, 2020, at 10:13 AM, David Rector <[hidden email]> wrote:
>
> Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.
>
> You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in
>
> Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)
>
> linked to here: https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6688.
>
> For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.
>
> Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):
> https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6955
>
> I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.
>
> - Dave
>
> On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:
>
> Once you have the FunctionDecl you've gone too far and any type sugar
> is lost, I believe. (because func<vectors32_t> is the same function as
> func<unsigned int[32]> or any other typedef/alias/etc of that type
> parameter, etc)
>
> I think you'd have to be able to see the call to the function, and go
> from there to find the type as written.
>
> On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
> <[hidden email]> wrote:
>
>
> Hi,
>
> I'm using clang-tool to extract type names in template arguments. For example,
>
> typedef unsigned int vectors32_t[32];
> template <typename T>
> func(T *const vec) {
>    ...
> }
> int main() {
>    ...
>    func<vector32_t>(...);
>    ...
> }
>
>
>
> I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".
>
> Any thoughts on how I can extract the type alias name "vector32_t" in my above example?
>
> Thanks,
> Oliver
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
>
>
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
Yes you’re right, good point.  In the FunctionDecl level the template argument types must be canonical.  

Oliver definitely take David’s advice to get the template arguments from the DeclRefExpr referenced in the CallExpr — hopefully that should contain the proper type sugar. 

Pratyush, this unfortunately may have the implications for the solution you employed in https://reviews.llvm.org/D77598 at my suggestion, in order to distinguish between deduced and non-deduced non-type template arguments.  

I think you should go with the first suggestion I gave you: simply change line https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6823 to this:

QualType CanonParamType = Context.getCanonicalType(ParamType);

// Note: this renders CanonParamType non-canonical, but since every instantiation
// of this argument will be wrapped in an AutoType (since Param->getType() will always
// be an AutoType for this template), there should be no difference in how arguments 
// are distinguished.
if (Param->getType()->getAs<AutoType>())
  CanonParamType = Context.getAutoType(CanonParamType, AutoTypeKeyword::Auto,
                                       false, false);

Good catch, David.

Dave


On Aug 13, 2020, at 11:58 AM, David Blaikie <[hidden email]> wrote:

On Thu, Aug 13, 2020 at 7:45 AM David Rector <[hidden email]> wrote:

Correction: I did not notice that was a typename parameter, not a non-type template parameter as Pratyush addressed — so the issue is broader.  Perhaps CheckTemplateArgument(TemplateTypeParmDecl *, …) needs to be addressed too, e.g. perhaps in this line the original type should be used instead of the canonical type:

https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6126

That fix, or one like it, would probably solve Oliver’s issue.

More generally there is no reason to be replacing types with their canonical types anywhere in the AST, I believe.

I believe there is - ultimately there's only one implicit
specialization of 'f1' (f1<int>, specifically) in code like this:

template<typename T> void f1() { }
int main() {
 using x = int;
 using y = int;
 f1<x>();
 f1<y>();
}

So the FunctionDecl for 'f1' can't refer to x or y, it has to refer to
'int', right?


- Dave

On Aug 13, 2020, at 10:13 AM, David Rector <[hidden email]> wrote:

Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.

You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in

Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)

linked to here: https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6688.

For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.

Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):
https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6955

I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.

- Dave

On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:

Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:


Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
  ...
}
int main() {
  ...
  func<vector32_t>(...);
  ...
}



I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".

Any thoughts on how I can extract the type alias name "vector32_t" in my above example?

Thanks,
Oliver
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev





_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev

On Thu, 13 Aug 2020 at 21:50, David Rector <[hidden email]> wrote:
Yes you’re right, good point.  In the FunctionDecl level the template argument types must be canonical.  

Oliver definitely take David’s advice to get the template arguments from the DeclRefExpr referenced in the CallExpr — hopefully that should contain the proper type sugar. 

Pratyush, this unfortunately may have the implications for the solution you employed in https://reviews.llvm.org/D77598 at my suggestion, in order to distinguish between deduced and non-deduced non-type template arguments.  

I think you should go with the first suggestion I gave you: simply change line https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6823 to this:

QualType CanonParamType = Context.getCanonicalType(ParamType);

// Note: this renders CanonParamType non-canonical, but since every instantiation
// of this argument will be wrapped in an AutoType (since Param->getType() will always
// be an AutoType for this template), there should be no difference in how arguments 
// are distinguished.
if (Param->getType()->getAs<AutoType>())
  CanonParamType = Context.getAutoType(CanonParamType, AutoTypeKeyword::Auto,
                                       false, false);

Good catch, David.

Dave


On Aug 13, 2020, at 11:58 AM, David Blaikie <[hidden email]> wrote:

On Thu, Aug 13, 2020 at 7:45 AM David Rector <[hidden email]> wrote:

Correction: I did not notice that was a typename parameter, not a non-type template parameter as Pratyush addressed — so the issue is broader.  Perhaps CheckTemplateArgument(TemplateTypeParmDecl *, …) needs to be addressed too, e.g. perhaps in this line the original type should be used instead of the canonical type:

https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6126

That fix, or one like it, would probably solve Oliver’s issue.

More generally there is no reason to be replacing types with their canonical types anywhere in the AST, I believe.

I believe there is - ultimately there's only one implicit
specialization of 'f1' (f1<int>, specifically) in code like this:

template<typename T> void f1() { }
int main() {
 using x = int;
 using y = int;
 f1<x>();
 f1<y>();
}

So the FunctionDecl for 'f1' can't refer to x or y, it has to refer to
'int', right?


- Dave

On Aug 13, 2020, at 10:13 AM, David Rector <[hidden email]> wrote:

Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.

You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in

Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)

linked to here: https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6688.

For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.

Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):
https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6955

I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.

- Dave

On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:

Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:


Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
  ...
}
int main() {
  ...
  func<vector32_t>(...);
  ...
}



I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".

Any thoughts on how I can extract the type alias name "vector32_t" in my above example?

Thanks,
Oliver
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev






--
Pratyush Das(Reik)

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
In reply to this post by Hubert Tong via cfe-dev
Thanks David and Dave for your nice suggestions and thoughts!

Unfortunately the case I need to handle is a little more complex than I thought, as implicit template specification is involved. Now the full example looks like this (differences from the previous example is highlighted):
typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
    ...
}
int main() {
    ...
    vector32_t *vecPtr = ...;
    func(vecPtr);
    ...
}

I didn't find a way to get the type alias name ("vector32_t") from an implicit template argument by using CallExpr or DeclRefExpr. Actually it seems information about "vector32_t" can only be retrieved from the typedef and the declaration of "vecPtr".

Best,
Oliver

On Fri, Aug 14, 2020 at 12:20 AM David Rector <[hidden email]> wrote:
Yes you’re right, good point.  In the FunctionDecl level the template argument types must be canonical.  

Oliver definitely take David’s advice to get the template arguments from the DeclRefExpr referenced in the CallExpr — hopefully that should contain the proper type sugar. 

Pratyush, this unfortunately may have the implications for the solution you employed in https://reviews.llvm.org/D77598 at my suggestion, in order to distinguish between deduced and non-deduced non-type template arguments.  

I think you should go with the first suggestion I gave you: simply change line https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6823 to this:

QualType CanonParamType = Context.getCanonicalType(ParamType);

// Note: this renders CanonParamType non-canonical, but since every instantiation
// of this argument will be wrapped in an AutoType (since Param->getType() will always
// be an AutoType for this template), there should be no difference in how arguments 
// are distinguished.
if (Param->getType()->getAs<AutoType>())
  CanonParamType = Context.getAutoType(CanonParamType, AutoTypeKeyword::Auto,
                                       false, false);

Good catch, David.

Dave


On Aug 13, 2020, at 11:58 AM, David Blaikie <[hidden email]> wrote:

On Thu, Aug 13, 2020 at 7:45 AM David Rector <[hidden email]> wrote:

Correction: I did not notice that was a typename parameter, not a non-type template parameter as Pratyush addressed — so the issue is broader.  Perhaps CheckTemplateArgument(TemplateTypeParmDecl *, …) needs to be addressed too, e.g. perhaps in this line the original type should be used instead of the canonical type:

https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6126

That fix, or one like it, would probably solve Oliver’s issue.

More generally there is no reason to be replacing types with their canonical types anywhere in the AST, I believe.

I believe there is - ultimately there's only one implicit
specialization of 'f1' (f1<int>, specifically) in code like this:

template<typename T> void f1() { }
int main() {
 using x = int;
 using y = int;
 f1<x>();
 f1<y>();
}

So the FunctionDecl for 'f1' can't refer to x or y, it has to refer to
'int', right?


- Dave

On Aug 13, 2020, at 10:13 AM, David Rector <[hidden email]> wrote:

Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.

You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in

Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)

linked to here: https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6688.

For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.

Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):
https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6955

I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.

- Dave

On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:

Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:


Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
  ...
}
int main() {
  ...
  func<vector32_t>(...);
  ...
}



I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".

Any thoughts on how I can extract the type alias name "vector32_t" in my above example?

Thanks,
Oliver
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev





_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
There will not be any template arguments in the DeclRefExpr in that example, as nothing was specifically written in brackets.  

If instead of func(vecPtr) you wrote func<vector32_t>(vecPtr), there would be a template argument in the DeclRefExpr with the proper sugared type (i.e. vector32_t, not unsigned int[32]).

But the DeclRefExpr does not implicitly generate this template argument, and probably should not, because that would muddy its purpose of representing the particular syntax used in referring to some declaration.

So, I think your best bet if you really want to refer to vector32_t instead of unsigned int[32] is to either a) explicitly specify the template arguments in your func calls or b) define vector32_t as a wrapper class instead of a typedef (such that when passed as a template argument it would be instantiated separately from an unsigned int[32] argument).

Hope that helps,

Dave

On Aug 17, 2020, at 12:41 AM, Oliver Zhang <[hidden email]> wrote:

Thanks David and Dave for your nice suggestions and thoughts!

Unfortunately the case I need to handle is a little more complex than I thought, as implicit template specification is involved. Now the full example looks like this (differences from the previous example is highlighted):
typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
    ...
}
int main() {
    ...
    vector32_t *vecPtr = ...;
    func(vecPtr);
    ...
}

I didn't find a way to get the type alias name ("vector32_t") from an implicit template argument by using CallExpr or DeclRefExpr. Actually it seems information about "vector32_t" can only be retrieved from the typedef and the declaration of "vecPtr".

Best,
Oliver

On Fri, Aug 14, 2020 at 12:20 AM David Rector <[hidden email]> wrote:
Yes you’re right, good point.  In the FunctionDecl level the template argument types must be canonical.  

Oliver definitely take David’s advice to get the template arguments from the DeclRefExpr referenced in the CallExpr — hopefully that should contain the proper type sugar. 

Pratyush, this unfortunately may have the implications for the solution you employed in https://reviews.llvm.org/D77598 at my suggestion, in order to distinguish between deduced and non-deduced non-type template arguments.  

I think you should go with the first suggestion I gave you: simply change line https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6823 to this:

QualType CanonParamType = Context.getCanonicalType(ParamType);

// Note: this renders CanonParamType non-canonical, but since every instantiation
// of this argument will be wrapped in an AutoType (since Param->getType() will always
// be an AutoType for this template), there should be no difference in how arguments 
// are distinguished.
if (Param->getType()->getAs<AutoType>())
  CanonParamType = Context.getAutoType(CanonParamType, AutoTypeKeyword::Auto,
                                       false, false);

Good catch, David.

Dave


On Aug 13, 2020, at 11:58 AM, David Blaikie <[hidden email]> wrote:

On Thu, Aug 13, 2020 at 7:45 AM David Rector <[hidden email]> wrote:

Correction: I did not notice that was a typename parameter, not a non-type template parameter as Pratyush addressed — so the issue is broader.  Perhaps CheckTemplateArgument(TemplateTypeParmDecl *, …) needs to be addressed too, e.g. perhaps in this line the original type should be used instead of the canonical type:

https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6126

That fix, or one like it, would probably solve Oliver’s issue.

More generally there is no reason to be replacing types with their canonical types anywhere in the AST, I believe.

I believe there is - ultimately there's only one implicit
specialization of 'f1' (f1<int>, specifically) in code like this:

template<typename T> void f1() { }
int main() {
 using x = int;
 using y = int;
 f1<x>();
 f1<y>();
}

So the FunctionDecl for 'f1' can't refer to x or y, it has to refer to
'int', right?


- Dave

On Aug 13, 2020, at 10:13 AM, David Rector <[hidden email]> wrote:

Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.

You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in

Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)

linked to here: https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6688.

For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.

Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):
https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6955

I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.

- Dave

On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:

Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:


Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
  ...
}
int main() {
  ...
  func<vector32_t>(...);
  ...
}



I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".

Any thoughts on how I can extract the type alias name "vector32_t" in my above example?

Thanks,
Oliver
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev






_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using clang-tool to Exact type names in template specification arguments

Hubert Tong via cfe-dev
Thanks for your thoughtful reply, Dave! It's really helpful!

Best,
Oliver

On Mon, Aug 17, 2020 at 11:50 PM David Rector <[hidden email]> wrote:
There will not be any template arguments in the DeclRefExpr in that example, as nothing was specifically written in brackets.  

If instead of func(vecPtr) you wrote func<vector32_t>(vecPtr), there would be a template argument in the DeclRefExpr with the proper sugared type (i.e. vector32_t, not unsigned int[32]).

But the DeclRefExpr does not implicitly generate this template argument, and probably should not, because that would muddy its purpose of representing the particular syntax used in referring to some declaration.

So, I think your best bet if you really want to refer to vector32_t instead of unsigned int[32] is to either a) explicitly specify the template arguments in your func calls or b) define vector32_t as a wrapper class instead of a typedef (such that when passed as a template argument it would be instantiated separately from an unsigned int[32] argument).

Hope that helps,

Dave

On Aug 17, 2020, at 12:41 AM, Oliver Zhang <[hidden email]> wrote:

Thanks David and Dave for your nice suggestions and thoughts!

Unfortunately the case I need to handle is a little more complex than I thought, as implicit template specification is involved. Now the full example looks like this (differences from the previous example is highlighted):
typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
    ...
}
int main() {
    ...
    vector32_t *vecPtr = ...;
    func(vecPtr);
    ...
}

I didn't find a way to get the type alias name ("vector32_t") from an implicit template argument by using CallExpr or DeclRefExpr. Actually it seems information about "vector32_t" can only be retrieved from the typedef and the declaration of "vecPtr".

Best,
Oliver

On Fri, Aug 14, 2020 at 12:20 AM David Rector <[hidden email]> wrote:
Yes you’re right, good point.  In the FunctionDecl level the template argument types must be canonical.  

Oliver definitely take David’s advice to get the template arguments from the DeclRefExpr referenced in the CallExpr — hopefully that should contain the proper type sugar. 

Pratyush, this unfortunately may have the implications for the solution you employed in https://reviews.llvm.org/D77598 at my suggestion, in order to distinguish between deduced and non-deduced non-type template arguments.  

I think you should go with the first suggestion I gave you: simply change line https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6823 to this:

QualType CanonParamType = Context.getCanonicalType(ParamType);

// Note: this renders CanonParamType non-canonical, but since every instantiation
// of this argument will be wrapped in an AutoType (since Param->getType() will always
// be an AutoType for this template), there should be no difference in how arguments 
// are distinguished.
if (Param->getType()->getAs<AutoType>())
  CanonParamType = Context.getAutoType(CanonParamType, AutoTypeKeyword::Auto,
                                       false, false);

Good catch, David.

Dave


On Aug 13, 2020, at 11:58 AM, David Blaikie <[hidden email]> wrote:

On Thu, Aug 13, 2020 at 7:45 AM David Rector <[hidden email]> wrote:

Correction: I did not notice that was a typename parameter, not a non-type template parameter as Pratyush addressed — so the issue is broader.  Perhaps CheckTemplateArgument(TemplateTypeParmDecl *, …) needs to be addressed too, e.g. perhaps in this line the original type should be used instead of the canonical type:

https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6126

That fix, or one like it, would probably solve Oliver’s issue.

More generally there is no reason to be replacing types with their canonical types anywhere in the AST, I believe.

I believe there is - ultimately there's only one implicit
specialization of 'f1' (f1<int>, specifically) in code like this:

template<typename T> void f1() { }
int main() {
 using x = int;
 using y = int;
 f1<x>();
 f1<y>();
}

So the FunctionDecl for 'f1' can't refer to x or y, it has to refer to
'int', right?


- Dave

On Aug 13, 2020, at 10:13 AM, David Rector <[hidden email]> wrote:

Ha, deja vu - Pratyush (cc’d) was just dealing with this exact issue in another context the other day, and Oliver we were kind of dealing with this same general issue the other week re: attributes.

You definitely *should* be able to get the full type sugar without fuss.  The obstacle to that is in

Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, …)

linked to here: https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6688.

For some reason within that function the Converted template argument is always constructed with Context.getCanonicalType(ParamType), instead of ParamType, which erases the type sugar needlessly.

Pratyush has solved this for the C++17 branch of that function in https://reviews.llvm.org/D77598, but Pratyush it is probably a good idea to replace all other instances of Context.getCanonicalType(XYZ) in that function with XYZ, e.g. this line (among others):
https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaTemplate.cpp#L6955

I suspect no tests will be broken with such a change, and the result will be that template arguments will always have the proper sugar available.

- Dave

On Aug 13, 2020, at 12:30 AM, David Blaikie via cfe-dev <[hidden email]> wrote:

Once you have the FunctionDecl you've gone too far and any type sugar
is lost, I believe. (because func<vectors32_t> is the same function as
func<unsigned int[32]> or any other typedef/alias/etc of that type
parameter, etc)

I think you'd have to be able to see the call to the function, and go
from there to find the type as written.

On Wed, Aug 12, 2020 at 8:14 PM Oliver Zhang via cfe-dev
<[hidden email]> wrote:


Hi,

I'm using clang-tool to extract type names in template arguments. For example,

typedef unsigned int vectors32_t[32];
template <typename T>
func(T *const vec) {
  ...
}
int main() {
  ...
  func<vector32_t>(...);
  ...
}



I'd like to get the type name "vector32_t" from func's template argument. So I use clang::FunctionDecl::getTemplateSpecializationArgs() to get func's template argument list, extract the argument from the list, and then try to get the type name for the argument by using clang::TemplateArgument::getAsType().getAsString(). However, "unsigned int [32]" is returned rather than "vector32_t".

Any thoughts on how I can extract the type alias name "vector32_t" in my above example?

Thanks,
Oliver
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev






_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev