Add ABSL_REQUIRE_EXPLICIT_INIT to Abseil to enable enforcing explicit 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
This commit is contained in:
Abseil Team
2025-02-05 13:25:23 -08:00
committed by Copybara-Service
parent 7a03cdb4c0
commit 74058c0f49
4 changed files with 136 additions and 0 deletions

View File

@@ -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"],

View File

@@ -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

View File

@@ -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"

View File

@@ -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