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

clang crashes when template instantiation results in a constant instead of a type #88832

Closed
igorkudrin opened this issue Apr 16, 2024 · 4 comments · Fixed by #89019
Closed

clang crashes when template instantiation results in a constant instead of a type #88832

igorkudrin opened this issue Apr 16, 2024 · 4 comments · Fixed by #89019
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party crash-on-invalid

Comments

@igorkudrin
Copy link
Collaborator

Reproducer:

template <typename T> struct O {
  static const T v = 0;
};

struct P {
  template <typename T> using I = typename O<T>::v;
};

struct Q
{
  template <typename T>
  int foo() { return T::template I<int>; }
};

int bar() {
  Q m;
  return m.foo<P>();
}

Compiling the sample with clang++ results in an assertion failure/crash:

Assertion failed: isa<To>(Val) && "cast<Ty>() argument of incompatible type!", file <...>\llvm\include\llvm/Support/Casting.h, line 578
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: <...>\\clang++.exe -c test.cpp -o tmp.o
1.	<eof> parser at end of file
2.	test.cpp:12:7: instantiating function definition 'Q::foo<P>'
Exception Code: 0x80000003
<...>
 #6 0x00007ff7e339e681 <...>\llvm\include\llvm\Support\Casting.h:578:0
 #7 0x00007ff7e45275e1 clang::Sema::ResolveSingleFunctionTemplateSpecialization(class clang::OverloadExpr *, bool, class clang::DeclAccessPair *, class clang::TemplateSpecCandidateSet *) <...>\clang\lib\Sema\SemaOverload.cpp:13504:0
 #8 0x00007ff7e456b514 `anonymous namespace'::AddressOfFunctionResolver::AddressOfFunctionResolver <...>\clang\lib\Sema\SemaOverload.cpp:12901:0
 #9 0x00007ff7e4526ac6 clang::Sema::ResolveAddressOfOverloadedFunction(class clang::Expr *, class clang::QualType, bool, class clang::DeclAccessPair &, bool *) <...>\clang\lib\Sema\SemaOverload.cpp:13288:0
