Add absl::SourceLocation

PiperOrigin-RevId: 881550268
Change-Id: I1add4438cecc44f41f01c0570c69bb85f706ecfc
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index cbeb96c..842c6b3 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -454,6 +454,7 @@
   "types/internal/span.h"
   "types/optional.h"
   "types/optional_ref.h"
+  "types/source_location.h"
   "types/span.h"
   "types/variant.h"
   "utility/utility.h"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a31c6a9..3583e3d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -227,7 +227,7 @@
 
   # Handle features that require at least C++20.
   if (ABSL_INTERNAL_AT_LEAST_CXX20)
-    foreach(FEATURE "ORDERING")
+    foreach(FEATURE "ORDERING" "SOURCE_LOCATION")
       string(REPLACE
       "#define ABSL_OPTION_USE_STD_${FEATURE} 2"
       "#define ABSL_OPTION_USE_STD_${FEATURE} 1"
diff --git a/absl/base/config.h b/absl/base/config.h
index 82e8009..b707654 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -531,6 +531,42 @@
 #define ABSL_HAVE_STD_VARIANT 1
 #define ABSL_USES_STD_VARIANT 1
 
+// ABSL_HAVE_STD_SOURCE_LOCATION
+//
+// Checks whether C++20 std::source_location is available.
+#ifdef ABSL_HAVE_STD_SOURCE_LOCATION
+#error "ABSL_HAVE_STD_SOURCE_LOCATION cannot be directly set."
+#elif (defined(__cpp_lib_source_location) &&    \
+       __cpp_lib_source_location >= 201907L) || \
+    (defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&   \
+     ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L)
+#ifdef __has_include
+#if __has_include(<source_location>)
+#define ABSL_HAVE_STD_SOURCE_LOCATION 1
+#endif
+#else
+// No __has_include support, so just assume C++ language version is correct.
+#define ABSL_HAVE_STD_SOURCE_LOCATION 1
+#endif
+#endif
+
+// ABSL_USES_STD_SOURCE_LOCATION
+//
+// Indicates whether absl::SourceLocation is an alias for std::source_location.
+#if !defined(ABSL_OPTION_USE_STD_SOURCE_LOCATION)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_SOURCE_LOCATION == 0 || \
+    (ABSL_OPTION_USE_STD_SOURCE_LOCATION == 2 &&  \
+     !defined(ABSL_HAVE_STD_SOURCE_LOCATION))
+#undef ABSL_USES_STD_SOURCE_LOCATION
+#elif ABSL_OPTION_USE_STD_SOURCE_LOCATION == 1 || \
+    (ABSL_OPTION_USE_STD_SOURCE_LOCATION == 2 &&  \
+     defined(ABSL_HAVE_STD_SOURCE_LOCATION))
+#define ABSL_USES_STD_SOURCE_LOCATION 1
+#else
+#error options.h is misconfigured.
+#endif
+
 // ABSL_HAVE_STD_ORDERING
 //
 // Checks whether C++20 std::{partial,weak,strong}_ordering are available.
@@ -799,6 +835,14 @@
 #define ABSL_INTERNAL_HAVE_ARM_NEON 1
 #endif
 
+#if ABSL_HAVE_BUILTIN(__builtin_LINE) && ABSL_HAVE_BUILTIN(__builtin_FILE)
+#define ABSL_INTERNAL_HAVE_BUILTIN_LINE_FILE 1
+#elif defined(__GNUC__) && !defined(__clang__) && 5 <= __GNUC__ && __GNUC__ < 10
+#define ABSL_INTERNAL_HAVE_BUILTIN_LINE_FILE 1
+#elif defined(_MSC_VER) && _MSC_VER >= 1926
+#define ABSL_INTERNAL_HAVE_BUILTIN_LINE_FILE 1
+#endif
+
 // ABSL_HAVE_CONSTANT_EVALUATED is used for compile-time detection of
 // constant evaluation support through `absl::is_constant_evaluated`.
 #ifdef ABSL_HAVE_CONSTANT_EVALUATED
diff --git a/absl/base/options.h b/absl/base/options.h
index 6f48e75..cfacc6e 100644
--- a/absl/base/options.h
+++ b/absl/base/options.h
@@ -73,6 +73,34 @@
 // Type Compatibility Options
 // -----------------------------------------------------------------------------
 
