This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGbc73ef0031b5: PR60985: Fix merging of lambda closure types
across modules. (authored by rsmith).
Changed prior to commit:
https://reviews.llvm.org/D145737?vs=505631&id=509817#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D145737/new/
https://reviews.llvm.org/D145737
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/Decl.h
clang/include/clang/AST/DeclCXX.h
clang/include/clang/AST/ExternalASTSource.h
clang/include/clang/AST/MangleNumberingContext.h
clang/include/clang/AST/Stmt.h
clang/include/clang/Sema/ExternalSemaSource.h
clang/include/clang/Sema/MultiplexExternalSemaSource.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Serialization/ASTReader.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/Decl.cpp
clang/lib/AST/DeclCXX.cpp
clang/lib/AST/ODRDiagsEmitter.cpp
clang/lib/Sema/MultiplexExternalSemaSource.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/Modules/lambda-in-variable.cpp
clang/test/OpenMP/parallel_master_taskloop_simd_codegen.cpp
Index: clang/test/OpenMP/parallel_master_taskloop_simd_codegen.cpp
===================================================================
--- clang/test/OpenMP/parallel_master_taskloop_simd_codegen.cpp
+++ clang/test/OpenMP/parallel_master_taskloop_simd_codegen.cpp
@@ -1457,11 +1457,31 @@
// CHECK2-NEXT: ret void
//
//
-// CHECK2-LABEL: define {{[^@]+}}@_ZN1SC2Ei
+// CHECK2-LABEL: define {{[^@]+}}@__cxx_global_var_init
+// CHECK2-SAME: () #[[ATTR6]] section "__TEXT,__StaticInit,regular,pure_instructions" {
+// CHECK2-NEXT: entry:
+// CHECK2-NEXT: call void @_ZN1SC1Ei(ptr noundef nonnull align 4 dereferenceable(4) @s, i32 noundef 1)
+// CHECK2-NEXT: ret void
+//
+//
+// CHECK2-LABEL: define {{[^@]+}}@_ZN1SC1Ei
// CHECK2-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR8:[0-9]+]] align 2 {
// CHECK2-NEXT: entry:
// CHECK2-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
// CHECK2-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// CHECK2-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
+// CHECK2-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// CHECK2-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
+// CHECK2-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// CHECK2-NEXT: call void @_ZN1SC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
+// CHECK2-NEXT: ret void
+//
+//
+// CHECK2-LABEL: define {{[^@]+}}@_ZN1SC2Ei
+// CHECK2-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR8]] align 2 {
+// CHECK2-NEXT: entry:
+// CHECK2-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
+// CHECK2-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i8, align 1
// CHECK2-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i64, align 8
// CHECK2-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
@@ -1650,26 +1670,6 @@
// CHECK2-NEXT: ret i32 0
//
//
-// CHECK2-LABEL: define {{[^@]+}}@_ZN1SC1Ei
-// CHECK2-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR8]] align 2 {
-// CHECK2-NEXT: entry:
-// CHECK2-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
-// CHECK2-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
-// CHECK2-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
-// CHECK2-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK2-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
-// CHECK2-NEXT: call void @_ZN1SC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
-// CHECK2-NEXT: ret void
-//
-//
-// CHECK2-LABEL: define {{[^@]+}}@__cxx_global_var_init
-// CHECK2-SAME: () #[[ATTR6]] section "__TEXT,__StaticInit,regular,pure_instructions" {
-// CHECK2-NEXT: entry:
-// CHECK2-NEXT: call void @_ZN1SC1Ei(ptr noundef nonnull align 4 dereferenceable(4) @s, i32 noundef 1)
-// CHECK2-NEXT: ret void
-//
-//
// CHECK2-LABEL: define {{[^@]+}}@_GLOBAL__sub_I_parallel_master_taskloop_simd_codegen.cpp
// CHECK2-SAME: () #[[ATTR6]] section "__TEXT,__StaticInit,regular,pure_instructions" {
// CHECK2-NEXT: entry:
@@ -3111,8 +3111,28 @@
// CHECK6-NEXT: ret i32 [[TMP48]]
//
//
+// CHECK6-LABEL: define {{[^@]+}}@__cxx_global_var_init
+// CHECK6-SAME: () #[[ATTR2:[0-9]+]] section "__TEXT,__StaticInit,regular,pure_instructions" {
+// CHECK6-NEXT: entry:
+// CHECK6-NEXT: call void @_ZN1SC1Ei(ptr noundef nonnull align 4 dereferenceable(4) @s, i32 noundef 1)
+// CHECK6-NEXT: ret void
+//
+//
+// CHECK6-LABEL: define {{[^@]+}}@_ZN1SC1Ei
+// CHECK6-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR3:[0-9]+]] align 2 {
+// CHECK6-NEXT: entry:
+// CHECK6-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
+// CHECK6-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// CHECK6-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
+// CHECK6-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// CHECK6-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
+// CHECK6-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// CHECK6-NEXT: call void @_ZN1SC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
+// CHECK6-NEXT: ret void
+//
+//
// CHECK6-LABEL: define {{[^@]+}}@_ZN1SC2Ei
-// CHECK6-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR2:[0-9]+]] align 2 {
+// CHECK6-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR3]] align 2 {
// CHECK6-NEXT: entry:
// CHECK6-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
// CHECK6-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
@@ -3195,28 +3215,8 @@
// CHECK6-NEXT: ret void
//
//
-// CHECK6-LABEL: define {{[^@]+}}@_ZN1SC1Ei
-// CHECK6-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR2]] align 2 {
-// CHECK6-NEXT: entry:
-// CHECK6-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
-// CHECK6-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
-// CHECK6-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
-// CHECK6-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
-// CHECK6-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK6-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
-// CHECK6-NEXT: call void @_ZN1SC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
-// CHECK6-NEXT: ret void
-//
-//
-// CHECK6-LABEL: define {{[^@]+}}@__cxx_global_var_init
-// CHECK6-SAME: () #[[ATTR3:[0-9]+]] section "__TEXT,__StaticInit,regular,pure_instructions" {
-// CHECK6-NEXT: entry:
-// CHECK6-NEXT: call void @_ZN1SC1Ei(ptr noundef nonnull align 4 dereferenceable(4) @s, i32 noundef 1)
-// CHECK6-NEXT: ret void
-//
-//
// CHECK6-LABEL: define {{[^@]+}}@_GLOBAL__sub_I_parallel_master_taskloop_simd_codegen.cpp
-// CHECK6-SAME: () #[[ATTR3]] section "__TEXT,__StaticInit,regular,pure_instructions" {
+// CHECK6-SAME: () #[[ATTR2]] section "__TEXT,__StaticInit,regular,pure_instructions" {
// CHECK6-NEXT: entry:
// CHECK6-NEXT: call void @__cxx_global_var_init()
// CHECK6-NEXT: ret void
@@ -3919,8 +3919,28 @@
// CHECK8-NEXT: ret i32 [[TMP62]]
//
//
+// CHECK8-LABEL: define {{[^@]+}}@__cxx_global_var_init
+// CHECK8-SAME: () #[[ATTR2:[0-9]+]] section "__TEXT,__StaticInit,regular,pure_instructions" {
+// CHECK8-NEXT: entry:
+// CHECK8-NEXT: call void @_ZN1SC1Ei(ptr noundef nonnull align 4 dereferenceable(4) @s, i32 noundef 1)
+// CHECK8-NEXT: ret void
+//
+//
+// CHECK8-LABEL: define {{[^@]+}}@_ZN1SC1Ei
+// CHECK8-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR3:[0-9]+]] align 2 {
+// CHECK8-NEXT: entry:
+// CHECK8-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
+// CHECK8-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// CHECK8-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
+// CHECK8-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// CHECK8-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
+// CHECK8-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// CHECK8-NEXT: call void @_ZN1SC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
+// CHECK8-NEXT: ret void
+//
+//
// CHECK8-LABEL: define {{[^@]+}}@_ZN1SC2Ei
-// CHECK8-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR2:[0-9]+]] align 2 {
+// CHECK8-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR3]] align 2 {
// CHECK8-NEXT: entry:
// CHECK8-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
// CHECK8-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
@@ -4003,28 +4023,8 @@
// CHECK8-NEXT: ret void
//
//
-// CHECK8-LABEL: define {{[^@]+}}@_ZN1SC1Ei
-// CHECK8-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]], i32 noundef [[C:%.*]]) unnamed_addr #[[ATTR2]] align 2 {
-// CHECK8-NEXT: entry:
-// CHECK8-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
-// CHECK8-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
-// CHECK8-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
-// CHECK8-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
-// CHECK8-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK8-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
-// CHECK8-NEXT: call void @_ZN1SC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
-// CHECK8-NEXT: ret void
-//
-//
-// CHECK8-LABEL: define {{[^@]+}}@__cxx_global_var_init
-// CHECK8-SAME: () #[[ATTR3:[0-9]+]] section "__TEXT,__StaticInit,regular,pure_instructions" {
-// CHECK8-NEXT: entry:
-// CHECK8-NEXT: call void @_ZN1SC1Ei(ptr noundef nonnull align 4 dereferenceable(4) @s, i32 noundef 1)
-// CHECK8-NEXT: ret void
-//
-//
// CHECK8-LABEL: define {{[^@]+}}@_GLOBAL__sub_I_parallel_master_taskloop_simd_codegen.cpp
-// CHECK8-SAME: () #[[ATTR3]] section "__TEXT,__StaticInit,regular,pure_instructions" {
+// CHECK8-SAME: () #[[ATTR2]] section "__TEXT,__StaticInit,regular,pure_instructions" {
// CHECK8-NEXT: entry:
// CHECK8-NEXT: call void @__cxx_global_var_init()
// CHECK8-NEXT: ret void
Index: clang/test/Modules/lambda-in-variable.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/lambda-in-variable.cpp
@@ -0,0 +1,120 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%t/module.modulemap %t/use.cpp -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -DDEFINE_LOCALLY -std=c++20 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%t/module.modulemap %t/use.cpp -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s
+
+//--- module.modulemap
+module a { header "a.h" export * }
+module b { header "b.h" export * }
+module c { header "c.h" export * }
+
+//--- nonmodular.h
+void not_constant();
+
+template<typename T> struct A {
+ template<T M> static inline T N = [] { not_constant(); return M; } ();
+};
+
+template<typename T, T M> inline T N = [] { not_constant(); return M; } ();
+
+template<typename T, T M> inline auto L = [] {};
+
+template<typename T> int Z;
+
+// These lambdas should not be merged, despite having the same context decl and
+// mangling number (but different signatures).
+inline auto MultipleLambdas = ((void)[](int*) { return 1; }, [] { return 2; });
+
+//--- a.h
+#include "nonmodular.h"
+
+//--- b.h
+#include "a.h"
+
+int b1() { return A<int>::N<1>; }
+int b2() { return N<int, 1>; }
+
+inline auto x1 = L<int, 1>;
+inline auto x2 = L<int, 2>;
+
+inline constexpr int *P = &Z<decltype([] { static int n; return &n; }())>;
+inline constexpr int *xP = P;
+
+static_assert(!__is_same(decltype(x1), decltype(x2)));
+
+//--- c.h
+#include "a.h"
+
+int c1() { return A<int>::N<2>; }
+int c2() { return N<int, 2>; }
+
+inline auto y2 = L<int, 2>;
+inline auto y1 = L<int, 1>;
+
+inline constexpr int *P = &Z<decltype([] { static int n; return &n; }())>;
+inline constexpr int *yP = P;
+
+//--- use.cpp
+#ifdef DEFINE_LOCALLY
+#include "nonmodular.h"
+
+inline constexpr int *P = &Z<decltype([] { static int n; return &n; }())>;
+inline constexpr int *zP = P;
+
+auto z0 = L<int, 0>;
+auto z2 = L<int, 2>;
+auto z1 = L<int, 1>;
+#endif
+
+#include "b.h"
+#include "c.h"
+
+int b1v = b1();
+int b2v = b2();
+int c1v = c1();
+int c2v = c2();
+
+// We should merge together matching lambdas.
+static_assert(__is_same(decltype(x1), decltype(y1)));
+static_assert(__is_same(decltype(x2), decltype(y2)));
+static_assert(!__is_same(decltype(x1), decltype(x2)));
+static_assert(!__is_same(decltype(y1), decltype(y2)));
+static_assert(!__is_same(decltype(x1), decltype(y2)));
+static_assert(!__is_same(decltype(x2), decltype(y1)));
+static_assert(xP == yP);
+#ifdef DEFINE_LOCALLY
+static_assert(!__is_same(decltype(x1), decltype(z0)));
+static_assert(!__is_same(decltype(x2), decltype(z0)));
+static_assert(__is_same(decltype(x1), decltype(z1)));
+static_assert(__is_same(decltype(x2), decltype(z2)));
+static_assert(xP == zP);
+#endif
+
+static_assert(MultipleLambdas() == 2);
+
+// We should not merge the instantiated lambdas from `b.h` and `c.h` together,
+// even though they will both have anonymous declaration number #1 within
+// A<int> and within the TU, respectively.
+
+// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_Z1NIiLi1EE) {
+// CHECK: load i8, ptr @_ZGV1NIiLi1EE, align 8
+// CHECK: call {{.*}} i32 @_ZNK1NIiLi1EEMUlvE_clEv(
+// CHECK: store i32 {{.*}}, ptr @_Z1NIiLi1EE
+
+// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_ZN1AIiE1NILi1EEE) {
+// CHECK: load i8, ptr @_ZGVN1AIiE1NILi1EEE, align 8
+// CHECK: call {{.*}} i32 @_ZNK1AIiE1NILi1EEMUlvE_clEv(
+// CHECK: store i32 {{.*}}, ptr @_ZN1AIiE1NILi1EEE
+
+// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_Z1NIiLi2EE) {
+// CHECK: load i8, ptr @_ZGV1NIiLi2EE, align 8
+// CHECK: call {{.*}} i32 @_ZNK1NIiLi2EEMUlvE_clEv(
+// CHECK: store i32 {{.*}}, ptr @_Z1NIiLi2EE
+
+// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_ZN1AIiE1NILi2EEE) {
+// CHECK: load i8, ptr @_ZGVN1AIiE1NILi2EEE, align 8
+// CHECK: call {{.*}} i32 @_ZNK1AIiE1NILi2EEMUlvE_clEv(
+// CHECK: store i32 {{.*}}, ptr @_ZN1AIiE1NILi2EEE
+
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -150,7 +150,7 @@
if (HasElse)
Record.AddStmt(S->getElse());
if (HasVar)
- Record.AddDeclRef(S->getConditionVariable());
+ Record.AddStmt(S->getConditionVariableDeclStmt());
if (HasInit)
Record.AddStmt(S->getInit());
@@ -177,7 +177,7 @@
if (HasInit)
Record.AddStmt(S->getInit());
if (HasVar)
- Record.AddDeclRef(S->getConditionVariable());
+ Record.AddStmt(S->getConditionVariableDeclStmt());
Record.AddSourceLocation(S->getSwitchLoc());
Record.AddSourceLocation(S->getLParenLoc());
@@ -198,7 +198,7 @@
Record.AddStmt(S->getCond());
Record.AddStmt(S->getBody());
if (HasVar)
- Record.AddDeclRef(S->getConditionVariable());
+ Record.AddStmt(S->getConditionVariableDeclStmt());
Record.AddSourceLocation(S->getWhileLoc());
Record.AddSourceLocation(S->getLParenLoc());
@@ -220,7 +220,7 @@
VisitStmt(S);
Record.AddStmt(S->getInit());
Record.AddStmt(S->getCond());
- Record.AddDeclRef(S->getConditionVariable());
+ Record.AddStmt(S->getConditionVariableDeclStmt());
Record.AddStmt(S->getInc());
Record.AddStmt(S->getBody());
Record.AddSourceLocation(S->getForLoc());
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -278,7 +278,7 @@
// Source locations require array (variable-length) abbreviations. The
// abbreviation infrastructure requires that arrays are encoded last, so
// we handle it here in the case of those classes derived from DeclaratorDecl
- if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
if (auto *TInfo = DD->getTypeSourceInfo())
Record.AddTypeLoc(TInfo->getTypeLoc());
}
@@ -286,16 +286,24 @@
// Handle FunctionDecl's body here and write it after all other Stmts/Exprs
// have been written. We want it last because we will not read it back when
// retrieving it from the AST, we'll just lazily set the offset.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
Record.push_back(FD->doesThisDeclarationHaveABody());
if (FD->doesThisDeclarationHaveABody())
Record.AddFunctionDefinition(FD);
}
+ // Similar to FunctionDecls, handle VarDecl's initializer here and write it
+ // after all other Stmts/Exprs. We will not read the initializer until after
+ // we have finished recursive deserialization, because it can recursively
+ // refer back to the variable.
+ if (auto *VD = dyn_cast<VarDecl>(D)) {
+ Record.AddVarDeclInit(VD);
+ }
+
// If this declaration is also a DeclContext, write blocks for the
// declarations that lexically stored inside its context and those
// declarations that are visible from its context.
- if (DeclContext *DC = dyn_cast<DeclContext>(D))
+ if (auto *DC = dyn_cast<DeclContext>(D))
VisitDeclContext(DC);
}
@@ -1037,6 +1045,7 @@
Record.push_back(D->getTSCSpec());
Record.push_back(D->getInitStyle());
Record.push_back(D->isARCPseudoStrong());
+ bool HasDeducedType = false;
if (!isa<ParmVarDecl>(D)) {
Record.push_back(D->isThisDeclarationADemotedDefinition());
Record.push_back(D->isExceptionVariable());
@@ -1053,36 +1062,34 @@
else
Record.push_back(0);
Record.push_back(D->isEscapingByref());
+ HasDeducedType = D->getType()->getContainedDeducedType();
+ Record.push_back(HasDeducedType);
}
Record.push_back(D->getLinkageInternal());
- Record.AddVarDeclInit(D);
-
- if (D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) {
+ if (D->hasAttr<BlocksAttr>()) {
BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D);
Record.AddStmt(Init.getCopyExpr());
if (Init.getCopyExpr())
Record.push_back(Init.canThrow());
}
- if (D->getStorageDuration() == SD_Static) {
- bool ModulesCodegen = false;
- if (Writer.WritingModule &&
- !D->getDescribedVarTemplate()) {
- // When building a C++20 module interface unit or a partition unit, a
- // strong definition in the module interface is provided by the
- // compilation of that unit, not by its users. (Inline variables are still
- // emitted in module users.)
- ModulesCodegen =
- (Writer.WritingModule->isInterfaceOrPartition() ||
- (D->hasAttr<DLLExportAttr>() &&
- Writer.Context->getLangOpts().BuildingPCHWithObjectFile)) &&
- Writer.Context->GetGVALinkageForVariable(D) >= GVA_StrongExternal;
- }
- Record.push_back(ModulesCodegen);
- if (ModulesCodegen)
- Writer.ModularCodegenDecls.push_back(Writer.GetDeclRef(D));
+ bool ModulesCodegen = false;
+ if (Writer.WritingModule && D->getStorageDuration() == SD_Static &&
+ !D->getDescribedVarTemplate()) {
+ // When building a C++20 module interface unit or a partition unit, a
+ // strong definition in the module interface is provided by the
+ // compilation of that unit, not by its users. (Inline variables are still
+ // emitted in module users.)
+ ModulesCodegen =
+ (Writer.WritingModule->isInterfaceOrPartition() ||
+ (D->hasAttr<DLLExportAttr>() &&
+ Writer.Context->getLangOpts().BuildingPCHWithObjectFile)) &&
+ Writer.Context->GetGVALinkageForVariable(D) >= GVA_StrongExternal;
}
+ Record.push_back(ModulesCodegen);
+ if (ModulesCodegen)
+ Writer.ModularCodegenDecls.push_back(Writer.GetDeclRef(D));
enum {
VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
@@ -1118,8 +1125,9 @@
!D->isConstexpr() &&
!D->isInitCapture() &&
!D->isPreviousDeclInSameBlockScope() &&
- !(D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) &&
+ !D->hasAttr<BlocksAttr>() &&
!D->isEscapingByref() &&
+ !HasDeducedType &&
D->getStorageDuration() != SD_Static &&
!D->getMemberSpecializationInfo())
AbbrevToUse = Writer.getDeclVarAbbrev();
@@ -1413,7 +1421,10 @@
VisitRecordDecl(D);
enum {
- CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
+ CXXRecNotTemplate = 0,
+ CXXRecTemplate,
+ CXXRecMemberSpecialization,
+ CXXLambda
};
if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) {
Record.push_back(CXXRecTemplate);
@@ -1424,6 +1435,15 @@
Record.AddDeclRef(MSInfo->getInstantiatedFrom());
Record.push_back(MSInfo->getTemplateSpecializationKind());
Record.AddSourceLocation(MSInfo->getPointOfInstantiation());
+ } else if (D->isLambda()) {
+ // For a lambda, we need some information early for merging.
+ Record.push_back(CXXLambda);
+ if (auto *Context = D->getLambdaContextDecl()) {
+ Record.AddDeclRef(Context);
+ Record.push_back(D->getLambdaIndexInContext());
+ } else {
+ Record.push_back(0);
+ }
} else {
Record.push_back(CXXRecNotTemplate);
}
@@ -2301,6 +2321,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
Abv->Add(BitCodeAbbrevOp(0)); // ImplicitParamKind
Abv->Add(BitCodeAbbrevOp(0)); // EscapingByref
+ Abv->Add(BitCodeAbbrevOp(0)); // HasDeducedType
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // HasConstant*
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local enum)
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -5175,6 +5175,7 @@
const Decl *D = DeclUpdate.first;
bool HasUpdatedBody = false;
+ bool HasAddedVarDefinition = false;
RecordData RecordData;
ASTRecordWriter Record(*this, RecordData);
for (auto &Update : DeclUpdate.second) {
@@ -5184,6 +5185,8 @@
// to skip over the lazy body to reach statements for other records.
if (Kind == UPD_CXX_ADDED_FUNCTION_DEFINITION)
HasUpdatedBody = true;
+ else if (Kind == UPD_CXX_ADDED_VAR_DEFINITION)
+ HasAddedVarDefinition = true;
else
Record.push_back(Kind);
@@ -5196,6 +5199,7 @@
break;
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
+ case UPD_CXX_ADDED_VAR_DEFINITION:
break;
case UPD_CXX_POINT_OF_INSTANTIATION:
@@ -5203,14 +5207,6 @@
Record.AddSourceLocation(Update.getLoc());
break;
- case UPD_CXX_ADDED_VAR_DEFINITION: {
- const VarDecl *VD = cast<VarDecl>(D);
- Record.push_back(VD->isInline());
- Record.push_back(VD->isInlineSpecified());
- Record.AddVarDeclInit(VD);
- break;
- }
-
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT:
Record.AddStmt(const_cast<Expr *>(
cast<ParmVarDecl>(Update.getDecl())->getDefaultArg()));
@@ -5322,12 +5318,20 @@
}
}
+ // Add a trailing update record, if any. These must go last because we
+ // lazily load their attached statement.
if (HasUpdatedBody) {
const auto *Def = cast<FunctionDecl>(D);
Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
Record.push_back(Def->isInlined());
Record.AddSourceLocation(Def->getInnerLocStart());
Record.AddFunctionDefinition(Def);
+ } else if (HasAddedVarDefinition) {
+ const auto *VD = cast<VarDecl>(D);
+ Record.push_back(UPD_CXX_ADDED_VAR_DEFINITION);
+ Record.push_back(VD->isInline());
+ Record.push_back(VD->isInlineSpecified());
+ Record.AddVarDeclInit(VD);
}
OffsetsRecord.push_back(GetDeclRef(D));
@@ -5917,6 +5921,7 @@
// getODRHash will compute the ODRHash if it has not been previously computed.
Record->push_back(D->getODRHash());
+
bool ModulesDebugInfo =
Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType();
Record->push_back(ModulesDebugInfo);
@@ -5925,24 +5930,24 @@
// IsLambda bit is already saved.
- Record->push_back(Data.NumBases);
- if (Data.NumBases > 0)
- AddCXXBaseSpecifiers(Data.bases());
-
- // FIXME: Make VBases lazily computed when needed to avoid storing them.
- Record->push_back(Data.NumVBases);
- if (Data.NumVBases > 0)
- AddCXXBaseSpecifiers(Data.vbases());
-
AddUnresolvedSet(Data.Conversions.get(*Writer->Context));
Record->push_back(Data.ComputedVisibleConversions);
if (Data.ComputedVisibleConversions)
AddUnresolvedSet(Data.VisibleConversions.get(*Writer->Context));
// Data.Definition is the owning decl, no need to write it.
- AddDeclRef(D->getFirstFriend());
- // Add lambda-specific data.
- if (Data.IsLambda) {
+ if (!Data.IsLambda) {
+ Record->push_back(Data.NumBases);
+ if (Data.NumBases > 0)
+ AddCXXBaseSpecifiers(Data.bases());
+
+ // FIXME: Make VBases lazily computed when needed to avoid storing them.
+ Record->push_back(Data.NumVBases);
+ if (Data.NumVBases > 0)
+ AddCXXBaseSpecifiers(Data.vbases());
+
+ AddDeclRef(D->getFirstFriend());
+ } else {
auto &Lambda = D->getLambdaData();
Record->push_back(Lambda.DependencyKind);
Record->push_back(Lambda.IsGenericLambda);
@@ -5952,7 +5957,8 @@
Record->push_back(Lambda.HasKnownInternalLinkage);
Record->push_back(Lambda.ManglingNumber);
Record->push_back(D->getDeviceLambdaManglingNumber());
- AddDeclRef(D->getLambdaContextDecl());
+ // The lambda context declaration and index within the context are provided
+ // separately, so that they can be used for merging.
AddTypeSourceInfo(Lambda.MethodTyInfo);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
const LambdaCapture &Capture = Lambda.Captures.front()[I];
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -228,7 +228,7 @@
if (HasElse)
S->setElse(Record.readSubStmt());
if (HasVar)
- S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
+ S->setConditionVariableDeclStmt(cast<DeclStmt>(Record.readSubStmt()));
if (HasInit)
S->setInit(Record.readSubStmt());
@@ -253,7 +253,7 @@
if (HasInit)
S->setInit(Record.readSubStmt());
if (HasVar)
- S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
+ S->setConditionVariableDeclStmt(cast<DeclStmt>(Record.readSubStmt()));
S->setSwitchLoc(readSourceLocation());
S->setLParenLoc(readSourceLocation());
@@ -279,7 +279,7 @@
S->setCond(Record.readSubExpr());
S->setBody(Record.readSubStmt());
if (HasVar)
- S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
+ S->setConditionVariableDeclStmt(cast<DeclStmt>(Record.readSubStmt()));
S->setWhileLoc(readSourceLocation());
S->setLParenLoc(readSourceLocation());
@@ -299,7 +299,7 @@
VisitStmt(S);
S->setInit(Record.readSubStmt());
S->setCond(Record.readSubExpr());
- S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>());
+ S->setConditionVariableDeclStmt(cast_or_null<DeclStmt>(Record.readSubStmt()));
S->setInc(Record.readSubExpr());
S->setBody(Record.readSubStmt());
S->setForLoc(readSourceLocation());
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -158,9 +158,12 @@
return Record.getSubmodule(readSubmoduleID());
}
- void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
+ void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update,
+ Decl *LambdaContext = nullptr,
+ unsigned IndexInLambdaContext = 0);
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
- const CXXRecordDecl *D);
+ const CXXRecordDecl *D, Decl *LambdaContext,
+ unsigned IndexInLambdaContext);
void MergeDefinitionData(CXXRecordDecl *D,
struct CXXRecordDecl::DefinitionData &&NewDD);
void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
@@ -377,6 +380,7 @@
void VisitTemplateParamObjectDecl(TemplateParamObjectDecl *D);
void VisitIndirectFieldDecl(IndirectFieldDecl *FD);
RedeclarableResult VisitVarDeclImpl(VarDecl *D);
+ void ReadVarDeclInit(VarDecl *VD);
void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); }
void VisitImplicitParamDecl(ImplicitParamDecl *PD);
void VisitParmVarDecl(ParmVarDecl *PD);
@@ -422,6 +426,9 @@
template <typename T>
void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
+ void mergeLambda(CXXRecordDecl *D, RedeclarableResult &Redecl,
+ Decl *Context, unsigned Number);
+
void mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
RedeclarableResult &Redecl);
@@ -564,6 +571,8 @@
// FIXME: Can we diagnose ODR violations somehow?
if (Record.readInt())
ReadFunctionDefinition(FD);
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ ReadVarDeclInit(VD);
}
}
@@ -861,10 +870,10 @@
void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
VisitNamedDecl(VD);
- // For function declarations, defer reading the type in case the function has
- // a deduced return type that references an entity declared within the
- // function.
- if (isa<FunctionDecl>(VD))
+ // For function or variable declarations, defer reading the type in case the
+ // declaration has a deduced type that references an entity declared within
+ // the function definition or variable initializer.
+ if (isa<FunctionDecl, VarDecl>(VD))
DeferredTypeID = Record.getGlobalTypeID(Record.readInt());
else
VD->setType(Record.readType());
@@ -1026,7 +1035,7 @@
// We'll set up the real type in Visit, once we've finished loading the
// function.
FD->setType(FD->getTypeSourceInfo()->getType());
- Reader.PendingFunctionTypes.push_back({FD, DeferredTypeID});
+ Reader.PendingDeducedFunctionTypes.push_back({FD, DeferredTypeID});
} else {
FD->setType(Reader.GetType(DeferredTypeID));
}
@@ -1571,6 +1580,7 @@
VD->VarDeclBits.TSCSpec = Record.readInt();
VD->VarDeclBits.InitStyle = Record.readInt();
VD->VarDeclBits.ARCPseudoStrong = Record.readInt();
+ bool HasDeducedType = false;
if (!isa<ParmVarDecl>(VD)) {
VD->NonParmVarDeclBits.IsThisDeclarationADemotedDefinition =
Record.readInt();
@@ -1585,7 +1595,18 @@
VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = Record.readInt();
VD->NonParmVarDeclBits.ImplicitParamKind = Record.readInt();
VD->NonParmVarDeclBits.EscapingByref = Record.readInt();
+ HasDeducedType = Record.readInt();
}
+
+ // If this variable has a deduced type, defer reading that type until we are
+ // done deserializing this variable, because the type might refer back to the
+ // variable.
+ if (HasDeducedType)
+ Reader.PendingDeducedVarTypes.push_back({VD, DeferredTypeID});
+ else
+ VD->setType(Reader.GetType(DeferredTypeID));
+ DeferredTypeID = 0;
+
auto VarLinkage = Linkage(Record.readInt());
VD->setCachedLinkage(VarLinkage);
@@ -1594,22 +1615,13 @@
VD->getLexicalDeclContext()->isFunctionOrMethod())
VD->setLocalExternDecl();
- if (uint64_t Val = Record.readInt()) {
- VD->setInit(Record.readExpr());
- if (Val != 1) {
- EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
- Eval->HasConstantInitialization = (Val & 2) != 0;
- Eval->HasConstantDestruction = (Val & 4) != 0;
- }
- }
-
- if (VD->hasAttr<BlocksAttr>() && VD->getType()->getAsCXXRecordDecl()) {
+ if (VD->hasAttr<BlocksAttr>()) {
Expr *CopyExpr = Record.readExpr();
if (CopyExpr)
Reader.getContext().setBlockVarCopyInit(VD, CopyExpr, Record.readInt());
}
- if (VD->getStorageDuration() == SD_Static && Record.readInt()) {
+ if (Record.readInt()) {
Reader.DefinitionSource[VD] =
Loc.F->Kind == ModuleKind::MK_MainFile ||
Reader.getContext().getLangOpts().BuildingPCHWithObjectFile;
@@ -1643,6 +1655,18 @@
return Redecl;
}
+void ASTDeclReader::ReadVarDeclInit(VarDecl *VD) {
+ if (uint64_t Val = Record.readInt()) {
+ EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
+ Eval->HasConstantInitialization = (Val & 2) != 0;
+ Eval->HasConstantDestruction = (Val & 4) != 0;
+ // Store the offset of the initializer. Don't deserialize it yet: it might
+ // not be needed, and might refer back to the variable, for example if it
+ // contains a lambda.
+ Eval->Value = GetCurrentCursorOffset();
+ }
+}
+
void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
VisitVarDecl(PD);
}
@@ -1894,10 +1918,10 @@
}
void ASTDeclReader::ReadCXXDefinitionData(
- struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) {
- #define FIELD(Name, Width, Merge) \
- Data.Name = Record.readInt();
- #include "clang/AST/CXXRecordDeclDefinitionBits.def"
+ struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D,
+ Decl *LambdaContext, unsigned IndexInLambdaContext) {
+#define FIELD(Name, Width, Merge) Data.Name = Record.readInt();
+#include "clang/AST/CXXRecordDeclDefinitionBits.def"
// Note: the caller has deserialized the IsLambda bit already.
Data.ODRHash = Record.readInt();
@@ -1909,21 +1933,26 @@
Reader.getContext().getLangOpts().BuildingPCHWithObjectFile;
}
- Data.NumBases = Record.readInt();
- if (Data.NumBases)
- Data.Bases = ReadGlobalOffset();
- Data.NumVBases = Record.readInt();
- if (Data.NumVBases)
- Data.VBases = ReadGlobalOffset();
-
Record.readUnresolvedSet(Data.Conversions);
Data.ComputedVisibleConversions = Record.readInt();
if (Data.ComputedVisibleConversions)
Record.readUnresolvedSet(Data.VisibleConversions);
assert(Data.Definition && "Data.Definition should be already set!");
- Data.FirstFriend = readDeclID();
- if (Data.IsLambda) {
+ if (!Data.IsLambda) {
+ assert(!LambdaContext && !IndexInLambdaContext &&
+ "given lambda context for non-lambda");
+
+ Data.NumBases = Record.readInt();
+ if (Data.NumBases)
+ Data.Bases = ReadGlobalOffset();
+
+ Data.NumVBases = Record.readInt();
+ if (Data.NumVBases)
+ Data.VBases = ReadGlobalOffset();
+
+ Data.FirstFriend = readDeclID();
+ } else {
using Capture = LambdaCapture;
auto &Lambda = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
@@ -1934,8 +1963,10 @@
Lambda.NumExplicitCaptures = Record.readInt();
Lambda.HasKnownInternalLinkage = Record.readInt();
Lambda.ManglingNumber = Record.readInt();
- D->setDeviceLambdaManglingNumber(Record.readInt());
- Lambda.ContextDecl = readDeclID();
+ if (unsigned DeviceManglingNumber = Record.readInt())
+ Reader.getContext().DeviceLambdaManglingNumbers[D] = DeviceManglingNumber;
+ Lambda.IndexInContext = IndexInLambdaContext;
+ Lambda.ContextDecl = LambdaContext;
Capture *ToCapture = nullptr;
if (Lambda.NumCaptures) {
ToCapture = (Capture *)Reader.getContext().Allocate(sizeof(Capture) *
@@ -2056,13 +2087,17 @@
{MergeDD.Definition, &MergeDD});
}
-void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
+void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update,
+ Decl *LambdaContext,
+ unsigned IndexInLambdaContext) {
struct CXXRecordDecl::DefinitionData *DD;
ASTContext &C = Reader.getContext();
// Determine whether this is a lambda closure type, so that we can
// allocate the appropriate DefinitionData structure.
bool IsLambda = Record.readInt();
+ assert(!(IsLambda && Update) &&
+ "lambda definition should not be added by update record");
if (IsLambda)
DD = new (C) CXXRecordDecl::LambdaDefinitionData(
D, nullptr, CXXRecordDecl::LDK_Unknown, false, LCD_None);
@@ -2076,7 +2111,7 @@
if (!Canon->DefinitionData)
Canon->DefinitionData = DD;
D->DefinitionData = Canon->DefinitionData;
- ReadCXXDefinitionData(*DD, D);
+ ReadCXXDefinitionData(*DD, D, LambdaContext, IndexInLambdaContext);
// We might already have a different definition for this record. This can
// happen either because we're reading an update record, or because we've
@@ -2103,8 +2138,15 @@
ASTContext &C = Reader.getContext();
enum CXXRecKind {
- CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
+ CXXRecNotTemplate = 0,
+ CXXRecTemplate,
+ CXXRecMemberSpecialization,
+ CXXLambda
};
+
+ Decl *LambdaContext = nullptr;
+ unsigned IndexInLambdaContext = 0;
+
switch ((CXXRecKind)Record.readInt()) {
case CXXRecNotTemplate:
// Merged when we merge the folding set entry in the primary template.
@@ -2136,11 +2178,19 @@
mergeRedeclarable(D, Redecl);
break;
}
+ case CXXLambda: {
+ LambdaContext = readDecl();
+ if (LambdaContext)
+ IndexInLambdaContext = Record.readInt();
+ mergeLambda(D, Redecl, LambdaContext, IndexInLambdaContext);
+ break;
+ }
}
bool WasDefinition = Record.readInt();
if (WasDefinition)
- ReadCXXRecordDefinition(D, /*Update*/false);
+ ReadCXXRecordDefinition(D, /*Update=*/false, LambdaContext,
+ IndexInLambdaContext);
else
// Propagate DefinitionData pointer from the canonical declaration.
D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
@@ -2742,6 +2792,41 @@
mergeRedeclarable(D, Existing, Redecl);
}
+/// Attempt to merge D with a previous declaration of the same lambda, which is
+/// found by its index within its context declaration, if it has one.
+///
+/// We can't look up lambdas in their enclosing lexical or semantic context in
+/// general, because for lambdas in variables, both of those might be a
+/// namespace or the translation unit.
+void ASTDeclReader::mergeLambda(CXXRecordDecl *D, RedeclarableResult &Redecl,
+ Decl *Context, unsigned IndexInContext) {
+ // If we don't have a mangling context, treat this like any other
+ // declaration.
+ if (!Context)
+ return mergeRedeclarable(D, Redecl);
+
+ // If modules are not available, there is no reason to perform this merge.
+ if (!Reader.getContext().getLangOpts().Modules)
+ return;
+
+ // If we're not the canonical declaration, we don't need to merge.
+ if (!D->isFirstDecl())
+ return;
+
+ if (auto *Existing = Redecl.getKnownMergeTarget())
+ // We already know of an existing declaration we should merge with.
+ mergeRedeclarable(D, cast<TagDecl>(Existing), Redecl);
+
+ // Look up this lambda to see if we've seen it before. If so, merge with the
+ // one we already loaded.
+ NamedDecl *&Slot = Reader.LambdaDeclarationsForMerging[{
+ Context->getCanonicalDecl(), IndexInContext}];
+ if (Slot)
+ mergeRedeclarable(D, cast<TagDecl>(Slot), Redecl);
+ else
+ Slot = D;
+}
+
void ASTDeclReader::mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
RedeclarableResult &Redecl) {
mergeRedeclarable(D, Redecl);
@@ -4306,13 +4391,9 @@
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
auto *RD = cast<CXXRecordDecl>(D);
- // FIXME: If we also have an update record for instantiating the
- // definition of D, we need that to happen before we get here.
Decl *MD = Record.readDecl();
assert(MD && "couldn't read decl from update record");
- // FIXME: We should call addHiddenDecl instead, to add the member
- // to its DeclContext.
- RD->addedMember(MD);
+ Reader.PendingAddedClassMembers.push_back({RD, MD});
break;
}
@@ -4340,15 +4421,7 @@
auto *VD = cast<VarDecl>(D);
VD->NonParmVarDeclBits.IsInline = Record.readInt();
VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt();
- uint64_t Val = Record.readInt();
- if (Val && !VD->getInit()) {
- VD->setInit(Record.readExpr());
- if (Val != 1) {
- EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
- Eval->HasConstantInitialization = (Val & 2) != 0;
- Eval->HasConstantDestruction = (Val & 4) != 0;
- }
- }
+ ReadVarDeclInit(VD);
break;
}
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -7367,6 +7367,7 @@
return nullptr;
}
ReadingKindTracker ReadingKind(Read_Decl, *this);
+ Deserializing D(this);
Expected<unsigned> MaybeCode = Cursor.ReadCode();
if (!MaybeCode) {
@@ -7401,6 +7402,7 @@
return nullptr;
}
ReadingKindTracker ReadingKind(Read_Decl, *this);
+ Deserializing D(this);
Expected<unsigned> MaybeCode = Cursor.ReadCode();
if (!MaybeCode) {
@@ -8568,6 +8570,17 @@
LateParsedTemplates.clear();
}
+void ASTReader::AssignedLambdaNumbering(const CXXRecordDecl *Lambda) {
+ if (Lambda->getLambdaContextDecl()) {
+ // Keep track of this lambda so it can be merged with another lambda that
+ // is loaded later.
+ LambdaDeclarationsForMerging.insert(
+ {{Lambda->getLambdaContextDecl()->getCanonicalDecl(),
+ Lambda->getLambdaIndexInContext()},
+ const_cast<CXXRecordDecl *>(Lambda)});
+ }
+}
+
void ASTReader::LoadSelector(Selector Sel) {
// It would be complicated to avoid reading the methods anyway. So don't.
ReadMethodPool(Sel);
@@ -9278,11 +9291,12 @@
}
void ASTReader::finishPendingActions() {
- while (!PendingIdentifierInfos.empty() || !PendingFunctionTypes.empty() ||
- !PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
- !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
- !PendingUpdateRecords.empty() ||
- !PendingObjCExtensionIvarRedeclarations.empty()) {
+ while (
+ !PendingIdentifierInfos.empty() || !PendingDeducedFunctionTypes.empty() ||
+ !PendingDeducedVarTypes.empty() || !PendingIncompleteDeclChains.empty() ||
+ !PendingDeclChains.empty() || !PendingMacroIDs.empty() ||
+ !PendingDeclContextInfos.empty() || !PendingUpdateRecords.empty() ||
+ !PendingObjCExtensionIvarRedeclarations.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
using TopLevelDeclsMap =
@@ -9300,9 +9314,9 @@
// Load each function type that we deferred loading because it was a
// deduced type that might refer to a local type declared within itself.
- for (unsigned I = 0; I != PendingFunctionTypes.size(); ++I) {
- auto *FD = PendingFunctionTypes[I].first;
- FD->setType(GetType(PendingFunctionTypes[I].second));
+ for (unsigned I = 0; I != PendingDeducedFunctionTypes.size(); ++I) {
+ auto *FD = PendingDeducedFunctionTypes[I].first;
+ FD->setType(GetType(PendingDeducedFunctionTypes[I].second));
// If we gave a function a deduced return type, remember that we need to
// propagate that along the redeclaration chain.
@@ -9311,7 +9325,15 @@
PendingDeducedTypeUpdates.insert(
{FD->getCanonicalDecl(), FD->getReturnType()});
}
- PendingFunctionTypes.clear();
+ PendingDeducedFunctionTypes.clear();
+
+ // Load each variable type that we deferred loading because it was a
+ // deduced type that might refer to a local type declared within itself.
+ for (unsigned I = 0; I != PendingDeducedVarTypes.size(); ++I) {
+ auto *VD = PendingDeducedVarTypes[I].first;
+ VD->setType(GetType(PendingDeducedVarTypes[I].second));
+ }
+ PendingDeducedVarTypes.clear();
// For each decl chain that we wanted to complete while deserializing, mark
// it as "still needs to be completed".
@@ -9487,7 +9509,6 @@
continue;
// FIXME: Check for =delete/=default?
- // FIXME: Complain about ODR violations here?
const FunctionDecl *Defn = nullptr;
if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) {
FD->setLazyBody(PB->second);
@@ -9518,6 +9539,12 @@
}
PendingBodies.clear();
+ // Inform any classes that had members added that they now have more members.
+ for (auto [RD, MD] : PendingAddedClassMembers) {
+ RD->addedMember(MD);
+ }
+ PendingAddedClassMembers.clear();
+
// Do some cleanup.
for (auto *ND : PendingMergedDefinitionsToDeduplicate)
getContext().deduplicateMergedDefinitonsFor(ND);
@@ -9694,9 +9721,6 @@
ObjCProtocolOdrMergeFailures.empty())
return;
- // Ensure we don't accidentally recursively enter deserialization while
- // we're producing our diagnostics.
- Deserializing RecursionGuard(this);
ODRDiagsEmitter DiagsEmitter(Diags, getContext(),
getPreprocessor().getLangOpts());
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -13316,13 +13316,6 @@
E->getCaptureDefault());
getDerived().transformedLocalDecl(OldClass, {Class});
- std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
- if (getDerived().ReplacingOriginal())
- Mangling = std::make_tuple(OldClass->hasKnownLambdaInternalLinkage(),
- OldClass->getLambdaManglingNumber(),
- OldClass->getDeviceLambdaManglingNumber(),
- OldClass->getLambdaContextDecl());
-
CXXMethodDecl *NewCallOperator =
getSema().CreateLambdaCallOperator(E->getIntroducerRange(), Class);
NewCallOperator->setLexicalDeclContext(getSema().CurContext);
@@ -13502,7 +13495,13 @@
{
// Number the lambda for linkage purposes if necessary.
Sema::ContextRAII ManglingContext(getSema(), Class->getDeclContext());
- getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling);
+
+ std::optional<CXXRecordDecl::LambdaNumbering> Numbering;
+ if (getDerived().ReplacingOriginal()) {
+ Numbering = OldClass->getLambdaNumbering();
+ }
+
+ getSema().handleLambdaNumbering(Class, NewCallOperator, Numbering);
}
// FIXME: Sema's lambda-building mechanism expects us to push an expression
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -389,22 +389,14 @@
void Sema::handleLambdaNumbering(
CXXRecordDecl *Class, CXXMethodDecl *Method,
- std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
-
- ContextRAII ManglingContext(*this, Class->getDeclContext());
-
- if (Mangling) {
- bool HasKnownInternalLinkage;
- unsigned ManglingNumber, DeviceManglingNumber;
- Decl *ManglingContextDecl;
- std::tie(HasKnownInternalLinkage, ManglingNumber, DeviceManglingNumber,
- ManglingContextDecl) = *Mangling;
- Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
- HasKnownInternalLinkage);
- Class->setDeviceLambdaManglingNumber(DeviceManglingNumber);
+ std::optional<CXXRecordDecl::LambdaNumbering> NumberingOverride) {
+ if (NumberingOverride) {
+ Class->setLambdaNumbering(*NumberingOverride);
return;
}
+ ContextRAII ManglingContext(*this, Class->getDeclContext());
+
auto getMangleNumberingContext =
[this](CXXRecordDecl *Class,
Decl *ManglingContextDecl) -> MangleNumberingContext * {
@@ -419,11 +411,10 @@
return &Context.getManglingNumberContext(DC);
};
+ CXXRecordDecl::LambdaNumbering Numbering;
MangleNumberingContext *MCtx;
- Decl *ManglingContextDecl;
- std::tie(MCtx, ManglingContextDecl) =
+ std::tie(MCtx, Numbering.ContextDecl) =
getCurrentMangleNumberContext(Class->getDeclContext());
- bool HasKnownInternalLinkage = false;
if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice ||
getLangOpts().SYCLIsHost)) {
// Force lambda numbering in CUDA/HIP as we need to name lambdas following
@@ -433,15 +424,19 @@
// Also force for SYCL, since we need this for the
// __builtin_sycl_unique_stable_name implementation, which depends on lambda
// mangling.
- MCtx = getMangleNumberingContext(Class, ManglingContextDecl);
+ MCtx = getMangleNumberingContext(Class, Numbering.ContextDecl);
assert(MCtx && "Retrieving mangle numbering context failed!");
- HasKnownInternalLinkage = true;
+ Numbering.HasKnownInternalLinkage = true;
}
if (MCtx) {
- unsigned ManglingNumber = MCtx->getManglingNumber(Method);
- Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
- HasKnownInternalLinkage);
- Class->setDeviceLambdaManglingNumber(MCtx->getDeviceManglingNumber(Method));
+ Numbering.IndexInContext = MCtx->getNextLambdaIndex();
+ Numbering.ManglingNumber = MCtx->getManglingNumber(Method);
+ Numbering.DeviceManglingNumber = MCtx->getDeviceManglingNumber(Method);
+ Class->setLambdaNumbering(Numbering);
+
+ if (auto *Source =
+ dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
+ Source->AssignedLambdaNumbering(Class);
}
}
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8232,12 +8232,12 @@
const VarDecl *DefVD = nullptr;
// If there is no initializer - this can not be a constant expression.
- if (!Var->getAnyInitializer(DefVD)) return true;
+ const Expr *Init = Var->getAnyInitializer(DefVD);
+ if (!Init)
+ return true;
assert(DefVD);
- if (DefVD->isWeak()) return false;
- EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
-
- Expr *Init = cast<Expr>(Eval->Value);
+ if (DefVD->isWeak())
+ return false;
if (Var->getType()->isDependentType() || Init->isValueDependent()) {
// FIXME: Teach the constant evaluator to deal with the non-dependent parts
Index: clang/lib/Sema/MultiplexExternalSemaSource.cpp
===================================================================
--- clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -341,3 +341,9 @@
}
return false;
}
+
+void MultiplexExternalSemaSource::AssignedLambdaNumbering(
+ const CXXRecordDecl *Lambda) {
+ for (auto *Source : Sources)
+ Source->AssignedLambdaNumbering(Lambda);
+}
Index: clang/lib/AST/ODRDiagsEmitter.cpp
===================================================================
--- clang/lib/AST/ODRDiagsEmitter.cpp
+++ clang/lib/AST/ODRDiagsEmitter.cpp
@@ -1742,6 +1742,7 @@
return true;
}
+ // Note, these calls can trigger deserialization.
const Expr *FirstInit = FirstParam->getInit();
const Expr *SecondInit = SecondParam->getInit();
if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -1646,10 +1646,15 @@
return getLambdaData().ContextDecl.get(Source);
}
-void CXXRecordDecl::setDeviceLambdaManglingNumber(unsigned Num) const {
+void CXXRecordDecl::setLambdaNumbering(LambdaNumbering Numbering) {
assert(isLambda() && "Not a lambda closure type!");
- if (Num)
- getASTContext().DeviceLambdaManglingNumbers[this] = Num;
+ getLambdaData().ManglingNumber = Numbering.ManglingNumber;
+ if (Numbering.DeviceManglingNumber)
+ getASTContext().DeviceLambdaManglingNumbers[this] =
+ Numbering.DeviceManglingNumber;
+ getLambdaData().IndexInContext = Numbering.IndexInContext;
+ getLambdaData().ContextDecl = Numbering.ContextDecl;
+ getLambdaData().HasKnownInternalLinkage = Numbering.HasKnownInternalLinkage;
}
unsigned CXXRecordDecl::getDeviceLambdaManglingNumber() const {
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -2356,12 +2356,15 @@
if (auto *S = Init.dyn_cast<Stmt *>())
return cast<Expr>(S);
- return cast_or_null<Expr>(Init.get<EvaluatedStmt *>()->Value);
+ auto *Eval = getEvaluatedStmt();
+ return cast<Expr>(Eval->Value.isOffset()
+ ? Eval->Value.get(getASTContext().getExternalSource())
+ : Eval->Value.get(nullptr));
}
Stmt **VarDecl::getInitAddress() {
if (auto *ES = Init.dyn_cast<EvaluatedStmt *>())
- return &ES->Value;
+ return ES->Value.getAddressOfPointer(getASTContext().getExternalSource());
return Init.getAddrOfPtr1();
}
@@ -2498,7 +2501,7 @@
bool IsConstantInitialization) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
- const auto *Init = cast<Expr>(Eval->Value);
+ const auto *Init = getInit();
assert(!Init->isValueDependent());
// We only produce notes indicating why an initializer is non-constant the
@@ -2582,7 +2585,7 @@
"already evaluated var value before checking for constant init");
assert(getASTContext().getLangOpts().CPlusPlus && "only meaningful in C++");
- assert(!cast<Expr>(Eval->Value)->isValueDependent());
+ assert(!getInit()->isValueDependent());
// Evaluate the initializer to check whether it's a constant expression.
Eval->HasConstantInitialization =
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2919,13 +2919,12 @@
DC, *TInfoOrErr, Loc, DCXX->getLambdaDependencyKind(),
DCXX->isGenericLambda(), DCXX->getLambdaCaptureDefault()))
return D2CXX;
- ExpectedDecl CDeclOrErr = import(DCXX->getLambdaContextDecl());
+ CXXRecordDecl::LambdaNumbering Numbering = DCXX->getLambdaNumbering();
+ ExpectedDecl CDeclOrErr = import(Numbering.ContextDecl);
if (!CDeclOrErr)
return CDeclOrErr.takeError();
- D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr,
- DCXX->hasKnownLambdaInternalLinkage());
- D2CXX->setDeviceLambdaManglingNumber(
- DCXX->getDeviceLambdaManglingNumber());
+ Numbering.ContextDecl = *CDeclOrErr;
+ D2CXX->setLambdaNumbering(Numbering);
} else if (DCXX->isInjectedClassName()) {
// We have to be careful to do a similar dance to the one in
// Sema::ActOnStartCXXMemberDeclarations
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -6622,6 +6622,10 @@
}
bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
+ // Caution: this function is called by the AST reader during deserialization,
+ // so it cannot rely on AST invariants being met. Non-trivial accessors
+ // should be avoided, along with any traversal of redeclaration chains.
+
if (X == Y)
return true;
@@ -6757,6 +6761,11 @@
if (const auto *VarX = dyn_cast<VarDecl>(X)) {
const auto *VarY = cast<VarDecl>(Y);
if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) {
+ // During deserialization, we might compare variables before we load
+ // their types. Assume the types will end up being the same.
+ if (VarX->getType().isNull() || VarY->getType().isNull())
+ return true;
+
if (hasSameType(VarX->getType(), VarY->getType()))
return true;
Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -560,6 +560,10 @@
llvm::DenseMap<Decl*, llvm::SmallVector<NamedDecl*, 2>>
AnonymousDeclarationsForMerging;
+ /// Map from numbering information for lambdas to the corresponding lambdas.
+ llvm::DenseMap<std::pair<const Decl *, unsigned>, NamedDecl *>
+ LambdaDeclarationsForMerging;
+
/// Key used to identify LifetimeExtendedTemporaryDecl for merging,
/// containing the lifetime-extending declaration and the mangling number.
using LETemporaryKey = std::pair<Decl *, unsigned>;
@@ -1101,7 +1105,13 @@
/// they might contain a deduced return type that refers to a local type
/// declared within the function.
SmallVector<std::pair<FunctionDecl *, serialization::TypeID>, 16>
- PendingFunctionTypes;
+ PendingDeducedFunctionTypes;
+
+ /// The list of deduced variable types that we have not yet read, because
+ /// they might contain a deduced type that refers to a local type declared
+ /// within the variable.
+ SmallVector<std::pair<VarDecl *, serialization::TypeID>, 16>
+ PendingDeducedVarTypes;
/// The list of redeclaration chains that still need to be
/// reconstructed, and the local offset to the corresponding list
@@ -1139,6 +1149,11 @@
2>
PendingObjCExtensionIvarRedeclarations;
+ /// Members that have been added to classes, for which the class has not yet
+ /// been notified. CXXRecordDecl::addedMember will be called for each of
+ /// these once recursive deserialization is complete.
+ SmallVector<std::pair<CXXRecordDecl*, Decl*>, 4> PendingAddedClassMembers;
+
/// The set of NamedDecls that have been loaded, but are members of a
/// context that has been merged into another context where the corresponding
/// declaration is either missing or has not yet been loaded.
@@ -2082,6 +2097,8 @@
llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>>
&LPTMap) override;
+ void AssignedLambdaNumbering(const CXXRecordDecl *Lambda) override;
+
/// Load a selector from disk, registering its ID if it exists.
void LoadSelector(Selector Sel);
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -7108,10 +7108,9 @@
Expr *TrailingRequiresClause);
/// Number lambda for linkage purposes if necessary.
- void handleLambdaNumbering(
- CXXRecordDecl *Class, CXXMethodDecl *Method,
- std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling =
- std::nullopt);
+ void handleLambdaNumbering(CXXRecordDecl *Class, CXXMethodDecl *Method,
+ std::optional<CXXRecordDecl::LambdaNumbering>
+ NumberingOverride = std::nullopt);
/// Endow the lambda scope info with the relevant properties.
void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator,
Index: clang/include/clang/Sema/MultiplexExternalSemaSource.h
===================================================================
--- clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -360,6 +360,9 @@
bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc,
QualType T) override;
+ // Inform all attached sources that a mangling number was assigned.
+ void AssignedLambdaNumbering(const CXXRecordDecl *Lambda) override;
+
/// LLVM-style RTTI.
/// \{
bool isA(const void *ClassID) const override {
Index: clang/include/clang/Sema/ExternalSemaSource.h
===================================================================
--- clang/include/clang/Sema/ExternalSemaSource.h
+++ clang/include/clang/Sema/ExternalSemaSource.h
@@ -230,6 +230,11 @@
return false;
}
+ /// Notify the external source that a lambda was assigned a mangling number.
+ /// This enables the external source to track the correspondence between
+ /// lambdas and mangling numbers if necessary.
+ virtual void AssignedLambdaNumbering(const CXXRecordDecl *Lambda) {}
+
/// LLVM-style RTTI.
/// \{
bool isA(const void *ClassID) const override {
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -2092,6 +2092,11 @@
: nullptr;
}
+ void setConditionVariableDeclStmt(DeclStmt *CondVar) {
+ assert(hasVarStorage());
+ getTrailingObjects<Stmt *>()[varOffset()] = CondVar;
+ }
+
Stmt *getInit() {
return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
: nullptr;
@@ -2324,6 +2329,11 @@
: nullptr;
}
+ void setConditionVariableDeclStmt(DeclStmt *CondVar) {
+ assert(hasVarStorage());
+ getTrailingObjects<Stmt *>()[varOffset()] = CondVar;
+ }
+
SwitchCase *getSwitchCaseList() { return FirstCase; }
const SwitchCase *getSwitchCaseList() const { return FirstCase; }
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
@@ -2487,6 +2497,11 @@
: nullptr;
}
+ void setConditionVariableDeclStmt(DeclStmt *CondVar) {
+ assert(hasVarStorage());
+ getTrailingObjects<Stmt *>()[varOffset()] = CondVar;
+ }
+
SourceLocation getWhileLoc() const { return WhileStmtBits.WhileLoc; }
void setWhileLoc(SourceLocation L) { WhileStmtBits.WhileLoc = L; }
@@ -2576,6 +2591,8 @@
/// the init/cond/inc parts of the ForStmt will be null if they were not
/// specified in the source.
class ForStmt : public Stmt {
+ friend class ASTStmtReader;
+
enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt.
SourceLocation LParenLoc, RParenLoc;
@@ -2603,10 +2620,18 @@
/// If this ForStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
+ DeclStmt *getConditionVariableDeclStmt() {
+ return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]);
+ }
+
const DeclStmt *getConditionVariableDeclStmt() const {
return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]);
}
+ void setConditionVariableDeclStmt(DeclStmt *CondVar) {
+ SubExprs[CONDVAR] = CondVar;
+ }
+
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); }
Stmt *getBody() { return SubExprs[BODY]; }
Index: clang/include/clang/AST/MangleNumberingContext.h
===================================================================
--- clang/include/clang/AST/MangleNumberingContext.h
+++ clang/include/clang/AST/MangleNumberingContext.h
@@ -27,6 +27,9 @@
/// Keeps track of the mangled names of lambda expressions and block
/// literals within a particular context.
class MangleNumberingContext {
+ // The index of the next lambda we encounter in this context.
+ unsigned LambdaIndex = 0;
+
public:
virtual ~MangleNumberingContext() {}
@@ -55,6 +58,11 @@
/// given call operator within the device context. No device number is
/// assigned if there's no device numbering context is associated.
virtual unsigned getDeviceManglingNumber(const CXXMethodDecl *) { return 0; }
+
+ // Retrieve the index of the next lambda appearing in this context, which is
+ // used for deduplicating lambdas across modules. Note that this is a simple
+ // sequence number and is not ABI-dependent.
+ unsigned getNextLambdaIndex() { return LambdaIndex++; }
};
} // end namespace clang
Index: clang/include/clang/AST/ExternalASTSource.h
===================================================================
--- clang/include/clang/AST/ExternalASTSource.h
+++ clang/include/clang/AST/ExternalASTSource.h
@@ -371,7 +371,7 @@
/// \param Source the external AST source.
///
/// \returns a pointer to the AST node.
- T* get(ExternalASTSource *Source) const {
+ T *get(ExternalASTSource *Source) const {
if (isOffset()) {
assert(Source &&
"Cannot deserialize a lazy pointer without an AST source");
@@ -379,6 +379,14 @@
}
return reinterpret_cast<T*>(Ptr);
}
+
+ /// Retrieve the address of the AST node pointer. Deserializes the pointee if
+ /// necessary.
+ T **getAddressOfPointer(ExternalASTSource *Source) const {
+ // Ensure the integer is in pointer form.
+ (void)get(Source);
+ return reinterpret_cast<T**>(&Ptr);
+ }
};
/// A lazy value (of type T) that is within an AST node of type Owner,
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -395,7 +395,7 @@
unsigned NumCaptures : 15;
/// The number of explicit captures in this lambda.
- unsigned NumExplicitCaptures : 13;
+ unsigned NumExplicitCaptures : 12;
/// Has known `internal` linkage.
unsigned HasKnownInternalLinkage : 1;
@@ -404,6 +404,10 @@
/// mangling in the Itanium C++ ABI.
unsigned ManglingNumber : 31;
+ /// The index of this lambda within its context declaration. This is not in
+ /// general the same as the mangling number.
+ unsigned IndexInContext;
+
/// The declaration that provides context for this lambda, if the
/// actual DeclContext does not suffice. This is used for lambdas that
/// occur within default arguments of function parameters within the class
@@ -424,7 +428,7 @@
: DefinitionData(D), DependencyKind(DK), IsGenericLambda(IsGeneric),
CaptureDefault(CaptureDefault), NumCaptures(0),
NumExplicitCaptures(0), HasKnownInternalLinkage(0), ManglingNumber(0),
- MethodTyInfo(Info) {
+ IndexInContext(0), MethodTyInfo(Info) {
IsLambda = true;
// C++1z [expr.prim.lambda]p4:
@@ -1772,18 +1776,31 @@
/// the declaration context suffices.
Decl *getLambdaContextDecl() const;
- /// Set the mangling number and context declaration for a lambda
- /// class.
- void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl,
- bool HasKnownInternalLinkage = false) {
+ /// Retrieve the index of this lambda within the context declaration returned
+ /// by getLambdaContextDecl().
+ unsigned getLambdaIndexInContext() const {
assert(isLambda() && "Not a lambda closure type!");
- getLambdaData().ManglingNumber = ManglingNumber;
- getLambdaData().ContextDecl = ContextDecl;
- getLambdaData().HasKnownInternalLinkage = HasKnownInternalLinkage;
+ return getLambdaData().IndexInContext;
}
- /// Set the device side mangling number.
- void setDeviceLambdaManglingNumber(unsigned Num) const;
+ /// Information about how a lambda is numbered within its context.
+ struct LambdaNumbering {
+ Decl *ContextDecl = nullptr;
+ unsigned IndexInContext = 0;
+ unsigned ManglingNumber = 0;
+ unsigned DeviceManglingNumber = 0;
+ bool HasKnownInternalLinkage = false;
+ };
+
+ /// Set the mangling numbers and context declaration for a lambda class.
+ void setLambdaNumbering(LambdaNumbering Numbering);
+
+ // Get the mangling numbers and context declaration for a lambda class.
+ LambdaNumbering getLambdaNumbering() const {
+ return {getLambdaContextDecl(), getLambdaIndexInContext(),
+ getLambdaManglingNumber(), getDeviceLambdaManglingNumber(),
+ hasKnownLambdaInternalLinkage()};
+ }
/// Retrieve the device side mangling number.
unsigned getDeviceLambdaManglingNumber() const;
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -900,7 +900,7 @@
bool HasICEInit : 1;
bool CheckedForICEInit : 1;
- Stmt *Value;
+ LazyDeclStmtPtr Value;
APValue Evaluated;
EvaluatedStmt()
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -257,6 +257,8 @@
- Fix handling of comments in function like macros so they are ignored in -CC
mode.
(`#60887 <https://github.com/llvm/llvm-project/issues/60887>`_)
+- Fix incorrect merging of lambdas across modules.
+ (`#60985 <https://github.com/llvm/llvm-project/issues/60985>`_)
Bug Fixes to Compiler Builtins
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits