168 changes: 168 additions & 0 deletions clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
//===--- BracesAroundStatement.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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file provides utilities to put braces around a statement.
///
//===----------------------------------------------------------------------===//

#include "BracesAroundStatement.h"
#include "../utils/LexerUtils.h"
#include "LexerUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/Lexer.h"

namespace clang::tidy::utils {

BraceInsertionHints::operator bool() const { return DiagnosticPos.isValid(); }

bool BraceInsertionHints::offersFixIts() const {
return OpeningBracePos.isValid() && ClosingBracePos.isValid();
}

unsigned BraceInsertionHints::resultingCompoundLineExtent(
const SourceManager &SourceMgr) const {
return SourceMgr.getSpellingLineNumber(ClosingBracePos) -
SourceMgr.getSpellingLineNumber(OpeningBracePos);
}

FixItHint BraceInsertionHints::openingBraceFixIt() const {
return OpeningBracePos.isValid()
? FixItHint::CreateInsertion(OpeningBracePos, " {")
: FixItHint();
}

FixItHint BraceInsertionHints::closingBraceFixIt() const {
return ClosingBracePos.isValid()
? FixItHint::CreateInsertion(ClosingBracePos, ClosingBrace)
: FixItHint();
}

static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
const LangOptions &LangOpts) {
Token Tok;
SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts);
assert(!Invalid && "Expected a valid token.");

if (Invalid)
return tok::NUM_TOKENS;

return Tok.getKind();
}

static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM,
const LangOptions &LangOpts) {
SourceLocation Loc = lexer::getUnifiedEndLoc(S, SM, LangOpts);
if (!Loc.isValid())
return Loc;

// Start searching right after S.
Loc = Loc.getLocWithOffset(1);

for (;;) {
assert(Loc.isValid());
while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) {
Loc = Loc.getLocWithOffset(1);
}

if (isVerticalWhitespace(*SM.getCharacterData(Loc))) {
// EOL, insert brace before.
break;
}
tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts);
if (TokKind != tok::comment) {
// Non-comment token, insert brace before.
break;
}

SourceLocation TokEndLoc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
SourceRange TokRange(Loc, TokEndLoc);
StringRef Comment = Lexer::getSourceText(
CharSourceRange::getTokenRange(TokRange), SM, LangOpts);
if (Comment.starts_with("/*") && Comment.contains('\n')) {
// Multi-line block comment, insert brace before.
break;
}
// else: Trailing comment, insert brace after the newline.

// Fast-forward current token.
Loc = TokEndLoc;
}
return Loc;
}

BraceInsertionHints getBraceInsertionsHints(const Stmt *const S,
const LangOptions &LangOpts,
const SourceManager &SM,
SourceLocation StartLoc,
SourceLocation EndLocHint) {
// 1) If there's a corresponding "else" or "while", the check inserts "} "
// right before that token.
// 2) If there's a multi-line block comment starting on the same line after
// the location we're inserting the closing brace at, or there's a non-comment
// token, the check inserts "\n}" right before that token.
// 3) Otherwise the check finds the end of line (possibly after some block or
// line comments) and inserts "\n}" right before that EOL.
if (!S || isa<CompoundStmt>(S)) {
// Already inside braces.
return {};
}

// When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt.
// This NullStmt can be detected according to beginning token.
const SourceLocation StmtBeginLoc = S->getBeginLoc();
if (isa<NullStmt>(S) && StmtBeginLoc.isValid() &&
getTokenKind(StmtBeginLoc, SM, LangOpts) == tok::l_brace)
return {};

if (StartLoc.isInvalid())
return {};

// Convert StartLoc to file location, if it's on the same macro expansion
// level as the start of the statement. We also need file locations for
// Lexer::getLocForEndOfToken working properly.
StartLoc = Lexer::makeFileCharRange(
CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM,
LangOpts)
.getBegin();
if (StartLoc.isInvalid())
return {};
StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOpts);

// StartLoc points at the location of the opening brace to be inserted.
SourceLocation EndLoc;
std::string ClosingInsertion;
if (EndLocHint.isValid()) {
EndLoc = EndLocHint;
ClosingInsertion = "} ";
} else {
EndLoc = findEndLocation(*S, SM, LangOpts);
ClosingInsertion = "\n}";
}

assert(StartLoc.isValid());

// Change only if StartLoc and EndLoc are on the same macro expansion level.
// This will also catch invalid EndLoc.
// Example: LLVM_DEBUG( for(...) do_something() );
// In this case fix-it cannot be provided as the semicolon which is not
// visible here is part of the macro. Adding braces here would require adding
// another semicolon.
if (Lexer::makeFileCharRange(
CharSourceRange::getTokenRange(SourceRange(
SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))),
SM, LangOpts)
.isInvalid())
return {StartLoc};
return {StartLoc, EndLoc, ClosingInsertion};
}

} // namespace clang::tidy::utils
75 changes: 75 additions & 0 deletions clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===--- BracesAroundStatement.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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file provides utilities to put braces around a statement.
///
//===----------------------------------------------------------------------===//

#include "clang/AST/Stmt.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"

namespace clang::tidy::utils {

/// A provider of fix-it hints to insert opening and closing braces. An instance
/// of this type is the result of calling `getBraceInsertionsHints` below.
struct BraceInsertionHints {
/// The position of a potential diagnostic. It coincides with the position of
/// the opening brace to insert, but can also just be the place to show a
/// diagnostic in case braces cannot be inserted automatically.
SourceLocation DiagnosticPos;

/// Constructor for a no-hint.
BraceInsertionHints() = default;

/// Constructor for a valid hint that cannot insert braces automatically.
BraceInsertionHints(SourceLocation DiagnosticPos)
: DiagnosticPos(DiagnosticPos) {}

/// Constructor for a hint offering fix-its for brace insertion. Both
/// positions must be valid.
BraceInsertionHints(SourceLocation OpeningBracePos,
SourceLocation ClosingBracePos, std::string ClosingBrace)
: DiagnosticPos(OpeningBracePos), OpeningBracePos(OpeningBracePos),
ClosingBracePos(ClosingBracePos), ClosingBrace(ClosingBrace) {
assert(offersFixIts());
}

/// Indicates whether the hint provides at least the position of a diagnostic.
operator bool() const;

/// Indicates whether the hint provides fix-its to insert braces.
bool offersFixIts() const;

/// The number of lines between the inserted opening brace and its closing
/// counterpart.
unsigned resultingCompoundLineExtent(const SourceManager &SourceMgr) const;

/// Fix-it to insert an opening brace.
FixItHint openingBraceFixIt() const;

/// Fix-it to insert a closing brace.
FixItHint closingBraceFixIt() const;

private:
SourceLocation OpeningBracePos;
SourceLocation ClosingBracePos;
std::string ClosingBrace;
};

/// Create fix-it hints for braces that wrap the given statement when applied.
/// The algorithm computing them respects comment before and after the statement
/// and adds line breaks before the braces accordingly.
BraceInsertionHints
getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts,
const SourceManager &SM, SourceLocation StartLoc,
SourceLocation EndLocHint = SourceLocation());

} // namespace clang::tidy::utils
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyUtils
Aliasing.cpp
ASTUtils.cpp
BracesAroundStatement.cpp
DeclRefExprUtils.cpp
DesignatedInitializers.cpp
ExceptionAnalyzer.cpp
Expand Down
8 changes: 8 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,14 @@ Changes in existing checks
analyzed, se the check now handles the common patterns
`const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`.

- Improved :doc:`readability-avoid-return-with-void-value
<clang-tidy/checks/readability/avoid-return-with-void-value>` check by adding
fix-its.

- Improved :doc:`readability-duplicate-include
<clang-tidy/checks/readability/duplicate-include>` check by excluding include
directives that form the filename using macro.

- Improved :doc:`readability-identifier-naming
<clang-tidy/checks/readability/identifier-naming>` check in `GetConfigPerFile`
mode by resolving symbolic links to header files. Fixed handling of Hungarian
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,30 @@ 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]
// CHECK-FIXES: f1();
}

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]
// CHECK-FIXES: if (b) { f1(); return;
// CHECK-NEXT: }
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]
// CHECK-FIXES: f2();
// CHECK-FIXES-LENIENT: f2();
}

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]
{ return f4<void>(); }
// CHECK-MESSAGES: :[[@LINE-1]]:7: 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]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-FIXES: { f4<void>(); return; }
// CHECK-FIXES-LENIENT: { f4<void>(); return; }
}

void f6() { return; }
Expand All @@ -41,6 +48,8 @@ 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]
// CHECK-FIXES: (void)f7();
// CHECK-FIXES-LENIENT: (void)f7();
}

#define RETURN_VOID return (void)1
Expand All @@ -50,12 +59,12 @@ void f10() {
// 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>
template <typename A>
struct C {
C(A) {}
};

template <class T>
template <class T>
C<T> f11() { return {}; }

using VOID = void;
Expand All @@ -66,4 +75,36 @@ 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]
// CHECK-FIXES: f12(); return;
// CHECK-FIXES-LENIENT: f12(); return;
(void)1;
}

void f14() {
return /* comment */ f1() /* comment */ ;
// 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]
// CHECK-FIXES: /* comment */ f1() /* comment */ ; return;
// CHECK-FIXES-LENIENT: /* comment */ f1() /* comment */ ; return;
(void)1;
}

void f15() {
return/*comment*/f1()/*comment*/;//comment
// 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]
// CHECK-FIXES: /*comment*/f1()/*comment*/; return;//comment
// CHECK-FIXES-LENIENT: /*comment*/f1()/*comment*/; return;//comment
(void)1;
}

