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] ICE on handling reference to consteval function in initializer #66562

Closed
groundswellaudio opened this issue Sep 16, 2023 · 3 comments
Closed
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" consteval C++20 consteval crash Prefer [crash-on-valid] or [crash-on-invalid]

Comments

@groundswellaudio
Copy link

namespace ns
{
    consteval int foo(int x) { return 1; }
}

template <class A>
struct T {
    static constexpr auto xx = ns::foo(A{});
};

crash with

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 <source> -isystem/opt/compiler-explorer/libs/catch2/v3.0.1/src
1.	<source>:9:44: current parser token ';'
2.	<source>:8:1: parsing struct/union/class body 'T'
 #0 0x00000000033cba18 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x33cba18)
 #1 0x00000000033c9b44 llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x33c9b44)
 #2 0x0000000003318b68 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007fc4f42c7420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #4 0x0000000000ad8e28 clang::Sema::MarkExpressionAsImmediateEscalating(clang::Expr*) (.cold) SemaExpr.cpp:0:0
 #5 0x0000000005f39f3d clang::Sema::PopExpressionEvaluationContext() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f39f3d)
 #6 0x0000000005a025e4 clang::Parser::ParseCXXMemberInitializer(clang::Decl*, bool, clang::SourceLocation&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a025e4)
 #7 0x0000000005a15a5f clang::Parser::ParseCXXClassMemberDeclaration(clang::AccessSpecifier, clang::ParsedAttributes&, clang::Parser::ParsedTemplateInfo const&, clang::ParsingDeclRAIIObject*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a15a5f)
 #8 0x0000000005a16d34 clang::Parser::ParseCXXClassMemberDeclarationWithPragmas(clang::AccessSpecifier&, clang::ParsedAttributes&, clang::TypeSpecifierType, clang::Decl*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a16d34)
 #9 0x0000000005a173a6 clang::Parser::ParseCXXMemberSpecification(clang::SourceLocation, clang::SourceLocation, clang::ParsedAttributes&, unsigned int, clang::Decl*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a173a6)
#10 0x0000000005a19679 clang::Parser::ParseClassSpecifier(clang::tok::TokenKind, clang::SourceLocation, clang::DeclSpec&, clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, bool, clang::Parser::DeclSpecContext, clang::ParsedAttributes&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a19679)
#11 0x00000000059e9414 clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec&, clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, clang::Parser::DeclSpecContext, clang::Parser::LateParsedAttrList*, clang::ImplicitTypenameContext) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x59e9414)
....

https://godbolt.org/z/5a8hPo5je

On Clang 16, this used to error out with :

<source>:9:32: error: cannot take address of consteval function 'foo' outside of an immediate invocation
    static constexpr auto xx = ns::foo(A{});
                               ^
<source>:4:19: note: declared here
    consteval int foo(int x) { return 1; }

I think the problem stems from
1/ during the parsing of the initializer, the ExpressionEvaluationContext is not set to ConstantEvaluated, so the reference to ns::foo is added to ReferenceToConsteval
2/ When popping the Sema::PopExpressionEvalContext is called, Context.InImmediateEscalatingFunctionContext is true, most likely because ParseCXXMemberInitializer contains this line :

 Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext = true;

Which does not makes a lot of sense to me (besides this kind of state mutation would be more suitable on the Sema side? e.g. in Sema::ActOnStartCXXInClassMemberInitializer/Finish).

Finally, the evaluation context should probably be set to ConstantEvaluated when the variable is constexpr to not error on the declaration reference.

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Sep 16, 2023
@shafik
Copy link
Collaborator

shafik commented Sep 16, 2023

CC @cor3ntin

@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" crash Prefer [crash-on-valid] or [crash-on-invalid] consteval C++20 consteval and removed clang Clang issues not falling into any other category labels Sep 16, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 16, 2023

@llvm/issue-subscribers-clang-frontend

```cpp namespace ns { consteval int foo(int x) { return 1; } }

template <class A>
struct T {
static constexpr auto xx = ns::foo(A{});
};


crash with 

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 <source> -isystem/opt/compiler-explorer/libs/catch2/v3.0.1/src

  1. <source>:9:44: current parser token ';'
  2. <source>:8:1: parsing struct/union/class body 'T'
    #0 0x00000000033cba18 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x33cba18)
    #1 0x00000000033c9b44 llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x33c9b44)
    #2 0x0000000003318b68 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
    #3 0x00007fc4f42c7420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
    #4 0x0000000000ad8e28 clang::Sema::MarkExpressionAsImmediateEscalating(clang::Expr*) (.cold) SemaExpr.cpp:0:0
    #5 0x0000000005f39f3d clang::Sema::PopExpressionEvaluationContext() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5f39f3d)
    #6 0x0000000005a025e4 clang::Parser::ParseCXXMemberInitializer(clang::Decl*, bool, clang::SourceLocation&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a025e4)
    #7 0x0000000005a15a5f clang::Parser::ParseCXXClassMemberDeclaration(clang::AccessSpecifier, clang::ParsedAttributes&, clang::Parser::ParsedTemplateInfo const&, clang::ParsingDeclRAIIObject*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a15a5f)
    #8 0x0000000005a16d34 clang::Parser::ParseCXXClassMemberDeclarationWithPragmas(clang::AccessSpecifier&, clang::ParsedAttributes&, clang::TypeSpecifierType, clang::Decl*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a16d34)
    #9 0x0000000005a173a6 clang::Parser::ParseCXXMemberSpecification(clang::SourceLocation, clang::SourceLocation, clang::ParsedAttributes&, unsigned int, clang::Decl*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a173a6)
    #10 0x0000000005a19679 clang::Parser::ParseClassSpecifier(clang::tok::TokenKind, clang::SourceLocation, clang::DeclSpec&, clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, bool, clang::Parser::DeclSpecContext, clang::ParsedAttributes&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5a19679)
    #11 0x00000000059e9414 clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec&, clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, clang::Parser::DeclSpecContext, clang::Parser::LateParsedAttrList*, clang::ImplicitTypenameContext) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x59e9414)
    ....

https://godbolt.org/z/5a8hPo5je

On Clang 16, this used to error out with : 

<source>:9:32: error: cannot take address of consteval function 'foo' outside of an immediate invocation
static constexpr auto xx = ns::foo(A{});
^
<source>:4:19: note: declared here
consteval int foo(int x) { return 1; }


I think the problem stems from 
1/ during the parsing of the initializer, the ExpressionEvaluationContext is not set to ConstantEvaluated, so the reference to ns::foo is added to ReferenceToConsteval
2/ When popping the Sema::PopExpressionEvalContext is called, `Context.InImmediateEscalatingFunctionContext` is true, most likely because `ParseCXXMemberInitializer` contains this line : 

Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext = true;


Which does not makes a lot of sense to me (besides this kind of state mutation would be more suitable on the Sema side? e.g. in Sema::ActOnStartCXXInClassMemberInitializer/Finish).

Finally, the evaluation context should probably be set to ConstantEvaluated when the variable is `constexpr` to not error on the declaration reference. 
</details>

@cor3ntin
Copy link
Contributor

@shafik this is #66021

cor3ntin added a commit to cor3ntin/llvm-project that referenced this issue Sep 16, 2023
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" consteval C++20 consteval crash Prefer [crash-on-valid] or [crash-on-invalid]
Projects
None yet
Development

No branches or pull requests

5 participants