summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2024-01-05 16:58:37 -0800
committerVitaly Buka <vitalybuka@google.com>2024-01-05 16:58:37 -0800
commit8424274a4958e4aff546de13049fbb3476e34e70 (patch)
tree783544032d2f3d6c224fea56a39dafab2bf0dd04
parent2d0ec769a30a344ce7db400e55caedf8ee9b2282 (diff)
parent2652243f19314cf0a7583402d37d28dbae9ec1e6 (diff)
Created using spr 1.3.4 [skip ci]
-rw-r--r--bolt/lib/Rewrite/JITLinkLinker.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp57
-rw-r--r--clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.h44
-rw-r--r--clang-tools-extra/clang-tidy/readability/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp3
-rw-r--r--clang-tools-extra/docs/ReleaseNotes.rst6
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/list.rst1
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/readability/avoid-return-with-void-value.rst51
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp69
-rw-r--r--clang/include/clang/AST/Attr.h1
-rw-r--r--clang/include/clang/Basic/Attr.td15
-rw-r--r--clang/include/clang/Basic/AttrDocs.td9
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp4
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp19
-rw-r--r--clang/test/CodeGen/LoongArch/attributes.cpp34
-rw-r--r--clang/test/Sema/attr-model.cpp64
-rw-r--r--libcxx/include/__algorithm/pop_heap.h3
-rw-r--r--libcxx/include/__algorithm/sift_down.h2
-rw-r--r--libcxx/include/__algorithm/sort.h4
-rw-r--r--libcxx/include/__charconv/to_chars_base_10.h6
-rw-r--r--libcxx/include/__charconv/to_chars_integral.h2
-rw-r--r--libcxx/include/__charconv/traits.h4
-rw-r--r--libcxx/include/__chrono/parser_std_format_spec.h7
-rw-r--r--libcxx/include/__config7
-rw-r--r--libcxx/include/__filesystem/directory_iterator.h3
-rw-r--r--libcxx/include/__filesystem/path_iterator.h4
-rw-r--r--libcxx/include/__format/buffer.h12
-rw-r--r--libcxx/include/__format/format_arg.h2
-rw-r--r--libcxx/include/__format/formatter_bool.h2
-rw-r--r--libcxx/include/__format/formatter_floating_point.h55
-rw-r--r--libcxx/include/__format/formatter_integral.h16
-rw-r--r--libcxx/include/__format/formatter_output.h6
-rw-r--r--libcxx/include/__format/formatter_string.h5
-rw-r--r--libcxx/include/__format/parser_std_format_spec.h7
-rw-r--r--libcxx/include/__format/range_formatter.h5
-rw-r--r--libcxx/include/__format/unicode.h14
-rw-r--r--libcxx/include/__format/write_escaped.h2
-rw-r--r--libcxx/include/__hash_table5
-rw-r--r--libcxx/include/__iterator/advance.h13
-rw-r--r--libcxx/include/__iterator/next.h6
-rw-r--r--libcxx/include/__iterator/prev.h6
-rw-r--r--libcxx/include/__random/negative_binomial_distribution.h7
-rw-r--r--libcxx/include/__ranges/chunk_by_view.h20
-rw-r--r--libcxx/include/__ranges/drop_while_view.h3
-rw-r--r--libcxx/include/__ranges/filter_view.h3
-rw-r--r--libcxx/include/__thread/thread.h2
-rw-r--r--libcxx/include/__utility/exception_guard.h2
-rw-r--r--libcxx/include/__utility/unreachable.h2
-rw-r--r--libcxx/include/print8
-rw-r--r--libcxx/include/regex23
-rw-r--r--libcxx/include/set32
-rw-r--r--libcxx/src/filesystem/error.h2
-rw-r--r--libcxx/src/filesystem/format_string.h2
-rw-r--r--libcxx/src/filesystem/posix_compat.h6
-rw-r--r--libcxx/src/include/to_chars_floating_point.h20
-rw-r--r--libcxx/src/memory_resource.cpp2
-rw-r--r--libcxx/src/strstream.cpp2
-rw-r--r--libcxx/src/system_error.cpp2
-rw-r--r--libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp2
-rw-r--r--llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h5
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/Core.h10
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h23
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h20
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/JITLink.cpp35
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp14
-rw-r--r--llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp12
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp12
-rw-r--r--llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp2
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp14
-rw-r--r--llvm/test/CodeGen/Generic/machine-function-splitter.ll6
-rw-r--r--llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp97
-rw-r--r--llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn1
-rw-r--r--mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp7
-rw-r--r--mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp16
-rw-r--r--mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp23
-rw-r--r--mlir/test/Dialect/SPIRV/IR/structure-ops.mlir15
-rw-r--r--mlir/test/Target/SPIRV/global-variable.mlir24
79 files changed, 854 insertions, 205 deletions
diff --git a/bolt/lib/Rewrite/JITLinkLinker.cpp b/bolt/lib/Rewrite/JITLinkLinker.cpp
index 10a3b6a0407f..66e129bf1d05 100644
--- a/bolt/lib/Rewrite/JITLinkLinker.cpp
+++ b/bolt/lib/Rewrite/JITLinkLinker.cpp
@@ -173,7 +173,8 @@ struct JITLinkLinker::Context : jitlink::JITLinkContext {
void notifyFinalized(
jitlink::JITLinkMemoryManager::FinalizedAlloc Alloc) override {
- Linker.Allocs.push_back(std::move(Alloc));
+ if (Alloc)
+ Linker.Allocs.push_back(std::move(Alloc));
++Linker.MM->ObjectsLoaded;
}
};
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
new file mode 100644
index 000000000000..e3400f614fa5
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
@@ -0,0 +1,57 @@
+//===--- AvoidReturnWithVoidValueCheck.cpp - clang-tidy -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidReturnWithVoidValueCheck.h"
+#include "clang/AST/Stmt.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static constexpr auto IgnoreMacrosName = "IgnoreMacros";
+static constexpr auto IgnoreMacrosDefault = true;
+
+static constexpr auto StrictModeName = "StrictMode";
+static constexpr auto StrictModeDefault = true;
+
+AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreMacros(
+ Options.getLocalOrGlobal(IgnoreMacrosName, IgnoreMacrosDefault)),
+ StrictMode(Options.getLocalOrGlobal(StrictModeName, StrictModeDefault)) {}
+
+void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ returnStmt(
+ hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))),
+ optionally(hasParent(compoundStmt().bind("compound_parent"))))
+ .bind("void_return"),
+ this);
+}
+
+void AvoidReturnWithVoidValueCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *VoidReturn = Result.Nodes.getNodeAs<ReturnStmt>("void_return");
+ if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
+ return;
+ if (!StrictMode && !Result.Nodes.getNodeAs<CompoundStmt>("compound_parent"))
+ return;
+ diag(VoidReturn->getBeginLoc(), "return statement within a void function "
+ "should not have a specified return value");
+}
+
+void AvoidReturnWithVoidValueCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, IgnoreMacrosName, IgnoreMacros);
+ Options.store(Opts, StrictModeName, StrictMode);
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.h b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.h
new file mode 100644
index 000000000000..f8148db43cd9
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.h
@@ -0,0 +1,44 @@
+//===--- AvoidReturnWithVoidValueCheck.h - clang-tidy -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDRETURNWITHVOIDVALUECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDRETURNWITHVOIDVALUECHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// Finds return statements with `void` values used within functions with `void`
+/// result types.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/avoid-return-with-void-value.html
+class AvoidReturnWithVoidValueCheck : public ClangTidyCheck {
+public:
+ AvoidReturnWithVoidValueCheck(StringRef Name, ClangTidyContext *Context);
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ bool IgnoreMacros;
+ bool StrictMode;
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDRETURNWITHVOIDVALUECHECK_H
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 5452c2d48a46..408c822b861c 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyReadabilityModule
AvoidConstParamsInDecls.cpp
+ AvoidReturnWithVoidValueCheck.cpp
AvoidUnconditionalPreprocessorIfCheck.cpp
BracesAroundStatementsCheck.cpp
ConstReturnTypeCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index b8e6e6414320..0b0aad7c0dcb 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -10,6 +10,7 @@
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "AvoidConstParamsInDecls.h"
+#include "AvoidReturnWithVoidValueCheck.h"
#include "AvoidUnconditionalPreprocessorIfCheck.h"
#include "BracesAroundStatementsCheck.h"
#include "ConstReturnTypeCheck.h"
@@ -63,6 +64,8 @@ public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<AvoidConstParamsInDecls>(
"readability-avoid-const-params-in-decls");
+ CheckFactories.registerCheck<AvoidReturnWithVoidValueCheck>(
+ "readability-avoid-return-with-void-value");
CheckFactories.registerCheck<AvoidUnconditionalPreprocessorIfCheck>(
"readability-avoid-unconditional-preprocessor-if");
CheckFactories.registerCheck<BracesAroundStatementsCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 4d25e2ebe85f..08ade306b5a0 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -230,6 +230,12 @@ New checks
Detects C++ code where a reference variable is used to extend the lifetime
of a temporary object that has just been constructed.
+- New :doc:`readability-avoid-return-with-void-value
+ <clang-tidy/checks/readability/avoid-return-with-void-value>` check.
+
+ Finds return statements with ``void`` values used within functions with
+ ``void`` result types.
+
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index b36bf7d497b9..2f86121ad872 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -337,6 +337,7 @@ Clang-Tidy Checks
:doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
:doc:`portability-std-allocator-const <portability/std-allocator-const>`,
:doc:`readability-avoid-const-params-in-decls <readability/avoid-const-params-in-decls>`, "Yes"
+ :doc:`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>`,
:doc:`readability-avoid-unconditional-preprocessor-if <readability/avoid-unconditional-preprocessor-if>`,
:doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
:doc:`readability-const-return-type <readability/const-return-type>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-return-with-void-value.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-return-with-void-value.rst
new file mode 100644
index 000000000000..d802f9be829c
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-return-with-void-value.rst
@@ -0,0 +1,51 @@
+.. title:: clang-tidy - readability-avoid-return-with-void-value
+
+readability-avoid-return-with-void-value
+========================================
+
+Finds return statements with ``void`` values used within functions with
+``void`` result types.
+
+A function with a ``void`` return type is intended to perform a task without
+producing a return value. Return statements with expressions could lead
+to confusion and may miscommunicate the function's intended behavior.
+
+Example:
+
+.. code-block::
+
+ void g();
+ void f() {
+ // ...
+ return g();
+ }
+
+In a long function body, the ``return`` statement suggests that the function
+returns a value. However, ``return g();`` is a combination of two statements
+that should be written as
+
+.. code-block::
+
+ g();
+ return;
+
+to make clear that ``g()`` is called and immediately afterwards the function
+returns (nothing).
+
+In C, the same issue is detected by the compiler if the ``-Wpedantic`` mode
+is enabled.
+
+Options
+-------
+
+.. option:: IgnoreMacros
+
+ The value `false` specifies that return statements expanded
+ from macros are not checked. The default value is `true`.
+
+.. option:: StrictMode
+
+ The value `false` specifies that a direct return statement shall
+ be excluded from the analysis if it is the only statement not
+ contained in a block like ``if (cond) return g();``. The default
+ value is `true`.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
new file mode 100644
index 000000000000..f00407c99ce5
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
@@ -0,0 +1,69 @@
+// RUN: %check_clang_tidy %s readability-avoid-return-with-void-value %t
+// RUN: %check_clang_tidy -check-suffixes=,INCLUDE-MACROS %s readability-avoid-return-with-void-value %t \
+// RUN: -- -config="{CheckOptions: [{key: readability-avoid-return-with-void-value.IgnoreMacros, value: false}]}" \
+// RUN: --
+// RUN: %check_clang_tidy -check-suffixes=LENIENT %s readability-avoid-return-with-void-value %t \
+// RUN: -- -config="{CheckOptions: [{key: readability-avoid-return-with-void-value.StrictMode, value: false}]}" \
+// RUN: --
+
+void f1();
+
+void f2() {
+ return f1();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+}
+
+void f3(bool b) {
+ if (b) return f1();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ return f2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+}
+
+template<class T>
+T f4() {}
+
+void f5() {
+ return f4<void>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+}
+
+void f6() { return; }
+
+int f7() { return 1; }
+
+int f8() { return f7(); }
+
+void f9() {
+ return (void)f7();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+}
+
+#define RETURN_VOID return (void)1
+
+void f10() {
+ RETURN_VOID;
+ // CHECK-MESSAGES-INCLUDE-MACROS: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+}
+
+template <typename A>
+struct C {
+ C(A) {}
+};
+
+template <class T>
+C<T> f11() { return {}; }
+
+using VOID = void;
+
+VOID f12();
+
+VOID f13() {
+ return f12();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+}
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 1b831c9511e2..8e9b7ad8b468 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -25,6 +25,7 @@
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/Frontend/HLSL/HLSLResource.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fda62aaae22c..d5eabaad4889 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -143,6 +143,11 @@ def ExternalGlobalVar : SubsetSubject<Var,
!S->isLocalExternDecl()}],
"external global variables">;
+def NonTLSGlobalVar : SubsetSubject<Var,
+ [{S->hasGlobalStorage() &&
+ S->getTLSKind() == 0}],
+ "non-TLS global variables">;
+
def InlineFunction : SubsetSubject<Function,
[{S->isInlineSpecified()}], "inline functions">;
@@ -431,6 +436,7 @@ def TargetAArch64 : TargetArch<["aarch64", "aarch64_be", "aarch64_32"]>;
def TargetAnyArm : TargetArch<!listconcat(TargetARM.Arches, TargetAArch64.Arches)>;
def TargetAVR : TargetArch<["avr"]>;
def TargetBPF : TargetArch<["bpfel", "bpfeb"]>;
+def TargetLoongArch : TargetArch<["loongarch32", "loongarch64"]>;
def TargetMips32 : TargetArch<["mips", "mipsel"]>;
def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
@@ -2738,6 +2744,15 @@ def PragmaClangTextSection : InheritableAttr {
let Documentation = [InternalOnly];
}
+def CodeModel : InheritableAttr, TargetSpecificAttr<TargetLoongArch> {
+ let Spellings = [GCC<"model">];
+ let Args = [EnumArgument<"Model", "llvm::CodeModel::Model",
+ ["normal", "medium", "extreme"], ["Small", "Medium", "Large"],
+ /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>];
+ let Subjects = SubjectList<[NonTLSGlobalVar], ErrorDiag>;
+ let Documentation = [CodeModelDocs];
+}
+
def Sentinel : InheritableAttr {
let Spellings = [GCC<"sentinel">];
let Args = [DefaultIntArgument<"Sentinel", 0>,
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index cd3dcf2ccf44..5416a0cbdd07 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -57,6 +57,15 @@ global variable or function should be in after translation.
let Heading = "section, __declspec(allocate)";
}
+def CodeModelDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+The ``model`` attribute allows overriding the translation unit's
+code model (specified by ``-mcmodel``) for a specific global variable.
+ }];
+ let Heading = "model";
+}
+
def UsedDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e54f969c1903..d150e08d5f5e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3415,6 +3415,8 @@ def warn_objc_redundant_literal_use : Warning<
def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
"\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;
+def err_attr_codemodel_arg : Error<"code model '%0' is not supported on this target">;
+
def err_aix_attr_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">;
def err_tls_var_aligned_over_maximum : Error<
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d78f2594a237..4fd32337cccc 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4869,6 +4869,10 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
GV->setSection(".cp.rodata");
+ // Handle code model attribute
+ if (const auto *CMA = D->getAttr<CodeModelAttr>())
+ GV->setCodeModel(CMA->getModel());
+
// Check if we a have a const declaration with an initializer, we may be
// able to emit it as available_externally to expose it's value to the
// optimizer.
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 4a385a396fa6..d059b406ef86 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3369,6 +3369,22 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
+static void handleCodeModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ StringRef Str;
+ SourceLocation LiteralLoc;
+ // Check that it is a string.
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
+ return;
+
+ llvm::CodeModel::Model CM;
+ if (!CodeModelAttr::ConvertStrToModel(Str, CM)) {
+ S.Diag(LiteralLoc, diag::err_attr_codemodel_arg) << Str;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) CodeModelAttr(S.Context, AL, CM));
+}
+
// This is used for `__declspec(code_seg("segname"))` on a decl.
// `#pragma code_seg("segname")` uses checkSectionName() instead.
static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc,
@@ -9253,6 +9269,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_Section:
handleSectionAttr(S, D, AL);
break;
+ case ParsedAttr::AT_CodeModel:
+ handleCodeModelAttr(S, D, AL);
+ break;
case ParsedAttr::AT_RandomizeLayout:
handleRandomizeLayoutAttr(S, D, AL);
break;
diff --git a/clang/test/CodeGen/LoongArch/attributes.cpp b/clang/test/CodeGen/LoongArch/attributes.cpp
new file mode 100644
index 000000000000..fb700ad30501
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/attributes.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -emit-llvm -triple loongarch64 %s -o - | FileCheck %s
+
+// CHECK: @_ZL2v1 ={{.*}} global i32 0, code_model "small"
+static int v1 __attribute__((model("normal")));
+
+void use1() {
+ v1 = 1;
+}
+
+// CHECK: @v2 ={{.*}} global i32 0, code_model "medium"
+int v2 __attribute__((model("medium")));
+
+// CHECK: @v3 ={{.*}} global float 0.000000e+00, code_model "large"
+float v3 __attribute__((model("extreme")));
+
+// CHECK: @_ZL2v4IiE ={{.*}} global i32 0, code_model "medium"
+template <typename T>
+static T v4 __attribute__((model("medium")));
+
+void use2() {
+ v4<int> = 1;
+}
+
+struct S {
+ double d;
+};
+
+// CHECK: @v5 ={{.*}} global {{.*}}, code_model "medium"
+S v5 __attribute__((model("medium")));
+
+typedef void (*F)();
+
+// CHECK: @v6 ={{.*}} global ptr null, code_model "large"
+F v6 __attribute__((model("extreme")));
diff --git a/clang/test/Sema/attr-model.cpp b/clang/test/Sema/attr-model.cpp
new file mode 100644
index 000000000000..898cc0393984
--- /dev/null
+++ b/clang/test/Sema/attr-model.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple aarch64 -verify=expected,aarch64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple loongarch64 -verify=expected,loongarch64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple mips64 -verify=expected,mips64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple powerpc64 -verify=expected,powerpc64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple riscv64 -verify=expected,riscv64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple x86_64 -verify=expected,x86_64 -fsyntax-only %s
+
+#if defined(__loongarch__) && !__has_attribute(model)
+#error "Should support model attribute"
+#endif
+
+int a __attribute((model("tiny"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // loongarch64-error {{code model 'tiny' is not supported on this target}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+int b __attribute((model("small"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // loongarch64-error {{code model 'small' is not supported on this target}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+int c __attribute((model("normal"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+int d __attribute((model("kernel"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // loongarch64-error {{code model 'kernel' is not supported on this target}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+int e __attribute((model("medium"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+int f __attribute((model("large"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // loongarch64-error {{code model 'large' is not supported on this target}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+int g __attribute((model("extreme"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+
+void __attribute((model("extreme"))) h() {} // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
+
+thread_local int i __attribute((model("extreme"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
+ // loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
+ // mips64-warning {{unknown attribute 'model' ignored}} \
+ // powerpc64-warning {{unknown attribute 'model' ignored}} \
+ // riscv64-warning {{unknown attribute 'model' ignored}} \
+ // x86_64-warning {{unknown attribute 'model' ignored}}
diff --git a/libcxx/include/__algorithm/pop_heap.h b/libcxx/include/__algorithm/pop_heap.h
index a93a9875f705..798a1d09934b 100644
--- a/libcxx/include/__algorithm/pop_heap.h
+++ b/libcxx/include/__algorithm/pop_heap.h
@@ -36,7 +36,8 @@ __pop_heap(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Compare& __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__len > 0, "The heap given to pop_heap must be non-empty");
+ // Calling `pop_heap` on an empty range is undefined behavior, but in practice it will be a no-op.
+ _LIBCPP_ASSERT_PEDANTIC(__len > 0, "The heap given to pop_heap must be non-empty");
__comp_ref_type<_Compare> __comp_ref = __comp;
diff --git a/libcxx/include/__algorithm/sift_down.h b/libcxx/include/__algorithm/sift_down.h
index 7f152e4dbd7f..42803e30631f 100644
--- a/libcxx/include/__algorithm/sift_down.h
+++ b/libcxx/include/__algorithm/sift_down.h
@@ -85,7 +85,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __floy
_Compare&& __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
- _LIBCPP_ASSERT_UNCATEGORIZED(__len >= 2, "shouldn't be called unless __len >= 2");
+ _LIBCPP_ASSERT_INTERNAL(__len >= 2, "shouldn't be called unless __len >= 2");
_RandomAccessIterator __hole = __first;
_RandomAccessIterator __child_i = __first;
diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 1b878c33c7a1..ac47489af0aa 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -533,7 +533,7 @@ __bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last,
using _Ops = _IterOps<_AlgPolicy>;
typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type;
typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type;
- _LIBCPP_ASSERT_UNCATEGORIZED(__last - __first >= difference_type(3), "");
+ _LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), "");
const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around
const _RandomAccessIterator __end = __last;
(void)__end; //
@@ -625,7 +625,7 @@ __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIte
using _Ops = _IterOps<_AlgPolicy>;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type;
- _LIBCPP_ASSERT_UNCATEGORIZED(__last - __first >= difference_type(3), "");
+ _LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), "");
const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around
const _RandomAccessIterator __end = __last;
(void)__end; //
diff --git a/libcxx/include/__charconv/to_chars_base_10.h b/libcxx/include/__charconv/to_chars_base_10.h
index 33c512e20f04..0dee351521f9 100644
--- a/libcxx/include/__charconv/to_chars_base_10.h
+++ b/libcxx/include/__charconv/to_chars_base_10.h
@@ -132,14 +132,14 @@ __base_10_u64(char* __buffer, uint64_t __value) noexcept {
/// range that can be used. However the range is sufficient for
/// \ref __base_10_u128.
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline __uint128_t __pow_10(int __exp) noexcept {
- _LIBCPP_ASSERT_UNCATEGORIZED(__exp >= __pow10_128_offset, "Index out of bounds");
+ _LIBCPP_ASSERT_INTERNAL(__exp >= __pow10_128_offset, "Index out of bounds");
return __pow10_128[__exp - __pow10_128_offset];
}
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char*
__base_10_u128(char* __buffer, __uint128_t __value) noexcept {
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __value > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fail when this isn't true.");
+ _LIBCPP_ASSERT_INTERNAL(
+ __value > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fails when this isn't true.");
// Unlike the 64 to 32 bit case the 128 bit case the "upper half" can't be
// stored in the "lower half". Instead we first need to handle the top most
diff --git a/libcxx/include/__charconv/to_chars_integral.h b/libcxx/include/__charconv/to_chars_integral.h
index f50cc55a4c6d..40fbe334d8d5 100644
--- a/libcxx/include/__charconv/to_chars_integral.h
+++ b/libcxx/include/__charconv/to_chars_integral.h
@@ -246,7 +246,7 @@ __to_chars_integral(char* __first, char* __last, _Tp __value) {
template <typename _Tp>
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value, unsigned __base) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__value >= 0, "The function requires a non-negative value.");
+ _LIBCPP_ASSERT_INTERNAL(__value >= 0, "The function requires a non-negative value.");
unsigned __base_2 = __base * __base;
unsigned __base_3 = __base_2 * __base;
diff --git a/libcxx/include/__charconv/traits.h b/libcxx/include/__charconv/traits.h
index d3884b560dfd..b4907c3f7757 100644
--- a/libcxx/include/__charconv/traits.h
+++ b/libcxx/include/__charconv/traits.h
@@ -101,11 +101,11 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(__u
/// zero is set to one. This means the first element of the lookup table is
/// zero.
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_INTERNAL(
__v > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fail when this isn't true.");
// There's always a bit set in the upper 64-bits.
auto __t = (128 - std::__libcpp_clz(static_cast<uint64_t>(__v >> 64))) * 1233 >> 12;
- _LIBCPP_ASSERT_UNCATEGORIZED(__t >= __itoa::__pow10_128_offset, "Index out of bounds");
+ _LIBCPP_ASSERT_INTERNAL(__t >= __itoa::__pow10_128_offset, "Index out of bounds");
// __t is adjusted since the lookup table misses the lower entries.
return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1;
}
diff --git a/libcxx/include/__chrono/parser_std_format_spec.h b/libcxx/include/__chrono/parser_std_format_spec.h
index 296be8794ec5..785bbae198e4 100644
--- a/libcxx/include/__chrono/parser_std_format_spec.h
+++ b/libcxx/include/__chrono/parser_std_format_spec.h
@@ -160,10 +160,9 @@ public:
private:
_LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator
__parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __begin != __end,
- "When called with an empty input the function will cause "
- "undefined behavior by evaluating data not in the input");
+ _LIBCPP_ASSERT_INTERNAL(__begin != __end,
+ "When called with an empty input the function will cause "
+ "undefined behavior by evaluating data not in the input");
if (*__begin != _CharT('%') && *__begin != _CharT('}'))
std::__throw_format_error("The format specifier expects a '%' or a '}'");
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 40e6da8bc03a..082c73e672c7 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -283,6 +283,9 @@
// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure
// the containers have compatible allocators.
//
+// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to
+// be benign in our implementation.
+//
// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on
// user input.
//
@@ -325,6 +328,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
// vulnerability.
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
@@ -339,6 +343,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message)
// Disabled checks.
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
@@ -352,6 +357,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
@@ -365,6 +371,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
diff --git a/libcxx/include/__filesystem/directory_iterator.h b/libcxx/include/__filesystem/directory_iterator.h
index 29bd8da6caa4..5287a4d8b055 100644
--- a/libcxx/include/__filesystem/directory_iterator.h
+++ b/libcxx/include/__filesystem/directory_iterator.h
@@ -73,7 +73,8 @@ public:
_LIBCPP_HIDE_FROM_ABI ~directory_iterator() = default;
_LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const {
- _LIBCPP_ASSERT_UNCATEGORIZED(__imp_, "The end iterator cannot be dereferenced");
+ // Note: this check duplicates a check in `__dereference()`.
+ _LIBCPP_ASSERT_NON_NULL(__imp_, "The end iterator cannot be dereferenced");
return __dereference();
}
diff --git a/libcxx/include/__filesystem/path_iterator.h b/libcxx/include/__filesystem/path_iterator.h
index 1a9aaf0e7d99..d2d65cd122ca 100644
--- a/libcxx/include/__filesystem/path_iterator.h
+++ b/libcxx/include/__filesystem/path_iterator.h
@@ -61,7 +61,7 @@ public:
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return &__stashed_elem_; }
_LIBCPP_HIDE_FROM_ABI iterator& operator++() {
- _LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _Singular, "attempting to increment a singular iterator");
+ _LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to increment a singular iterator");
_LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _AtEnd, "attempting to increment the end iterator");
return __increment();
}
@@ -73,7 +73,7 @@ public:
}
_LIBCPP_HIDE_FROM_ABI iterator& operator--() {
- _LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _Singular, "attempting to decrement a singular iterator");
+ _LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to decrement a singular iterator");
_LIBCPP_ASSERT_UNCATEGORIZED(
__entry_.data() != __path_ptr_->native().data(), "attempting to decrement the begin iterator");
return __decrement();
diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index 7ee583d81394..8598f0a1c039 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -115,7 +115,7 @@ public:
// The output doesn't fit in the internal buffer.
// Copy the data in "__capacity_" sized chunks.
- _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
+ _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
const _InCharT* __first = __str.data();
do {
size_t __chunk = std::min(__n, __capacity_);
@@ -134,7 +134,7 @@ public:
class _UnaryOperation,
__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
+ _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
size_t __n = static_cast<size_t>(__last - __first);
__flush_on_overflow(__n);
@@ -146,7 +146,7 @@ public:
// The output doesn't fit in the internal buffer.
// Transform the data in "__capacity_" sized chunks.
- _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
+ _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
do {
size_t __chunk = std::min(__n, __capacity_);
std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
@@ -168,7 +168,7 @@ public:
// The output doesn't fit in the internal buffer.
// Fill the buffer in "__capacity_" sized chunks.
- _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
+ _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
do {
size_t __chunk = std::min(__n, __capacity_);
std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
@@ -596,7 +596,7 @@ public:
class _UnaryOperation,
__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
+ _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
size_t __n = static_cast<size_t>(__last - __first);
if (__size_ + __n >= __capacity_)
@@ -623,7 +623,7 @@ private:
_LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
_LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__capacity > __capacity_, "the buffer must grow");
+ _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
auto __result = std::__allocate_at_least(__alloc_, __capacity);
auto __guard = std::__make_exception_guard([&] {
allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
diff --git a/libcxx/include/__format/format_arg.h b/libcxx/include/__format/format_arg.h
index 280c91082417..10fca15d5a7a 100644
--- a/libcxx/include/__format/format_arg.h
+++ b/libcxx/include/__format/format_arg.h
@@ -83,7 +83,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __use_packed_format_arg_store(size_t __size
}
_LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__id <= __packed_types_max, "");
+ _LIBCPP_ASSERT_INTERNAL(__id <= __packed_types_max, "");
if (__id > 0)
__types >>= __id * __packed_arg_t_bits;
diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h
index 3c8ae95f55fa..1c479501b675 100644
--- a/libcxx/include/__format/formatter_bool.h
+++ b/libcxx/include/__format/formatter_bool.h
@@ -62,7 +62,7 @@ public:
static_cast<unsigned>(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx));
default:
- _LIBCPP_ASSERT_UNCATEGORIZED(false, "The parse function should have validated the type");
+ _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type");
__libcpp_unreachable();
}
}
diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h
index 33cc2a4ed661..6802a8b7bd4c 100644
--- a/libcxx/include/__format/formatter_floating_point.h
+++ b/libcxx/include/__format/formatter_floating_point.h
@@ -57,21 +57,21 @@ namespace __formatter {
template <floating_point _Tp>
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value) {
to_chars_result __r = std::to_chars(__first, __last, __value);
- _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small");
+ _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
return __r.ptr;
}
template <floating_point _Tp>
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt) {
to_chars_result __r = std::to_chars(__first, __last, __value, __fmt);
- _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small");
+ _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
return __r.ptr;
}
template <floating_point _Tp>
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt, int __precision) {
to_chars_result __r = std::to_chars(__first, __last, __value, __fmt, __precision);
- _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small");
+ _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
return __r.ptr;
}
@@ -252,10 +252,10 @@ __format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value, char*
__result.__radix_point = __result.__last;
// clang-format off
- _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) &&
- (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
- (__result.__exponent == __result.__last || *__result.__exponent == 'e'),
- "Post-condition failure.");
+ _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
+ (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+ (__result.__exponent == __result.__last || *__result.__exponent == 'e'),
+ "Post-condition failure.");
// clang-format on
return __result;
@@ -304,10 +304,10 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case(
}
// clang-format off
- _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) &&
- (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
- (__result.__exponent != __result.__last && *__result.__exponent == 'p'),
- "Post-condition failure.");
+ _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
+ (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+ (__result.__exponent != __result.__last && *__result.__exponent == 'p'),
+ "Post-condition failure.");
// clang-format on
return __result;
@@ -332,7 +332,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case(
__formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::scientific, __precision);
char* __first = __integral + 1;
- _LIBCPP_ASSERT_UNCATEGORIZED(__first != __result.__last, "No exponent present");
+ _LIBCPP_ASSERT_INTERNAL(__first != __result.__last, "No exponent present");
if (*__first == '.') {
__result.__radix_point = __first;
__result.__exponent = __formatter::__find_exponent(__first + 1, __result.__last);
@@ -342,10 +342,10 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case(
}
// clang-format off
- _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) &&
- (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
- (__result.__exponent != __result.__last && *__result.__exponent == 'e'),
- "Post-condition failure.");
+ _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
+ (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+ (__result.__exponent != __result.__last && *__result.__exponent == 'e'),
+ "Post-condition failure.");
// clang-format on
return __result;
}
@@ -374,10 +374,10 @@ __format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value, int __pr
__result.__exponent = __result.__last;
// clang-format off
- _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) &&
- (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
- (__result.__exponent == __result.__last),
- "Post-condition failure.");
+ _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
+ (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+ (__result.__exponent == __result.__last),
+ "Post-condition failure.");
// clang-format on
return __result;
}
@@ -410,10 +410,10 @@ __format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value, i
}
// clang-format off
- _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) &&
- (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
- (__result.__exponent == __result.__last || *__result.__exponent == 'e'),
- "Post-condition failure.");
+ _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
+ (__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
+ (__result.__exponent == __result.__last || *__result.__exponent == 'e'),
+ "Post-condition failure.");
// clang-format on
return __result;
@@ -485,7 +485,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer(
return __formatter::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first);
default:
- _LIBCPP_ASSERT_UNCATEGORIZED(false, "The parser should have validated the type");
+ _LIBCPP_ASSERT_INTERNAL(false, "The parser should have validated the type");
__libcpp_unreachable();
}
}
@@ -620,9 +620,8 @@ _LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros(
size_t __size,
const _CharT* __exponent,
size_t __num_trailing_zeros) -> decltype(__out_it) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range");
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
+ _LIBCPP_ASSERT_INTERNAL(__first <= __last, "Not a valid range");
+ _LIBCPP_ASSERT_INTERNAL(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
__padding_size_result __padding =
__formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_);
diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h
index ca66e26ede10..e0217a240027 100644
--- a/libcxx/include/__format/formatter_integral.h
+++ b/libcxx/include/__format/formatter_integral.h
@@ -90,10 +90,8 @@ _LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __neg
* regardless whether the @c std::numpunct's type is @c char or @c wchar_t.
*/
_LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const string& __grouping) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
- !__grouping.empty() && __size > __grouping[0],
- "The slow grouping formatting is used while there will be no "
- "separators written");
+ _LIBCPP_ASSERT_INTERNAL(!__grouping.empty() && __size > __grouping[0],
+ "The slow grouping formatting is used while there will be no separators written");
string __r;
auto __end = __grouping.end() - 1;
auto __ptr = __grouping.begin();
@@ -161,7 +159,7 @@ _LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last,
// TODO FMT Evaluate code overhead due to not calling the internal function
// directly. (Should be zero overhead.)
to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base);
- _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small");
+ _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
auto __diff = __r.ptr - std::to_address(__first);
return __first + __diff;
}
@@ -248,10 +246,8 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(
auto __r = __grouping.rbegin();
auto __e = __grouping.rend() - 1;
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __r != __e,
- "The slow grouping formatting is used while "
- "there will be no separators written.");
+ _LIBCPP_ASSERT_INTERNAL(
+ __r != __e, "The slow grouping formatting is used while there will be no separators written.");
// The output is divided in small groups of numbers to write:
// - A group before the first separator.
// - A separator and a group, repeated for the number of separators.
@@ -380,7 +376,7 @@ __format_integer(_Tp __value,
return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0X", 16);
}
default:
- _LIBCPP_ASSERT_UNCATEGORIZED(false, "The parse function should have validated the type");
+ _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type");
__libcpp_unreachable();
}
}
diff --git a/libcxx/include/__format/formatter_output.h b/libcxx/include/__format/formatter_output.h
index 31e06425703a..eebe880d69ef 100644
--- a/libcxx/include/__format/formatter_output.h
+++ b/libcxx/include/__format/formatter_output.h
@@ -66,8 +66,8 @@ struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result {
_LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result
__padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__width > __size, "don't call this function when no padding is required");
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_INTERNAL(__width > __size, "don't call this function when no padding is required");
+ _LIBCPP_ASSERT_INTERNAL(
__align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding");
size_t __fill = __width - __size;
@@ -296,7 +296,7 @@ _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
basic_string_view<_CharT> __str,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
- _LIBCPP_ASSERT_UNCATEGORIZED(!__specs.__has_precision(), "use __write_string");
+ _LIBCPP_ASSERT_INTERNAL(!__specs.__has_precision(), "use __write_string");
// No padding -> copy the string
if (!__specs.__has_width())
diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h
index 4ba5617a49c8..d1ccfb9b5f7d 100644
--- a/libcxx/include/__format/formatter_string.h
+++ b/libcxx/include/__format/formatter_string.h
@@ -64,10 +64,7 @@ struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT> : public __formatte
template <class _FormatContext>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const {
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __str,
- "The basic_format_arg constructor should have "
- "prevented an invalid pointer.");
+ _LIBCPP_ASSERT_INTERNAL(__str, "The basic_format_arg constructor should have prevented an invalid pointer.");
__format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx);
# if _LIBCPP_STD_VER >= 23
diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h
index e38729db965c..cf8af87b2128 100644
--- a/libcxx/include/__format/parser_std_format_spec.h
+++ b/libcxx/include/__format/parser_std_format_spec.h
@@ -733,10 +733,9 @@ private:
__format::__parse_number_result __r = __format::__parse_number(__begin, __end);
__width_ = __r.__value;
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __width_ != 0,
- "A zero value isn't allowed and should be impossible, "
- "due to validations in this function");
+ _LIBCPP_ASSERT_INTERNAL(__width_ != 0,
+ "A zero value isn't allowed and should be impossible, "
+ "due to validations in this function");
__begin = __r.__last;
return true;
}
diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h
index d13278009fcf..691563074349 100644
--- a/libcxx/include/__format/range_formatter.h
+++ b/libcxx/include/__format/range_formatter.h
@@ -246,9 +246,8 @@ private:
__parse_empty_range_underlying_spec(_ParseContext& __ctx, typename _ParseContext::iterator __begin) {
__ctx.advance_to(__begin);
[[maybe_unused]] typename _ParseContext::iterator __result = __underlying_.parse(__ctx);
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __result == __begin,
- "the underlying's parse function should not advance the input beyond the end of the input");
+ _LIBCPP_ASSERT_INTERNAL(__result == __begin,
+ "the underlying's parse function should not advance the input beyond the end of the input");
return __begin;
}
diff --git a/libcxx/include/__format/unicode.h b/libcxx/include/__format/unicode.h
index 8e1e7bb192a0..40067ca3448b 100644
--- a/libcxx/include/__format/unicode.h
+++ b/libcxx/include/__format/unicode.h
@@ -153,7 +153,7 @@ public:
// - The parser always needs to consume these code units
// - The code is optimized for well-formed UTF-8
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept {
- _LIBCPP_ASSERT_UNCATEGORIZED(__first_ != __last_, "can't move beyond the end of input");
+ _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input");
// Based on the number of leading 1 bits the number of code units in the
// code point can be determined. See
@@ -259,7 +259,7 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept {
- _LIBCPP_ASSERT_UNCATEGORIZED(__first_ != __last_, "can't move beyond the end of input");
+ _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input");
char32_t __value = static_cast<char32_t>(*__first_++);
if constexpr (sizeof(wchar_t) == 2) {
@@ -305,8 +305,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __at_extended_grapheme_cluster_break(
// *** Break at the start and end of text, unless the text is empty. ***
- _LIBCPP_ASSERT_UNCATEGORIZED(__prev != __property::__sot, "should be handled in the constructor"); // GB1
- _LIBCPP_ASSERT_UNCATEGORIZED(__prev != __property::__eot, "should be handled by our caller"); // GB2
+ _LIBCPP_ASSERT_INTERNAL(__prev != __property::__sot, "should be handled in the constructor"); // GB1
+ _LIBCPP_ASSERT_INTERNAL(__prev != __property::__eot, "should be handled by our caller"); // GB2
// *** Do not break between a CR and LF. Otherwise, break before and after controls. ***
if (__prev == __property::__CR && __next == __property::__LF) // GB3
@@ -401,8 +401,8 @@ public:
};
_LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() {
- _LIBCPP_ASSERT_UNCATEGORIZED(__next_prop_ != __extended_grapheme_custer_property_boundary::__property::__eot,
- "can't move beyond the end of input");
+ _LIBCPP_ASSERT_INTERNAL(__next_prop_ != __extended_grapheme_custer_property_boundary::__property::__eot,
+ "can't move beyond the end of input");
char32_t __code_point = __next_code_point_;
if (!__code_point_view_.__at_end())
@@ -459,7 +459,7 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept {
- _LIBCPP_ASSERT_UNCATEGORIZED(__first_ != __last_, "can't move beyond the end of input");
+ _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input");
return {static_cast<char32_t>(*__first_++)};
}
diff --git a/libcxx/include/__format/write_escaped.h b/libcxx/include/__format/write_escaped.h
index 15141eebc029..ec1283a173e9 100644
--- a/libcxx/include/__format/write_escaped.h
+++ b/libcxx/include/__format/write_escaped.h
@@ -71,7 +71,7 @@ __write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _
char __buffer[8];
to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16);
- _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small");
+ _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it);
__str += _CharT('}');
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index 3cee48ef8538..4ca49fe42606 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -915,7 +915,10 @@ public:
return __bc != 0 ? (float)size() / __bc : 0.f;
}
_LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) _NOEXCEPT {
- _LIBCPP_ASSERT_UNCATEGORIZED(__mlf > 0, "unordered container::max_load_factor(lf) called with lf <= 0");
+ // While passing a non-positive load factor is undefined behavior, in practice the result will be benign (the
+ // call will be equivalent to `max_load_factor(load_factor())`, which is also the case for passing a valid value
+ // less than the current `load_factor`).
+ _LIBCPP_ASSERT_PEDANTIC(__mlf > 0, "unordered container::max_load_factor(lf) called with lf <= 0");
max_load_factor() = std::max(__mlf, load_factor());
}
diff --git a/libcxx/include/__iterator/advance.h b/libcxx/include/__iterator/advance.h
index 64c8d249f78f..73473f899eac 100644
--- a/libcxx/include/__iterator/advance.h
+++ b/libcxx/include/__iterator/advance.h
@@ -65,8 +65,9 @@ template < class _InputIter,
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) {
typedef typename iterator_traits<_InputIter>::difference_type _Difference;
_Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n));
- _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
- "Attempt to advance(it, n) with negative n on a non-bidirectional iterator");
+ // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
+ _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
+ "Attempt to advance(it, n) with negative n on a non-bidirectional iterator");
std::__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category());
}
@@ -99,7 +100,8 @@ public:
// Preconditions: If `I` does not model `bidirectional_iterator`, `n` is not negative.
template <input_or_output_iterator _Ip>
_LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, iter_difference_t<_Ip> __n) const {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
+ _LIBCPP_ASSERT_PEDANTIC(
__n >= 0 || bidirectional_iterator<_Ip>, "If `n < 0`, then `bidirectional_iterator<I>` must be true.");
// If `I` models `random_access_iterator`, equivalent to `i += n`.
@@ -149,8 +151,9 @@ public:
template <input_or_output_iterator _Ip, sentinel_for<_Ip> _Sp>
_LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip>
operator()(_Ip& __i, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const {
- _LIBCPP_ASSERT_UNCATEGORIZED((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>),
- "If `n < 0`, then `bidirectional_iterator<I> && same_as<I, S>` must be true.");
+ // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
+ _LIBCPP_ASSERT_PEDANTIC((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>),
+ "If `n < 0`, then `bidirectional_iterator<I> && same_as<I, S>` must be true.");
// If `S` and `I` model `sized_sentinel_for<S, I>`:
if constexpr (sized_sentinel_for<_Sp, _Ip>) {
// If |n| >= |bound_sentinel - i|, equivalent to `ranges::advance(i, bound_sentinel)`.
diff --git a/libcxx/include/__iterator/next.h b/libcxx/include/__iterator/next.h
index da60aacfd08d..21d3688ad9eb 100644
--- a/libcxx/include/__iterator/next.h
+++ b/libcxx/include/__iterator/next.h
@@ -27,8 +27,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
next(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
- "Attempt to next(it, n) with negative n on a non-bidirectional iterator");
+ // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
+ // Note that this check duplicates the similar check in `std::advance`.
+ _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
+ "Attempt to next(it, n) with negative n on a non-bidirectional iterator");
std::advance(__x, __n);
return __x;
diff --git a/libcxx/include/__iterator/prev.h b/libcxx/include/__iterator/prev.h
index 1651942acea9..2f0e6a088edb 100644
--- a/libcxx/include/__iterator/prev.h
+++ b/libcxx/include/__iterator/prev.h
@@ -27,8 +27,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
- "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator");
+ // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
+ // Note that this check duplicates the similar check in `std::advance`.
+ _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
+ "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator");
std::advance(__x, -__n);
return __x;
}
diff --git a/libcxx/include/__random/negative_binomial_distribution.h b/libcxx/include/__random/negative_binomial_distribution.h
index 580c74d46440..eed4f511e871 100644
--- a/libcxx/include/__random/negative_binomial_distribution.h
+++ b/libcxx/include/__random/negative_binomial_distribution.h
@@ -113,10 +113,9 @@ _IntType negative_binomial_distribution<_IntType>::operator()(_URNG& __urng, con
else
++__f;
}
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __f >= 0,
- "std::negative_binomial_distribution should never produce negative values. "
- "This is almost certainly a signed integer overflow issue on __f.");
+ _LIBCPP_ASSERT_INTERNAL(__f >= 0,
+ "std::negative_binomial_distribution should never produce negative values. "
+ "This is almost certainly a signed integer overflow issue on __f.");
return __f;
}
return poisson_distribution<result_type>(gamma_distribution<double>(__k, (1 - __p) / __p)(__urng))(__urng);
diff --git a/libcxx/include/__ranges/chunk_by_view.h b/libcxx/include/__ranges/chunk_by_view.h
index 3ecc018cac9d..c5b3240a7d0b 100644
--- a/libcxx/include/__ranges/chunk_by_view.h
+++ b/libcxx/include/__ranges/chunk_by_view.h
@@ -66,7 +66,8 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG chunk_by_view
class __iterator;
_LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_next(iterator_t<_View> __current) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ // Note: this duplicates a check in `optional` but provides a better error message.
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__pred_.__has_value(), "Trying to call __find_next() on a chunk_by_view that does not have a valid predicate.");
auto __reversed_pred = [this]<class _Tp, class _Up>(_Tp&& __x, _Up&& __y) -> bool {
return !std::invoke(*__pred_, std::forward<_Tp>(__x), std::forward<_Up>(__y));
@@ -78,9 +79,10 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG chunk_by_view
_LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_prev(iterator_t<_View> __current)
requires bidirectional_range<_View>
{
- _LIBCPP_ASSERT_UNCATEGORIZED(
- __current != ranges::begin(__base_), "Trying to call __find_prev() on a begin iterator.");
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ // Attempting to decrement a begin iterator is a no-op (`__find_prev` would return the same argument given to it).
+ _LIBCPP_ASSERT_PEDANTIC(__current != ranges::begin(__base_), "Trying to call __find_prev() on a begin iterator.");
+ // Note: this duplicates a check in `optional` but provides a better error message.
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__pred_.__has_value(), "Trying to call __find_prev() on a chunk_by_view that does not have a valid predicate.");
auto __first = ranges::begin(__base_);
@@ -110,7 +112,8 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; }
_LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ // Note: this duplicates a check in `optional` but provides a better error message.
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__pred_.__has_value(), "Trying to call begin() on a chunk_by_view that does not have a valid predicate.");
auto __first = ranges::begin(__base_);
@@ -154,12 +157,15 @@ public:
_LIBCPP_HIDE_FROM_ABI __iterator() = default;
_LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const {
- _LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to dereference past-the-end chunk_by_view iterator.");
+ // If the iterator is at end, this would return an empty range which can be checked by the calling code and doesn't
+ // necessarily lead to a bad access.
+ _LIBCPP_ASSERT_PEDANTIC(__current_ != __next_, "Trying to dereference past-the-end chunk_by_view iterator.");
return {__current_, __next_};
}
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
- _LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to increment past end chunk_by_view iterator.");
+ // Attempting to increment an end iterator is a no-op (`__find_next` would return the same argument given to it).
+ _LIBCPP_ASSERT_PEDANTIC(__current_ != __next_, "Trying to increment past end chunk_by_view iterator.");
__current_ = __next_;
__next_ = __parent_->__find_next(__current_);
return *this;
diff --git a/libcxx/include/__ranges/drop_while_view.h b/libcxx/include/__ranges/drop_while_view.h
index eb3783eb42f1..b367f735c141 100644
--- a/libcxx/include/__ranges/drop_while_view.h
+++ b/libcxx/include/__ranges/drop_while_view.h
@@ -66,7 +66,8 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; }
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ // Note: this duplicates a check in `optional` but provides a better error message.
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__pred_.__has_value(),
"drop_while_view needs to have a non-empty predicate before calling begin() -- did a previous "
"assignment to this drop_while_view fail?");
diff --git a/libcxx/include/__ranges/filter_view.h b/libcxx/include/__ranges/filter_view.h
index 868ad128e894..ecb78eee3810 100644
--- a/libcxx/include/__ranges/filter_view.h
+++ b/libcxx/include/__ranges/filter_view.h
@@ -83,7 +83,8 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr _Pred const& pred() const { return *__pred_; }
_LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ // Note: this duplicates a check in `optional` but provides a better error message.
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__pred_.__has_value(), "Trying to call begin() on a filter_view that does not have a valid predicate.");
if constexpr (_UseCache) {
if (!__cached_begin_.__has_value()) {
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index f3300752ac9e..463bbd677255 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -104,7 +104,7 @@ __thread_specific_ptr<_Tp>::~__thread_specific_ptr() {
template <class _Tp>
void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
- _LIBCPP_ASSERT_UNCATEGORIZED(get() == nullptr, "Attempting to overwrite thread local data");
+ _LIBCPP_ASSERT_INTERNAL(get() == nullptr, "Attempting to overwrite thread local data");
std::__libcpp_tls_set(__key_, __p);
}
diff --git a/libcxx/include/__utility/exception_guard.h b/libcxx/include/__utility/exception_guard.h
index 389fca6c7101..8d90dfd5f190 100644
--- a/libcxx/include/__utility/exception_guard.h
+++ b/libcxx/include/__utility/exception_guard.h
@@ -115,7 +115,7 @@ struct __exception_guard_noexceptions {
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG ~__exception_guard_noexceptions() {
- _LIBCPP_ASSERT_UNCATEGORIZED(__completed_, "__exception_guard not completed with exceptions disabled");
+ _LIBCPP_ASSERT_INTERNAL(__completed_, "__exception_guard not completed with exceptions disabled");
}
private:
diff --git a/libcxx/include/__utility/unreachable.h b/libcxx/include/__utility/unreachable.h
index 49334decc8f6..d833f74c2e4f 100644
--- a/libcxx/include/__utility/unreachable.h
+++ b/libcxx/include/__utility/unreachable.h
@@ -19,7 +19,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void __libcpp_unreachable() {
- _LIBCPP_ASSERT_UNCATEGORIZED(false, "std::unreachable() was reached");
+ _LIBCPP_ASSERT_INTERNAL(false, "std::unreachable() was reached");
__builtin_unreachable();
}
diff --git a/libcxx/include/print b/libcxx/include/print
index 0f8e73f8eb5c..5e00fc87f47e 100644
--- a/libcxx/include/print
+++ b/libcxx/include/print
@@ -122,6 +122,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt&, char32_t) = delete;
template <class _OutIt>
requires __utf16_code_unit<iter_value_t<_OutIt>>
_LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value) {
+ // [print.fun]/7 : "if `out` contains invalid code units, the behavior is undefined and implementations are encouraged
+ // to diagnose it".
_LIBCPP_ASSERT_UNCATEGORIZED(__is_scalar_value(__value), "an invalid unicode scalar value results in invalid UTF-16");
if (__value < 0x10000) {
@@ -137,6 +139,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value
template <class _OutIt>
requires __utf32_code_unit<iter_value_t<_OutIt>>
_LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value) {
+ // [print.fun]/7 : "if `out` contains invalid code units, the behavior is undefined and implementations are encouraged
+ // to diagnose it".
_LIBCPP_ASSERT_UNCATEGORIZED(__is_scalar_value(__value), "an invalid unicode scalar value results in invalid UTF-32");
*__out_it++ = __value;
}
@@ -214,7 +218,7 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_terminal(FILE* __stream) {
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI inline void
__vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__stream, "__stream is a valid pointer to an output C stream");
+ _LIBCPP_ASSERT_NON_NULL(__stream, "__stream must be a valid pointer to an output C stream");
string __str = std::vformat(__fmt, __args);
if (__write_nl)
__str.push_back('\n');
@@ -290,7 +294,7 @@ __vprint_unicode([[maybe_unused]] FILE* __stream,
[[maybe_unused]] string_view __fmt,
[[maybe_unused]] format_args __args,
[[maybe_unused]] bool __write_nl) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__stream, "__stream is a valid pointer to an output C stream");
+ _LIBCPP_ASSERT_NON_NULL(__stream, "__stream must be a valid pointer to an output C stream");
// [print.fun]
// 7 - Effects: If stream refers to a terminal capable of displaying
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 061194cb2eba..b575a267583b 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -4587,28 +4587,36 @@ public:
// element access:
_LIBCPP_HIDE_FROM_ABI difference_type length(size_type __sub = 0) const {
- _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::length() called when not ready");
+ // If the match results are not ready, this will return `0`.
+ _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::length() called when not ready");
return (*this)[__sub].length();
}
_LIBCPP_HIDE_FROM_ABI difference_type position(size_type __sub = 0) const {
- _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::position() called when not ready");
+ // If the match results are not ready, this will return the result of subtracting two default-constructed iterators
+ // (which is typically a well-defined operation).
+ _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::position() called when not ready");
return std::distance(__position_start_, (*this)[__sub].first);
}
_LIBCPP_HIDE_FROM_ABI string_type str(size_type __sub = 0) const {
- _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::str() called when not ready");
+ // If the match results are not ready, this will return an empty string.
+ _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::str() called when not ready");
return (*this)[__sub].str();
}
_LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const {
- _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::operator[]() called when not ready");
+ // If the match results are not ready, this call will be equivalent to calling this function with `__n >= size()`,
+ // returning an empty subrange.
+ _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::operator[]() called when not ready");
return __n < __matches_.size() ? __matches_[__n] : __unmatched_;
}
_LIBCPP_HIDE_FROM_ABI const_reference prefix() const {
- _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::prefix() called when not ready");
+ // If the match results are not ready, this will return a default-constructed empty `__suffix_`.
+ _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::prefix() called when not ready");
return __prefix_;
}
_LIBCPP_HIDE_FROM_ABI const_reference suffix() const {
- _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::suffix() called when not ready");
+ // If the match results are not ready, this will return a default-constructed empty `__suffix_`.
+ _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::suffix() called when not ready");
return __suffix_;
}
@@ -4722,7 +4730,8 @@ _OutputIter match_results<_BidirectionalIterator, _Allocator>::format(
const char_type* __fmt_first,
const char_type* __fmt_last,
regex_constants::match_flag_type __flags) const {
- _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::format() called when not ready");
+ // Note: this duplicates a check in `vector::operator[]` but provides a better error message.
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(ready(), "match_results::format() called when not ready");
if (__flags & regex_constants::format_sed) {
for (; __fmt_first != __fmt_last; ++__fmt_first) {
if (*__fmt_first == '&')
diff --git a/libcxx/include/set b/libcxx/include/set
index 08677a94054f..55ba8f8208be 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -769,13 +769,13 @@ public:
#if _LIBCPP_STD_VER >= 17
_LIBCPP_HIDE_FROM_ABI insert_return_type insert(node_type&& __nh) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
- "node_type with incompatible allocator passed to set::insert()");
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
+ "node_type with incompatible allocator passed to set::insert()");
return __tree_.template __node_handle_insert_unique< node_type, insert_return_type>(std::move(__nh));
}
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, node_type&& __nh) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
- "node_type with incompatible allocator passed to set::insert()");
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
+ "node_type with incompatible allocator passed to set::insert()");
return __tree_.template __node_handle_insert_unique<node_type>(__hint, std::move(__nh));
}
_LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
@@ -786,25 +786,25 @@ public:
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(set<key_type, _Compare2, allocator_type>& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_unique(__source.__tree_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(set<key_type, _Compare2, allocator_type>&& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_unique(__source.__tree_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(multiset<key_type, _Compare2, allocator_type>& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_unique(__source.__tree_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(multiset<key_type, _Compare2, allocator_type>&& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_unique(__source.__tree_);
}
@@ -1227,13 +1227,13 @@ public:
#if _LIBCPP_STD_VER >= 17
_LIBCPP_HIDE_FROM_ABI iterator insert(node_type&& __nh) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
- "node_type with incompatible allocator passed to multiset::insert()");
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
+ "node_type with incompatible allocator passed to multiset::insert()");
return __tree_.template __node_handle_insert_multi<node_type>(std::move(__nh));
}
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, node_type&& __nh) {
- _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
- "node_type with incompatible allocator passed to multiset::insert()");
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
+ "node_type with incompatible allocator passed to multiset::insert()");
return __tree_.template __node_handle_insert_multi<node_type>(__hint, std::move(__nh));
}
_LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
@@ -1244,25 +1244,25 @@ public:
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(multiset<key_type, _Compare2, allocator_type>& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_multi(__source.__tree_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(multiset<key_type, _Compare2, allocator_type>&& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_multi(__source.__tree_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(set<key_type, _Compare2, allocator_type>& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_multi(__source.__tree_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(set<key_type, _Compare2, allocator_type>&& __source) {
- _LIBCPP_ASSERT_UNCATEGORIZED(
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__source.get_allocator() == get_allocator(), "merging container with incompatible allocator");
__tree_.__node_handle_merge_multi(__source.__tree_);
}
diff --git a/libcxx/src/filesystem/error.h b/libcxx/src/filesystem/error.h
index b86f4ed41071..572cc73292a1 100644
--- a/libcxx/src/filesystem/error.h
+++ b/libcxx/src/filesystem/error.h
@@ -99,7 +99,7 @@ inline errc __win_err_to_errc(int err) {
#endif // _LIBCPP_WIN32API
inline error_code capture_errno() {
- _LIBCPP_ASSERT_UNCATEGORIZED(errno != 0, "Expected errno to be non-zero");
+ _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero");
return error_code(errno, generic_category());
}
diff --git a/libcxx/src/filesystem/format_string.h b/libcxx/src/filesystem/format_string.h
index 215d42421b2a..a44def86f53e 100644
--- a/libcxx/src/filesystem/format_string.h
+++ b/libcxx/src/filesystem/format_string.h
@@ -47,7 +47,7 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) string vformat_string(const ch
size_t size_with_null = static_cast<size_t>(ret) + 1;
result.__resize_default_init(size_with_null - 1);
ret = ::vsnprintf(&result[0], size_with_null, msg, ap);
- _LIBCPP_ASSERT_UNCATEGORIZED(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
+ _LIBCPP_ASSERT_INTERNAL(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
}
return result;
}
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
index ec2de49960be..760cdb65dae1 100644
--- a/libcxx/src/filesystem/posix_compat.h
+++ b/libcxx/src/filesystem/posix_compat.h
@@ -318,8 +318,8 @@ inline int statvfs(const wchar_t* p, StatVFS* buf) {
inline wchar_t* getcwd([[maybe_unused]] wchar_t* in_buf, [[maybe_unused]] size_t in_size) {
// Only expected to be used with us allocating the buffer.
- _LIBCPP_ASSERT_UNCATEGORIZED(in_buf == nullptr, "Windows getcwd() assumes in_buf==nullptr");
- _LIBCPP_ASSERT_UNCATEGORIZED(in_size == 0, "Windows getcwd() assumes in_size==0");
+ _LIBCPP_ASSERT_INTERNAL(in_buf == nullptr, "Windows getcwd() assumes in_buf==nullptr");
+ _LIBCPP_ASSERT_INTERNAL(in_size == 0, "Windows getcwd() assumes in_size==0");
size_t buff_size = MAX_PATH + 10;
std::unique_ptr<wchar_t, decltype(&::free)> buff(static_cast<wchar_t*>(malloc(buff_size * sizeof(wchar_t))), &::free);
@@ -338,7 +338,7 @@ inline wchar_t* getcwd([[maybe_unused]] wchar_t* in_buf, [[maybe_unused]] size_t
inline wchar_t* realpath(const wchar_t* path, [[maybe_unused]] wchar_t* resolved_name) {
// Only expected to be used with us allocating the buffer.
- _LIBCPP_ASSERT_UNCATEGORIZED(resolved_name == nullptr, "Windows realpath() assumes a null resolved_name");
+ _LIBCPP_ASSERT_INTERNAL(resolved_name == nullptr, "Windows realpath() assumes a null resolved_name");
WinHandle h(path, FILE_READ_ATTRIBUTES, 0);
if (!h) {
diff --git a/libcxx/src/include/to_chars_floating_point.h b/libcxx/src/include/to_chars_floating_point.h
index 3110bc20e160..e4715d10d97d 100644
--- a/libcxx/src/include/to_chars_floating_point.h
+++ b/libcxx/src/include/to_chars_floating_point.h
@@ -269,7 +269,7 @@ to_chars_result _Floating_to_chars_hex_precision(
// * Print the leading hexit, then mask it away.
{
const uint32_t _Nibble = static_cast<uint32_t>(_Adjusted_mantissa >> _Adjusted_explicit_bits);
- _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 3, "");
+ _LIBCPP_ASSERT_INTERNAL(_Nibble < 3, "");
const char _Leading_hexit = static_cast<char>('0' + _Nibble);
*_First++ = _Leading_hexit;
@@ -288,12 +288,12 @@ to_chars_result _Floating_to_chars_hex_precision(
int32_t _Number_of_bits_remaining = _Adjusted_explicit_bits; // 24 for float, 52 for double
for (;;) {
- _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining >= 4, "");
- _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining % 4 == 0, "");
+ _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining >= 4, "");
+ _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining % 4 == 0, "");
_Number_of_bits_remaining -= 4;
const uint32_t _Nibble = static_cast<uint32_t>(_Adjusted_mantissa >> _Number_of_bits_remaining);
- _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 16, "");
+ _LIBCPP_ASSERT_INTERNAL(_Nibble < 16, "");
const char _Hexit = __itoa::_Charconv_digits[_Nibble];
*_First++ = _Hexit;
@@ -415,12 +415,12 @@ to_chars_result _Floating_to_chars_hex_shortest(
// '0' hexits, the same condition works (as we print the final hexit and mask it away); we don't need to test
// _Number_of_bits_remaining.
do {
- _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining >= 4, "");
- _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining % 4 == 0, "");
+ _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining >= 4, "");
+ _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining % 4 == 0, "");
_Number_of_bits_remaining -= 4;
const uint32_t _Nibble = static_cast<uint32_t>(_Adjusted_mantissa >> _Number_of_bits_remaining);
- _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 16, "");
+ _LIBCPP_ASSERT_INTERNAL(_Nibble < 16, "");
const char _Hexit = __itoa::_Charconv_digits[_Nibble];
if (_First == _Last) {
@@ -940,13 +940,13 @@ to_chars_result _Floating_to_chars_general_precision(
_Effective_precision = std::min(_Precision - (_Scientific_exponent_X + 1), _Max_fixed_precision);
const to_chars_result _Buf_result =
_Floating_to_chars_fixed_precision(_Buffer, std::end(_Buffer), _Value, _Effective_precision);
- _LIBCPP_ASSERT_UNCATEGORIZED(_Buf_result.ec == errc{}, "");
+ _LIBCPP_ASSERT_INTERNAL(_Buf_result.ec == errc{}, "");
_Significand_last = _Buf_result.ptr;
} else {
_Effective_precision = std::min(_Precision - 1, _Max_scientific_precision);
const to_chars_result _Buf_result =
_Floating_to_chars_scientific_precision(_Buffer, std::end(_Buffer), _Value, _Effective_precision);
- _LIBCPP_ASSERT_UNCATEGORIZED(_Buf_result.ec == errc{}, "");
+ _LIBCPP_ASSERT_INTERNAL(_Buf_result.ec == errc{}, "");
_Significand_last = std::find(_Buffer, _Buf_result.ptr, 'e');
_Exponent_first = _Significand_last;
_Exponent_last = _Buf_result.ptr;
@@ -992,7 +992,7 @@ to_chars_result _Floating_to_chars(
char* _First, char* const _Last, _Floating _Value, const chars_format _Fmt, const int _Precision) noexcept {
if constexpr (_Overload == _Floating_to_chars_overload::_Plain) {
- _LIBCPP_ASSERT_UNCATEGORIZED(_Fmt == chars_format{}, ""); // plain overload must pass chars_format{} internally
+ _LIBCPP_ASSERT_INTERNAL(_Fmt == chars_format{}, ""); // plain overload must pass chars_format{} internally
} else {
_LIBCPP_ASSERT_UNCATEGORIZED(_Fmt == chars_format::general || _Fmt == chars_format::scientific
|| _Fmt == chars_format::fixed || _Fmt == chars_format::hex,
diff --git a/libcxx/src/memory_resource.cpp b/libcxx/src/memory_resource.cpp
index afd1b892086d..42c366893f73 100644
--- a/libcxx/src/memory_resource.cpp
+++ b/libcxx/src/memory_resource.cpp
@@ -230,7 +230,7 @@ public:
}
void* __allocate_in_new_chunk(memory_resource* upstream, size_t block_size, size_t chunk_size) {
- _LIBCPP_ASSERT_UNCATEGORIZED(chunk_size % block_size == 0, "");
+ _LIBCPP_ASSERT_INTERNAL(chunk_size % block_size == 0, "");
static_assert(__default_alignment >= alignof(std::max_align_t), "");
static_assert(__default_alignment >= alignof(__chunk_footer), "");
static_assert(__default_alignment >= alignof(__vacancy_header), "");
diff --git a/libcxx/src/strstream.cpp b/libcxx/src/strstream.cpp
index a9b5989ec495..70374191c6ab 100644
--- a/libcxx/src/strstream.cpp
+++ b/libcxx/src/strstream.cpp
@@ -120,7 +120,7 @@ strstreambuf::int_type strstreambuf::overflow(int_type __c) {
if (buf == nullptr)
return int_type(EOF);
if (old_size != 0) {
- _LIBCPP_ASSERT_UNCATEGORIZED(eback(), "overflow copying from NULL");
+ _LIBCPP_ASSERT_INTERNAL(eback(), "strstreambuf::overflow reallocating but the get area is a null pointer");
memcpy(buf, eback(), static_cast<size_t>(old_size));
}
ptrdiff_t ninp = gptr() - eback();
diff --git a/libcxx/src/system_error.cpp b/libcxx/src/system_error.cpp
index 034b73c5480a..f518b480a278 100644
--- a/libcxx/src/system_error.cpp
+++ b/libcxx/src/system_error.cpp
@@ -68,7 +68,7 @@ __attribute__((unused)) const char* handle_strerror_r_return(int strerror_return
if (new_errno == EINVAL)
return "";
- _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r");
+ _LIBCPP_ASSERT_INTERNAL(new_errno == ERANGE, "unexpected error from ::strerror_r");
// FIXME maybe? 'strerror_buff_size' is likely to exceed the
// maximum error size so ERANGE shouldn't be returned.
std::abort();
diff --git a/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp b/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp
index 8c14b84278cb..cf6b7bef3ebc 100644
--- a/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp
+++ b/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
-// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// REQUIRES: libcpp-hardening-mode=debug
// XFAIL: availability-verbose_abort-missing
// ADDITIONAL_COMPILE_FLAGS: -fno-exceptions
diff --git a/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp b/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp
index 112b687cb17e..f95b83ff4eb3 100644
--- a/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp
+++ b/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// REQUIRES: libcpp-hardening-mode=debug
// XFAIL: availability-verbose_abort-missing
// Make sure that reaching std::unreachable() with assertions enabled triggers an assertion.
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
index 8a019492c12d..f4d2f56c34d9 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
@@ -1923,6 +1924,10 @@ void visitExistingEdges(LinkGraph &G, VisitorTs &&...Vs) {
Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromObject(MemoryBufferRef ObjectBuffer);
+/// Create a \c LinkGraph defining the given absolute symbols.
+std::unique_ptr<LinkGraph> absoluteSymbolsLinkGraph(const Triple &TT,
+ orc::SymbolMap Symbols);
+
/// Link the given graph.
void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx);
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h
index ba164c6b629e..6a9bcf712169 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h
@@ -1210,14 +1210,13 @@ private:
SymbolTableEntry() = default;
SymbolTableEntry(JITSymbolFlags Flags)
: Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
- MaterializerAttached(false), PendingRemoval(false) {}
+ MaterializerAttached(false) {}
ExecutorAddr getAddress() const { return Addr; }
JITSymbolFlags getFlags() const { return Flags; }
SymbolState getState() const { return static_cast<SymbolState>(State); }
bool hasMaterializerAttached() const { return MaterializerAttached; }
- bool isPendingRemoval() const { return PendingRemoval; }
void setAddress(ExecutorAddr Addr) { this->Addr = Addr; }
void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
@@ -1231,18 +1230,13 @@ private:
this->MaterializerAttached = MaterializerAttached;
}
- void setPendingRemoval(bool PendingRemoval) {
- this->PendingRemoval = PendingRemoval;
- }
-
ExecutorSymbolDef getSymbol() const { return {Addr, Flags}; }
private:
ExecutorAddr Addr;
JITSymbolFlags Flags;
- uint8_t State : 6;
+ uint8_t State : 7;
uint8_t MaterializerAttached : 1;
- uint8_t PendingRemoval : 1;
};
using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
index 63797edec89e..e56afe4fe656 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
@@ -25,6 +25,7 @@ class ExecutorProcessControl;
class EPCDynamicLibrarySearchGenerator : public DefinitionGenerator {
public:
using SymbolPredicate = unique_function<bool(const SymbolStringPtr &)>;
+ using AddAbsoluteSymbolsFn = unique_function<Error(JITDylib &, SymbolMap)>;
/// Create a DynamicLibrarySearchGenerator that searches for symbols in the
/// library with the given handle.
@@ -32,24 +33,31 @@ public:
/// If the Allow predicate is given then only symbols matching the predicate
/// will be searched for. If the predicate is not given then all symbols will
/// be searched for.
- EPCDynamicLibrarySearchGenerator(ExecutionSession &ES,
- tpctypes::DylibHandle H,
- SymbolPredicate Allow = SymbolPredicate())
- : EPC(ES.getExecutorProcessControl()), H(H), Allow(std::move(Allow)) {}
+ ///
+ /// If \p AddAbsoluteSymbols is provided, it is used to add the symbols to the
+ /// \c JITDylib; otherwise it uses JD.define(absoluteSymbols(...)).
+ EPCDynamicLibrarySearchGenerator(
+ ExecutionSession &ES, tpctypes::DylibHandle H,
+ SymbolPredicate Allow = SymbolPredicate(),
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr)
+ : EPC(ES.getExecutorProcessControl()), H(H), Allow(std::move(Allow)),
+ AddAbsoluteSymbols(std::move(AddAbsoluteSymbols)) {}
/// Permanently loads the library at the given path and, on success, returns
/// a DynamicLibrarySearchGenerator that will search it for symbol definitions
/// in the library. On failure returns the reason the library failed to load.
static Expected<std::unique_ptr<EPCDynamicLibrarySearchGenerator>>
Load(ExecutionSession &ES, const char *LibraryPath,
- SymbolPredicate Allow = SymbolPredicate());
+ SymbolPredicate Allow = SymbolPredicate(),
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr);
/// Creates a EPCDynamicLibrarySearchGenerator that searches for symbols in
/// the target process.
static Expected<std::unique_ptr<EPCDynamicLibrarySearchGenerator>>
GetForTargetProcess(ExecutionSession &ES,
- SymbolPredicate Allow = SymbolPredicate()) {
- return Load(ES, nullptr, std::move(Allow));
+ SymbolPredicate Allow = SymbolPredicate(),
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr) {
+ return Load(ES, nullptr, std::move(Allow), std::move(AddAbsoluteSymbols));
}
Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
@@ -60,6 +68,7 @@ private:
ExecutorProcessControl &EPC;
tpctypes::DylibHandle H;
SymbolPredicate Allow;
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols;
};
} // end namespace orc
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
index 6a43376a5bd9..f7c286bec778 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
@@ -216,6 +216,7 @@ private:
class DynamicLibrarySearchGenerator : public DefinitionGenerator {
public:
using SymbolPredicate = std::function<bool(const SymbolStringPtr &)>;
+ using AddAbsoluteSymbolsFn = unique_function<Error(JITDylib &, SymbolMap)>;
/// Create a DynamicLibrarySearchGenerator that searches for symbols in the
/// given sys::DynamicLibrary.
@@ -223,22 +224,30 @@ public:
/// If the Allow predicate is given then only symbols matching the predicate
/// will be searched for. If the predicate is not given then all symbols will
/// be searched for.
- DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix,
- SymbolPredicate Allow = SymbolPredicate());
+ ///
+ /// If \p AddAbsoluteSymbols is provided, it is used to add the symbols to the
+ /// \c JITDylib; otherwise it uses JD.define(absoluteSymbols(...)).
+ DynamicLibrarySearchGenerator(
+ sys::DynamicLibrary Dylib, char GlobalPrefix,
+ SymbolPredicate Allow = SymbolPredicate(),
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr);
/// Permanently loads the library at the given path and, on success, returns
/// a DynamicLibrarySearchGenerator that will search it for symbol definitions
/// in the library. On failure returns the reason the library failed to load.
static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>>
Load(const char *FileName, char GlobalPrefix,
- SymbolPredicate Allow = SymbolPredicate());
+ SymbolPredicate Allow = SymbolPredicate(),
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr);
/// Creates a DynamicLibrarySearchGenerator that searches for symbols in
/// the current process.
static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>>
GetForCurrentProcess(char GlobalPrefix,
- SymbolPredicate Allow = SymbolPredicate()) {
- return Load(nullptr, GlobalPrefix, std::move(Allow));
+ SymbolPredicate Allow = SymbolPredicate(),
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr) {
+ return Load(nullptr, GlobalPrefix, std::move(Allow),
+ std::move(AddAbsoluteSymbols));
}
Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
@@ -248,6 +257,7 @@ public:
private:
sys::DynamicLibrary Dylib;
SymbolPredicate Allow;
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols;
char GlobalPrefix;
};
diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
index d86ceb99ded0..7f743dba60a9 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
@@ -468,6 +468,41 @@ createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) {
};
}
+std::unique_ptr<LinkGraph> absoluteSymbolsLinkGraph(const Triple &TT,
+ orc::SymbolMap Symbols) {
+ unsigned PointerSize;
+ endianness Endianness =
+ TT.isLittleEndian() ? endianness::little : endianness::big;
+ switch (TT.getArch()) {
+ case Triple::aarch64:
+ case llvm::Triple::riscv64:
+ case Triple::x86_64:
+ PointerSize = 8;
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::riscv32:
+ case llvm::Triple::x86:
+ PointerSize = 4;
+ break;
+ default:
+ llvm::report_fatal_error("unhandled target architecture");
+ }
+
+ static std::atomic<uint64_t> Counter = {0};
+ auto Index = Counter.fetch_add(1, std::memory_order_relaxed);
+ auto G = std::make_unique<LinkGraph>(
+ "<Absolute Symbols " + std::to_string(Index) + ">", TT, PointerSize,
+ Endianness, /*GetEdgeKindName=*/nullptr);
+ for (auto &[Name, Def] : Symbols) {
+ auto &Sym =
+ G->addAbsoluteSymbol(*Name, Def.getAddress(), /*Size=*/0,
+ Linkage::Strong, Scope::Default, /*IsLive=*/true);
+ Sym.setCallable(Def.getFlags().isCallable());
+ }
+
+ return G;
+}
+
void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx) {
switch (G->getTargetTriple().getObjectFormat()) {
case Triple::MachO:
diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
index 5361272ae79e..01144763ac4c 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
@@ -48,6 +48,14 @@ void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) {
if (auto Err = runPasses(Passes.PostPrunePasses))
return Ctx->notifyFailed(std::move(Err));
+ // Skip straight to phase 2 if the graph is empty with no associated actions.
+ if (G->allocActions().empty() && llvm::all_of(G->sections(), [](Section &S) {
+ return S.getMemLifetime() == orc::MemLifetime::NoAlloc;
+ })) {
+ linkPhase2(std::move(Self), nullptr);
+ return;
+ }
+
Ctx->getMemoryManager().allocate(
Ctx->getJITLinkDylib(), *G,
[S = std::move(Self)](AllocResult AR) mutable {
@@ -163,6 +171,12 @@ void JITLinkerBase::linkPhase3(std::unique_ptr<JITLinkerBase> Self,
if (auto Err = runPasses(Passes.PostFixupPasses))
return abandonAllocAndBailOut(std::move(Self), std::move(Err));
+ // Skip straight to phase 4 if the graph has no allocation.
+ if (!Alloc) {
+ linkPhase4(std::move(Self), JITLinkMemoryManager::FinalizedAlloc{});
+ return;
+ }
+
Alloc->finalize([S = std::move(Self)](FinalizeResult FR) mutable {
// FIXME: Once MSVC implements c++17 order of evaluation rules for calls
// this can be simplified to
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
index 2e2e7a9c5f32..460f4e1c448e 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
@@ -12,15 +12,15 @@ namespace llvm {
namespace orc {
Expected<std::unique_ptr<EPCDynamicLibrarySearchGenerator>>
-EPCDynamicLibrarySearchGenerator::Load(ExecutionSession &ES,
- const char *LibraryPath,
- SymbolPredicate Allow) {
+EPCDynamicLibrarySearchGenerator::Load(
+ ExecutionSession &ES, const char *LibraryPath, SymbolPredicate Allow,
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols) {
auto Handle = ES.getExecutorProcessControl().loadDylib(LibraryPath);
if (!Handle)
return Handle.takeError();
- return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle,
- std::move(Allow));
+ return std::make_unique<EPCDynamicLibrarySearchGenerator>(
+ ES, *Handle, std::move(Allow), std::move(AddAbsoluteSymbols));
}
Error EPCDynamicLibrarySearchGenerator::tryToGenerate(
@@ -62,6 +62,8 @@ Error EPCDynamicLibrarySearchGenerator::tryToGenerate(
return Error::success();
// Define resolved symbols.
+ if (AddAbsoluteSymbols)
+ return AddAbsoluteSymbols(JD, std::move(NewSymbols));
return JD.define(absoluteSymbols(std::move(NewSymbols)));
}
diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
index 8d5608cc4d4c..3952445bb1aa 100644
--- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
@@ -218,19 +218,23 @@ void ItaniumCXAAtExitSupport::runAtExits(void *DSOHandle) {
}
DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator(
- sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow)
+ sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow,
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols)
: Dylib(std::move(Dylib)), Allow(std::move(Allow)),
+ AddAbsoluteSymbols(std::move(AddAbsoluteSymbols)),
GlobalPrefix(GlobalPrefix) {}
Expected<std::unique_ptr<DynamicLibrarySearchGenerator>>
DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix,
- SymbolPredicate Allow) {
+ SymbolPredicate Allow,
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols) {
std::string ErrMsg;
auto Lib = sys::DynamicLibrary::getPermanentLibrary(FileName, &ErrMsg);
if (!Lib.isValid())
return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
return std::make_unique<DynamicLibrarySearchGenerator>(
- std::move(Lib), GlobalPrefix, std::move(Allow));
+ std::move(Lib), GlobalPrefix, std::move(Allow),
+ std::move(AddAbsoluteSymbols));
}
Error DynamicLibrarySearchGenerator::tryToGenerate(
@@ -261,6 +265,8 @@ Error DynamicLibrarySearchGenerator::tryToGenerate(
if (NewSymbols.empty())
return Error::success();
+ if (AddAbsoluteSymbols)
+ return AddAbsoluteSymbols(JD, std::move(NewSymbols));
return JD.define(absoluteSymbols(std::move(NewSymbols)));
}
diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
index 9057300bf043..6c17f14aa4c7 100644
--- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
@@ -1608,6 +1608,8 @@ Error MachOPlatform::MachOPlatformPlugin::prepareSymbolTableRegistration(
SmallVector<jitlink::Symbol *> SymsToProcess;
for (auto *Sym : G.defined_symbols())
SymsToProcess.push_back(Sym);
+ for (auto *Sym : G.absolute_symbols())
+ SymsToProcess.push_back(Sym);
for (auto *Sym : SymsToProcess) {
if (!Sym->hasName())
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index 3d77f82e6569..b8282948034e 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -93,15 +93,20 @@ private:
Interface LGI;
- for (auto *Sym : G.defined_symbols()) {
+ auto AddSymbol = [&](Symbol *Sym) {
// Skip local symbols.
if (Sym->getScope() == Scope::Local)
- continue;
+ return;
assert(Sym->hasName() && "Anonymous non-local symbol?");
LGI.SymbolFlags[ES.intern(Sym->getName())] =
getJITSymbolFlagsForSymbol(*Sym);
- }
+ };
+
+ for (auto *Sym : G.defined_symbols())
+ AddSymbol(Sym);
+ for (auto *Sym : G.absolute_symbols())
+ AddSymbol(Sym);
if (hasInitializerSection(G))
LGI.InitSymbol = makeInitSymbol(ES, G);
@@ -705,6 +710,9 @@ Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR,
if (Err)
return Err;
+ if (!FA)
+ return Error::success();
+
return MR.withResourceKeyDo(
[&](ResourceKey K) { Allocs[K].push_back(std::move(FA)); });
}
diff --git a/llvm/test/CodeGen/Generic/machine-function-splitter.ll b/llvm/test/CodeGen/Generic/machine-function-splitter.ll
index a236f201eaaf..d7cc3941ee7a 100644
--- a/llvm/test/CodeGen/Generic/machine-function-splitter.ll
+++ b/llvm/test/CodeGen/Generic/machine-function-splitter.ll
@@ -12,6 +12,7 @@
; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -aarch64-min-jump-table-entries=4 -enable-split-machine-functions -mfs-psi-cutoff=0 -mfs-count-threshold=2000 | FileCheck %s --dump-input=always -check-prefixes=MFS-OPTS1,MFS-OPTS1-AARCH64
; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -aarch64-min-jump-table-entries=4 -enable-split-machine-functions -mfs-psi-cutoff=950000 | FileCheck %s -check-prefixes=MFS-OPTS2,MFS-OPTS2-AARCH64
; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -aarch64-min-jump-table-entries=4 -enable-split-machine-functions -mfs-split-ehcode | FileCheck %s -check-prefixes=MFS-EH-SPLIT,MFS-EH-SPLIT-AARCH64
+; RUN: llc < %s -mtriple=aarch64 -split-machine-functions -O0 -mfs-psi-cutoff=0 -mfs-count-threshold=10000 | FileCheck %s -check-prefixes=MFS-O0,MFS-O0-AARCH64
; RUN: llc < %s -mtriple=aarch64 -enable-split-machine-functions -aarch64-redzone | FileCheck %s -check-prefixes=MFS-REDZONE-AARCH64
; COM: Machine function splitting with AFDO profiles
@@ -470,9 +471,8 @@ define void @foo16(i1 zeroext %0) nounwind !prof !14 !section_prefix !15 {
; MFS-O0-LABEL: foo16
; MFS-O0-X86: jmp
; MFS-O0-X86-NOT: jmp
-; MFS-O0-AARCH64: br
-; MFS-O0-AARCH64: br
-; MFS-O0-AARCH64-NOT: br
+; MFS-O0-AARCH64: b foo16.cold
+; MFS-O0-AARCH64-NOT: b foo16.cold
; MFS-O0: .section .text.split.foo16
; MFS-O0-NEXT: foo16.cold
%2 = call i32 @baz()
diff --git a/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
index 91659240c9d6..edd12ebb62e1 100644
--- a/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
@@ -10,6 +10,11 @@
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
@@ -173,4 +178,96 @@ TEST_F(ObjectLinkingLayerTest, HandleErrorDuringPostAllocationPass) {
EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_anchor"), Failed());
}
+TEST(ObjectLinkingLayerSearchGeneratorTest, AbsoluteSymbolsObjectLayer) {
+ class TestEPC : public UnsupportedExecutorProcessControl {
+ public:
+ TestEPC()
+ : UnsupportedExecutorProcessControl(nullptr, nullptr,
+ "x86_64-apple-darwin") {}
+
+ Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
+ return ExecutorAddr::fromPtr((void *)nullptr);
+ }
+
+ Expected<std::vector<tpctypes::LookupResult>>
+ lookupSymbols(ArrayRef<LookupRequest> Request) override {
+ std::vector<ExecutorSymbolDef> Result;
+ EXPECT_EQ(Request.size(), 1u);
+ for (auto &LR : Request) {
+ EXPECT_EQ(LR.Symbols.size(), 1u);
+ for (auto &Sym : LR.Symbols) {
+ if (*Sym.first == "_testFunc") {
+ ExecutorSymbolDef Def{ExecutorAddr::fromPtr((void *)0x1000),
+ JITSymbolFlags::Exported};
+ Result.push_back(Def);
+ } else {
+ ADD_FAILURE() << "unexpected symbol request " << *Sym.first;
+ }
+ }
+ }
+ return std::vector<tpctypes::LookupResult>{1, Result};
+ }
+ };
+
+ ExecutionSession ES{std::make_unique<TestEPC>()};
+ JITDylib &JD = ES.createBareJITDylib("main");
+ ObjectLinkingLayer ObjLinkingLayer{
+ ES, std::make_unique<InProcessMemoryManager>(4096)};
+
+ auto G = EPCDynamicLibrarySearchGenerator::GetForTargetProcess(
+ ES, {}, [&](JITDylib &JD, SymbolMap Syms) {
+ auto G =
+ absoluteSymbolsLinkGraph(ES.getTargetTriple(), std::move(Syms));
+ return ObjLinkingLayer.add(JD, std::move(G));
+ });
+ ASSERT_THAT_EXPECTED(G, Succeeded());
+ JD.addGenerator(std::move(*G));
+
+ class CheckDefs : public ObjectLinkingLayer::Plugin {
+ public:
+ ~CheckDefs() { EXPECT_TRUE(SawSymbolDef); }
+
+ void modifyPassConfig(MaterializationResponsibility &MR,
+ jitlink::LinkGraph &G,
+ jitlink::PassConfiguration &Config) override {
+ Config.PostAllocationPasses.push_back([this](LinkGraph &G) {
+ unsigned SymCount = 0;
+ for (Symbol *Sym : G.absolute_symbols()) {
+ SymCount += 1;
+ if (!Sym->hasName()) {
+ ADD_FAILURE() << "unexpected unnamed symbol";
+ continue;
+ }
+ if (Sym->getName() == "_testFunc")
+ SawSymbolDef = true;
+ else
+ ADD_FAILURE() << "unexpected symbol " << Sym->getName();
+ }
+ EXPECT_EQ(SymCount, 1u);
+ return Error::success();
+ });
+ }
+
+ Error notifyFailed(MaterializationResponsibility &MR) override {
+ return Error::success();
+ }
+
+ Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
+ return Error::success();
+ }
+ void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
+ ResourceKey SrcKey) override {
+ llvm_unreachable("unexpected resource transfer");
+ }
+
+ private:
+ bool SawSymbolDef = false;
+ };
+
+ ObjLinkingLayer.addPlugin(std::make_unique<CheckDefs>());
+
+ EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_testFunc"), Succeeded());
+ EXPECT_THAT_ERROR(ES.endSession(), Succeeded());
+}
+
} // end anonymous namespace
diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn
index 56d2c25e06d8..ad4de05f136f 100644
--- a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn
@@ -13,6 +13,7 @@ static_library("readability") {
]
sources = [
"AvoidConstParamsInDecls.cpp",
+ "AvoidReturnWithVoidValueCheck.cpp",
"AvoidUnconditionalPreprocessorIfCheck.cpp",
"BracesAroundStatementsCheck.cpp",
"ConstReturnTypeCheck.cpp",
diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
index 2a1d08330828..5343a12132a9 100644
--- a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
@@ -1162,10 +1162,11 @@ LogicalResult spirv::GlobalVariableOp::verify() {
// TODO: Currently only variable initialization with specialization
// constants and other variables is supported. They could be normal
// constants in the module scope as well.
- if (!initOp ||
- !isa<spirv::GlobalVariableOp, spirv::SpecConstantOp>(initOp)) {
+ if (!initOp || !isa<spirv::GlobalVariableOp, spirv::SpecConstantOp,
+ spirv::SpecConstantCompositeOp>(initOp)) {
return emitOpError("initializer must be result of a "
- "spirv.SpecConstant or spirv.GlobalVariable op");
+ "spirv.SpecConstant or spirv.GlobalVariable or "
+ "spirv.SpecConstantCompositeOp op");
}
}
diff --git a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
index 89e2e7ad52fa..00645d2c4551 100644
--- a/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
+++ b/mlir/lib/Target/SPIRV/Deserialization/Deserializer.cpp
@@ -637,14 +637,22 @@ spirv::Deserializer::processGlobalVariable(ArrayRef<uint32_t> operands) {
// Initializer.
FlatSymbolRefAttr initializer = nullptr;
+
if (wordIndex < operands.size()) {
- auto initializerOp = getGlobalVariable(operands[wordIndex]);
- if (!initializerOp) {
+ Operation *op = nullptr;
+
+ if (auto initOp = getGlobalVariable(operands[wordIndex]))
+ op = initOp;
+ else if (auto initOp = getSpecConstant(operands[wordIndex]))
+ op = initOp;
+ else if (auto initOp = getSpecConstantComposite(operands[wordIndex]))
+ op = initOp;
+ else
return emitError(unknownLoc, "unknown <id> ")
<< operands[wordIndex] << "used as initializer";
- }
+
+ initializer = SymbolRefAttr::get(op);
wordIndex++;
- initializer = SymbolRefAttr::get(initializerOp.getOperation());
}
if (wordIndex != operands.size()) {
return emitError(unknownLoc,
diff --git a/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp b/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp
index 44538c38a41b..7bfcca5b4dcd 100644
--- a/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp
+++ b/mlir/lib/Target/SPIRV/Serialization/SerializeOps.cpp
@@ -383,20 +383,31 @@ Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) {
operands.push_back(static_cast<uint32_t>(varOp.storageClass()));
// Encode initialization.
- if (auto initializer = varOp.getInitializer()) {
- auto initializerID = getVariableID(*initializer);
- if (!initializerID) {
+ StringRef initAttrName = varOp.getInitializerAttrName().getValue();
+ if (std::optional<StringRef> initSymbolName = varOp.getInitializer()) {
+ uint32_t initializerID = 0;
+ auto initRef = varOp->getAttrOfType<FlatSymbolRefAttr>(initAttrName);
+ Operation *initOp = SymbolTable::lookupNearestSymbolFrom(
+ varOp->getParentOp(), initRef.getAttr());
+
+ // Check if initializer is GlobalVariable or SpecConstant* cases.
+ if (isa<spirv::GlobalVariableOp>(initOp))
+ initializerID = getVariableID(*initSymbolName);
+ else
+ initializerID = getSpecConstID(*initSymbolName);
+
+ if (!initializerID)
return emitError(varOp.getLoc(),
"invalid usage of undefined variable as initializer");
- }
+
operands.push_back(initializerID);
- elidedAttrs.push_back("initializer");
+ elidedAttrs.push_back(initAttrName);
}
if (failed(emitDebugLine(typesGlobalValues, varOp.getLoc())))
return failure();
encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpVariable, operands);
- elidedAttrs.push_back("initializer");
+ elidedAttrs.push_back(initAttrName);
// Encode decorations.
for (auto attr : varOp->getAttrs()) {
diff --git a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
index 722e4434aeaf..77b605050e14 100644
--- a/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/structure-ops.mlir
@@ -349,6 +349,19 @@ spirv.SpecConstant @sc = 4.0 : f32
// CHECK: spirv.GlobalVariable @var initializer(@sc)
spirv.GlobalVariable @var initializer(@sc) : !spirv.ptr<f32, Private>
+
+// -----
+// Allow SpecConstantComposite as initializer
+ spirv.module Logical GLSL450 {
+ spirv.SpecConstant @sc1 = 1 : i8
+ spirv.SpecConstant @sc2 = 2 : i8
+ spirv.SpecConstant @sc3 = 3 : i8
+ spirv.SpecConstantComposite @scc (@sc1, @sc2, @sc3) : !spirv.array<3 x i8>
+
+ // CHECK: spirv.GlobalVariable @var initializer(@scc) : !spirv.ptr<!spirv.array<3 x i8>, Private>
+ spirv.GlobalVariable @var initializer(@scc) : !spirv.ptr<!spirv.array<3 x i8>, Private>
+}
+
// -----
spirv.module Logical GLSL450 {
@@ -410,7 +423,7 @@ spirv.module Logical GLSL450 {
// -----
spirv.module Logical GLSL450 {
- // expected-error @+1 {{op initializer must be result of a spirv.SpecConstant or spirv.GlobalVariable op}}
+ // expected-error @+1 {{op initializer must be result of a spirv.SpecConstant or spirv.GlobalVariable or spirv.SpecConstantCompositeOp op}}
spirv.GlobalVariable @var0 initializer(@var1) : !spirv.ptr<f32, Private>
}
diff --git a/mlir/test/Target/SPIRV/global-variable.mlir b/mlir/test/Target/SPIRV/global-variable.mlir
index 66d0782c205c..f22d2a9b3d14 100644
--- a/mlir/test/Target/SPIRV/global-variable.mlir
+++ b/mlir/test/Target/SPIRV/global-variable.mlir
@@ -24,6 +24,30 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
// -----
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
+ // CHECK: spirv.SpecConstant @sc = 1 : i8
+ // CHECK-NEXT: spirv.GlobalVariable @var initializer(@sc) : !spirv.ptr<i8, Uniform>
+ spirv.SpecConstant @sc = 1 : i8
+
+ spirv.GlobalVariable @var initializer(@sc) : !spirv.ptr<i8, Uniform>
+}
+
+// -----
+
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
+ // CHECK: spirv.SpecConstantComposite @scc (@sc0, @sc1, @sc2) : !spirv.array<3 x i8>
+ // CHECK-NEXT: spirv.GlobalVariable @var initializer(@scc) : !spirv.ptr<!spirv.array<3 x i8>, Uniform>
+ spirv.SpecConstant @sc0 = 1 : i8
+ spirv.SpecConstant @sc1 = 2 : i8
+ spirv.SpecConstant @sc2 = 3 : i8
+
+ spirv.SpecConstantComposite @scc (@sc0, @sc1, @sc2) : !spirv.array<3 x i8>
+
+ spirv.GlobalVariable @var initializer(@scc) : !spirv.ptr<!spirv.array<3 x i8>, Uniform>
+}
+
+// -----
+
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
spirv.GlobalVariable @globalInvocationID built_in("GlobalInvocationId") : !spirv.ptr<vector<3xi32>, Input>
spirv.func @foo() "None" {
// CHECK: %[[ADDR:.*]] = spirv.mlir.addressof @globalInvocationID : !spirv.ptr<vector<3xi32>, Input>