LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 34343 - After r305903, Assertion failed: (Replacement.isCanonical() && "replacement types must always be canonical"), function getSubstTemplateTypeParmType,
Summary: After r305903, Assertion failed: (Replacement.isCanonical() && "replacement t...
Status: NEW
Alias: None
Product: clang
Classification: Unclassified
Component: -New Bugs (show other bugs)
Version: trunk
Hardware: All All
: P normal
Assignee: Unassigned Clang Bugs
URL:
Keywords: regression
Depends on:
Blocks:
 
Reported: 2017-08-28 04:34 PDT by Dimitry Andric
Modified: 2018-10-25 20:12 PDT (History)
5 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dimitry Andric 2017-08-28 04:34:42 PDT
In https://bugs.freebsd.org/221864, Jan Beich describes how building a vulkan LLVM wrapper causes clang 5.0.0 rc2 to assert with: 'Assertion failed: (Replacement.isCanonical() && "replacement types must always be canonical"), function getSubstTemplateTypeParmType, file /poudriere/jails/head-amd64/usr/src/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp, line 3520.'

This also reproduces on trunk r311836, resulting in:

Assertion failed: (Replacement.isCanonical() && "replacement types must always be canonical"), function getSubstTemplateTypeParmType, file /share/dim/src/llvm/trunk/tools/clang/lib/AST/ASTContext.cpp, line 3516.
#0 0x00000000012e2c08 llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/share/dim/llvm/311836-trunk-freebsd12-amd64-ninja-rel-1/bin/clang+0x12e2c08)
#1 0x00000000012e31f6 SignalHandler(int) (/share/dim/llvm/311836-trunk-freebsd12-amd64-ninja-rel-1/bin/clang+0x12e31f6)
#2 0x0000000803b0c8f6 handle_signal /usr/src/lib/libthr/thread/thr_sig.c:0:3
Stack dump:
0.      Program arguments: /share/dim/llvm/311836-trunk-freebsd12-amd64-ninja-rel-1/bin/clang -cc1 -triple x86_64-unknown-freebsd12.0 -emit-obj -mrelax-all -disable-free -main-file-name llvm_wrapper.cpp -mrelocation-model static -mthread-model posix -mdisable-fp-elim -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -coverage-notes-file /tmp/vulkan-cpu/src/llvm_wrapper/CMakeFiles/vulkan_cpu_llvm_wrapper.dir/llvm_wrapper.cpp.gcno -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -Wall -Werror -Wno-error=#warnings -std=gnu++14 -fdeprecated-macro -ftemplate-depth 1024 -ferror-limit 19 -fmessage-length 101 -fobjc-runtime=gnustep -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -x c++ llvm_wrapper-eb0531.cpp
1.      /tmp/vulkan-cpu/src/llvm_wrapper/llvm_wrapper.h:202:5: current parser token '{'
2.      /tmp/vulkan-cpu/src/llvm_wrapper/llvm_wrapper.h:43:1: parsing namespace 'vulkan_cpu'
3.      /tmp/vulkan-cpu/src/llvm_wrapper/llvm_wrapper.h:45:1: parsing namespace 'vulkan_cpu::llvm_wrapper'
4.      /tmp/vulkan-cpu/src/llvm_wrapper/llvm_wrapper.h:189:1: parsing struct/union/class body 'vulkan_cpu::llvm_wrapper::Target'
5.      /tmp/vulkan-cpu/src/util/variant.h:895:7: instantiating class definition 'vulkan_cpu::util::variant<vulkan_cpu::llvm_wrapper::Target, vulkan_cpu::llvm_wrapper::LLVM_string>'

Bisection shows that this started occurring after https://reviews.llvm.org/rL305903 ("Function with unparsed body is a definition"), which is a fix for bug 14785.

Minimized test case:

// clang -cc1 -triple x86_64 -S -std=c++11 -fcxx-exceptions -fexceptions testcase.cpp
template <int, class> struct a;
namespace b {
constexpr int c() { return 0; }
template <int, typename> struct d;
template <typename... e> using f = d<0, e...>;
}
template <typename> struct g {
  template <typename... h>
  friend constexpr typename a<b::f<h...>::i, bool>::j
  operator==(const g<h...> &, const g<h...> &) noexcept(b::f<h...>::k);
};
template <typename... e>
constexpr typename a<b::f<e...>::i, bool>::j
operator==(const g<e...> &, const g<e...> &) noexcept(b::f<e...>::k);
void l(g<int>) {}
Comment 1 Serge Pavlov 2017-09-24 06:55:04 PDT
Revision 305903 introduced the change into SemaTemplateInstantiateDecl.cpp:

if (isFriend)
    Function->setObjectOfFriendDecl();

Previously an instantiation of a friend function was not marked as a friend declaration, which is wrong. As a result the code in Sema::getTemplateInstantiationArgs is executed:

      // If this is a friend declaration and it declares an entity at
      // namespace scope, take arguments from its lexical parent
      // instead of its semantic parent, unless of course the pattern we're
      // instantiating actually comes from the file's context!
      if (Function->getFriendObjectKind() &&
          Function->getDeclContext()->isFileContext() &&
          (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
        Ctx = Function->getLexicalDeclContext();
        RelativeToPrimary = false;
        continue;
      }

It changed instantiation stack for the friend operator. Previously it contained only (<typename... h>), now it contains two levels: (<int>, <typename... h>). Both are wrong as we do not have arguments for <typename… h>, it is a template parameter. The correct state of state of instantiation stack would be (<int>), a template argument of containing class. Previously code worked due to behavior of Sema::CheckParameterPacksForExpansion:

      // If we don't have a template argument at this depth/index, then we 
      // cannot expand the pack expansion. Make a note of this, but we still 
      // want to check any parameter packs we *do* have arguments for.
      if (Depth >= TemplateArgs.getNumLevels() ||
          !TemplateArgs.hasTemplateArgument(Depth, Index)) {
        ShouldExpand = false;
        continue;
      }

Depth of the template function parameter <typename… h> was 0. It is incorrect but template argument stack was incorrect too (<typename… h>) and `ShouldExpand` was set to false, it prevented the pack expansion. Now 'Depth' has right value (1), but template argument stack is wrong (<int>, <typename… h>). `ShouldExpand` is set to `true`, but instantiation stack contains template parameters instead of template arguments and assertion check is fired.

Instantiation of friend function templates was fixed in the patch https://reviews.llvm.org/D21767. With it the code presented in this report compiles successfully.