Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICE on template template parameter with constraints #57410

Closed
Fedr opened this issue Aug 28, 2022 · 8 comments · Fixed by #76811
Closed

ICE on template template parameter with constraints #57410

Fedr opened this issue Aug 28, 2022 · 8 comments · Fixed by #76811
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts crash Prefer [crash-on-valid] or [crash-on-invalid]

Comments

@Fedr
Copy link

Fedr commented Aug 28, 2022

The following program

template<typename T>
concept C = true;

template<template<C T> typename Wrapper>
using Test = Wrapper<int>;

results in segfault in Clang:

PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-trunk/bin/clang++ -gdwarf-4 -g -o /app/output.s -mllvm --x86-asm-syntax=intel -S --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot -fcolor-diagnostics -fno-crash-diagnostics -std=c++20 -pedantic-errors -pthread <source>
1.	<source>:5:14: at annotation token
 #0 0x000055a06874dd34 PrintStackTraceSignalHandler(void*) Signals.cpp:0:0
 #1 0x000055a06874bb9c llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3945b9c)
 #2 0x000055a068689828 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007f3c56df2420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #4 0x000055a06baf168d clang::StmtVisitorBase<llvm::make_const_ptr, (anonymous namespace)::IntExprEvaluator, bool>::Visit(clang::Stmt const*) ExprConstant.cpp:0:0
 #5 0x000055a06baf7bf6 Evaluate(clang::APValue&, (anonymous namespace)::EvalInfo&, clang::Expr const*) ExprConstant.cpp:0:0
 #6 0x000055a06bb0d2be EvaluateInPlace(clang::APValue&, (anonymous namespace)::EvalInfo&, (anonymous namespace)::LValue const&, clang::Expr const*, bool) ExprConstant.cpp:0:0
 #7 0x000055a06bb48ea0 clang::Expr::EvaluateAsConstantExpr(clang::Expr::EvalResult&, clang::ASTContext const&, clang::Expr::ConstantExprKind) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x6d42ea0)
 #8 0x000055a06ae2f005 bool calculateConstraintSatisfaction<calculateConstraintSatisfaction(clang::Sema&, clang::NamedDecl const*, clang::SourceLocation, clang::MultiLevelTemplateArgumentList const&, clang::Expr const*, clang::ConstraintSatisfaction&)::'lambda'(clang::Expr const*)>(clang::Sema&, clang::Expr const*, clang::ConstraintSatisfaction&, calculateConstraintSatisfaction(clang::Sema&, clang::NamedDecl const*, clang::SourceLocation, clang::MultiLevelTemplateArgumentList const&, clang::Expr const*, clang::ConstraintSatisfaction&)::'lambda'(clang::Expr const*)&&) SemaConcept.cpp:0:0
 #9 0x000055a06ae2f615 CheckConstraintSatisfaction(clang::Sema&, clang::NamedDecl const*, llvm::ArrayRef<clang::Expr const*>, clang::MultiLevelTemplateArgumentList const&, clang::SourceRange, clang::ConstraintSatisfaction&) SemaConcept.cpp:0:0
