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)