Skip to content

Commit 524344e

Browse files
committed
[RFC][C++20][Modules] Fix crash when function and lambda inside loaded from different modules
Summary: Because AST loading code is lazy and happens in unpredictable order it could happen that function and lambda inside function can be loaded from different modules. In this case, captured DeclRefExpr won’t match the corresponding VarDecl inside function. In AST it looks like this: ``` FunctionDecl 0x555564f4aff0 <Conv.h:33:1, line:41:1> line:33:35 imported in ./thrift_cpp2_base.h hidden tryTo 'Expected<Tgt, const char *> ()' inline |-also in ./folly-conv.h `-CompoundStmt 0x555564f7cfc8 <col:43, line:41:1> |-DeclStmt 0x555564f7ced8 <line:34:3, col:17> | `-VarDecl 0x555564f7cef8 <col:3, col:16> col:7 imported in ./thrift_cpp2_base.h hidden referenced result 'Tgt' cinit | `-IntegerLiteral 0x555564f7d080 <col:16> 'int' 0 |-CallExpr 0x555564f7cea8 <line:39:3, col:76> '<dependent type>' | |-UnresolvedLookupExpr 0x555564f7bea0 <col:3, col:19> '<overloaded function type>' lvalue (no ADL) = 'then_' 0x555564f7bef0 | |-CXXTemporaryObjectExpr 0x555564f7bcb0 <col:25, col:45> 'Expected<bool, int>':'folly::Expected<bool, int>' 'void () noexcept' zeroing | `-LambdaExpr 0x555564f7bc88 <col:48, col:75> '(lambda at Conv.h:39:48)' | |-CXXRecordDecl 0x555564f76b88 <col:48> col:48 imported in ./folly-conv.h hidden implicit <undeserialized declarations> class definition | | |-also in ./thrift_cpp2_base.h | | `-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init | | |-DefaultConstructor defaulted_is_constexpr | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param | | |-MoveConstructor exists simple trivial needs_implicit | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param | | |-MoveAssignment | | `-Destructor simple irrelevant trivial constexpr needs_implicit | `-CompoundStmt 0x555564f7d1a8 <col:58, col:75> | `-ReturnStmt 0x555564f7d198 <col:60, col:67> | `-DeclRefExpr 0x555564f7d0a0 <col:67> 'Tgt' lvalue Var 0x555564f7d0c8 'result' 'Tgt' refers_to_enclosing_variable_or_capture `-ReturnStmt 0x555564f7bc78 <line:40:3, col:11> `-InitListExpr 0x555564f7bc38 <col:10, col:11> 'void' ``` I’m not sure that it is the right fix for the problem so any ideas how to fix it better are very appreciated. Test Plan: check-clang
1 parent 8772795 commit 524344e

File tree

2 files changed

+12
-0
lines changed

2 files changed

+12
-0
lines changed

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4387,6 +4387,11 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
43874387
// a previous declaration.
43884388
if (const TagDecl *Tag = dyn_cast<TagDecl>(CheckD))
43894389
CheckD = Tag->getPreviousDecl();
4390+
else if (const VarDecl *VD = dyn_cast<VarDecl>(CheckD))
4391+
// Check re-declaration chain for variable to deduplicate variables
4392+
// that might be captured inside lambdas. Function and lambda class
4393+
// inside can be loaded from different modules.
4394+
CheckD = VD->getPreviousDecl();
43904395
else
43914396
CheckD = nullptr;
43924397
} while (CheckD);

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3291,6 +3291,13 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
32913291
if (auto *TU = dyn_cast<TranslationUnitDecl>(DC))
32923292
return TU->getPrimaryContext();
32933293

3294+
// Merge VarDecls inside functions to deduplicate variables that might be
3295+
// captured inside lambdas. Function and lambda class inside can be loaded
3296+
// from different modules.
3297+
if (auto *FD = dyn_cast<FunctionDecl>(DC))
3298+
if (FD->getOwningModule())
3299+
return FD->getCanonicalDecl();
3300+
32943301
return nullptr;
32953302
}
32963303

0 commit comments

Comments
 (0)