pw_assert: Assert macro facade
Allows PW_ASSERT/PW_DASSERT macros to expand to macro-based handlers.
This greatly expands the quantity of information that can potentially be
captured at a callsite. The API established by this CL is transitional,
and will see breakages in the future as pw_assert's API is reassessed.
Bug: 246
Change-Id: Id4682e961bff32078e1528b11d126708d463c7f3
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/78188
Reviewed-by: Keir Mierle <keir@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Armando Montanez <amontanez@google.com>
diff --git a/pw_assert/BUILD.bazel b/pw_assert/BUILD.bazel
index a7e3658..e81bb11 100644
--- a/pw_assert/BUILD.bazel
+++ b/pw_assert/BUILD.bazel
@@ -26,13 +26,17 @@
pw_cc_facade(
name = "facade",
hdrs = [
+ "assert_lite_public_overrides/pw_assert_backend/assert_lite_backend.h",
"public/pw_assert/assert.h",
"public/pw_assert/check.h",
"public/pw_assert/config.h",
"public/pw_assert/internal/check_impl.h",
"public/pw_assert/short.h",
],
- includes = ["public"],
+ includes = [
+ "assert_lite_public_overrides",
+ "public",
+ ],
deps = [
"//pw_preprocessor",
],
diff --git a/pw_assert/BUILD.gn b/pw_assert/BUILD.gn
index d73d0ca..916bdc5 100644
--- a/pw_assert/BUILD.gn
+++ b/pw_assert/BUILD.gn
@@ -25,8 +25,14 @@
# public config (which may -include a file or add defines directly).
pw_assert_CONFIG = pw_build_DEFAULT_MODULE_CONFIG
- # Backend for the pw_assert module.
+ # Backend for the pw_assert module's CHECK facade.
pw_assert_BACKEND = ""
+
+ # Backend for the pw_assert module's ASSERT facade.
+ #
+ # Warning: This naming is transitional. Modifying this build argument WILL
+ # result in future breakages. (pwbug/246)
+ pw_assert_LITE_BACKEND = "${dir_pw_assert}:lite_compatibility_backend"
}
config("public_include_path") {
@@ -34,6 +40,11 @@
visibility = [ ":*" ]
}
+config("lite_backend_overrides") {
+ include_dirs = [ "assert_lite_public_overrides" ]
+ visibility = [ ":*" ]
+}
+
pw_source_set("config") {
public = [ "public/pw_assert/config.h" ]
public_configs = [ ":public_include_path" ]
@@ -80,20 +91,27 @@
}
# Provide "pw_assert/assert.h" in its own source set, so it can be used without
-# depending on pw_assert_BACKEND. This makes it possible to use PW_ASSERT in
-# situations that might result in circular dependencies, such as in low-level
-# headers like polyfill or span. See the docs for more discussion around where
-# to use which assert headers.
-#
-# The implementation function pw_assert_HandleFailure() must be provided at link
-# time. It is linked by the pw_assert:pw_assert (or pw_assert:check) targets.
-pw_source_set("assert") {
+# depending on pw_assert_BACKEND.
+pw_facade("assert") {
+ backend = pw_assert_LITE_BACKEND
public_configs = [ ":public_include_path" ]
public = [ "public/pw_assert/assert.h" ]
- public_deps = [
- ":config",
- dir_pw_preprocessor,
- ]
+ public_deps = [ ":config" ]
+}
+
+# This backend to pw_assert's PW_ASSERT()/PW_DASSERT() macros provides backwards
+# compatibility with pw_assert's previous C-symbol based API.
+#
+# Warning: The "lite" naming is transitional. assert_lite_backend.h headers
+# will be renamed as the pw_assert API is reassessed. (pwbug/246)
+pw_source_set("lite_compatibility_backend") {
+ public_configs = [ ":lite_backend_overrides" ]
+ public_deps = [ dir_pw_preprocessor ]
+ public =
+ [ "assert_lite_public_overrides/pw_assert_backend/assert_lite_backend.h" ]
+}
+
+group("lite_compatibility_backend.impl") {
}
# pw_assert is low-level and ubiquitous. Because of this, it can often cause
@@ -113,6 +131,10 @@
public_deps +=
[ get_label_info(pw_assert_BACKEND, "label_no_toolchain") + ".impl" ]
}
+ if (pw_assert_LITE_BACKEND != "") {
+ public_deps += [ get_label_info(pw_assert_LITE_BACKEND,
+ "label_no_toolchain") + ".impl" ]
+ }
}
# Note: While this is technically a test, doesn't verify any of the output and
diff --git a/pw_assert/CMakeLists.txt b/pw_assert/CMakeLists.txt
index c3d6e9a..93308d6 100644
--- a/pw_assert/CMakeLists.txt
+++ b/pw_assert/CMakeLists.txt
@@ -21,3 +21,4 @@
pw_preprocessor
${pw_assert_CONFIG}
)
+target_include_directories(pw_assert PUBLIC assert_lite_public_overrides)
diff --git a/pw_assert/assert_lite_public_overrides/pw_assert_backend/assert_lite_backend.h b/pw_assert/assert_lite_public_overrides/pw_assert_backend/assert_lite_backend.h
new file mode 100644
index 0000000..367c39d
--- /dev/null
+++ b/pw_assert/assert_lite_public_overrides/pw_assert_backend/assert_lite_backend.h
@@ -0,0 +1,25 @@
+// Copyright 2022 The Pigweed 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.
+#pragma once
+
+#include "pw_preprocessor/compiler.h"
+#include "pw_preprocessor/util.h"
+
+PW_EXTERN_C_START
+
+PW_NO_RETURN void pw_assert_HandleFailure(void);
+
+PW_EXTERN_C_END
+
+#define PW_ASSERT_HANDLE_FAILURE(condition_string) pw_assert_HandleFailure()
diff --git a/pw_assert/docs.rst b/pw_assert/docs.rst
index 525050c..03c4fda 100644
--- a/pw_assert/docs.rst
+++ b/pw_assert/docs.rst
@@ -595,6 +595,36 @@
common problem with ``pw_assert`` because it is so widely used. See
:ref:`module-pw_assert-circular-deps`.
+Macro-based PW_ASSERT()/PW_DASSERT() backend
+============================================
+The pw_assert API is being re-assessed to provide more helpful information in
+contexts where ``PW_CHECK_*()`` macros cannot be used. A first step towards this
+is providing a macro-based backend API for the ``PW_ASSERT()`` and
+``PW_DASSERT()`` macros.
+
+.. warning::
+ This part of ``pw_assert``'s API is transitional, and any project-specific
+ reliance on any of the API mentioned here will likely experience breakages.
+ In particular, ``PW_ASSERT_HANDLE_FAILURE`` and ``PW_HANDLE_ASSERT_FAILURE``
+ are extremely confusingly similar and are NOT interchangeable.
+
+A macro-based backend for the ``PW_ASSERT()`` macros must provide the following
+macro in a header at ``pw_assert_backend/assert_lite_backend.h``.
+
+.. cpp:function:: PW_ASSERT_HANDLE_FAILURE(expression)
+
+ Handle a low-level crash. This crash entry happens through
+ ``pw_assert/assert.h``. Backends must ensure their implementation is safe for
+ usage in headers, constexpr contexts, and templates. This macro should expand
+ to an expression that does not return.
+
+Similar to the ``PW_CHECK_*()`` facade, the header backend that provides an
+expansion for the ``PW_ASSERT_HANDLE_FAILURE()`` macro can be controlled in the
+GN build using the ``pw_assert_LITE_BACKEND`` build argument. In addition to
+the header-based target at ``${pw_assert_LITE_BACKEND}``, a source set at
+``${pw_assert_LITE_BACKEND}.impl`` is also required as a way to reduce the
+impact of :ref:`circular dependencies <module-pw_assert-circular-deps>`.
+
--------------------------
Frequently Asked Questions
--------------------------
diff --git a/pw_assert/public/pw_assert/assert.h b/pw_assert/public/pw_assert/assert.h
index 53b0f15..ec4995f 100644
--- a/pw_assert/public/pw_assert/assert.h
+++ b/pw_assert/public/pw_assert/assert.h
@@ -14,14 +14,7 @@
#pragma once
#include "pw_assert/config.h" // For PW_ASSERT_ENABLE_DEBUG
-#include "pw_preprocessor/compiler.h"
-#include "pw_preprocessor/util.h"
-
-PW_EXTERN_C_START
-
-PW_NO_RETURN void pw_assert_HandleFailure(void);
-
-PW_EXTERN_C_END
+#include "pw_assert_backend/assert_lite_backend.h"
// A header- and constexpr-safe version of PW_CHECK().
//
@@ -34,11 +27,11 @@
// stringified expression. Use these macros only when absolutely necessary --
// in headers, constexr contexts, or in rare cases where the call site overhead
// of a full PW_CHECK must be avoided. Use PW_CHECK_*() whenever possible.
-#define PW_ASSERT(condition) \
- do { \
- if (!(condition)) { \
- pw_assert_HandleFailure(); \
- } \
+#define PW_ASSERT(condition) \
+ do { \
+ if (!(condition)) { \
+ PW_ASSERT_HANDLE_FAILURE(#condition); \
+ } \
} while (0)
// A header- and constexpr-safe version of PW_DCHECK().
@@ -54,6 +47,6 @@
#define PW_DASSERT(condition) \
do { \
if ((PW_ASSERT_ENABLE_DEBUG == 1) && !(condition)) { \
- pw_assert_HandleFailure(); \
+ PW_ASSERT_HANDLE_FAILURE(#condition); \
} \
} while (0)