#10 0x000055a06ae2f9f0 clang::Sema::CheckConstraintSatisfaction(clang::NamedDecl const*, llvm::ArrayRef<clang::Expr const*>, clang::MultiLevelTemplateArgumentList const&, clang::SourceRange, clang::ConstraintSatisfaction&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x60299f0)
#11 0x000055a06ae3056d clang::Sema::EnsureTemplateArgumentListConstraints(clang::TemplateDecl*, clang::MultiLevelTemplateArgumentList const&, clang::SourceRange) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x602a56d)
#12 0x000055a06b496d76 clang::Sema::CheckTemplateArgumentList(clang::TemplateDecl*, clang::SourceLocation, clang::TemplateArgumentListInfo&, bool, llvm::SmallVectorImpl<clang::TemplateArgument>&, bool, bool*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x6690d76)
#13 0x000055a06b49f5cb clang::Sema::CheckTemplateIdType(clang::TemplateName, clang::SourceLocation, clang::TemplateArgumentListInfo&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x66995cb)
#14 0x000055a06b4a2717 clang::Sema::ActOnTemplateIdType(clang::Scope*, clang::CXXScopeSpec&, clang::SourceLocation, clang::OpaquePtr<clang::TemplateName>, clang::IdentifierInfo*, clang::SourceLocation, clang::SourceLocation, llvm::MutableArrayRef<clang::ParsedTemplateArgument>, clang::SourceLocation, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x669c717)
#15 0x000055a06ac8e72b clang::Parser::AnnotateTemplateIdTokenAsType(clang::CXXScopeSpec&, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5e8872b)
#16 0x000055a06abc1a08 clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec&, clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, clang::Parser::DeclSpecContext, clang::Parser::LateParsedAttrList*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5dbba08)
#17 0x000055a06abc4d05 clang::Parser::ParseSpecifierQualifierList(clang::DeclSpec&, clang::AccessSpecifier, clang::Parser::DeclSpecContext) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5dbed05)
#18 0x000055a06abc5183 clang::Parser::ParseTypeName(clang::SourceRange*, clang::DeclaratorContext, clang::AccessSpecifier, clang::Decl**, clang::ParsedAttributes*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5dbf183)
#19 0x000055a06abdf82a clang::Parser::ParseAliasDeclarationAfterDeclarator(clang::Parser::ParsedTemplateInfo const&, clang::SourceLocation, clang::Parser::UsingDeclarator&, clang::SourceLocation&, clang::AccessSpecifier, clang::ParsedAttributes&, clang::Decl**) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5dd982a)
#20 0x000055a06abea5f8 clang::Parser::ParseUsingDeclaration(clang::DeclaratorContext, clang::Parser::ParsedTemplateInfo const&, clang::SourceLocation, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5de45f8)
#21 0x000055a06abeb325 clang::Parser::ParseUsingDirectiveOrDeclaration(clang::DeclaratorContext, clang::Parser::ParsedTemplateInfo const&, clang::SourceLocation&, clang::ParsedAttributes&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5de5325)
#22 0x000055a06ac9526b clang::Parser::ParseSingleDeclarationAfterTemplate(clang::DeclaratorContext, clang::Parser::ParsedTemplateInfo const&, clang::ParsingDeclRAIIObject&, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5e8f26b)
#23 0x000055a06ac9d7ed clang::Parser::ParseTemplateDeclarationOrSpecialization(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5e977ed)
#24 0x000055a06ac9dad3 clang::Parser::ParseDeclarationStartingWithTemplate(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5e97ad3)
#25 0x000055a06abce5b5 clang::Parser::ParseDeclaration(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::ParsedAttributes&, clang::SourceLocation*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5dc85b5)
#26 0x000055a06ab9fb36 clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsingDeclSpec*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5d99b36)
#27 0x000055a06aba18fa clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5d9b8fa)
#28 0x000055a06ab9127a clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5d8b27a)
#29 0x000055a0699adf95 clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x4ba7f95)
#30 0x000055a0692b8441 clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x44b2441)
#31 0x000055a06923f0e3 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x44390e3)
#32 0x000055a06939696b clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x459096b)
#33 0x000055a066068ca4 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x1262ca4)
#34 0x000055a06606229b ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) driver.cpp:0:0
#35 0x000055a0690a9659 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0
#36 0x000055a068689f97 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3883f97)
#37 0x000055a0690a9c4c clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#38 0x000055a069073769 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x426d769)
#39 0x000055a06907415d clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x426e15d)
#40 0x000055a06907e86c clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x427886c)
#41 0x000055a0660669c9 clang_main(int, char**) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x12609c9)
#42 0x00007f3c568a0083 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24083)
#43 0x000055a066061eae _start (/opt/compiler-explorer/clang-trunk/bin/clang+++0x125beae)

Online demo: https://godbolt.org/z/TeWo7nsEd

Found in the discussion: https://stackoverflow.com/a/73494870/7325599

@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" crash Prefer [crash-on-valid] or [crash-on-invalid] and removed new issue labels Aug 28, 2022
@llvmbot
Copy link
Member

llvmbot commented Aug 28, 2022

@llvm/issue-subscribers-clang-frontend

@royjacobson royjacobson added the concepts C++20 concepts label Aug 28, 2022
@inclyc
Copy link
Member

inclyc commented Aug 28, 2022

clang++: /root/llvm-project/clang/lib/AST/ExprConstant.cpp:15151: bool clang::Expr::EvaluateAsConstantExpr(clang::Expr::EvalResult&, const clang::ASTContext&, clang::Expr::ConstantExprKind) const: Assertion `!isValueDependent() && "Expression evaluator can't be called on a dependent expression."' failed.

Assertion trunk: https://godbolt.org/z/3x7ca9r9o

@erichkeane
Copy link
Collaborator

I've seen a good amount of this problem around concepts instantiation (or forms of this issue at least). It DOES however seem that my deferred concepts implementation fixes this, even with an instantiation after the fact. So once that gets in, I'd expect this to be closable.

@erichkeane
Copy link
Collaborator

Looks like https://reviews.llvm.org/D126907 fixed this! Closing.

@zyn0217
Copy link
Contributor

zyn0217 commented Jan 1, 2024

This is still happening on trunk, so I'm reopening now.

https://godbolt.org/z/aoe8hqh6x

@erichkeane Have we altered anything after babdef2?

In terms of constraints on template-template parameters, does CWG have any explanations on "if the check should happen or not" after our implementation for P0857? If still not yet, is the (possible) fix that skips the check for template-template parameters in CheckConstraintSatisfaction appropriate at the moment?

static bool CheckConstraintSatisfaction(
Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
llvm::SmallVectorImpl<Expr *> &Converted,
const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
if (ConstraintExprs.empty()) {
Satisfaction.IsSatisfied = true;
return false;
}
if (TemplateArgsLists.isAnyArgInstantiationDependent()) {
// No need to check satisfaction for dependent constraint expressions.
Satisfaction.IsSatisfied = true;
return false;
}

@zyn0217
Copy link
Contributor

zyn0217 commented Jan 2, 2024

is the (possible) fix that skips the check for template-template parameters in CheckConstraintSatisfaction appropriate at the moment?

I was wrong. Our previous behavior (clang-16) was to check these constraints.

The bug seems to be inside getTemplateInstantiationArgs, where we failed to handle template template parameters correctly and ended up slipping through the type substitution from TransformConceptSpecializationExpr. I'd like to take a look into this.

QualType
TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
TemplateTypeParmTypeLoc TL,
bool SuppressObjCLifetime) {
const TemplateTypeParmType *T = TL.getTypePtr();
if (T->getDepth() < TemplateArgs.getNumLevels()) {

@zyn0217
Copy link
Contributor

zyn0217 commented Jan 2, 2024

if (Innermost) {
Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND),
Innermost->asArray(), Final);
CurDecl = Response::UseNextDecl(ND).NextDecl;
}

Our template-template parameter Decl is at the file scope, and this code changes the current scope to its parent so that we won't fall into the following loop. CC @alexander-shaposhnikov

@zyn0217
Copy link
Contributor

zyn0217 commented Jan 3, 2024

Filed a patch trying to resolve it. Hopefully, I'm getting on the right track.

zyn0217 added a commit to zyn0217/llvm-project that referenced this issue Jan 6, 2024
…e template parameters

This fixes the bug introduced by
llvm@6db007a.

We construct placeholder template arguments for template-template parameters to
avoid mismatching argument substitution since they have different depths
with their corresponding template arguments. In this case,

```cpp
template <template <Concept C> class T> void foo(T<int>);
```

T lies at the depth 0, and C lies at 1. The corresponding argument, of which
there is exactly one, int, is at depth 0. If we consider the
argument as the outermost one, then we would end up substituting 'int'
into the wrong parameter T.

We used to perform such placeholder construction during the context walk-up.
In the previous patch, we slipped through that inadvertently because we would
walk up to the parent, which is precisely a FileContext for template-template
parameters, after adding innermost arguments.

Besides, this patch moves the sanity check up to the context switch.
That way, we avoid dereferencing null pointers if ND is unspecified.

Closes llvm#57410.
zyn0217 added a commit that referenced this issue Jan 6, 2024
…parameters (#76811)

This fixes the bug introduced by

6db007a.

We construct placeholder template arguments for template-template
parameters to avoid mismatching argument substitution since they have
different depths with their corresponding template arguments. In this
case,

```cpp
template <template <Concept C> class T> void foo(T<int>);
```

T lies at the depth 0, and C lies at 1. The corresponding argument, of
which there is exactly one, int, is at depth 0. If we consider the
argument as the outermost one, then we would end up substituting 'int'
into the wrong parameter T.

We used to perform such placeholder construction during the context
walk-up. In the previous patch, we slipped through that inadvertently
because we would walk up to the parent, which is precisely a FileContext
for template-template parameters, after adding innermost arguments.

Besides, this patch moves the sanity check up to the context switch.
That way, we avoid dereferencing null pointers if ND is unspecified.

Closes #57410.
Closes #76604. (The case is
slightly different than that in #57410. We should *not* assume the
surrounding context to be a file-scope one.)
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this issue Jan 28, 2024
…parameters (llvm#76811)

This fixes the bug introduced by

llvm@6db007a.

We construct placeholder template arguments for template-template
parameters to avoid mismatching argument substitution since they have
different depths with their corresponding template arguments. In this
case,

```cpp
template <template <Concept C> class T> void foo(T<int>);
```

T lies at the depth 0, and C lies at 1. The corresponding argument, of
which there is exactly one, int, is at depth 0. If we consider the
argument as the outermost one, then we would end up substituting 'int'
into the wrong parameter T.

We used to perform such placeholder construction during the context
walk-up. In the previous patch, we slipped through that inadvertently
because we would walk up to the parent, which is precisely a FileContext
for template-template parameters, after adding innermost arguments.

Besides, this patch moves the sanity check up to the context switch.
That way, we avoid dereferencing null pointers if ND is unspecified.

Closes llvm#57410.
Closes llvm#76604. (The case is
slightly different than that in llvm#57410. We should *not* assume the
surrounding context to be a file-scope one.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts crash Prefer [crash-on-valid] or [crash-on-invalid]
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

7 participants