+// ABSL_OPTION_USE_STD_SOURCE_LOCATION
+//
+// This option controls whether absl::SourceLocation is implemented as an alias
+// to the std::source_location type, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation.  This requires only C++17
+// support, and is expected to run on every toolchain we support, and to
+// properly capture source location information on every toolchain that supports
+// the necessary built-ins (such as `__builtin_LINE`).
+//
+// A value of 1 means to use aliases.  This requires that all code using Abseil
+// is built in C++20 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if working std::source_location types are available.
+// This option is useful when you are building your program from source.  It
+// should not be used otherwise -- for example, if you are distributing Abseil
+// in a binary package manager -- since in mode 2, they will name different
+// types, with different mangled names and binary layout, depending on the
+// compiler flags passed by the end user.  For more info, see
+// https://abseil.io/about/design/dropin-types.
+//
+// User code should not inspect this macro.  To check in the preprocessor if
+// the source location type is an alias of std::source_location type, use the
+// feature macro ABSL_USES_STD_SOURCE_LOCATION.
+//
+#define ABSL_OPTION_USE_STD_SOURCE_LOCATION 2
+
 // ABSL_OPTION_USE_STD_ORDERING
 //
 // This option controls whether absl::{partial,weak,strong}_ordering are
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index a52c358..19709a5 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -51,6 +51,32 @@
 )
 
 cc_library(
+    name = "source_location",
+    hdrs = ["source_location.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+        "//absl/base:nullability",
+    ],
+)
+
+cc_test(
+    name = "source_location_test",
+    size = "small",
+    srcs = ["source_location_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":source_location",
+        "//absl/base:config",
+        "//absl/strings:string_view",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "span",
     srcs = [
         "internal/span.h",
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index 75dd07d..f69a1ea 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -129,6 +129,32 @@
 
 absl_cc_library(
   NAME
+    source_location
+  HDRS
+    "source_location.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::nullability
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    source_location_test
+  SRCS
+    "source_location_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::config
+    absl::source_location
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
     compare
   HDRS
     "compare.h"
diff --git a/absl/types/source_location.h b/absl/types/source_location.h
new file mode 100644
index 0000000..6e14836
--- /dev/null
+++ b/absl/types/source_location.h
@@ -0,0 +1,172 @@
+// Copyright 2017 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.
+//
+// -----------------------------------------------------------------------------
+// File: source_location.h
+// -----------------------------------------------------------------------------
+//
+// absl::SourceLocation provides source-code location info for C++17 and later.
+//
+// Critically, it is a **view type** (like std::string_view). Unlike
+// std::source_location, it is not permanently valid and must not outlive its
+// source. Using an invalid location is an error and may result in warnings
+// or crashes.
+//
+// Additionally, it does not guarantee the retention of all caller information
+// (e.g. column or function name) and may e.g. return unspecified values for
+// performance reasons.
+//
+// To define a function that has access to the source location of the
+// callsite, define it with a parameter of type `absl::SourceLocation`. The
+// caller can then invoke the function, passing
+// `absl::SourceLocation::current()` as the argument.
+//
+// If at all possible, make the `absl::SourceLocation` parameter be the
+// function's last parameter. That way, when `std::source_location` is
+// available, you will be able to switch to it, and give the parameter a default
+// argument of `std::source_location::current()`. Users will then be able to
+// omit that argument, and the default will automatically capture the location
+// of the callsite.
+
+#ifndef ABSL_TYPES_SOURCE_LOCATION_H_
+#define ABSL_TYPES_SOURCE_LOCATION_H_
+
+#include <cstdint>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/base/nullability.h"
+
+// This needs to come after absl/base/config.h, which is responsible for
+// defining ABSL_HAVE_STD_SOURCE_LOCATION
+#ifdef ABSL_HAVE_STD_SOURCE_LOCATION
+#include <source_location>  // NOLINT(build/c++20)
+#endif
+
+// For OSS release, whether to alias to std::source_location is configurable via
+// config.h/options.h, similar to std::string_view/variant/etc.
+#if defined(ABSL_USES_STD_SOURCE_LOCATION) && \
+    defined(ABSL_HAVE_STD_SOURCE_LOCATION)
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using SourceLocation = std::source_location;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_SOURCE_LOCATION
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// C++17-compatible class representing a specific location in the source code of
+// a program. Similar to std::source_location, but with a few key differences
+// explained above.
+class SourceLocation {
+  struct PrivateTag {
+   private:
+    explicit PrivateTag() = default;
+    friend class SourceLocation;
+  };
+
+ public:
+  // Avoid this constructor; it populates the object with dummy values.
+  SourceLocation() = default;
+
+#ifdef ABSL_HAVE_STD_SOURCE_LOCATION
+  constexpr SourceLocation(  // NOLINT(google-explicit-constructor)
+      std::source_location loc)
+      : SourceLocation(loc.line(), loc.file_name()) {}
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_BUILTIN_LINE_FILE
+  // SourceLocation::current
+  //
+  // Creates a `SourceLocation` based on the current source location. Currently,
+  // it only captures file and line information for efficiency purposes, but
+  // that is subject to change. APIs that accept a `SourceLocation` as a default
+  // parameter can use this to capture their caller's locations.
+  //
+  // Example:
+  //
+  //   void TracedAdd(int i, SourceLocation loc = SourceLocation::current()) {
+  //     std::cout << loc.file_name() << ":" << loc.line() << " added " << i;
+  //     ...
+  //   }
+  //
+  //   void UserCode() {
+  //     TracedAdd(1);
+  //     TracedAdd(2);
+  //   }
+  static constexpr SourceLocation current(
+      PrivateTag = PrivateTag{}, std::uint_least32_t line = __builtin_LINE(),
+      const char* absl_nonnull file_name = __builtin_FILE()) {
+    return SourceLocation(line, file_name);
+  }
+#else
+  // Creates a dummy `SourceLocation` of "<source_location>" at line number 1,
+  // if no `SourceLocation::current()` implementation is available.
+  static constexpr SourceLocation current() {
+    return SourceLocation(1, "<source_location>");
+  }
+#endif
+  // The line number of the captured source location, or an unspecified value
+  // if this information is not available.
+  constexpr std::uint_least32_t line() const noexcept { return line_; }
+
+  // The column number of the captured source location, or an unspecified value
+  // if this information is not available.
+  constexpr std::uint_least32_t column() const noexcept { return 0; }
+
+  // The file name of the captured source location, or an unspecified string
+  // if this information is not available. Guaranteed to never be NULL.
+  constexpr const char* absl_nonnull file_name() const noexcept {
+    return file_name_;
+  }
+
+  // The function name of the captured source location, or an unspecified string
+  // if this information is not available. Guaranteed to never be NULL.
+  //
+  // NOTE: Currently, we deliberately avoid providing the function name, as it
+  // can bloat binary sizes and is non-critical. This may change in the future.
+  constexpr const char* absl_nonnull function_name() const noexcept {
+    return "";
+  }
+
+ private:
+  // `file_name` must outlive all copies of the `absl::SourceLocation` object,
+  // so in practice it should be a string literal.
+  constexpr SourceLocation(std::uint_least32_t line,
+                           const char* absl_nonnull file_name)
+      : line_(line), file_name_(file_name) {}
+
+  // We would use [[maybe_unused]] here, but it doesn't work on all supported
+  // toolchains at the moment.
+  friend constexpr int UseUnused() {
+    static_assert(SourceLocation(0, nullptr).unused_column_ == 0,
+                  "Use the otherwise-unused member.");
+    return 0;
+  }
+
+  // "unused" members are present to minimize future changes in the size of this
+  // type.
+  std::uint_least32_t line_ = 0;
+  std::uint_least32_t unused_column_ = 0;
+  const char* absl_nonnull file_name_ = "";
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // ABSL_HAVE_STD_SOURCE_LOCATION
+
+#endif  // ABSL_TYPES_SOURCE_LOCATION_H_
diff --git a/absl/types/source_location_test.cc b/absl/types/source_location_test.cc
new file mode 100644
index 0000000..a312aa9
--- /dev/null
+++ b/absl/types/source_location_test.cc
@@ -0,0 +1,139 @@
+// Copyright 2017 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/types/source_location.h"
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_HAVE_STD_SOURCE_LOCATION
+#include <source_location>  // NOLINT(build/c++20)
+#endif
+#include <type_traits>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/string_view.h"
+
+namespace {
+
+using ::absl::SourceLocation;
+using ::testing::EndsWith;
+
+TEST(SourceLocationTest, DefaultConstructionWorks) {
+  static_assert(!std::is_trivially_default_constructible_v<SourceLocation>);
+  static_assert(std::is_nothrow_default_constructible_v<SourceLocation>);
+  constexpr SourceLocation loc1 [[maybe_unused]];
+  SourceLocation loc2 [[maybe_unused]]{};
+  EXPECT_EQ(loc1.line(), loc2.line());
+}
+
+#ifdef ABSL_INTERNAL_HAVE_BUILTIN_LINE_FILE
+
+TEST(SourceLocationTest, ConstexprMembers) {
+  constexpr SourceLocation loc1 = absl::SourceLocation::current();
+  const SourceLocation loc2 = absl::SourceLocation::current();
+  EXPECT_EQ(loc1.line(), loc2.line() - 1);
+  EXPECT_EQ(absl::string_view(loc1.file_name()), loc2.file_name());
+}
+
+TEST(SourceLocationTest, ConversionFromStdSourceLocationWorks) {
+#ifndef ABSL_HAVE_STD_SOURCE_LOCATION
+  GTEST_SKIP() << "std::source_location is not available";
+#else
+  constexpr SourceLocation loc1 = std::source_location::current();
+  const std::source_location loc2 = std::source_location::current();
+  EXPECT_EQ(loc1.line(), loc2.line() - 1);
+  EXPECT_EQ(absl::string_view(loc1.file_name()), loc2.file_name());
+#endif
+}
+
+TEST(SourceLocationTest, CopyConstructionWorks) {
+  constexpr SourceLocation location = absl::SourceLocation::current();
+  constexpr int line = __LINE__ - 1;
+
+  EXPECT_EQ(location.line(), line);
+  EXPECT_THAT(location.file_name(), EndsWith("source_location_test.cc"));
+}
+
+TEST(SourceLocationTest, CopyAssignmentWorks) {
+  SourceLocation location;
+  location = absl::SourceLocation::current();
+  constexpr int line = __LINE__ - 1;
+
+  EXPECT_EQ(location.line(), line);
+  EXPECT_THAT(location.file_name(), EndsWith("source_location_test.cc"));
+}
+
+SourceLocation Echo(const SourceLocation& location) { return location; }
+
+TEST(SourceLocationTest, ExpectedUsageWorks) {
+  SourceLocation location = Echo(absl::SourceLocation::current());
+  constexpr int line = __LINE__ - 1;
+
+  EXPECT_EQ(location.line(), line);
+  EXPECT_THAT(location.file_name(), EndsWith("source_location_test.cc"));
+}
+
+TEST(SourceLocationTest, CurrentWorks) {
+  constexpr SourceLocation location = SourceLocation::current();
+  constexpr int line = __LINE__ - 1;
+
+  EXPECT_EQ(location.line(), line);
+  EXPECT_THAT(location.file_name(), EndsWith("source_location_test.cc"));
+}
+
+SourceLocation FuncWithDefaultParam(
+    SourceLocation loc = SourceLocation::current()) {
+  return loc;
+}
+
+TEST(SourceLocationTest, CurrentWorksAsDefaultParam) {
+  SourceLocation location = FuncWithDefaultParam();
+  constexpr int line = __LINE__ - 1;
+
+  EXPECT_EQ(location.line(), line);
+  EXPECT_THAT(location.file_name(), EndsWith("source_location_test.cc"));
+}
+
+#endif
+
+template <typename T>
+bool TryPassLineAndFile(decltype(T::current(0, ""))*) {
+  return true;
+}
+template <typename T>
+bool TryPassLineAndFile(decltype(T::current({}, 0, ""))*) {
+  return true;
+}
+template <typename T>
+bool TryPassLineAndFile(decltype(T::current(typename T::Tag{}, 0, ""))*) {
+  return true;
+}
+template <typename T>
+bool TryPassLineAndFile(...) {
+  return false;
+}
+
+TEST(SourceLocationTest, CantPassLineAndFile) {
+#ifdef ABSL_HAVE_STD_SOURCE_LOCATION
+  using StdSourceLocation = std::source_location;
+#else
+  using StdSourceLocation = void;
+#endif
+  if constexpr (!std::is_same_v<absl::SourceLocation, StdSourceLocation>) {
+    EXPECT_FALSE(TryPassLineAndFile<absl::SourceLocation>(nullptr));
+  }
+}
+
+}  // namespace
diff --git a/ci/absl_alternate_options.h b/ci/absl_alternate_options.h
index d5567f3..7f70aad 100644
--- a/ci/absl_alternate_options.h
+++ b/ci/absl_alternate_options.h
@@ -20,6 +20,7 @@
 #ifndef ABSL_CI_ABSL_ALTERNATE_OPTIONS_H_
 #define ABSL_CI_ABSL_ALTERNATE_OPTIONS_H_
 
+#define ABSL_OPTION_USE_STD_SOURCE_LOCATION 0
 #define ABSL_OPTION_USE_STD_ORDERING 0
 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1
 #define ABSL_OPTION_INLINE_NAMESPACE_NAME ns