Skip to content

Commit 0975c09

Browse files
authored
[clang][p2719] Module deserialization does not restore allocator flags (#137102)
When serializing and deserializing a FunctionDecl we don't recover whether or not the decl was a type aware allocator or destroying delete, because in the final PR that information was placed in a side table in ASTContext. In principle it should be possible to re-do the semantic checks to determine what these flags should be when deserializing, but it seems like the most robust path is simply recording the flags directly in the serialized AST.
1 parent de1af6b commit 0975c09

File tree

7 files changed

+159
-0
lines changed

7 files changed

+159
-0
lines changed

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
10761076
FD->setFriendConstraintRefersToEnclosingTemplate(
10771077
FunctionDeclBits.getNextBit());
10781078
FD->setUsesSEHTry(FunctionDeclBits.getNextBit());
1079+
FD->setIsDestroyingOperatorDelete(FunctionDeclBits.getNextBit());
1080+
FD->setIsTypeAwareOperatorNewOrDelete(FunctionDeclBits.getNextBit());
10791081

10801082
FD->EndRangeLoc = readSourceLocation();
10811083
if (FD->isExplicitlyDefaulted())

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
847847
FunctionDeclBits.addBit(D->isInstantiatedFromMemberTemplate());
848848
FunctionDeclBits.addBit(D->FriendConstraintRefersToEnclosingTemplate());
849849
FunctionDeclBits.addBit(D->usesSEHTry());
850+
FunctionDeclBits.addBit(D->isDestroyingOperatorDelete());
851+
FunctionDeclBits.addBit(D->isTypeAwareOperatorNewOrDelete());
850852
Record.push_back(FunctionDeclBits);
851853

852854
Record.AddSourceLocation(D->getEndLoc());
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module type_aware_destroying_new_delete { header "type_aware_destroying_new_delete.h" export * }
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
namespace std {
3+
struct destroying_delete_t { };
4+
template <class T> struct type_identity {
5+
using type = T;
6+
};
7+
typedef __SIZE_TYPE__ size_t;
8+
enum class align_val_t : size_t;
9+
};
10+
11+
struct A {
12+
A();
13+
void *operator new(std::size_t);
14+
void operator delete(A*, std::destroying_delete_t);
15+
};
16+
17+
struct B {
18+
B();
19+
void *operator new(std::type_identity<B>, std::size_t, std::align_val_t);
20+
void operator delete(std::type_identity<B>, void*, std::size_t, std::align_val_t);
21+
};
22+
23+
struct C {
24+
C();
25+
template <class T> void *operator new(std::type_identity<T>, std::size_t, std::align_val_t);
26+
template <class T> void operator delete(std::type_identity<T>, void*, std::size_t, std::align_val_t);
27+
};
28+
29+
struct D {
30+
D();
31+
};
32+
void *operator new(std::type_identity<D>, std::size_t, std::align_val_t);
33+
void operator delete(std::type_identity<D>, void*, std::size_t, std::align_val_t);
34+
35+
struct E {
36+
E();
37+
};
38+
template <class T> void *operator new(std::type_identity<T>, std::size_t, std::align_val_t);
39+
template <class T> void operator delete(std::type_identity<T>, void*, std::size_t, std::align_val_t);
40+
41+
void in_module_tests() {
42+
A* a = new A;
43+
delete a;
44+
B *b = new B;
45+
delete b;
46+
C *c = new C;
47+
delete c;
48+
D *d = new D;
49+
delete d;
50+
E *e = new E;
51+
delete e;
52+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: rm -rf %t
2+
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x c++ -std=c++26 -fmodules-cache-path=%t -I %S/Inputs/PR137102 -emit-llvm-only %s
3+
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x c++ -std=c++26 -fmodules-cache-path=%t -I %S/Inputs/PR137102 -emit-llvm-only %s -triple i686-windows
4+
5+
#include "type_aware_destroying_new_delete.h"
6+
7+
8+
static void call_in_module_function(void) {
9+
in_module_tests();
10+
}
11+
12+
void out_of_module_tests() {
13+
A* a = new A;
14+
delete a;
15+
B *b = new B;
16+
delete b;
17+
C *c = new C;
18+
delete c;
19+
D *d = new D;
20+
delete d;
21+
E *e = new E;
22+
delete e;
23+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
namespace std {
3+
struct destroying_delete_t { };
4+
template <class T> struct type_identity {
5+
using type = T;
6+
};
7+
typedef __SIZE_TYPE__ size_t;
8+
enum class align_val_t : size_t;
9+
};
10+
11+
struct A {
12+
A();
13+
void *operator new(std::size_t);
14+
void operator delete(A*, std::destroying_delete_t);
15+
};
16+
17+
struct B {
18+
B();
19+
void *operator new(std::type_identity<B>, std::size_t, std::align_val_t);
20+
void operator delete(std::type_identity<B>, void*, std::size_t, std::align_val_t);
21+
};
22+
23+
struct C {
24+
C();
25+
template <class T> void *operator new(std::type_identity<T>, std::size_t, std::align_val_t);
26+
template <class T> void operator delete(std::type_identity<T>, void*, std::size_t, std::align_val_t);
27+
};
28+
29+
struct D {
30+
D();
31+
};
32+
void *operator new(std::type_identity<D>, std::size_t, std::align_val_t);
33+
void operator delete(std::type_identity<D>, void*, std::size_t, std::align_val_t);
34+
35+
struct E {
36+
E();
37+
};
38+
template <class T> void *operator new(std::type_identity<T>, std::size_t, std::align_val_t);
39+
template <class T> void operator delete(std::type_identity<T>, void*, std::size_t, std::align_val_t);
40+
41+
void in_pch_tests() {
42+
A* a = new A;
43+
delete a;
44+
B *b = new B;
45+
delete b;
46+
C *c = new C;
47+
delete c;
48+
D *d = new D;
49+
delete d;
50+
E *e = new E;
51+
delete e;
52+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Test this without pch.
2+
// RUN: %clang_cc1 -x c++ -std=c++26 -include %S/Inputs/type_aware_destroying_new_delete.h -emit-llvm -o - %s
3+
4+
// Test with pch.
5+
// RUN: %clang_cc1 -x c++ -std=c++26 -emit-pch -o %t %S/Inputs/type_aware_destroying_new_delete.h
6+
// RUN: %clang_cc1 -x c++ -std=c++26 -include-pch %t -emit-llvm -o - %s
7+
8+
// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -fpch-instantiate-templates -o %t %S/Inputs/type_aware_destroying_new_delete.h
9+
// RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t -emit-llvm -o - %s
10+
11+
12+
static void call_in_pch_function(void) {
13+
in_pch_tests();
14+
}
15+
16+
void out_of_pch_tests() {
17+
A* a = new A;
18+
delete a;
19+
B *b = new B;
20+
delete b;
21+
C *c = new C;
22+
delete c;
23+
D *d = new D;
24+
delete d;
25+
E *e = new E;
26+
delete e;
27+
}

0 commit comments

Comments
 (0)