#10 0x00007ff7e45450ed IsStandardConversion <...>\clang\lib\Sema\SemaOverload.cpp:2087:0
#11 0x00007ff7e454d1f9 TryImplicitConversion <...>\clang\lib\Sema\SemaOverload.cpp:1699:0
#12 0x00007ff7e4513802 clang::Sema::TryImplicitConversion(class clang::Expr *, class clang::QualType, bool, enum clang::Sema::AllowedExplicit, bool, bool, bool) <...>\clang\lib\Sema\SemaOverload.cpp:1752:0
#13 0x00007ff7e425fab2 clang::InitializationSequence::InitializeFrom(class clang::Sema &, class clang::InitializedEntity const &, class clang::InitializationKind const &, class llvm::MutableArrayRef<class clang::Expr *>, bool, bool) <...>\clang\lib\Sema\SemaInit.cpp:6555:0
#14 0x00007ff7e425dc2d clang::InitializationSequence::InitializationSequence(class clang::Sema &, class clang::InitializedEntity const &, class clang::InitializationKind const &, class llvm::MutableArrayRef<class clang::Expr *>, bool, bool) <...>\clang\lib\Sema\SemaInit.cpp:6119:0
#15 0x00007ff7e425ae5f clang::Sema::PerformCopyInitialization(class clang::InitializedEntity const &, class clang::SourceLocation, class clang::ActionResult<class clang::Expr *, 1>, bool, bool) <...>\clang\lib\Sema\SemaInit.cpp:10673:0
#16 0x00007ff7e3bfbfa1 clang::Sema::PerformMoveOrCopyInitialization(class clang::InitializedEntity const &, struct clang::Sema::NamedReturnInfo const &, class clang::Expr *, bool) <...>\clang\lib\Sema\SemaStmt.cpp:3634:0
#17 0x00007ff7e3bfe4b2 clang::Sema::BuildReturnStmt(class clang::SourceLocation, class clang::Expr *, bool) <...>\clang\lib\Sema\SemaStmt.cpp:4254:0
#18 0x00007ff7e410ff86 clang::TreeTransform<`anonymous namespace'::TemplateInstantiator>::RebuildReturnStmt <...>\clang\lib\Sema\TreeTransform.h:1494:0
#19 0x00007ff7e41b492b clang::TreeTransform<`anonymous namespace'::TemplateInstantiator>::TransformReturnStmt <...>\clang\lib\Sema\TreeTransform.h:8153:0
#20 0x00007ff7e41b8249 clang::TreeTransform<`anonymous namespace'::TemplateInstantiator>::TransformStmt <...>\build\tools\clang\include\clang\AST\StmtNodes.inc:920:0
#21 0x00007ff7e4166b80 clang::TreeTransform<`anonymous namespace'::TemplateInstantiator>::TransformCompoundStmt <...>\clang\lib\Sema\TreeTransform.h:7738:0
#22 0x00007ff7e41668fa clang::TreeTransform<`anonymous namespace'::TemplateInstantiator>::TransformCompoundStmt <...>\clang\lib\Sema\TreeTransform.h:7717:0
#23 0x00007ff7e41ba0cd clang::TreeTransform<`anonymous namespace'::TemplateInstantiator>::TransformStmt <...>\build\tools\clang\include\clang\AST\StmtNodes.inc:1526:0
#24 0x00007ff7e40fc8d0 clang::Sema::SubstStmt(class clang::Stmt *, class clang::MultiLevelTemplateArgumentList const &) <...>\clang\lib\Sema\SemaTemplateInstantiate.cpp:4353:0
#25 0x00007ff7e45a91bf clang::Sema::InstantiateFunctionDefinition(class clang::SourceLocation, class clang::FunctionDecl *, bool, bool, bool) <...>\clang\lib\Sema\SemaTemplateInstantiateDecl.cpp:5220:0
#26 0x00007ff7e45ae25e clang::Sema::PerformPendingInstantiations(bool) <...>\clang\lib\Sema\SemaTemplateInstantiateDecl.cpp:6494:0
#27 0x00007ff7e2732011 clang::Sema::ActOnEndOfTranslationUnitFragment(enum clang::Sema::TUFragmentKind) <...>\clang\lib\Sema\Sema.cpp:1095:0
#28 0x00007ff7e272f878 clang::Sema::ActOnEndOfTranslationUnit(void) <...>\clang\lib\Sema\Sema.cpp:1136:0
<...>
clang++: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 19.0.0git
Target: x86_64-pc-windows-msvc
Thread model: posix
Build config: +unoptimized, +assertions
clang++: note: diagnostic msg: 
********************
@igorkudrin igorkudrin added clang:frontend Language frontend issues, e.g. anything involving "Sema" crash-on-invalid labels Apr 16, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Apr 16, 2024

@llvm/issue-subscribers-clang-frontend

Author: Igor Kudrin (igorkudrin)