void f16(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]
// CHECK-FIXES: if (b) { f1(); return;
// CHECK-NEXT: }
else return f2();
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-FIXES: else { f2(); return;
// CHECK-NEXT: }
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,18 @@ int r;
// CHECK-FIXES: {{^int q;$}}
// CHECK-FIXES-NEXT: {{^#include <sys/types.h>$}}
// CHECK-FIXES-NEXT: {{^int r;$}}

namespace Issue_87303 {
#define RESET_INCLUDE_CACHE
// Expect no warnings

#define MACRO_FILENAME "duplicate-include.h"
#include MACRO_FILENAME
#include "duplicate-include.h"

#define MACRO_FILENAME_2 <duplicate-include2.h>
#include <duplicate-include2.h>
#include MACRO_FILENAME_2

#undef RESET_INCLUDE_CACHE
} // Issue_87303
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def ext_vla_folded_to_constant : ExtWarn<
"variable length array folded to constant array as an extension">,
InGroup<GNUFoldingConstant>;
def err_vla_unsupported : Error<
"variable length arrays are not supported for %select{the current target|'%1'}0">;
"variable length arrays are not supported %select{for the current target|in '%1'}0">;
def err_vla_in_coroutine_unsupported : Error<
"variable length arrays in a coroutine are not supported">;
def note_vla_unsupported : Note<
Expand Down
313 changes: 56 additions & 257 deletions clang/include/clang/Sema/Sema.h

Large diffs are not rendered by default.

224 changes: 224 additions & 0 deletions clang/include/clang/Sema/SemaBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
//===--- SemaBase.h - Common utilities for semantic analysis-----*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the SemaBase class, which provides utilities for Sema
// and its parts like SemaOpenACC.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMABASE_H
#define LLVM_CLANG_SEMA_SEMABASE_H

#include "clang/AST/Decl.h"
#include "clang/AST/Redeclarable.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "llvm/ADT/DenseMap.h"
#include <optional>
#include <type_traits>
#include <utility>
#include <vector>

namespace clang {

class ASTContext;
class DiagnosticsEngine;
class LangOptions;
class Sema;

class SemaBase {
public:
SemaBase(Sema &S);

Sema &SemaRef;

ASTContext &getASTContext() const;
DiagnosticsEngine &getDiagnostics() const;
const LangOptions &getLangOpts() const;

/// Helper class that creates diagnostics with optional
/// template instantiation stacks.
///
/// This class provides a wrapper around the basic DiagnosticBuilder
/// class that emits diagnostics. ImmediateDiagBuilder is
/// responsible for emitting the diagnostic (as DiagnosticBuilder
/// does) and, if the diagnostic comes from inside a template
/// instantiation, printing the template instantiation stack as
/// well.
class ImmediateDiagBuilder : public DiagnosticBuilder {
Sema &SemaRef;
unsigned DiagID;

public:
ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
: DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID)
: DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}

// This is a cunning lie. DiagnosticBuilder actually performs move
// construction in its copy constructor (but due to varied uses, it's not
// possible to conveniently express this as actual move construction). So
// the default copy ctor here is fine, because the base class disables the
// source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op
// in that case anwyay.
ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default;

~ImmediateDiagBuilder();

/// Teach operator<< to produce an object of the correct type.
template <typename T>
friend const ImmediateDiagBuilder &
operator<<(const ImmediateDiagBuilder &Diag, const T &Value) {
const DiagnosticBuilder &BaseDiag = Diag;
BaseDiag << Value;
return Diag;
}

// It is necessary to limit this to rvalue reference to avoid calling this
// function with a bitfield lvalue argument since non-const reference to
// bitfield is not allowed.
template <typename T,
typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
const ImmediateDiagBuilder &operator<<(T &&V) const {
const DiagnosticBuilder &BaseDiag = *this;
BaseDiag << std::move(V);
return *this;
}
};

/// A generic diagnostic builder for errors which may or may not be deferred.
///
/// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch)
/// which are not allowed to appear inside __device__ functions and are
/// allowed to appear in __host__ __device__ functions only if the host+device
/// function is never codegen'ed.
///
/// To handle this, we use the notion of "deferred diagnostics", where we
/// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed.
///
/// This class lets you emit either a regular diagnostic, a deferred
/// diagnostic, or no diagnostic at all, according to an argument you pass to
/// its constructor, thus simplifying the process of creating these "maybe
/// deferred" diagnostics.
class SemaDiagnosticBuilder {
public:
enum Kind {
/// Emit no diagnostics.
K_Nop,
/// Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
K_Immediate,
/// Emit the diagnostic immediately, and, if it's a warning or error, also
/// emit a call stack showing how this function can be reached by an a
/// priori known-emitted function.
K_ImmediateWithCallStack,
/// Create a deferred diagnostic, which is emitted only if the function
/// it's attached to is codegen'ed. Also emit a call stack as with
/// K_ImmediateWithCallStack.
K_Deferred
};

SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID,
const FunctionDecl *Fn, Sema &S);
SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D);
SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default;

// The copy and move assignment operator is defined as deleted pending
// further motivation.
SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete;
SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete;

~SemaDiagnosticBuilder();

bool isImmediate() const { return ImmediateDiag.has_value(); }

/// Convertible to bool: True if we immediately emitted an error, false if
/// we didn't emit an error or we created a deferred error.
///
/// Example usage:
///
/// if (SemaDiagnosticBuilder(...) << foo << bar)
/// return ExprError();
///
/// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably
/// want to use these instead of creating a SemaDiagnosticBuilder yourself.
operator bool() const { return isImmediate(); }

template <typename T>
friend const SemaDiagnosticBuilder &
operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) {
if (Diag.ImmediateDiag)
*Diag.ImmediateDiag << Value;
else if (Diag.PartialDiagId)
Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second
<< Value;
return Diag;
}

// It is necessary to limit this to rvalue reference to avoid calling this
// function with a bitfield lvalue argument since non-const reference to
// bitfield is not allowed.
template <typename T,
typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
const SemaDiagnosticBuilder &operator<<(T &&V) const {
if (ImmediateDiag)
*ImmediateDiag << std::move(V);
else if (PartialDiagId)
getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V);
return *this;
}

friend const SemaDiagnosticBuilder &
operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD);

void AddFixItHint(const FixItHint &Hint) const;

friend ExprResult ExprError(const SemaDiagnosticBuilder &) {
return ExprError();
}
friend StmtResult StmtError(const SemaDiagnosticBuilder &) {
return StmtError();
}
operator ExprResult() const { return ExprError(); }
operator StmtResult() const { return StmtError(); }
operator TypeResult() const { return TypeError(); }
operator DeclResult() const { return DeclResult(true); }
operator MemInitResult() const { return MemInitResult(true); }

using DeferredDiagnosticsType =
llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>,
std::vector<PartialDiagnosticAt>>;

private:
Sema &S;
SourceLocation Loc;
unsigned DiagID;
const FunctionDecl *Fn;
bool ShowCallStack;

// Invariant: At most one of these Optionals has a value.
// FIXME: Switch these to a Variant once that exists.
std::optional<ImmediateDiagBuilder> ImmediateDiag;
std::optional<unsigned> PartialDiagId;

DeferredDiagnosticsType &getDeviceDeferredDiags() const;
};

/// Emit a diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID,
bool DeferHint = false);

/// Emit a partial diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD,
bool DeferHint = false);
};

} // namespace clang

#endif
14 changes: 2 additions & 12 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,14 @@
#include "clang/Basic/OpenACCKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaBase.h"

