Skip to content

Commit

Permalink
Add ABSL_REQUIRE_EXPLICIT_INIT to Abseil to enable enforcing explicit…
Browse files Browse the repository at this point in the history
… field initializations

Also include portable fallbacks for other compilers. They don't produce good error messages, but they do prevent silent breakages on other platforms/toolchains.

PiperOrigin-RevId: 723629074
Change-Id: I29ee8fbc679b70bb67d42577d0723b52268f7caf
  • Loading branch information
Abseil Team authored and copybara-github committed Feb 5, 2025
1 parent 7a03cdb commit 74058c0
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
15 changes: 15 additions & 0 deletions absl/base/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,21 @@ cc_test(
],
)

cc_test(
name = "attributes_test",
srcs = [
"attributes_test.cc",
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":core_headers",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)

cc_test(
name = "c_header_test",
srcs = ["c_header_test.c"],
Expand Down
13 changes: 13 additions & 0 deletions absl/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,19 @@ absl_cc_test(
GTest::gtest_main
)

absl_cc_test(
NAME
attributes_test
SRCS
"attributes_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::config
absl::core_headers
GTest::gtest_main
)

absl_cc_test(
NAME
bit_cast_test
Expand Down
65 changes: 65 additions & 0 deletions absl/base/attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,71 @@
#define ABSL_CONST_INIT
#endif

// ABSL_REQUIRE_EXPLICIT_INIT
//
// ABSL_REQUIRE_EXPLICIT_INIT is placed *after* the data members of an aggregate
// type to indicate that the annotated member must be explicitly initialized by
// the user whenever the aggregate is constructed. For example:
//
// struct Coord {
// int x ABSL_REQUIRE_EXPLICIT_INIT;
// int y ABSL_REQUIRE_EXPLICIT_INIT;
// };
// Coord coord = {1}; // warning: field 'y' is not explicitly initialized
//
// Note that usage on C arrays is not supported in C++.
// Use a struct (such as std::array) to wrap the array member instead.
//
// Avoid applying this attribute to the members of non-aggregate types.
// The behavior within non-aggregates is unspecified and subject to change.
//
// Do NOT attempt to suppress or demote the error generated by this attribute.
// Just like with a missing function argument, it is a hard error by design.
//
// See the upstream documentation for more details:
// https://clang.llvm.org/docs/AttributeReference.html#require-explicit-initialization
#ifdef __cplusplus
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_explicit_initialization)
// clang-format off
#define ABSL_REQUIRE_EXPLICIT_INIT \
[[clang::require_explicit_initialization]] = \
AbslInternal_YouForgotToExplicitlyInitializeAField::v
#else
#define ABSL_REQUIRE_EXPLICIT_INIT \
= AbslInternal_YouForgotToExplicitlyInitializeAField::v
#endif
// clang-format on
#else
// clang-format off
#if ABSL_HAVE_ATTRIBUTE(require_explicit_initialization)
#define ABSL_REQUIRE_EXPLICIT_INIT \
__attribute__((require_explicit_initialization))
#else
#define ABSL_REQUIRE_EXPLICIT_INIT \
/* No portable fallback for C is available */
#endif
// clang-format on
#endif

#ifdef __cplusplus
struct AbslInternal_YouForgotToExplicitlyInitializeAField {
// A portable version of [[clang::require_explicit_initialization]] that
// never builds, as a last resort for all toolchains.
// The error messages are poor, so we don't rely on this unless we have to.
template <class T>
#if !defined(SWIG)
constexpr
#endif
operator T() const /* NOLINT */ {
// Infinite loop to prevent constexpr compilation
for (;;) {
}
}
// This is deliberately left undefined to prevent linking
static AbslInternal_YouForgotToExplicitlyInitializeAField v;
};
#endif

// ABSL_ATTRIBUTE_PURE_FUNCTION
//
// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
Expand Down
43 changes: 43 additions & 0 deletions absl/base/attributes_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2025 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "absl/base/attributes.h"

#include "gtest/gtest.h"
#include "absl/base/config.h"

namespace {

TEST(Attributes, RequireExplicitInit) {
struct Agg {
int f1;
int f2 ABSL_REQUIRE_EXPLICIT_INIT;
};
Agg good1 ABSL_ATTRIBUTE_UNUSED = {1, 2};
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
Agg good2 ABSL_ATTRIBUTE_UNUSED(1, 2);
#endif
Agg good3 ABSL_ATTRIBUTE_UNUSED{1, 2};
Agg good4 ABSL_ATTRIBUTE_UNUSED = {1, 2};
Agg good5 ABSL_ATTRIBUTE_UNUSED = Agg{1, 2};
Agg good6[1] ABSL_ATTRIBUTE_UNUSED = {{1, 2}};
Agg good7[1] ABSL_ATTRIBUTE_UNUSED = {Agg{1, 2}};
union {
Agg agg;
} good8 ABSL_ATTRIBUTE_UNUSED = {{1, 2}};
constexpr Agg good9 ABSL_ATTRIBUTE_UNUSED = {1, 2};
constexpr Agg good10 ABSL_ATTRIBUTE_UNUSED{1, 2};
}

} // namespace

0 comments on commit 74058c0

Please sign in to comment.