Reproducer: ```cpp template <typename T> struct O { static const T v = 0; };

struct P {
template <typename T> using I = typename O<T>::v;
};

struct Q
{
template <typename T>
int foo() { return T::template I<int>; }
};

int bar() {
Q m;
return m.foo<P>();
}


Compiling the sample with `clang++` results in an assertion failure/crash:

Assertion failed: isa<To>(Val) && "cast<Ty>() argument of incompatible type!", file <...>\llvm\include\llvm/Support/Casting.h, line 578
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: <...>\clang++.exe -c test.cpp -o tmp.o

  1. <eof> parser at end of file
  2. test.cpp:12:7: instantiating function definition 'Q::foo<P>'
    Exception Code: 0x80000003
    <...>
    #6 0x00007ff7e339e681 <...>\llvm\include\llvm\Support\Casting.h:578:0
    #7 0x00007ff7e45275e1 clang::Sema::ResolveSingleFunctionTemplateSpecialization(class clang::OverloadExpr *, bool, class clang::DeclAccessPair *, class clang::TemplateSpecCandidateSet *) <...>\clang\lib\Sema\SemaOverload.cpp:13504:0
    #8 0x00007ff7e456b514 anonymous namespace'::AddressOfFunctionResolver::AddressOfFunctionResolver &lt;...&gt;\clang\lib\Sema\SemaOverload.cpp:12901:0 #<!-- -->9 0x00007ff7e4526ac6 clang::Sema::ResolveAddressOfOverloadedFunction(class clang::Expr *, class clang::QualType, bool, class clang::DeclAccessPair &amp;, bool *) &lt;...&gt;\clang\lib\Sema\SemaOverload.cpp:13288:0 #<!-- -->10 0x00007ff7e45450ed IsStandardConversion &lt;...&gt;\clang\lib\Sema\SemaOverload.cpp:2087:0 #<!-- -->11 0x00007ff7e454d1f9 TryImplicitConversion &lt;...&gt;\clang\lib\Sema\SemaOverload.cpp:1699:0 #<!-- -->12 0x00007ff7e4513802 clang::Sema::TryImplicitConversion(class clang::Expr *, class clang::QualType, bool, enum clang::Sema::AllowedExplicit, bool, bool, bool) &lt;...&gt;\clang\lib\Sema\SemaOverload.cpp:1752:0 #<!-- -->13 0x00007ff7e425fab2 clang::InitializationSequence::InitializeFrom(class clang::Sema &amp;, class clang::InitializedEntity const &amp;, class clang::InitializationKind const &amp;, class llvm::MutableArrayRef&lt;class clang::Expr *&gt;, bool, bool) &lt;...&gt;\clang\lib\Sema\SemaInit.cpp:6555:0 #<!-- -->14 0x00007ff7e425dc2d clang::InitializationSequence::InitializationSequence(class clang::Sema &amp;, class clang::InitializedEntity const &amp;, class clang::InitializationKind const &amp;, class llvm::MutableArrayRef&lt;class clang::Expr *&gt;, bool, bool) &lt;...&gt;\clang\lib\Sema\SemaInit.cpp:6119:0 #<!-- -->15 0x00007ff7e425ae5f clang::Sema::PerformCopyInitialization(class clang::InitializedEntity const &amp;, class clang::SourceLocation, class clang::ActionResult&lt;class clang::Expr *, 1&gt;, bool, bool) &lt;...&gt;\clang\lib\Sema\SemaInit.cpp:10673:0 #<!-- -->16 0x00007ff7e3bfbfa1 clang::Sema::PerformMoveOrCopyInitialization(class clang::InitializedEntity const &amp;, struct clang::Sema::NamedReturnInfo const &amp;, class clang::Expr *, bool) &lt;...&gt;\clang\lib\Sema\SemaStmt.cpp:3634:0 #<!-- -->17 0x00007ff7e3bfe4b2 clang::Sema::BuildReturnStmt(class clang::SourceLocation, class clang::Expr *, bool) &lt;...&gt;\clang\lib\Sema\SemaStmt.cpp:4254:0 #<!-- -->18 0x00007ff7e410ff86 clang::TreeTransform&lt;anonymous namespace'::TemplateInstantiator>::RebuildReturnStmt <...>\clang\lib\Sema\TreeTransform.h:1494:0
    #19 0x00007ff7e41b492b clang::TreeTransform<anonymous namespace'::TemplateInstantiator&gt;::TransformReturnStmt &lt;...&gt;\clang\lib\Sema\TreeTransform.h:8153:0 #<!-- -->20 0x00007ff7e41b8249 clang::TreeTransform&lt;anonymous namespace'::TemplateInstantiator>::TransformStmt <...>\build\tools\clang\include\clang\AST\StmtNodes.inc:920:0
    #21 0x00007ff7e4166b80 clang::TreeTransform<anonymous namespace'::TemplateInstantiator&gt;::TransformCompoundStmt &lt;...&gt;\clang\lib\Sema\TreeTransform.h:7738:0 #<!-- -->22 0x00007ff7e41668fa clang::TreeTransform&lt;anonymous namespace'::TemplateInstantiator>::TransformCompoundStmt <...>\clang\lib\Sema\TreeTransform.h:7717:0
    #23 0x00007ff7e41ba0cd clang::TreeTransform<`anonymous namespace'::TemplateInstantiator>::TransformStmt <...>\build\tools\clang\include\clang\AST\StmtNodes.inc:1526:0
    #24 0x00007ff7e40fc8d0 clang::Sema::SubstStmt(class clang::Stmt *, class clang::MultiLevelTemplateArgumentList const &) <...>\clang\lib\Sema\SemaTemplateInstantiate.cpp:4353:0
    #25 0x00007ff7e45a91bf clang::Sema::InstantiateFunctionDefinition(class clang::SourceLocation, class clang::FunctionDecl *, bool, bool, bool) <...>\clang\lib\Sema\SemaTemplateInstantiateDecl.cpp:5220:0
    #26 0x00007ff7e45ae25e clang::Sema::PerformPendingInstantiations(bool) <...>\clang\lib\Sema\SemaTemplateInstantiateDecl.cpp:6494:0
    #27 0x00007ff7e2732011 clang::Sema::ActOnEndOfTranslationUnitFragment(enum clang::Sema::TUFragmentKind) <...>\clang\lib\Sema\Sema.cpp:1095:0
    #28 0x00007ff7e272f878 clang::Sema::ActOnEndOfTranslationUnit(void) <...>\clang\lib\Sema\Sema.cpp:1136:0
    <...>
    clang++: error: clang frontend command failed due to signal (use -v to see invocation)
    clang version 19.0.0git
    Target: x86_64-pc-windows-msvc
    Thread model: posix
    Build config: +unoptimized, +assertions
    clang++: note: diagnostic msg:

</details>

@shafik
Copy link
Collaborator

shafik commented Apr 16, 2024

Confirmed: https://godbolt.org/z/3jsoj9j6W

Maybe related: #63243

@shafik shafik added the confirmed Verified by a second party label Apr 16, 2024
@zyn0217
Copy link
Contributor

zyn0217 commented Apr 16, 2024

Upon a rough investigation, I think this is brought by 6170072#diff-666d45282070e66014f8fb70e6c089762ea67ad4891f9819fdf5f8a5d5a0f570R1081, which has been included since clang 12, and we didn't experience such crashes prior to it: https://godbolt.org/z/d5xrdbxce.

The highlighted lines create an UnresolvedLookupExpr for T::template I<int>. By default, an UnresolvedLookupExpr is of Context.OverloadTy type, whose intent is to describe overload functions rather than type alias templates.

@shafik
Copy link
Collaborator

shafik commented Apr 16, 2024

CC @zygoloid

zyn0217 added a commit to zyn0217/llvm-project that referenced this issue Apr 17, 2024
This patch revolves around the misuse of UnresolvedLookupExpr in
BuildTemplateIdExpr.

Basically, we build up an UnresolvedLookupExpr not only for function
overloads but for "unresolved" templates wherever we need an expression
for template decls. For example, a dependent VarTemplateDecl can be
wrapped with such an expression before template instantiation. (See
llvm@6170072)

Also, one important thing is that UnresolvedLookupExpr uses a "canonical"
QualType to describe the containing unresolved decls: a DependentTy is
for dependent expressions and an OverloadTy otherwise. Therefore, this
modeling for non-dependent templates leaves a problem in that the expression
is marked and perceived as if describing overload functions. The consumer then
expects functions for every such expression, although the fact is the reverse.
Hence, we run into crashes.

As to the patch, I added a new canonical type "UnresolvedTemplateTy" to
model these cases. Given that we have been using this model (intentionally or
accidentally) and it is pretty baked in throughout the code, I think
extending the role of UnresolvedLookupExpr is reasonable. Further, I added
some diagnostics for the direct occurrence of these expressions, which
are supposed to be ill-formed.

As a bonus, this patch also fixes some typos in the diagnostics and creates
RecoveryExprs rather than nothing in the hope of a better error-recovery
for clangd.

Fixes llvm#88832
Fixes llvm#63243
Fixes llvm#48673
zyn0217 added a commit that referenced this issue May 5, 2024
)

This patch revolves around the misuse of UnresolvedLookupExpr in
BuildTemplateIdExpr.
    
Basically, we build up an UnresolvedLookupExpr not only for function
overloads but for "unresolved" templates wherever we need an expression
for template decls. For example, a dependent VarTemplateDecl can be
wrapped with such an expression before template instantiation. (See

6170072)
    
Also, one important thing is that UnresolvedLookupExpr uses a
"canonical"
QualType to describe the containing unresolved decls: a DependentTy is
for dependent expressions and an OverloadTy otherwise. Therefore, this
modeling for non-dependent templates leaves a problem in that the
expression
is marked and perceived as if describing overload functions. The
consumer then
expects functions for every such expression, although the fact is the
reverse.
Hence, we run into crashes.
    
As to the patch, I added a new canonical type "UnresolvedTemplateTy" to
model these cases. Given that we have been using this model
(intentionally or
accidentally) and it is pretty baked in throughout the code, I think
extending the role of UnresolvedLookupExpr is reasonable. Further, I
added
some diagnostics for the direct occurrence of these expressions, which
are supposed to be ill-formed.

As a bonus, this patch also fixes some typos in the diagnostics and
creates
RecoveryExprs rather than nothing in the hope of a better error-recovery
for clangd.
    
Fixes #88832
Fixes #63243
Fixes #48673
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" confirmed Verified by a second party crash-on-invalid
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants