From 352d1f8fb2c3d2013033133b42714a6be9683e20 Mon Sep 17 00:00:00 2001 From: Christian Blichmann Date: Mon, 14 Aug 2023 06:13:51 -0700 Subject: [PATCH] Clang tool: Emit aggregates with default initialized members PiperOrigin-RevId: 556765694 Change-Id: I2547919cdc1fcb048c99de325a8b2c24800b0e06 --- .../tools/clang_generator/emitter.cc | 18 +++++-- .../tools/clang_generator/emitter_test.cc | 47 +++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/sandboxed_api/tools/clang_generator/emitter.cc b/sandboxed_api/tools/clang_generator/emitter.cc index 99b962e..0066f95 100644 --- a/sandboxed_api/tools/clang_generator/emitter.cc +++ b/sandboxed_api/tools/clang_generator/emitter.cc @@ -247,12 +247,20 @@ std::string GetSpelling(const clang::Decl* decl) { } if (const auto* record_decl = llvm::dyn_cast(decl)) { - if (!record_decl->isCLike()) { - // For C++ classes/structs, only emit a forward declaration. - return absl::StrCat(PrintRecordTemplateArguments(record_decl), - record_decl->isClass() ? "class " : "struct ", - ToStringView(record_decl->getName())); + if (record_decl->hasDefinition() && + // Aggregates capture all C-like structs, but also structs with + // non-static members that have default initializers. + record_decl->isAggregate() && + // Make sure to skip types with user-defined methods (including + // constructors). + record_decl->methods().empty()) { + return PrintDecl(decl); } + // For unsupported types or types with no definition, only emit a forward + // declaration. + return absl::StrCat(PrintRecordTemplateArguments(record_decl), + record_decl->isClass() ? "class " : "struct ", + ToStringView(record_decl->getName())); } return PrintDecl(decl); } diff --git a/sandboxed_api/tools/clang_generator/emitter_test.cc b/sandboxed_api/tools/clang_generator/emitter_test.cc index 332e947..cdfb8ba 100644 --- a/sandboxed_api/tools/clang_generator/emitter_test.cc +++ b/sandboxed_api/tools/clang_generator/emitter_test.cc @@ -201,6 +201,53 @@ TEST_F(EmitterTest, ParentNotCollected) { " int data; }")); } +TEST_F(EmitterTest, StructForwardDecl) { + EmitterForTesting emitter; + ASSERT_THAT( + RunFrontendAction( + R"(struct A; + extern "C" void UsingForwardDeclaredStruct(A* s);)", + std::make_unique(emitter, GeneratorOptions())), + IsOk()); + + EXPECT_THAT(UglifyAll(emitter.SpellingsForNS("")), ElementsAre("struct A")); +} + +TEST_F(EmitterTest, AggregateStructWithDefaultedMembers) { + EmitterForTesting emitter; + ASSERT_THAT( + RunFrontendAction( + R"(struct A { + int a = 0; + int b = 42; + }; + extern "C" void AggregateStruct(A* s);)", + std::make_unique(emitter, GeneratorOptions())), + IsOk()); + + EXPECT_THAT(UglifyAll(emitter.SpellingsForNS("")), + ElementsAre("struct A {" + " int a = 0;" + " int b = 42; }")); +} + +TEST_F(EmitterTest, AggregateStructWithMethods) { + EmitterForTesting emitter; + ASSERT_THAT( + RunFrontendAction( + R"(struct A { + int a = 0; + int b = 42; + int my_mem_fn(); + }; + extern "C" void AggregateStruct(A* s);)", + std::make_unique(emitter, GeneratorOptions())), + IsOk()); + + // Expect a forward decl in this case + EXPECT_THAT(UglifyAll(emitter.SpellingsForNS("")), ElementsAre("struct A")); +} + TEST_F(EmitterTest, RemoveQualifiers) { EmitterForTesting emitter; ASSERT_THAT(