Emit the note when we fail to deduce a return type, or deduce conflicting return types.
Diff Detail
- Repository
- rG LLVM Github Monorepo
Unit Tests
Event Timeline
I am curious about the behavior if we removed the guard if (OrigResultType.getBeginLoc().isValid()).
clang/lib/Sema/SemaStmt.cpp | ||
---|---|---|
3804–3807 | What if merge this one into above block where the diagnostic happens. |
clang/lib/Sema/SemaStmt.cpp | ||
---|---|---|
3805 |
That caused the note to be emitted in some cases without a source location (similar to https://github.com/llvm/llvm-project/issues/29054 ). I admit I should check to make sure we have a test case for each of these four ifs, though; I suspect we don't. $ cat x.cpp auto f = []() { return x; }; $ clang++ x.cpp x.cpp:1:24: error: use of undeclared identifier 'x' auto f = []() { return x; }; ^ note: deducing return type for 'operator()' 1 error generated. |
clang/lib/Sema/SemaStmt.cpp | ||
---|---|---|
3804–3809 | The approach of tacking a note onto the end of someone else's diagnostic is an antipattern and should be avoided in new code. For example, if DeduceAutoType produces an error (which is shown) then a warning (which is hidden), the note will be attached to the warning, and will not appear. The right thing to do is to create a new kind of CodeSynthesisContext for this case and push that. Then we'll use the same logic as in template instantiation backtraces, and the note will get properly attached to the first emitted diagnostic within the context. This will also remove the need to track down all the different places that emit diagnostics (like we see below): you just push the context when you start doing the action you want to attach the note to and pop it when you're done. It'll also properly order the note with respect to other context notes. |
I'll update with the CodeSynthesisContext approach in a little bit. But meanwhile there's a problem with both the current patch and (I think even more) with the new approach. @rsmith any help?:
When I try my latest patch with the libc++ tests, with bin/llvm-lit -sv --param enable_modules=True (which corresponds to the -fmodules compiler flag), I get lots of errors like the following. Do you have any idea what's going wrong?
I can't minimize the example beyond "all of libc++" because Modules prevents creduce from doing anything meaningful. And unfortunately whatever's going wrong seems to be specifically about Modules.
Assertion failed: (Replacement.isCanonical() && "replacement types must always be canonical"), function getSubstTemplateTypeParmType, file /Users/aodwyer/llvm-project/clang/lib/AST/ASTContext.cpp, line 4691. 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: /Users/aodwyer/llvm-project/build3/bin/clang-14 -cc1 -triple x86_64-apple-macosx10.15.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all --mrelax-relocations -disable-free -clear-ast-before-backend -main-file-name rbegin.pass.cpp -mrelocation-model pic -pic-level 2 -mframe-pointer=all -ffp-contract=on -fno-rounding-math -funwind-tables=2 -target-sdk-version=10.15.6 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -target-cpu penryn -tune-cpu generic -mllvm -treat-scalable-fixed-error-as-warning -debugger-tuning=lldb -target-linker-version 609.8 -v -fcoverage-compilation-dir=/Users/aodwyer/llvm-project/build3/projects/libcxx/test/std/ranges/range.access -nostdinc++ -resource-dir /Users/aodwyer/llvm-project/build3/lib/clang/15.0.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -isystem /Users/aodwyer/llvm-project/build3/include/c++/v1 -I /Users/aodwyer/llvm-project/build3/projects/libcxx/include/c++build -I /Users/aodwyer/llvm-project/libcxx/test/support -D _LIBCPP_DISABLE_AVAILABILITY -D _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -stdlib=libc++ -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/local/include -internal-isystem /Users/aodwyer/llvm-project/build3/lib/clang/15.0.0/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include -Werror -Wall -Wextra -Wshadow -Wundef -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-c++11-extensions -Wno-user-defined-literals -Wno-noexcept-type -Wno-atomic-alignment -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Werror=thread-safety -Wuser-defined-warnings -std=c++20 -fdeprecated-macro -fdebug-compilation-dir=/Users/aodwyer/llvm-project/build3/projects/libcxx/test/std/ranges/range.access -ferror-limit 19 -stack-protector 1 -fblocks -fencode-extended-block-signature -fcoroutines-ts -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fmodules -fimplicit-module-maps -fmodules-cache-path=/var/folders/0l/9t0yv2890_g4wgmy53n_mg7w0000gy/C/clang/ModuleCache -fmodules-validate-system-headers -fcxx-exceptions -fexceptions -fmax-type-align=16 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/0l/9t0yv2890_g4wgmy53n_mg7w0000gy/T/lit-tmp-fkh9o_f4/rbegin-d58043.o -x c++ /Users/aodwyer/llvm-project/libcxx/test/std/ranges/range.access/rbegin.pass.cpp 1. /Users/aodwyer/llvm-project/libcxx/test/support/test_iterators.h:524:30: current parser token '{' Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it): 0 clang-14 0x000000010634385d llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 61 1 clang-14 0x0000000106343ddb PrintStackTraceSignalHandler(void*) + 27 2 clang-14 0x0000000106341cfa llvm::sys::RunSignalHandlers() + 138 3 clang-14 0x00000001063457af SignalHandler(int) + 223 4 libsystem_platform.dylib 0x00007fff677255fd _sigtramp + 29 5 libsystem_platform.dylib 0x00007ffeed912f58 _sigtramp + 18446744071664753016 6 libsystem_c.dylib 0x00007fff675fb808 abort + 120 7 libsystem_c.dylib 0x00007fff675faac6 err + 0 8 clang-14 0x000000010b769ce1 clang::ASTContext::getSubstTemplateTypeParmType(clang::TemplateTypeParmType const*, clang::QualType) const + 161 9 clang-14 0x000000010b1feb40 (anonymous namespace)::TemplateInstantiator::TransformTemplateTypeParmType(clang::TypeLocBuilder&, clang::TemplateTypeParmTypeLoc) + 1456 10 clang-14 0x000000010b1ba74f clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformType(clang::TypeLocBuilder&, clang::TypeLoc) + 4383 11 clang-14 0x000000010b1b91e2 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformType(clang::TypeSourceInfo*) + 354 12 clang-14 0x000000010b1e9137 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTemplateArgument(clang::TemplateArgumentLoc const&, clang::TemplateArgumentLoc&, bool) + 1079 13 clang-14 0x000000010b1e8c4f bool clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTemplateArguments<clang::TemplateArgumentLocInventIterator<(anonymous namespace)::TemplateInstantiator, clang::TemplateArgument const*> >(clang::TemplateArgumentLocInventIterator<(anonymous namespace)::TemplateInstantiator, clang::TemplateArgument const*>, clang::TemplateArgumentLocInventIterator<(anonymous namespace)::TemplateInstantiator, clang::TemplateArgument const*>, clang::TemplateArgumentListInfo&, bool) + 2447 14 clang-14 0x000000010b1e7981 bool clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTemplateArguments<clang::TemplateArgumentLocContainerIterator<clang::TemplateSpecializationTypeLoc> >(clang::TemplateArgumentLocContainerIterator<clang::TemplateSpecializationTypeLoc>, clang::TemplateArgumentLocContainerIterator<clang::TemplateSpecializationTypeLoc>, clang::TemplateArgumentListInfo&, bool) + 289 15 clang-14 0x000000010b1e6e3e clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTemplateSpecializationType(clang::TypeLocBuilder&, clang::TemplateSpecializationTypeLoc, clang::TemplateName) + 286 16 clang-14 0x000000010b1e6a7b clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTSIInObjectScope(clang::TypeLoc, clang::QualType, clang::NamedDecl*, clang::CXXScopeSpec&) + 523 17 clang-14 0x000000010b21c0c5 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTypeInObjectScope(clang::TypeLoc, clang::QualType, clang::NamedDecl*, clang::CXXScopeSpec&) + 165 18 clang-14 0x000000010b1c88a5 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc, clang::QualType, clang::NamedDecl*) + 1365 19 clang-14 0x000000010b1f5f55 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformDependentNameType(clang::TypeLocBuilder&, clang::DependentNameTypeLoc, bool) + 149 20 clang-14 0x000000010b1fa140 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformDependentNameType(clang::TypeLocBuilder&, clang::DependentNameTypeLoc) + 64 21 clang-14 0x000000010b1b9d4a clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformType(clang::TypeLocBuilder&, clang::TypeLoc) + 1818 22 clang-14 0x000000010b1b91e2 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformType(clang::TypeSourceInfo*) + 354 23 clang-14 0x000000010b1bad21 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformType(clang::QualType) + 161 24 clang-14 0x000000010b1fdf9f clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformSubstTemplateTypeParmType(clang::TypeLocBuilder&, clang::SubstTemplateTypeParmTypeLoc) + 143 25 clang-14 0x000000010b1ba5d3 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformType(clang::TypeLocBuilder&, clang::TypeLoc) + 4003 26 clang-14 0x000000010b1b91e2 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformType(clang::TypeSourceInfo*) + 354 27 clang-14 0x000000010b1e9137 clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTemplateArgument(clang::TemplateArgumentLoc const&, clang::TemplateArgumentLoc&, bool) + 1079 28 clang-14 0x000000010b1c543c bool clang::TreeTransform<(anonymous namespace)::TemplateInstantiator>::TransformTemplateArguments<clang::TemplateArgumentLoc const*>(clang::TemplateArgumentLoc const*, clang::TemplateArgumentLoc const*, clang::TemplateArgumentListInfo&, bool) + 2428 29 clang-14 0x000000010b1bc136 clang::Sema::SubstTemplateArguments(llvm::ArrayRef<clang::TemplateArgumentLoc>, clang::MultiLevelTemplateArgumentList const&, clang::TemplateArgumentListInfo&) + 182 30 clang-14 0x000000010a4d15f6 substituteParameterMappings(clang::Sema&, clang::NormalizedConstraint&, clang::ConceptDecl*, llvm::ArrayRef<clang::TemplateArgument>, clang::ASTTemplateArgumentListInfo const*) + 1574 31 clang-14 0x000000010a4d1088 substituteParameterMappings(clang::Sema&, clang::NormalizedConstraint&, clang::ConceptDecl*, llvm::ArrayRef<clang::TemplateArgument>, clang::ASTTemplateArgumentListInfo const*) + 184 32 clang-14 0x000000010a4d1088 substituteParameterMappings(clang::Sema&, clang::NormalizedConstraint&, clang::ConceptDecl*, llvm::ArrayRef<clang::TemplateArgument>, clang::ASTTemplateArgumentListInfo const*) + 184 33 clang-14 0x000000010a4d1088 substituteParameterMappings(clang::Sema&, clang::NormalizedConstraint&, clang::ConceptDecl*, llvm::ArrayRef<clang::TemplateArgument>, clang::ASTTemplateArgumentListInfo const*) + 184 34 clang-14 0x000000010a4d0cf7 clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 1079 35 clang-14 0x000000010a4d0a05 clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 325 36 clang-14 0x000000010a4d099e clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 222 37 clang-14 0x000000010a4d099e clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 222 38 clang-14 0x000000010a4d03e4 clang::NormalizedConstraint::fromConstraintExprs(clang::Sema&, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 164 39 clang-14 0x000000010a4cffa7 clang::Sema::getNormalizedAssociatedConstraints(clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 151 40 clang-14 0x000000010a4d0bec clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 812 41 clang-14 0x000000010a4d03e4 clang::NormalizedConstraint::fromConstraintExprs(clang::Sema&, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 164 42 clang-14 0x000000010a4cffa7 clang::Sema::getNormalizedAssociatedConstraints(clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 151 43 clang-14 0x000000010a4d0bec clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 812 44 clang-14 0x000000010a4d0a05 clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 325 45 clang-14 0x000000010a4d099e clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 222 46 clang-14 0x000000010a4d099e clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 222 47 clang-14 0x000000010a4d03e4 clang::NormalizedConstraint::fromConstraintExprs(clang::Sema&, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 164 48 clang-14 0x000000010a4cffa7 clang::Sema::getNormalizedAssociatedConstraints(clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 151 49 clang-14 0x000000010a4d0bec clang::NormalizedConstraint::fromConstraintExpr(clang::Sema&, clang::NamedDecl*, clang::Expr const*) + 812 50 clang-14 0x000000010a4d03e4 clang::NormalizedConstraint::fromConstraintExprs(clang::Sema&, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 164 51 clang-14 0x000000010a4cffa7 clang::Sema::getNormalizedAssociatedConstraints(clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>) + 151 52 clang-14 0x000000010a4d1d96 bool subsumes<clang::Sema::IsAtLeastAsConstrained(clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, bool&)::$_2>(clang::Sema&, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, bool&, clang::Sema::IsAtLeastAsConstrained(clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, bool&)::$_2) + 150 53 clang-14 0x000000010a4d1a2b clang::Sema::IsAtLeastAsConstrained(clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, clang::NamedDecl*, llvm::ArrayRef<clang::Expr const*>, bool&) + 411 54 clang-14 0x000000010b0cfe2c clang::Sema::isMoreSpecializedThanPrimary(clang::ClassTemplatePartialSpecializationDecl*, clang::sema::TemplateDeductionInfo&) + 428 55 clang-14 0x000000010b0758dd void checkMoreSpecializedThanPrimary<clang::ClassTemplatePartialSpecializationDecl>(clang::Sema&, clang::ClassTemplatePartialSpecializationDecl*) + 141 56 clang-14 0x000000010af84a20 void checkTemplatePartialSpecialization<clang::ClassTemplatePartialSpecializationDecl>(clang::Sema&, clang::ClassTemplatePartialSpecializationDecl*) + 32 57 clang-14 0x000000010af849ed clang::Sema::CheckTemplatePartialSpecialization(clang::ClassTemplatePartialSpecializationDecl*) + 29 58 clang-14 0x000000010af932db clang::Sema::ActOnClassTemplateSpecialization(clang::Scope*, unsigned int, clang::Sema::TagUseKind, clang::SourceLocation, clang::SourceLocation, clang::CXXScopeSpec&, clang::TemplateIdAnnotation&, clang::ParsedAttributesView const&, llvm::MutableArrayRef<clang::TemplateParameterList*>, clang::Sema::SkipBodyInfo*) + 5195 59 clang-14 0x0000000109f81f63 clang::Parser::ParseClassSpecifier(clang::tok::TokenKind, clang::SourceLocation, clang::DeclSpec&, clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, bool, clang::Parser::DeclSpecContext, clang::ParsedAttributesWithRange&) + 7187 60 clang-14 0x0000000109f60058 clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec&, clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, clang::Parser::DeclSpecContext, clang::Parser::LateParsedAttrList*) + 17192 61 clang-14 0x000000010a0336e9 clang::Parser::ParseSingleDeclarationAfterTemplate(clang::DeclaratorContext, clang::Parser::ParsedTemplateInfo const&, clang::ParsingDeclRAIIObject&, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) + 841 62 clang-14 0x000000010a032a22 clang::Parser::ParseTemplateDeclarationOrSpecialization(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) + 1426 63 clang-14 0x000000010a032354 clang::Parser::ParseDeclarationStartingWithTemplate(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::AccessSpecifier) + 228
I don't see any obvious way that this patch could be responsible for that failure, unless it's something like a pre-existing use of uninitialized memory or a use-after-free and this patch is just changing the happenstance behavior.
I can't minimize the example beyond "all of libc++" because Modules prevents creduce from doing anything meaningful. And unfortunately whatever's going wrong seems to be specifically about Modules.
It'd likely be useful to know what the Replacement type is, if you can observe this crash in a debugger. I think it's possible for a type that was canonical prior to serialization and deserialization to be non-canonical afterwards (perhaps because we picked a different declaration of the type to be the first one or merged types in a different order or something like that). It may be that we just need to map to a canonical type in some suitable place.
Apply @rsmith's suggested approach.
I don't see any obvious way that this patch could be responsible for that failure, unless it's something like a pre-existing use of uninitialized memory or a use-after-free and this patch is just changing the happenstance behavior.
Well, it might more likely be the fault of D119184 rather than this one per se. D119184 is doing things with Context.VoidTy that weren't there before; could any of that new code be the culprit?
Thanks, the structure of the change looks good to me.
Looking through the test changes, I'm a bit torn by the value proposition of this note. Some of the errors were already pointing at the return type itself, and others were pointing at the return statement. I can see value in making sure that we mention both when diagnosing return type deduction errors, but pointing out the return type twice and never mentioning the return statement seems a bit noisy. I don't think I have any great suggestions here, though; there's not really a great way we can determine which of the two a diagnostic is pointing at so we can point the note at the other one.
The cases that I found in the tests that seem particularly bad today:
template<typename T> concept Never = false; void g(); // error: cannot form a reference to 'void' auto &f() { // ... return g(); } // error: deduced type 'void' does not satisfy 'Never' Never auto h() { // ... return g(); }
... would both benefit from a note saying "return type deduced from returned expression of type 'void' here" or something like that, and aren't really helped much by this change. But I think noting *both* the return statement and the return type would be too much (then we guarantee we always have at least one noisy note). :(
What do you think? This seems on balance to be near the edge between a useful note and a noisy note, though in many of the specific cases it's pretty clearly on one side or the other.
I don't see any obvious way that this patch could be responsible for that failure, unless it's something like a pre-existing use of uninitialized memory or a use-after-free and this patch is just changing the happenstance behavior.
Well, it might more likely be the fault of D119184 rather than this one per se. D119184 is doing things with Context.VoidTy that weren't there before; could any of that new code be the culprit?
That seems more likely, but nothing in that patch is jumping out at me. Especially given that it only affects the behavior of return type deduction in a function with either no return statements or only return;, it's pretty weird that libc++ would even exercise the patch.
clang/test/SemaCXX/deduced-return-void.cpp | ||
---|---|---|
153–155 | This seems like an unfortunate case: both the error and the note point at the return type and neither points at the return statement. | |
clang/test/SemaTemplate/concepts.cpp | ||
177–180 | This is an unfortunate case: the existing error message already points at the C auto constraint, so we now have an error and a note both pointing at the return type, and nothing pointing to the return statement itself. |
That caused the note to be emitted in some cases without a source location (similar to https://github.com/llvm/llvm-project/issues/29054 ). I admit I should check to make sure we have a test case for each of these four ifs, though; I suspect we don't.