namespace clang {

class ASTContext;
class DiagnosticEngine;
class LangOptions;
class Sema;

class SemaOpenACC {
class SemaOpenACC : public SemaBase {
public:
SemaOpenACC(Sema &S);

ASTContext &getASTContext() const;
DiagnosticsEngine &getDiagnostics() const;
const LangOptions &getLangOpts() const;

Sema &SemaRef;

/// Called after parsing an OpenACC Clause so that it can be checked.
bool ActOnClause(OpenACCClauseKind ClauseKind, SourceLocation StartLoc);

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2511,6 +2511,7 @@ unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
assert(!P.getGlobal(VD));
assert(!Locals.contains(VD));
(void)VD;
}

// FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ void Environment::setValue(const Expr &E, Value &Val) {
if (auto *RecordVal = dyn_cast<RecordValue>(&Val)) {
assert(isOriginalRecordConstructor(CanonE) ||
&RecordVal->getLoc() == &getResultObjectLocation(CanonE));
(void)RecordVal;
}

assert(CanonE.isPRValue());
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Path.h"

#include <set>

using AIX = clang::driver::toolchains::AIX;
using namespace clang::driver;
using namespace clang::driver::tools;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ bool FormatTokenLexer::tryMergeNullishCoalescingEqual() {
return false;
auto &NullishCoalescing = *(Tokens.end() - 2);
auto &Equal = *(Tokens.end() - 1);
if (NullishCoalescing->getType() != TT_NullCoalescingOperator ||
if (NullishCoalescing->isNot(TT_NullCoalescingOperator) ||
Equal->isNot(tok::equal)) {
return false;
}
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Format/FormatTokenSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ class FormatTokenSource {
// getNextToken() -> a1
// getNextToken() -> a2
virtual FormatToken *insertTokens(ArrayRef<FormatToken *> Tokens) = 0;

[[nodiscard]] FormatToken *getNextNonComment() {
FormatToken *Tok;
do {
Tok = getNextToken();
assert(Tok);
} while (Tok->is(tok::comment));
return Tok;
}
};

class IndexedTokenSource : public FormatTokenSource {
Expand Down
10 changes: 4 additions & 6 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -825,8 +825,7 @@ class AnnotatingParser {
Parent->overwriteFixedType(TT_BinaryOperator);
}
// An arrow after an ObjC method expression is not a lambda arrow.
if (CurrentToken->getType() == TT_ObjCMethodExpr &&
CurrentToken->Next &&
if (CurrentToken->is(TT_ObjCMethodExpr) && CurrentToken->Next &&
CurrentToken->Next->is(TT_TrailingReturnArrow)) {
CurrentToken->Next->overwriteFixedType(TT_Unknown);
}
Expand Down Expand Up @@ -1563,7 +1562,7 @@ class AnnotatingParser {
case tok::l_brace:
if (Style.Language == FormatStyle::LK_TextProto) {
FormatToken *Previous = Tok->getPreviousNonComment();
if (Previous && Previous->getType() != TT_DictLiteral)
if (Previous && Previous->isNot(TT_DictLiteral))
Previous->setType(TT_SelectorName);
}
Scopes.push_back(getScopeType(*Tok));
Expand All @@ -1583,7 +1582,7 @@ class AnnotatingParser {
Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) {
Tok->setType(TT_DictLiteral);
FormatToken *Previous = Tok->getPreviousNonComment();
if (Previous && Previous->getType() != TT_DictLiteral)
if (Previous && Previous->isNot(TT_DictLiteral))
Previous->setType(TT_SelectorName);
}
if (Style.isTableGen())
Expand Down Expand Up @@ -4754,8 +4753,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
// Objective-C dictionary literal -> no space before closing brace.
return false;
}
if (Right.getType() == TT_TrailingAnnotation &&
Right.isOneOf(tok::amp, tok::ampamp) &&
if (Right.is(TT_TrailingAnnotation) && Right.isOneOf(tok::amp, tok::ampamp) &&
Left.isOneOf(tok::kw_const, tok::kw_volatile) &&
(!Right.Next || Right.Next->is(tok::semi))) {
// Match const and volatile ref-qualifiers without any additional
Expand Down
38 changes: 15 additions & 23 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,11 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
nextToken();
continue;
}
tok::TokenKind kind = FormatTok->Tok.getKind();
if (FormatTok->getType() == TT_MacroBlockBegin)
kind = tok::l_brace;
else if (FormatTok->getType() == TT_MacroBlockEnd)
kind = tok::r_brace;
tok::TokenKind Kind = FormatTok->Tok.getKind();
if (FormatTok->is(TT_MacroBlockBegin))
Kind = tok::l_brace;
else if (FormatTok->is(TT_MacroBlockEnd))
Kind = tok::r_brace;

auto ParseDefault = [this, OpeningBrace, IfKind, &IfLBrace, &HasDoWhile,
&HasLabel, &StatementCount] {
Expand All @@ -380,7 +380,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
assert(StatementCount > 0 && "StatementCount overflow!");
};

switch (kind) {
switch (Kind) {
case tok::comment:
nextToken();
addUnwrappedLine();
Expand Down Expand Up @@ -427,11 +427,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
break;
case tok::kw_default: {
unsigned StoredPosition = Tokens->getPosition();
FormatToken *Next;
do {
Next = Tokens->getNextToken();
assert(Next);
} while (Next->is(tok::comment));
auto *Next = Tokens->getNextNonComment();
FormatTok = Tokens->setPosition(StoredPosition);
if (Next->isNot(tok::colon)) {
// default not followed by ':' is not a case label; treat it like
Expand Down Expand Up @@ -497,10 +493,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
assert(Tok->is(tok::l_brace));

do {
FormatToken *NextTok;
do {
NextTok = Tokens->getNextToken();
} while (NextTok->is(tok::comment));
auto *NextTok = Tokens->getNextNonComment();

if (!Line->InMacroBody && !Style.isTableGen()) {
// Skip PPDirective lines and comments.
Expand Down Expand Up @@ -3280,8 +3273,8 @@ void UnwrappedLineParser::parseSwitch() {
}

// Operators that can follow a C variable.
static bool isCOperatorFollowingVar(tok::TokenKind kind) {
switch (kind) {
static bool isCOperatorFollowingVar(tok::TokenKind Kind) {
switch (Kind) {
case tok::ampamp:
case tok::ampequal:
case tok::arrow:
Expand Down Expand Up @@ -4709,14 +4702,13 @@ void UnwrappedLineParser::readToken(int LevelDifference) {
do {
FormatTok = Tokens->getNextToken();
assert(FormatTok);
while (FormatTok->getType() == TT_ConflictStart ||
FormatTok->getType() == TT_ConflictEnd ||
FormatTok->getType() == TT_ConflictAlternative) {
if (FormatTok->getType() == TT_ConflictStart)
while (FormatTok->isOneOf(TT_ConflictStart, TT_ConflictEnd,
TT_ConflictAlternative)) {
if (FormatTok->is(TT_ConflictStart))
conditionalCompilationStart(/*Unreachable=*/false);
else if (FormatTok->getType() == TT_ConflictAlternative)
else if (FormatTok->is(TT_ConflictAlternative))
conditionalCompilationAlternative();
else if (FormatTok->getType() == TT_ConflictEnd)
else if (FormatTok->is(TT_ConflictEnd))
conditionalCompilationEnd();
FormatTok = Tokens->getNextToken();
FormatTok->MustBreakBefore = true;
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
Style.ReferenceAlignment != FormatStyle::RAS_Right &&
Style.ReferenceAlignment != FormatStyle::RAS_Pointer;
for (int Previous = i - 1;
Previous >= 0 &&
Changes[Previous].Tok->getType() == TT_PointerOrReference;
Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference);
--Previous) {
assert(Changes[Previous].Tok->isPointerOrReference());
if (Changes[Previous].Tok->isNot(tok::star)) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ add_clang_library(clangSema
SemaAttr.cpp
SemaAPINotes.cpp
SemaAvailability.cpp
SemaBase.cpp
SemaCXXScopeSpec.cpp
SemaCast.cpp
SemaChecking.cpp
Expand Down
45 changes: 9 additions & 36 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,15 @@ const uint64_t Sema::MaximumAlignment;

Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
: CollectStats(false), TUKind(TUKind), CurFPFeatures(pp.getLangOpts()),
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
APINotes(SourceMgr, LangOpts), AnalysisWarnings(*this),
ThreadSafetyDeclCache(nullptr), LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr),
CurContext(nullptr), ExternalSource(nullptr), CurScope(nullptr),
Ident_super(nullptr), OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
: SemaBase(*this), CollectStats(false), TUKind(TUKind),
CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
SourceMgr(PP.getSourceManager()), APINotes(SourceMgr, LangOpts),
AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr),
CurScope(nullptr), Ident_super(nullptr),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()),
Expand Down Expand Up @@ -1612,11 +1613,6 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
PrintContextStack();
}

Sema::SemaDiagnosticBuilder
Sema::Diag(SourceLocation Loc, const PartialDiagnostic &PD, bool DeferHint) {
return Diag(Loc, PD.getDiagID(), DeferHint) << PD;
}

bool Sema::hasUncompilableErrorOccurred() const {
if (getDiagnostics().hasUncompilableErrorOccurred())
return true;
Expand Down Expand Up @@ -1911,29 +1907,6 @@ Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) {
FD, *this);
}

Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID,
bool DeferHint) {
bool IsError = Diags.getDiagnosticIDs()->isDefaultMappingAsError(DiagID);
bool ShouldDefer = getLangOpts().CUDA && LangOpts.GPUDeferDiag &&
DiagnosticIDs::isDeferrable(DiagID) &&
(DeferHint || DeferDiags || !IsError);
auto SetIsLastErrorImmediate = [&](bool Flag) {
if (IsError)
IsLastErrorImmediate = Flag;
};
if (!ShouldDefer) {
SetIsLastErrorImmediate(true);
return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc,
DiagID, getCurFunctionDecl(), *this);
}

SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice
? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
SetIsLastErrorImmediate(DB.isImmediate());
return DB;
}

void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
if (isUnevaluatedContext() || Ty.isNull())
return;
Expand Down
85 changes: 85 additions & 0 deletions clang/lib/Sema/SemaBase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "clang/Sema/SemaBase.h"
#include "clang/Sema/Sema.h"

namespace clang {

SemaBase::SemaBase(Sema &S) : SemaRef(S) {}

ASTContext &SemaBase::getASTContext() const { return SemaRef.Context; }
DiagnosticsEngine &SemaBase::getDiagnostics() const { return SemaRef.Diags; }
const LangOptions &SemaBase::getLangOpts() const { return SemaRef.LangOpts; }

SemaBase::ImmediateDiagBuilder::~ImmediateDiagBuilder() {
// If we aren't active, there is nothing to do.
if (!isActive())
return;

// Otherwise, we need to emit the diagnostic. First clear the diagnostic
// builder itself so it won't emit the diagnostic in its own destructor.
//
// This seems wasteful, in that as written the DiagnosticBuilder dtor will
// do its own needless checks to see if the diagnostic needs to be
// emitted. However, because we take care to ensure that the builder
// objects never escape, a sufficiently smart compiler will be able to
// eliminate that code.
Clear();

// Dispatch to Sema to emit the diagnostic.
SemaRef.EmitCurrentDiagnostic(DiagID);
}

const SemaBase::SemaDiagnosticBuilder &
operator<<(const SemaBase::SemaDiagnosticBuilder &Diag,
const PartialDiagnostic &PD) {
if (Diag.ImmediateDiag)
PD.Emit(*Diag.ImmediateDiag);
else if (Diag.PartialDiagId)
Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD;
return Diag;
}

void SemaBase::SemaDiagnosticBuilder::AddFixItHint(
const FixItHint &Hint) const {
if (ImmediateDiag)
ImmediateDiag->AddFixItHint(Hint);
else if (PartialDiagId)
S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint);
}

llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>,
std::vector<PartialDiagnosticAt>> &
SemaBase::SemaDiagnosticBuilder::getDeviceDeferredDiags() const {
return S.DeviceDeferredDiags;
}

Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, unsigned DiagID,
bool DeferHint) {
bool IsError =
getDiagnostics().getDiagnosticIDs()->isDefaultMappingAsError(DiagID);
bool ShouldDefer = getLangOpts().CUDA && getLangOpts().GPUDeferDiag &&
DiagnosticIDs::isDeferrable(DiagID) &&
(DeferHint || SemaRef.DeferDiags || !IsError);
auto SetIsLastErrorImmediate = [&](bool Flag) {
if (IsError)
SemaRef.IsLastErrorImmediate = Flag;
};
if (!ShouldDefer) {
SetIsLastErrorImmediate(true);
return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc,
DiagID, SemaRef.getCurFunctionDecl(), SemaRef);
}

SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice
? SemaRef.CUDADiagIfDeviceCode(Loc, DiagID)
: SemaRef.CUDADiagIfHostCode(Loc, DiagID);
SetIsLastErrorImmediate(DB.isImmediate());
return DB;
}

Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc,
const PartialDiagnostic &PD,
bool DeferHint) {
return Diag(Loc, PD.getDiagID(), DeferHint) << PD;
}

} // namespace clang
832 changes: 412 additions & 420 deletions clang/lib/Sema/SemaChecking.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7479,7 +7479,7 @@ ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy,
SourceLocation RParenLoc) {
TypeSourceInfo *TInfo;
GetTypeFromParser(ParsedDestTy, &TInfo);
return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
return ConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
}

/// BuildResolvedCallExpr - Build a call to a resolved expression,
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3938,9 +3938,8 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
llvm_unreachable("Unreachable, bad result from BestViableFunction");
}

ExprResult
Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult,
bool IsDelete) {
ExprResult Sema::BuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult,
bool IsDelete) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
if (!getLangOpts().CPlusPlus) {
Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language)
Expand Down Expand Up @@ -6026,6 +6025,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
return false;
}
case BTT_IsLayoutCompatible: {
if (LhsT->isVariableArrayType() || RhsT->isVariableArrayType())
Self.Diag(KeyLoc, diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
return Self.IsLayoutCompatible(LhsT, RhsT);
}
default: llvm_unreachable("not a BTT");
Expand Down
16 changes: 5 additions & 11 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//

#include "clang/AST/StmtOpenACC.h"
#include "clang/Sema/SemaOpenACC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/Sema.h"

Expand All @@ -31,19 +31,14 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
if (!IsStmt)
return S.SemaRef.Diag(StartLoc, diag::err_acc_construct_appertainment)
<< K;
return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K;
break;
}
return false;
}
} // namespace

SemaOpenACC::SemaOpenACC(Sema &S) : SemaRef(S) {}

ASTContext &SemaOpenACC::getASTContext() const { return SemaRef.Context; }
DiagnosticsEngine &SemaOpenACC::getDiagnostics() const { return SemaRef.Diags; }
const LangOptions &SemaOpenACC::getLangOpts() const { return SemaRef.LangOpts; }
SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}

bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind,
SourceLocation StartLoc) {
Expand All @@ -53,8 +48,7 @@ bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind,
// whatever it can do. This function will eventually need to start returning
// some sort of Clause AST type, but for now just return true/false based on
// success.
return SemaRef.Diag(StartLoc, diag::warn_acc_clause_unimplemented)
<< ClauseKind;
return Diag(StartLoc, diag::warn_acc_clause_unimplemented) << ClauseKind;
}
void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
SourceLocation StartLoc) {
Expand All @@ -72,7 +66,7 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
// here as these constructs do not take any arguments.
break;
default:
SemaRef.Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K;
Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K;
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6354,6 +6354,7 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value,
// by this point.
assert(CE->getResultStorageKind() != ConstantResultStorageKind::None &&
"ConstantExpr has no value associated with it");
(void)CE;
} else {
E = ConstantExpr::Create(Context, Result.get(), Value);
}
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -3890,15 +3890,14 @@ class TreeTransform {
FPOptionsOverride());

// Type-check the __builtin_shufflevector expression.
return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.get()));
return SemaRef.BuiltinShuffleVector(cast<CallExpr>(TheCall.get()));
}

/// Build a new convert vector expression.
ExprResult RebuildConvertVectorExpr(SourceLocation BuiltinLoc,
Expr *SrcExpr, TypeSourceInfo *DstTInfo,
SourceLocation RParenLoc) {
return SemaRef.SemaConvertVectorExpr(SrcExpr, DstTInfo,
BuiltinLoc, RParenLoc);
return SemaRef.ConvertVectorExpr(SrcExpr, DstTInfo, BuiltinLoc, RParenLoc);
}

/// Build a new template argument pack expansion.
Expand Down
40 changes: 40 additions & 0 deletions clang/test/CXX/drs/dr392.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK

#if __cplusplus == 199711L
#define NOTHROW throw()
#else
#define NOTHROW noexcept(true)
#endif

namespace dr392 { // dr392: 2.8

struct A {
operator bool() NOTHROW;
};

class C {
public:
C() NOTHROW;
~C() NOTHROW;
A& get() NOTHROW { return p; }
private:
A p;
};

void f()
{
if (C().get()) {}
}

} // namespace dr392

// CHECK-LABEL: define {{.*}} void @dr392::f()()
// CHECK: call {{.*}} i1 @dr392::A::operator bool()
// CHECK: call void @dr392::C::~C()
// CHECK-LABEL: }
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/dr3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@ namespace dr387 { // dr387: 2.8
}
}

// FIXME: dr388 needs codegen test
// FIXME: dr388 needs libc++abi test

namespace dr389 { // dr389: no
struct S {
Expand Down Expand Up @@ -1567,7 +1567,7 @@ namespace dr391 { // dr391: 2.8 c++11
const C<int> &c = fc();
}

// dr392 FIXME write codegen test
// dr392 is in dr392.cpp
// dr394: na

namespace dr395 { // dr395: 3.0
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/dr4xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ namespace dr460 { // dr460: yes
// dr464: na
// dr465: na

namespace dr466 { // dr466: no
namespace dr466 { // dr466: 2.8
typedef int I;
typedef const int CI;
typedef volatile int VI;
Expand All @@ -960,7 +960,7 @@ namespace dr466 { // dr466: no
a->CI::~CI();
a->VI::~VI();

a->CI::~VI(); // FIXME: This is invalid; CI and VI are not the same scalar type.
a->CI::~VI(); // allowed by changes to [expr.id.prim.qual]/2 introduced in P1131R2

b->~I();
b->~CI();
Expand Down
10 changes: 6 additions & 4 deletions clang/test/SemaCXX/type-traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ void is_bounded_array(int n) {
static_assert(!__is_bounded_array(cvoid *));

int t32[n];
(void)__is_bounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported for '__is_bounded_array'}}
(void)__is_bounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported in '__is_bounded_array'}}
}

void is_unbounded_array(int n) {
Expand Down Expand Up @@ -772,7 +772,7 @@ void is_unbounded_array(int n) {
static_assert(!__is_unbounded_array(cvoid *));

int t32[n];
(void)__is_unbounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported for '__is_unbounded_array'}}
(void)__is_unbounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported in '__is_unbounded_array'}}
}

void is_referenceable() {
Expand Down Expand Up @@ -1741,8 +1741,10 @@ void is_layout_compatible(int n)
static_assert(!__is_layout_compatible(unsigned char, signed char));
static_assert(__is_layout_compatible(int[], int[]));
static_assert(__is_layout_compatible(int[2], int[2]));
static_assert(!__is_layout_compatible(int[n], int[2])); // FIXME: VLAs should be rejected
static_assert(!__is_layout_compatible(int[n], int[n])); // FIXME: VLAs should be rejected
static_assert(!__is_layout_compatible(int[n], int[2]));
// expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
static_assert(!__is_layout_compatible(int[n], int[n]));
// expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
static_assert(__is_layout_compatible(int&, int&));
static_assert(!__is_layout_compatible(int&, char&));
static_assert(__is_layout_compatible(void(int), void(int)));
Expand Down
7 changes: 3 additions & 4 deletions clang/utils/TableGen/MveEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ class ACLEIntrinsic {
llvm::APInt ArgTypeRange = llvm::APInt::getMaxValue(ArgTypeBits).zext(128);
llvm::APInt ActualRange = (hi-lo).trunc(64).sext(128);
if (ActualRange.ult(ArgTypeRange))
SemaChecks.push_back("SemaBuiltinConstantArgRange(TheCall, " + Index +
SemaChecks.push_back("BuiltinConstantArgRange(TheCall, " + Index +
", " + signedHexLiteral(lo) + ", " +
signedHexLiteral(hi) + ")");

Expand All @@ -942,9 +942,8 @@ class ACLEIntrinsic {
}
Suffix = (Twine(", ") + Arg).str();
}
SemaChecks.push_back((Twine("SemaBuiltinConstantArg") +
IA.ExtraCheckType + "(TheCall, " + Index +
Suffix + ")")
SemaChecks.push_back((Twine("BuiltinConstantArg") + IA.ExtraCheckType +
"(TheCall, " + Index + Suffix + ")")
.str());
}

Expand Down
4 changes: 2 additions & 2 deletions clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -2392,7 +2392,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/392.html">392</a></td>
<td>CD1</td>
<td>Use of full expression lvalue before temporary destruction</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.8</td>
</tr>
<tr id="393">
<td><a href="https://cplusplus.github.io/CWG/issues/393.html">393</a></td>
Expand Down Expand Up @@ -2836,7 +2836,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/466.html">466</a></td>
<td>CD1</td>
<td>cv-qualifiers on pseudo-destructor type</td>
<td class="none" align="center">No</td>
<td class="full" align="center">Clang 2.8</td>
</tr>
<tr id="467">
<td><a href="https://cplusplus.github.io/CWG/issues/467.html">467</a></td>
Expand Down
23 changes: 23 additions & 0 deletions compiler-rt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,29 @@ string(APPEND COMPILER_RT_TEST_COMPILER_CFLAGS " ${stdlib_flag}")
string(REPLACE " " ";" COMPILER_RT_UNITTEST_CFLAGS "${COMPILER_RT_TEST_COMPILER_CFLAGS}")
set(COMPILER_RT_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_CFLAGS})

option(COMPILER_RT_TEST_STANDALONE_BUILD_LIBS
"When set to ON and testing in a standalone build, test the runtime \
libraries built by this standalone build rather than the runtime libraries \
shipped with the compiler (used for testing). When set to OFF and testing \
in a standalone build, test the runtime libraries shipped with the compiler \
(used for testing). This option has no effect if the compiler and this \
build are configured to use the same runtime library path."
ON)
if (COMPILER_RT_TEST_STANDALONE_BUILD_LIBS)
# Ensure that the unit tests can find the sanitizer headers prior to installation.
list(APPEND COMPILER_RT_UNITTEST_CFLAGS "-I${CMAKE_CURRENT_LIST_DIR}/include")
# Ensure that unit tests link against the just-built runtime libraries instead
# of the ones bundled with the compiler by overriding the resource directory.
#
if ("${COMPILER_RT_TEST_COMPILER_ID}" MATCHES "Clang")
list(APPEND COMPILER_RT_UNITTEST_LINK_FLAGS "-resource-dir=${COMPILER_RT_OUTPUT_DIR}")
endif()
get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} rtlib_dir)
if (NOT WIN32)
list(APPEND COMPILER_RT_UNITTEST_LINK_FLAGS "-Wl,-rpath,${rtlib_dir}")
endif()
endif()

if(COMPILER_RT_USE_LLVM_UNWINDER)
# We're linking directly against the libunwind that we're building so don't
# try to link in the toolchain's default libunwind which may be missing.
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/cmake/Modules/AddCompilerRT.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,7 @@ function(configure_compiler_rt_lit_site_cfg input output)
get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir)

string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER})
string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_OUTPUT_DIR ${COMPILER_RT_OUTPUT_DIR})
string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR ${output_dir})

configure_lit_site_cfg(${input} ${output})
Expand Down
8 changes: 0 additions & 8 deletions compiler-rt/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
# Needed for lit support in standalone builds.
include(AddLLVM)

option(COMPILER_RT_TEST_STANDALONE_BUILD_LIBS
"When set to ON and testing in a standalone build, test the runtime \
libraries built by this standalone build rather than the runtime libraries \
shipped with the compiler (used for testing). When set to OFF and testing \
in a standalone build, test the runtime libraries shipped with the compiler \
(used for testing). This option has no effect if the compiler and this \
build are configured to use the same runtime library path."
ON)
pythonize_bool(COMPILER_RT_TEST_STANDALONE_BUILD_LIBS)

pythonize_bool(LLVM_ENABLE_EXPENSIVE_CHECKS)
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/fuzzer/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=False):
return " ".join(
[
compiler_cmd,
config.target_cflags,
std_cmd,
"-O2 -gline-tables-only",
sanitizers_cmd,
Expand Down
86 changes: 64 additions & 22 deletions compiler-rt/test/lit.common.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@
import lit.util


def get_path_from_clang(args, allow_failure):
clang_cmd = [
config.clang.strip(),
f"--target={config.target_triple}",
*args,
]
path = None
try:
result = subprocess.run(
clang_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
)
path = result.stdout.decode().strip()
except subprocess.CalledProcessError as e:
msg = f"Failed to run {clang_cmd}\nrc:{e.returncode}\nstdout:{e.stdout}\ne.stderr{e.stderr}"
if allow_failure:
lit_config.warning(msg)
else:
lit_config.fatal(msg)
return path, clang_cmd


def find_compiler_libdir():
"""
Returns the path to library resource directory used
Expand All @@ -26,26 +47,6 @@ def find_compiler_libdir():
# TODO: Support other compilers.
return None

def get_path_from_clang(args, allow_failure):
clang_cmd = [
config.clang.strip(),
f"--target={config.target_triple}",
]
clang_cmd.extend(args)
path = None
try:
result = subprocess.run(
clang_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
)
path = result.stdout.decode().strip()
except subprocess.CalledProcessError as e:
msg = f"Failed to run {clang_cmd}\nrc:{e.returncode}\nstdout:{e.stdout}\ne.stderr{e.stderr}"
if allow_failure:
lit_config.warning(msg)
else:
lit_config.fatal(msg)
return path, clang_cmd

# Try using `-print-runtime-dir`. This is only supported by very new versions of Clang.
# so allow failure here.
runtime_dir, clang_cmd = get_path_from_clang(
Expand Down Expand Up @@ -168,10 +169,51 @@ def push_dynamic_library_lookup_path(config, new_path):
r"/i386(?=-[^/]+$)", "/x86_64", config.compiler_rt_libdir
)


# Check if the test compiler resource dir matches the local build directory
# (which happens with -DLLVM_ENABLE_PROJECTS=clang;compiler-rt) or if we are
# using an installed clang to test compiler-rt standalone. In the latter case
# we may need to override the resource dir to match the path of the just-built
# compiler-rt libraries.
test_cc_resource_dir, _ = get_path_from_clang(
shlex.split(config.target_cflags) + ["-print-resource-dir"], allow_failure=True
)
# Normalize the path for comparison
if test_cc_resource_dir is not None:
test_cc_resource_dir = os.path.realpath(test_cc_resource_dir)
if lit_config.debug:
lit_config.note(f"Resource dir for {config.clang} is {test_cc_resource_dir}")
local_build_resource_dir = os.path.realpath(config.compiler_rt_output_dir)
if test_cc_resource_dir != local_build_resource_dir and config.test_standalone_build_libs:
if config.compiler_id == "Clang":
if lit_config.debug:
lit_config.note(
f"Overriding test compiler resource dir to use "
f'libraries in "{config.compiler_rt_libdir}"'
)
# Ensure that we use the just-built static libraries when linking by
# overriding the Clang resource directory. Additionally, we want to use
# the builtin headers shipped with clang (e.g. stdint.h), so we
# explicitly add this as an include path (since the headers are not
# going to be in the current compiler-rt build directory).
# We also tell the linker to add an RPATH entry for the local library
# directory so that the just-built shared libraries are used.
config.target_cflags += f" -nobuiltininc"
config.target_cflags += f" -I{config.compiler_rt_src_root}/include"
config.target_cflags += f" -idirafter {test_cc_resource_dir}/include"
config.target_cflags += f" -resource-dir={config.compiler_rt_output_dir}"
config.target_cflags += f" -Wl,-rpath,{config.compiler_rt_libdir}"
else:
lit_config.warning(
f"Cannot override compiler-rt library directory with non-Clang "
f"compiler: {config.compiler_id}"
)


# Ask the compiler for the path to libraries it is going to use. If this
# doesn't match config.compiler_rt_libdir then it means we might be testing the
# compiler's own runtime libraries rather than the ones we just built.
# Warn about about this and handle appropriately.
# Warn about this and handle appropriately.
compiler_libdir = find_compiler_libdir()
if compiler_libdir:
compiler_rt_libdir_real = os.path.realpath(config.compiler_rt_libdir)
Expand All @@ -182,7 +224,7 @@ def push_dynamic_library_lookup_path(config, new_path):
f'compiler-rt libdir: "{compiler_rt_libdir_real}"'
)
if config.test_standalone_build_libs:
# Use just built runtime libraries, i.e. the the libraries this built just built.
# Use just built runtime libraries, i.e. the libraries this build just built.
if not config.test_suite_supports_overriding_runtime_lib_path:
# Test suite doesn't support this configuration.
# TODO(dliew): This should be an error but it seems several bots are
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/lit.common.configured.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ set_default("compiler_id", "@COMPILER_RT_TEST_COMPILER_ID@")
set_default("python_executable", "@Python3_EXECUTABLE@")
set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@)
set_default("compiler_rt_intercept_libdispatch", @COMPILER_RT_INTERCEPT_LIBDISPATCH_PYBOOL@)
set_default("compiler_rt_output_dir", "@COMPILER_RT_RESOLVED_OUTPUT_DIR@")
set_default("compiler_rt_libdir", "@COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR@")
set_default("emulator", "@COMPILER_RT_EMULATOR@")
set_default("asan_shadow_scale", "@COMPILER_RT_ASAN_SHADOW_SCALE@")
Expand Down
10 changes: 8 additions & 2 deletions compiler-rt/test/safestack/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@

# Add clang substitutions.
config.substitutions.append(
("%clang_nosafestack ", config.clang + " -O0 -fno-sanitize=safe-stack ")
(
"%clang_nosafestack ",
config.clang + config.target_cflags + " -O0 -fno-sanitize=safe-stack ",
)
)
config.substitutions.append(
("%clang_safestack ", config.clang + " -O0 -fsanitize=safe-stack ")
(
"%clang_safestack ",
config.clang + config.target_cflags + " -O0 -fsanitize=safe-stack ",
)
)

if config.lto_supported:
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3772,7 +3772,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
localSymbols.pushScope();
auto transferKindAttr = fir::CUDADataTransferKindAttr::get(
builder.getContext(), fir::CUDADataTransferKind::DeviceHost);
unsigned nbDeviceResidentObject = 0;
[[maybe_unused]] unsigned nbDeviceResidentObject = 0;
for (const Fortran::semantics::Symbol &sym :
Fortran::evaluate::CollectSymbols(assign.rhs)) {
if (const auto *details =
Expand Down
2 changes: 1 addition & 1 deletion libc/fuzzing/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ add_libc_fuzzer(
SRCS
uint_fuzz.cpp
DEPENDS
libc.src.__support.uint
libc.src.__support.big_int
)
2 changes: 1 addition & 1 deletion libc/fuzzing/__support/uint_fuzz.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "src/__support/CPP/bit.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"
#include "src/string/memory_utils/inline_memcpy.h"

using namespace LIBC_NAMESPACE;
Expand Down
21 changes: 21 additions & 0 deletions libc/hdr/math_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@

#include <math.h>

// Some older math.h header does not have FP_INT_* constants yet.
#ifndef FP_INT_UPWARD
#define FP_INT_UPWARD 0
#endif // FP_INT_UPWARD

#ifndef FP_INT_DOWNWARD
#define FP_INT_DOWNWARD 1
#endif // FP_INT_DOWNWARD

#ifndef FP_INT_TOWARDZERO
#define FP_INT_TOWARDZERO 2
#endif // FP_INT_TOWARDZERO

#ifndef FP_INT_TONEARESTFROMZERO
#define FP_INT_TONEARESTFROMZERO 3
#endif // FP_INT_TONEARESTFROMZERO

#ifndef FP_INT_TONEAREST
#define FP_INT_TONEAREST 4
#endif // FP_INT_TONEAREST

#endif // LLVM_LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_MATH_MACROS_H
10 changes: 5 additions & 5 deletions libc/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ add_header_library(
HDRS
integer_to_string.h
DEPENDS
.uint
.big_int
libc.src.__support.common
libc.src.__support.CPP.algorithm
libc.src.__support.CPP.limits
Expand Down Expand Up @@ -204,9 +204,9 @@ add_header_library(
)

add_header_library(
uint
big_int
HDRS
UInt.h
big_int.h
DEPENDS
.math_extras
.number_pair
Expand All @@ -220,9 +220,9 @@ add_header_library(
add_header_library(
uint128
HDRS
UInt128.h
uint128.h
DEPENDS
.uint
.big_int
libc.src.__support.macros.properties.types
)

Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/BasicOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

#include "FEnvImpl.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/uint128.h"

namespace LIBC_NAMESPACE {
namespace fputil {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ add_header_library(
DEPENDS
.fp_bits
.multiply_add
libc.src.__support.big_int
libc.src.__support.common
libc.src.__support.uint
libc.src.__support.macros.optimization
)

Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/FPBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@

#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/libc_assert.h" // LIBC_ASSERT
#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_FLOAT128
#include "src/__support/math_extras.h" // mask_trailing_ones
#include "src/__support/sign.h" // Sign
#include "src/__support/uint128.h"

#include <stdint.h>

Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/Hypot.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#include "rounding_mode.h"
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/uint128.h"

namespace LIBC_NAMESPACE {
namespace fputil {
Expand Down
8 changes: 5 additions & 3 deletions libc/src/__support/FPUtil/dyadic_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "FPBits.h"
#include "multiply_add.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY

#include <stddef.h>
Expand Down Expand Up @@ -122,15 +122,17 @@ template <size_t Bits> struct DyadicFloat {

int exp_lo = exp_hi - static_cast<int>(PRECISION) - 1;

MantissaType m_hi(mantissa >> shift);
MantissaType m_hi =
shift >= MantissaType::BITS ? MantissaType(0) : mantissa >> shift;

T d_hi = FPBits<T>::create_value(
sign, exp_hi,
(static_cast<output_bits_t>(m_hi) & FPBits<T>::SIG_MASK) |
IMPLICIT_MASK)
.get_val();

MantissaType round_mask = MantissaType(1) << (shift - 1);
MantissaType round_mask =
shift > MantissaType::BITS ? 0 : MantissaType(1) << (shift - 1);
MantissaType sticky_mask = round_mask - MantissaType(1);

bool round_bit = !(mantissa & round_mask).is_zero();
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/generic/FMA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/UInt128.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/uint128.h"

namespace LIBC_NAMESPACE {
namespace fputil {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/generic/sqrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/uint128.h"

namespace LIBC_NAMESPACE {
namespace fputil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/uint128.h"

namespace LIBC_NAMESPACE {
namespace fputil {
Expand Down
12 changes: 5 additions & 7 deletions libc/src/__support/UInt.h → libc/src/__support/big_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,19 +249,15 @@ LIBC_INLINE constexpr bool is_negative(cpp::array<word, N> &array) {
enum Direction { LEFT, RIGHT };

// A bitwise shift on an array of elements.
// TODO: Make the result UB when 'offset' is greater or equal to the number of
// bits in 'array'. This will allow for better code performance.
// 'offset' must be less than TOTAL_BITS (i.e., sizeof(word) * CHAR_BIT * N)
// otherwise the behavior is undefined.
template <Direction direction, bool is_signed, typename word, size_t N>
LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
size_t offset) {
static_assert(direction == LEFT || direction == RIGHT);
constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits;
constexpr size_t TOTAL_BITS = N * WORD_BITS;
if (LIBC_UNLIKELY(offset == 0))
return array;
if (LIBC_UNLIKELY(offset >= TOTAL_BITS))
return {};
#ifdef LIBC_TYPES_HAS_INT128
constexpr size_t TOTAL_BITS = N * WORD_BITS;
if constexpr (TOTAL_BITS == 128) {
using type = cpp::conditional_t<is_signed, __int128_t, __uint128_t>;
auto tmp = cpp::bit_cast<type>(array);
Expand All @@ -272,6 +268,8 @@ LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
return cpp::bit_cast<cpp::array<word, N>>(tmp);
}
#endif
if (LIBC_UNLIKELY(offset == 0))
return array;
const bool is_neg = is_signed && is_negative(array);
constexpr auto at = [](size_t index) -> int {
// reverse iteration when direction == LEFT.
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/float_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"
#include "src/__support/common.h"
#include "src/__support/libc_assert.h"
#include "src/__support/macros/attributes.h"
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

#include "src/__support/CPP/bit.h" // rotl
#include "src/__support/CPP/limits.h" // numeric_limits
#include "src/__support/UInt128.h" // UInt128
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/uint128.h" // UInt128
#include <stdint.h> // For uint64_t

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/integer_literals.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
#define LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H

#include "src/__support/CPP/limits.h" // CHAR_BIT
#include "src/__support/UInt128.h" // UInt128
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/uint128.h" // UInt128
#include <stddef.h> // size_t
#include <stdint.h> // uintxx_t

Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/integer_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
#include "src/__support/CPP/span.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt.h" // make_integral_or_big_int_unsigned_t
#include "src/__support/big_int.h" // make_integral_or_big_int_unsigned_t
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/str_to_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/detailed_powers_of_ten.h"
#include "src/__support/high_precision_decimal.h"
#include "src/__support/str_to_integer.h"
#include "src/__support/str_to_num_result.h"
#include "src/__support/uint128.h"
#include "src/errno/libc_errno.h" // For ERANGE

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/str_to_integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/str_to_num_result.h"
#include "src/__support/uint128.h"
#include "src/errno/libc_errno.h" // For ERANGE

namespace LIBC_NAMESPACE {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_UINT128_H
#define LLVM_LIBC_SRC___SUPPORT_UINT128_H

#include "UInt.h"
#include "big_int.h"
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128

#ifdef LIBC_TYPES_HAS_INT128
Expand Down
5 changes: 3 additions & 2 deletions libc/src/math/generic/log1p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ using LIBC_NAMESPACE::operator""_u128;

namespace {

// Extra errors from P is from using x^2 to reduce evaluation latency.
constexpr double P_ERR = 0x1.0p-50;
// Extra errors from P is from using x^2 to reduce evaluation latency and
// directional rounding.
constexpr double P_ERR = 0x1.0p-49;

// log(2) with 128-bit precision generated by SageMath with:
// def format_hex(value):
Expand Down
2 changes: 1 addition & 1 deletion libc/src/math/generic/log_range_reduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include "common_constants.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/UInt128.h"
#include "src/__support/uint128.h"

namespace LIBC_NAMESPACE {

Expand Down
12 changes: 6 additions & 6 deletions libc/src/stdio/printf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,21 @@ add_object_library(
float_dec_converter.h
fixed_converter.h #TODO: Check if this should be disabled when fixed unavail
DEPENDS
.writer
.core_structs
.printf_config
.writer
libc.src.__support.big_int
libc.src.__support.common
libc.src.__support.CPP.limits
libc.src.__support.CPP.span
libc.src.__support.CPP.string_view
libc.src.__support.FPUtil.fp_bits
libc.src.__support.float_to_string
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.rounding_mode
libc.src.__support.common
libc.src.__support.integer_to_string
libc.src.__support.libc_assert
libc.src.__support.uint
libc.src.__support.uint128
libc.src.__support.integer_to_string
libc.src.__support.float_to_string
)


Expand Down
2 changes: 1 addition & 1 deletion libc/src/stdio/printf_core/float_dec_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "src/__support/CPP/string_view.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/UInt.h" // is_big_int_v
#include "src/__support/big_int.h" // is_big_int_v
#include "src/__support/float_to_string.h"
#include "src/__support/integer_to_string.h"
#include "src/__support/libc_assert.h"
Expand Down
4 changes: 2 additions & 2 deletions libc/test/UnitTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ add_unittest_framework_library(
Test.h
TestLogger.h
DEPENDS
libc.src.__support.big_int
libc.src.__support.c_string
libc.src.__support.CPP.string
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
libc.src.__support.fixed_point.fx_rep
libc.src.__support.macros.properties.types
libc.src.__support.OSUtil.osutil
libc.src.__support.uint
libc.src.__support.uint128
)

Expand Down Expand Up @@ -103,9 +103,9 @@ add_header_library(
HDRS
StringUtils.h
DEPENDS
libc.src.__support.big_int
libc.src.__support.CPP.string
libc.src.__support.CPP.type_traits
libc.src.__support.uint
)

add_unittest_framework_library(
Expand Down
2 changes: 1 addition & 1 deletion libc/test/UnitTest/LibcTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/string.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/UInt128.h"
#include "src/__support/fixed_point/fx_rep.h"
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128
#include "src/__support/uint128.h"
#include "test/UnitTest/TestLogger.h"

#if __STDC_HOSTED__
Expand Down
2 changes: 1 addition & 1 deletion libc/test/UnitTest/StringUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include "src/__support/CPP/string.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"

namespace LIBC_NAMESPACE {

Expand Down
6 changes: 3 additions & 3 deletions libc/test/UnitTest/TestLogger.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include "test/UnitTest/TestLogger.h"
#include "src/__support/CPP/string.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/io.h" // write_to_stderr
#include "src/__support/UInt.h" // is_big_int
#include "src/__support/UInt128.h"
#include "src/__support/OSUtil/io.h" // write_to_stderr
#include "src/__support/big_int.h" // is_big_int
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128
#include "src/__support/uint128.h"

#include <stdint.h>

Expand Down
8 changes: 4 additions & 4 deletions libc/test/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ add_libc_test(
SRCS
integer_to_string_test.cpp
DEPENDS
libc.src.__support.big_int
libc.src.__support.CPP.limits
libc.src.__support.CPP.string_view
libc.src.__support.integer_literals
libc.src.__support.integer_to_string
libc.src.__support.uint
libc.src.__support.uint128
)

Expand All @@ -101,15 +101,15 @@ endif()

if(NOT LIBC_TARGET_ARCHITECTURE_IS_NVPTX)
add_libc_test(
uint_test
big_int_test
SUITE
libc-support-tests
SRCS
uint_test.cpp
big_int_test.cpp
DEPENDS
libc.src.__support.big_int
libc.src.__support.CPP.optional
libc.src.__support.macros.properties.types
libc.src.__support.uint
)
endif()

Expand Down
4 changes: 2 additions & 2 deletions libc/test/src/__support/CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ add_libc_test(
SRCS
bit_test.cpp
DEPENDS
libc.src.__support.big_int
libc.src.__support.CPP.bit
libc.src.__support.macros.properties.types
libc.src.__support.uint
)

add_libc_test(
Expand Down Expand Up @@ -59,9 +59,9 @@ add_libc_test(
SRCS
limits_test.cpp
DEPENDS
libc.src.__support.big_int
libc.src.__support.CPP.limits
libc.src.__support.macros.properties.types
libc.src.__support.uint
)

add_libc_test(
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/__support/CPP/bit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/bit.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128
#include "test/UnitTest/Test.h"

Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/__support/CPP/limits_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/limits.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128
#include "test/UnitTest/Test.h"

Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/__support/FPUtil/dyadic_float_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/optional.h"
#include "src/__support/UInt.h"
#include "src/__support/big_int.h"
#include "src/__support/integer_literals.h" // parse_unsigned_bigint
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128

Expand Down Expand Up @@ -192,7 +192,7 @@ TYPED_TEST(LlvmLibcUIntClassTest, Masks, Types) {

TYPED_TEST(LlvmLibcUIntClassTest, CountBits, Types) {
if constexpr (!T::SIGNED) {
for (size_t i = 0; i <= T::BITS; ++i) {
for (size_t i = 0; i < T::BITS; ++i) {
const auto l_one = T::all_ones() << i; // 0b111...000
const auto r_one = T::all_ones() >> i; // 0b000...111
const int zeros = i;
Expand Down Expand Up @@ -559,10 +559,6 @@ TEST(LlvmLibcUIntClassTest, ShiftLeftTests) {
LL_UInt128 result5({0, 0x2468ace000000000});
EXPECT_EQ((val2 << 100), result5);

LL_UInt128 result6({0, 0});
EXPECT_EQ((val2 << 128), result6);
EXPECT_EQ((val2 << 256), result6);

LL_UInt192 val3({1, 0, 0});
LL_UInt192 result7({0, 1, 0});
EXPECT_EQ((val3 << 64), result7);
Expand All @@ -589,10 +585,6 @@ TEST(LlvmLibcUIntClassTest, ShiftRightTests) {
LL_UInt128 result5({0x0000000001234567, 0});
EXPECT_EQ((val2 >> 100), result5);

LL_UInt128 result6({0, 0});
EXPECT_EQ((val2 >> 128), result6);
EXPECT_EQ((val2 >> 256), result6);

LL_UInt128 v1({0x1111222233334444, 0xaaaabbbbccccdddd});
LL_UInt128 r1({0xaaaabbbbccccdddd, 0});
EXPECT_EQ((v1 >> 64), r1);
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/__support/high_precision_decimal_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//

#include "src/__support/UInt128.h"
#include "src/__support/high_precision_decimal.h"
#include "src/__support/uint128.h"

#include "test/UnitTest/Test.h"

Expand Down
4 changes: 2 additions & 2 deletions libc/test/src/__support/integer_to_string_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/span.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/UInt.h"
#include "src/__support/UInt128.h"
#include "src/__support/big_int.h"
#include "src/__support/integer_literals.h"
#include "src/__support/integer_to_string.h"
#include "src/__support/uint128.h"

#include "test/UnitTest/Test.h"

Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/__support/math_extras_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
//
//===----------------------------------------------------------------------===//

#include "src/__support/UInt128.h" // UInt<128>
#include "src/__support/integer_literals.h"
#include "src/__support/math_extras.h"
#include "src/__support/uint128.h" // UInt<128>
#include "test/UnitTest/Test.h"

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/__support/str_to_fp_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//

#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/UInt128.h"
#include "src/__support/str_to_float.h"
#include "src/__support/uint128.h"
#include "src/errno/libc_errno.h"

#include "test/UnitTest/Test.h"
Expand Down
3 changes: 2 additions & 1 deletion libc/test/src/math/log1p_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ TEST_F(LlvmLibcLog1pTest, SpecialNumbers) {
}

TEST_F(LlvmLibcLog1pTest, TrickyInputs) {
constexpr int N = 41;
constexpr int N = 42;
constexpr uint64_t INPUTS[N] = {
0x3ff0000000000000, // x = 1.0
0x4024000000000000, // x = 10.0
Expand Down Expand Up @@ -65,6 +65,7 @@ TEST_F(LlvmLibcLog1pTest, TrickyInputs) {
0x3c90c40cef04efb5, 0x449d2ccad399848e, 0x4aa12ccdffd9d2ec,
0x5656f070b92d36ce, 0x6db06dcb74f76bcc, 0x7f1954e72ffd4596,
0x5671e2f1628093e4, 0x73dac56e2bf1a951, 0x8001bc6879ea14c5,
0x45ca5f497ec291df, // x = 0x1.a5f497ec291dfp+93
};
for (int i = 0; i < N; ++i) {
double x = FPBits(INPUTS[i]).get_val();
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/math/smoke/nanf128_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/UInt128.h"
#include "src/__support/uint128.h"
#include "src/math/nanf128.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/stdlib/strtold_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/UInt128.h"
#include "src/__support/uint128.h"
#include "src/errno/libc_errno.h"
#include "src/stdlib/strtold.h"

Expand Down
1 change: 1 addition & 0 deletions libcxx/benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ set(BENCHMARK_TESTS
algorithms/make_heap.bench.cpp
algorithms/make_heap_then_sort_heap.bench.cpp
algorithms/min.bench.cpp
algorithms/minmax.bench.cpp
algorithms/min_max_element.bench.cpp
algorithms/mismatch.bench.cpp
algorithms/pop_heap.bench.cpp
Expand Down
68 changes: 68 additions & 0 deletions libcxx/benchmarks/algorithms/minmax.bench.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <algorithm>
#include <cassert>

#include <benchmark/benchmark.h>

void run_sizes(auto benchmark) {
benchmark->Arg(1)
->Arg(2)
->Arg(3)
->Arg(4)
->Arg(5)
->Arg(6)
->Arg(7)
->Arg(8)
->Arg(9)
->Arg(10)
->Arg(11)
->Arg(12)
->Arg(13)
->Arg(14)
->Arg(15)
->Arg(16)
->Arg(17)
->Arg(18)
->Arg(19)
->Arg(20)
->Arg(21)
->Arg(22)
->Arg(23)
->Arg(24)
->Arg(25)
->Arg(26)
->Arg(27)
->Arg(28)
->Arg(29)
->Arg(30)
->Arg(31)
->Arg(32)
->Arg(64)
->Arg(512)
->Arg(1024)
->Arg(4000)
->Arg(4096)
->Arg(5500)
->Arg(64000)
->Arg(65536)
->Arg(70000);
}

template <class T>
static void BM_std_minmax(benchmark::State& state) {
std::vector<T> vec(state.range(), 3);

for (auto _ : state) {
benchmark::DoNotOptimize(vec);
benchmark::DoNotOptimize(std::ranges::minmax(vec));
}
}
BENCHMARK(BM_std_minmax<char>)->Apply(run_sizes);
BENCHMARK(BM_std_minmax<short>)->Apply(run_sizes);
BENCHMARK(BM_std_minmax<int>)->Apply(run_sizes);
BENCHMARK(BM_std_minmax<long long>)->Apply(run_sizes);
BENCHMARK(BM_std_minmax<unsigned char>)->Apply(run_sizes);
BENCHMARK(BM_std_minmax<unsigned short>)->Apply(run_sizes);
BENCHMARK(BM_std_minmax<unsigned int>)->Apply(run_sizes);
BENCHMARK(BM_std_minmax<unsigned long long>)->Apply(run_sizes);

BENCHMARK_MAIN();
8 changes: 8 additions & 0 deletions libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Implemented Papers
- P2495R3 - Interfacing ``stringstream``\s with ``string_view``
- P2867R2 - Remove Deprecated ``strstream``\s From C++26
- P2872R3 - Remove ``wstring_convert`` From C++26
- P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23)
- P2302R4 - ``std::ranges::contains``
- P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``

Expand All @@ -55,6 +56,8 @@ Improvements and New Features
resulting in a performance increase of up to 1400x.
- The ``std::mismatch`` algorithm has been optimized for integral types, which can lead up to 40x performance
improvements.
- The ``std::ranges::minmax`` algorithm has been optimized for integral types, resulting in a performance increase of
up to 100x.

- The ``_LIBCPP_ENABLE_CXX26_REMOVED_STRSTREAM`` macro has been added to make the declarations in ``<strstream>`` available.

Expand Down Expand Up @@ -92,6 +95,11 @@ Deprecations and Removals
libatomic is not available. If you are one such user, please reach out to the libc++ developers so we can collaborate
on a path for supporting atomics properly on freestanding platforms.

- LWG3430 disallow implicit conversion of the source arguments to ``std::filesystem::path`` when
constructing ``std::basic_*fstream``. This effectively removes the possibility to directly construct
a ``std::basic_*fstream`` from a ``std::basic_string_view``, a input-iterator or a C-string, instead
you can construct a temporary ``std::basic_string``. This change has been applied to C++17 and later.


Upcoming Deprecations and Removals
----------------------------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx23Issues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
`2818 <https://wg21.link/LWG2818>`__,"``::std::`` everywhere rule needs tweaking","June 2021","|Nothing To Do|",""
`2997 <https://wg21.link/LWG2997>`__,"LWG 491 and the specification of ``{forward_,}list::unique``","June 2021","",""
`3410 <https://wg21.link/LWG3410>`__,"``lexicographical_compare_three_way`` is overspecified","June 2021","|Complete|","17.0","|spaceship|"
`3430 <https://wg21.link/LWG3430>`__,"``std::fstream`` & co. should be constructible from string_view","June 2021","",""
`3430 <https://wg21.link/LWG3430>`__,"``std::fstream`` & co. should be constructible from string_view","June 2021","|Complete|","19.0",""
`3462 <https://wg21.link/LWG3462>`__,"§[formatter.requirements]: Formatter requirements forbid use of ``fc.arg()``","June 2021","|Nothing To Do|","","|format|"
`3481 <https://wg21.link/LWG3481>`__,"``viewable_range`` mishandles lvalue move-only views","June 2021","Superseded by `P2415R2 <https://wg21.link/P2415R2>`__","","|ranges|"
`3506 <https://wg21.link/LWG3506>`__,"Missing allocator-extended constructors for ``priority_queue``","June 2021","|Complete|","14.0"
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"`P2869R4 <https://wg21.link/P2869R4>`__","LWG","Remove Deprecated ``shared_ptr`` Atomic Access APIs from C++26","Tokyo March 2024","","",""
"`P2872R3 <https://wg21.link/P2872R3>`__","LWG","Remove ``wstring_convert`` From C++26","Tokyo March 2024","|Complete|","19.0",""
"`P3107R5 <https://wg21.link/P3107R5>`__","LWG","Permit an efficient implementation of ``std::print``","Tokyo March 2024","","","|format| |DR|"
"`P3142R0 <https://wg21.link/P3142R0>`__","LWG","Printing Blank Lines with ``println``","Tokyo March 2024","","","|format|"
"`P3142R0 <https://wg21.link/P3142R0>`__","LWG","Printing Blank Lines with ``println``","Tokyo March 2024","|Complete|","19.0","|format|"
"`P2845R8 <https://wg21.link/P2845R8>`__","LWG","Formatting of ``std::filesystem::path``","Tokyo March 2024","","","|format|"
"`P0493R5 <https://wg21.link/P0493R5>`__","LWG","Atomic minimum/maximum","Tokyo March 2024","","",""
"`P2542R8 <https://wg21.link/P2542R8>`__","LWG","``views::concat``","Tokyo March 2024","","","|ranges|"
Expand Down
4 changes: 4 additions & 0 deletions libcxx/docs/Status/FormatIssues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Number,Name,Standard,Assignee,Status,First released version
"`P2905R2 <https://wg21.link/P2905R2>`__","Runtime format strings","C++26 DR","Mark de Wever","|Complete|",18.0
"`P2918R2 <https://wg21.link/P2918R2>`__","Runtime format strings II","C++26","Mark de Wever","|Complete|",18.0
"`P2909R4 <https://wg21.link/P2909R4>`__","Fix formatting of code units as integers (Dude, where’s my ``char``?)","C++26 DR","Mark de Wever","|Complete|",18.0
"`P3107R5 <https://wg21.link/P3107R5>`__","Permit an efficient implementation of ``std::print``","C++26 DR","Mark de Wever","|In Progress|",""
"`P3142R0 <https://wg21.link/P3142R0>`__","Printing Blank Lines with ``println``","C++26 DR","Hristo Hristov","|Complete|",19.0
"`P2845R8 <https://wg21.link/P2845R8>`__","Formatting of ``std::filesystem::path``","C++26","Mark de Wever","",""

`P1361 <https://wg21.link/P1361>`_,"Integration of chrono with text formatting","C++20",Mark de Wever,|In Progress|,
`P2372 <https://wg21.link/P2372>`__,"Fixing locale handling in chrono formatters","C++20",Mark de Wever,|In Progress|,
"`P2419R2 <https://wg21.link/P2419R2>`__","Clarify handling of encodings in localized formatting of chrono types","C++23",
27 changes: 4 additions & 23 deletions libcxx/docs/Status/FormatPaper.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ Section,Description,Dependencies,Assignee,Status,First released version
`P1361 <https://wg21.link/P1361>`__ `P2372 <https://wg21.link/P2372>`__,"Formatting chrono"
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::duration<Rep, Period>``",,Mark de Wever,|Complete|,16.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::sys_time<Duration>``",,Mark de Wever,|Complete|,17.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::utc_time<Duration>``",A ``<chrono>`` implementation,Not assigned,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::tai_time<Duration>``",A ``<chrono>`` implementation,Not assigned,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::gps_time<Duration>``",A ``<chrono>`` implementation,Not assigned,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::utc_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::tai_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::gps_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::file_time<Duration>``",,Mark de Wever,|Complete|,17.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_time<Duration>``",,Mark de Wever,|Complete|,17.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local-time-format-t<Duration>``",A ``<chrono>`` implementation,Not assigned,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local-time-format-t<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::day``",,Mark de Wever,|Complete|,16.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::month``",,Mark de Wever,|Complete|,16.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::year``",,Mark de Wever,|Complete|,16.0
Expand All @@ -28,25 +28,6 @@ Section,Description,Dependencies,Assignee,Status,First released version
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_info``",A ``<chrono>`` implementation,Mark de Wever,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::zoned_time<Duration, TimeZonePtr>``",A ``<chrono>`` implementation,Mark de Wever,,

`P2286R8 <https://wg21.link/P2286R8>`__,"Formatting ranges"
`[format.syn] <https://wg21.link/format.syn>`_,"Concept ``formattable``",,Mark de Wever,|Complete|,16.0
`[format.string.std] <https://wg21.link/format.string.std>`_,"std-format-spec ``type`` debug",,Mark de Wever,|Complete|,16.0
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: sequences",,Mark de Wever,|Complete|,16.0
`[format.range.fmtmap] <https://wg21.link/format.range.fmtmap>`_,"Formatting for ranges: map",,Mark de Wever,|Complete|,16.0
`[format.range.fmtset] <https://wg21.link/format.range.fmtset>`_,"Formatting for ranges: set",,Mark de Wever,|Complete|,16.0
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: container adaptors",,Mark de Wever,|Complete|,16.0
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: ``pair`` and ``tuple``",,Mark de Wever,|Complete|,16.0
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: ``vector<bool>``",,Mark de Wever,|Complete|,16.0

"`P2585R0 <https://wg21.link/P2585R0>`__","Improving default container formatting"
`[format.range.fmtstr] <https://wg21.link/format.range.fmtstr>`_,"Formatting for ranges: strings",,Mark de Wever,|Complete|,17.0
`[format.range.fmtstr] <https://wg21.link/format.range.fmtstr>`_,"Formatting for ranges: debug_strings",,Mark de Wever,|Complete|,17.0

"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``"
`[thread.thread.id] <https://wg21.link/thread.thread.id>`_,"Formatting ``thread::id``",,Mark de Wever,|Complete|,17.0
`[stacktrace.format] <https://wg21.link/stacktrace.format>`_,"Formatting ``stacktrace``",A ``<stacktrace>`` implementation,Mark de Wever,,

"`P2093R14 <https://wg21.link/P2093R14>`__","Formatted output"
`[print.fun] <https://wg21.link/print.fun>`__,"Output to ``stdout``",,Mark de Wever,|Complete|, 17.0
`[print.fun] <https://wg21.link/print.fun>`__,"Output to ``FILE*``",,Mark de Wever,|Complete|, 17.0
`[ostream.formatted.print] <https://wg21.link/ostream.formatted.print>`__,"Output to ``ostream``",,Mark de Wever,|Complete|, 18.0
3 changes: 3 additions & 0 deletions libcxx/include/__algorithm/comp.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ struct __less<void, void> {
}
};

template <class _Tp>
inline const bool __desugars_to_v<__less_tag, __less<>, _Tp, _Tp> = true;

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___ALGORITHM_COMP_H
17 changes: 16 additions & 1 deletion libcxx/include/__algorithm/ranges_minmax.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__type_traits/desugars_to.h>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_trivially_copyable.h>
#include <__type_traits/remove_cvref.h>
#include <__utility/forward.h>
#include <__utility/move.h>
Expand Down Expand Up @@ -83,7 +85,20 @@ struct __fn {

_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__first != __last, "range has to contain at least one element");

if constexpr (forward_range<_Range>) {
// This optimiation is not in minmax_element because clang doesn't see through the pointers and as a result doesn't
// vectorize the code.
if constexpr (contiguous_range<_Range> && is_integral_v<_ValueT> &&
__is_cheap_to_copy<_ValueT> & __is_identity<_Proj>::value &&
__desugars_to_v<__less_tag, _Comp, _ValueT, _ValueT>) {
minmax_result<_ValueT> __result = {__r[0], __r[0]};
for (auto __e : __r) {
if (__e < __result.min)
__result.min = __e;
if (__result.max < __e)
__result.max = __e;
}
return __result;
} else if constexpr (forward_range<_Range>) {
// Special-case the one element case. Avoid repeatedly initializing objects from the result of an iterator
// dereference when doing so might not be idempotent. The `if constexpr` avoids the extra branch in cases where
// it's not needed.
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/__functional/operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ struct _LIBCPP_TEMPLATE_VIS less : __binary_function<_Tp, _Tp, bool> {
};
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(less);

template <class _Tp>
inline const bool __desugars_to_v<__less_tag, less<_Tp>, _Tp, _Tp> = true;

#if _LIBCPP_STD_VER >= 14
template <>
struct _LIBCPP_TEMPLATE_VIS less<void> {
Expand All @@ -370,6 +373,9 @@ struct _LIBCPP_TEMPLATE_VIS less<void> {
}
typedef void is_transparent;
};

template <class _Tp>
inline const bool __desugars_to_v<__less_tag, less<>, _Tp, _Tp> = true;
#endif

#if _LIBCPP_STD_VER >= 14
Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/__functional/ranges_operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ struct greater_equal {
template <class _Tp, class _Up>
inline const bool __desugars_to_v<__equal_tag, ranges::equal_to, _Tp, _Up> = true;

template <class _Tp, class _Up>
inline const bool __desugars_to_v<__less_tag, ranges::less, _Tp, _Up> = true;

#endif // _LIBCPP_STD_VER >= 20

_LIBCPP_END_NAMESPACE_STD
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__type_traits/desugars_to.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// Tags to represent the canonical operations
struct __equal_tag {};
struct __plus_tag {};
struct __less_tag {};

// This class template is used to determine whether an operation "desugars"
// (or boils down) to a given canonical operation.
Expand Down
23 changes: 14 additions & 9 deletions libcxx/include/fstream
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ public:
basic_ifstream();
explicit basic_ifstream(const char* s, ios_base::openmode mode = ios_base::in);
explicit basic_ifstream(const string& s, ios_base::openmode mode = ios_base::in);
explicit basic_ifstream(const filesystem::path& p,
ios_base::openmode mode = ios_base::in); // C++17
template<class T>
explicit basic_ifstream(const T& s, ios_base::openmode mode = ios_base::in); // Since C++17
basic_ifstream(basic_ifstream&& rhs);

basic_ifstream& operator=(basic_ifstream&& rhs);
Expand Down Expand Up @@ -117,8 +117,8 @@ public:
basic_ofstream();
explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
explicit basic_ofstream(const string& s, ios_base::openmode mode = ios_base::out);
explicit basic_ofstream(const filesystem::path& p,
ios_base::openmode mode = ios_base::out); // C++17
template<class T>
explicit basic_ofstream(const T& s, ios_base::openmode mode = ios_base::out); // Since C++17
basic_ofstream(basic_ofstream&& rhs);

basic_ofstream& operator=(basic_ofstream&& rhs);
Expand Down Expand Up @@ -158,8 +158,8 @@ public:
basic_fstream();
explicit basic_fstream(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
explicit basic_fstream(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);
explicit basic_fstream(const filesystem::path& p,
ios_base::openmode mode = ios_base::in|ios_base::out); C++17
template<class T>
explicit basic_fstream(const T& s, ios_base::openmode mode = ios_base::in | ios_base::out); // Since C++17
basic_fstream(basic_fstream&& rhs);

basic_fstream& operator=(basic_fstream&& rhs);
Expand Down Expand Up @@ -192,6 +192,8 @@ typedef basic_fstream<wchar_t> wfstream;
#include <__config>
#include <__fwd/fstream.h>
#include <__locale>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_same.h>
#include <__utility/move.h>
#include <__utility/swap.h>
#include <__utility/unreachable.h>
Expand Down Expand Up @@ -1101,8 +1103,9 @@ public:
# endif
_LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(const string& __s, ios_base::openmode __mode = ios_base::in);
# if _LIBCPP_STD_VER >= 17
template <class _Tp, class = enable_if_t<is_same_v<_Tp, filesystem::path>>>
_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(
const filesystem::path& __p, ios_base::openmode __mode = ios_base::in)
const _Tp& __p, ios_base::openmode __mode = ios_base::in)
: basic_ifstream(__p.c_str(), __mode) {}
# endif // _LIBCPP_STD_VER >= 17
_LIBCPP_HIDE_FROM_ABI basic_ifstream(basic_ifstream&& __rhs);
Expand Down Expand Up @@ -1255,8 +1258,9 @@ public:
_LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(const string& __s, ios_base::openmode __mode = ios_base::out);

# if _LIBCPP_STD_VER >= 17
template <class _Tp, class = enable_if_t<is_same_v<_Tp, filesystem::path>>>
_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(
const filesystem::path& __p, ios_base::openmode __mode = ios_base::out)
const _Tp& __p, ios_base::openmode __mode = ios_base::out)
: basic_ofstream(__p.c_str(), __mode) {}
# endif // _LIBCPP_STD_VER >= 17

Expand Down Expand Up @@ -1414,8 +1418,9 @@ public:
ios_base::openmode __mode = ios_base::in | ios_base::out);

# if _LIBCPP_STD_VER >= 17
template <class _Tp, class = enable_if_t<is_same_v<_Tp, filesystem::path>>>
_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI explicit basic_fstream(
const filesystem::path& __p, ios_base::openmode __mode = ios_base::in | ios_base::out)
const _Tp& __p, ios_base::openmode __mode = ios_base::in | ios_base::out)
: basic_fstream(__p.c_str(), __mode) {}
# endif // _LIBCPP_STD_VER >= 17

Expand Down
4 changes: 4 additions & 0 deletions libcxx/include/ostream
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ template<class... Args>
void print(ostream& os, format_string<Args...> fmt, Args&&... args);
template<class... Args> // since C++23
void println(ostream& os, format_string<Args...> fmt, Args&&... args);
void println(ostream& os); // since C++26

void vprint_unicode(ostream& os, string_view fmt, format_args args); // since C++23
void vprint_nonunicode(ostream& os, string_view fmt, format_args args); // since C++23
Expand Down Expand Up @@ -1163,6 +1164,9 @@ _LIBCPP_HIDE_FROM_ABI void println(ostream& __os, format_string<_Args...> __fmt,
# endif // _LIBCPP_HAS_NO_UNICODE
}

template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI inline void println(ostream& __os) { std::print(__os, "\n"); }

#endif // _LIBCPP_STD_VER >= 23

_LIBCPP_END_NAMESPACE_STD
Expand Down
8 changes: 8 additions & 0 deletions libcxx/include/print
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ namespace std {
// [print.fun], print functions
template<class... Args>
void print(format_string<Args...> fmt, Args&&... args);
void println(); // Since C++26
template<class... Args>
void print(FILE* stream, format_string<Args...> fmt, Args&&... args);
void println(FILE* stream); // Since C++26

template<class... Args>
void println(format_string<Args...> fmt, Args&&... args);
Expand Down Expand Up @@ -356,6 +358,12 @@ _LIBCPP_HIDE_FROM_ABI void println(FILE* __stream, format_string<_Args...> __fmt
# endif // _LIBCPP_HAS_NO_UNICODE
}

template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI inline void println(FILE* __stream) { std::print(__stream, "\n"); }

template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI inline void println() { println(stdout); }

template <class... _Args>
_LIBCPP_HIDE_FROM_ABI void println(format_string<_Args...> __fmt, _Args&&... __args) {
std::println(stdout, __fmt, std::forward<_Args>(__args)...);
Expand Down
Loading