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 frontend C++ crash on referencing undeclared member during class initialization #63496

Closed
brutalsavage opened this issue Jun 24, 2023 · 12 comments · Fixed by llvm/llvm-project-release-prs#549
Assignees
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" crash-on-invalid release:backport release:merged

Comments

@brutalsavage
Copy link

To quickly reproduce: https://gcc.godbolt.org/z/Mxbvv6Y1s (assertion-trunk)

#include <tuple>
#include <type_traits>

template < typename... T >
using variant_impl = std::tuple<int, int>;

template < typename... T >
struct variant : 
public std::conditional_t<
        false,
        int,
        variant_impl<T...>
> {
        // int value; // note if uncomment this line, code compiles correctly
        template < typename... T_ >
        constexpr variant(T_ &&... ts) : value(){};
};


int main() {
    variant<int> v{42};
    return 0;
}

Compiling the above code crashes clang clang++ -x c++ , crashes locally using clang-17.0 (a10019a), also on trunk with assertion (see godbolt link)

Note that adding back the int value; leads to successful compilation

@brutalsavage
Copy link
Author

Assertion:

clang++: /root/llvm-project/clang/lib/AST/ExprConstant.cpp:2355: 
bool CheckEvaluationResult(CheckEvaluationResultKind, {anonymous}::EvalInfo&, clang::SourceLocation, clang::QualType, const clang::APValue&, clang::ConstantExprKind, const clang::FieldDecl*, CheckedTemporaries&): 
Assertion `SubobjectDecl && "SubobjectDecl shall be non-null"' failed.

Backtrace:

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-assertions-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 <source>
1.	<eof> parser at end of file
2.	<source>:20:12: parsing function body 'main'
 #0 0x000055fb771551af llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c4e1af)
 #1 0x000055fb77152f1c llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3c4bf1c)
 #2 0x000055fb7709d608 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007fd8c416e420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #4 0x00007fd8c3c3b00b raise (/lib/x86_64-linux-gnu/libc.so.6+0x4300b)
 #5 0x00007fd8c3c1a859 abort (/lib/x86_64-linux-gnu/libc.so.6+0x22859)
 #6 0x00007fd8c3c1a729 (/lib/x86_64-linux-gnu/libc.so.6+0x22729)
 #7 0x00007fd8c3c2bfd6 (/lib/x86_64-linux-gnu/libc.so.6+0x33fd6)
 #8 0x000055fb7aa4e199 CheckEvaluationResult(CheckEvaluationResultKind, (anonymous namespace)::EvalInfo&, clang::SourceLocation, clang::QualType, clang::APValue const&, clang::Expr::ConstantExprKind, clang::FieldDecl const*, llvm::SmallPtrSet<clang::MaterializeTemporaryExpr const*, 8u>&) ExprConstant.cpp:0:0
 #9 0x000055fb7aa4dddd CheckEvaluationResult(CheckEvaluationResultKind, (anonymous namespace)::EvalInfo&, clang::SourceLocation, clang::QualType, clang::APValue const&, clang::Expr::ConstantExprKind, clang::FieldDecl const*, llvm::SmallPtrSet<clang::MaterializeTemporaryExpr const*, 8u>&) ExprConstant.cpp:0:0
#10 0x000055fb7aa4f4ba CheckConstantExpression((anonymous namespace)::EvalInfo&, clang::SourceLocation, clang::QualType, clang::APValue const&, clang::Expr::ConstantExprKind) ExprConstant.cpp:0:0
#11 0x000055fb7aab8d86 clang::Expr::EvaluateAsInitializer(clang::APValue&, clang::ASTContext const&, clang::VarDecl const*, llvm::SmallVectorImpl<std::pair<clang::SourceLocation, clang::PartialDiagnostic>>&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x75b1d86)
#12 0x000055fb7a98a1f2 clang::VarDecl::evaluateValueImpl(llvm::SmallVectorImpl<std::pair<clang::SourceLocation, clang::PartialDiagnostic>>&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x74831f2)
#13 0x000055fb7a98a33c clang::VarDecl::evaluateValue() const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x748333c)
#14 0x000055fb79c318ff clang::Sema::DiagnoseUnusedDecl(clang::NamedDecl const*, llvm::function_ref<void (clang::SourceLocation, clang::PartialDiagnostic)>) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x672a8ff)
#15 0x000055fb79c33d0d clang::Sema::ActOnPopScope(clang::SourceLocation, clang::Scope*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x672cd0d)
#16 0x000055fb798d2379 clang::Parser::ExitScope() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x63cb379)
#17 0x000055fb799b5a4f clang::Parser::ParseFunctionStatementBody(clang::Decl*, clang::Parser::ParseScope&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x64aea4f)
#18 0x000055fb798e0681 clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&, clang::Parser::ParsedTemplateInfo const&, clang::Parser::LateParsedAttrList*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x63d9681)
#19 0x000055fb79907590 clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, clang::DeclaratorContext, clang::ParsedAttributes&, clang::SourceLocation*, clang::Parser::ForRangeInit*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x6400590)
#20 0x000055fb798d3f21 clang::Parser::ParseDeclOrFunctionDefInternal(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec&, clang::AccessSpecifier) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x63ccf21)
#21 0x000055fb798d47df clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*, clang::AccessSpecifier) (.part.0) Parser.cpp:0:0
#22 0x000055fb798db181 clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x63d4181)
#23 0x000055fb798dbaf6 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x63d4af6)
#24 0x000055fb798cf89a clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x63c889a)
#25 0x000055fb783d0e08 clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x4ec9e08)
#26 0x000055fb77c1b9e9 clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x47149e9)
#27 0x000055fb77ba1606 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x469a606)
#28 0x000055fb77cffea6 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x47f8ea6)
#29 0x000055fb745fc06d cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x10f506d)
#30 0x000055fb745f7d6a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#31 0x000055fb77a01d0d void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0
#32 0x000055fb7709db10 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x3b96b10)
#33 0x000055fb77a0232f clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#34 0x000055fb779c949c clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x44c249c)
#35 0x000055fb779c9f2d clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x44c2f2d)
#36 0x000055fb779d200d clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x44cb00d)
#37 0x000055fb745fa2ca clang_main(int, char**, llvm::ToolContext const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x10f32ca)
#38 0x000055fb745005b5 main (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0xff95b5)
#39 0x00007fd8c3c1c083 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24083)
#40 0x000055fb745f2b4e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+++0x10ebb4e)
clang++: error: clang frontend command failed with exit code 134 (use -v to see invocation)
Compiler returned: 134

@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" crash-on-invalid and removed new issue labels Jun 25, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Jun 25, 2023

@llvm/issue-subscribers-clang-frontend

@tbaederr
Copy link
Contributor

CC @hazohelet

@hazohelet
Copy link
Member

Smaller reproducer:

struct Base{};

struct Foo : Base {
    constexpr Foo() : {}
};

constexpr Foo v;

Link: https://gcc.godbolt.org/z/KejaW9qfK
The stack trace is a bit different, but the cause seems to be the same.
Relevant patch: https://reviews.llvm.org/D146358

This is an instance where the note about uninitialized subobject before the patch points to the base class itself (subobject of type 'Base' is not initialized) which I did not expect to get triggered.
In this case, the note does not seem to make sence because the initialization of Base class is not releated to the error. The code compiles when we remove the : in line 4.

So I think there is a bug in the error recovery for invalid member initializers.

@hazohelet
Copy link
Member

struct A {
    A()=delete;
};
struct B : A {
    constexpr B() {}
};

constexpr B bb;

Link: https://godbolt.org/z/xxM9cdj78

This piece of code also crashes for the same reason, and this is not related to the error recovery of member initializer parser.
I think the old diagnostic subobject of type 'A' is not initialized makes sense in this case, although there's space for improvement in the wording.

I think we can bring back the old diagnostic for these uninitialized-baseclass cases, but it also seems not quite nice that we are evaluating constructors that we know are semantically erroneous.

Do you have any thoughts on this topic? @AaronBallman @erichkeane

@erichkeane
Copy link
Collaborator

That is the regression that a few of us brought up on the patch that changed that diagnostic, right? Why was that original patch not reverted if it is regressing like that?

I believe my suggestion on that review at the time was to fall back to the old diagnostic in the case where the subobject is invalid. I think we still want to evaluate the invalid constructor as it'll give more diagnostics in some cases that are perhaps interesting/actionable.

@hazohelet
Copy link
Member

I disagreed with the fallback at the review because the old diagnostic message was invalid for the regressing case, and the assertion failure seemed like a symptom of bugs in other parts because it had caught a few bugs at that time.

But now that we have a crashing code that makes the old diagnostic valid, I agree with the fallback and I'll submit a patch soon.

@hazohelet hazohelet self-assigned this Jun 26, 2023
@hazohelet
Copy link
Member

Proposed fix: https://reviews.llvm.org/D153969

@hazohelet
Copy link
Member

/cherry-pick 24c91d4

@llvmbot
Copy link
Collaborator

llvmbot commented Aug 8, 2023

Failed to cherry-pick: 24c91d4

https://github.com/llvm/llvm-project/actions/runs/5796314601

Please manually backport the fix and push it to your github fork. Once this is done, please add a comment like this:

/branch <user>/<repo>/<branch>

@hazohelet
Copy link
Member

/branch hazohelet/llvm-project/release/17.x

@llvmbot
Copy link
Collaborator

llvmbot commented Aug 8, 2023

/pull-request llvm/llvm-project-release-prs#549

tru pushed a commit to llvm/llvm-project-release-prs that referenced this issue Aug 30, 2023
This patch fixes the reported regression caused by D146358 through adding notes about an uninitialized base class when we diagnose uninitialized constructor.

This also changes the wording from the old one in order to make it clear that the uninitialized subobject is a base class and its constructor is not called.
Wording changes:
BEFORE: `subobject of type 'Base' is not initialized`
AFTER: `constructor of base class 'Base' is not called`

Fixes llvm/llvm-project#63496

Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D153969
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" crash-on-invalid release:backport release:merged
Projects
Development

Successfully merging a pull request may close this issue.

6 participants