If a template function contained a pragma that made it strictfp, code
generation for such function crashed, because the instantiation did not
have strictfp attribute. As a solution this attribute is copied from the
template to instantiation.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
We have code somewhere to generically copy attributes from function templates to instantiations, right? Why do we need to explicitly copy StrictFPAttr in particular, separate from that?
It's the call to InstantiateAttrs in InitFunctionInstantiation. InstantiateAttrs hard-codes a list of attributes to clone, which seems like a bad design, but it's easy enough to add your attribute as another case to that list.
Thanks!
InstantiateAttrs is updated accordingly. It solves the problem but not for late-parsed templates. Strictfp is evaluated based on function body, but when a declaration for late-parsed template is instantiated, the body is absent yet. A new method is added to Sema to make attribute update when template body is available.
If the "strictfp" attribute is based on the contents of the function body, should we recompute it when the function is instantiated, as opposed to copying it? For example, say you have a pragma inside an "if constexpr"; should that set the strictfp attribute if it's discarded?
Otherwise, I guess updateAttrsForLateParsedTemplate makes sense.
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | ||
---|---|---|
817 | Is this necessary? The non-delayed-parsed case seems to work correctly on trunk without any changes, so I suspect the autogenerated sema::instantiateTemplateAttribute is doing the right thing. |
Recomputing is certainly a better solution, as it would provide actual properties. It however should be applied to all instantiations, not only late parsed. With this change the code:
template <typename T, bool F> T templ_01(T x, T y) { if constexpr (F) { #pragma STDC FENV_ACCESS ON return x - y; } else return x + y; } float func_02(float x, float y) { return templ_01<float, true>(x, y); } float func_03(float x, float y) { return templ_01<float, false>(x, y); }
compiled without late parsing produces func_03 with strictfp attribute. However constarined intrinsics in it are semantically equivalent to non-constrained operations. Adding unneeded strictfp attribute is not an error.
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | ||
---|---|---|
817 | Yes, it is necessary. Without it the code from the added test crashes, as constrained intrinsic is used in a function without strictfp attribute. |
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | ||
---|---|---|
817 | https://godbolt.org/z/MvPrejY75 indicates this is only an issue with -fdelayed-template-parsing; am I missing something? |
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | ||
---|---|---|
817 | Indeed. I used Windows where this flag is on by default. Thank you for the catch. |
Is this necessary? The non-delayed-parsed case seems to work correctly on trunk without any changes, so I suspect the autogenerated sema::instantiateTemplateAttribute is doing the right thing.