354 changes: 177 additions & 177 deletions clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp

Large diffs are not rendered by default.

17 changes: 8 additions & 9 deletions clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,12 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
// shall be run.
const auto FunctionScope =
functionDecl(
hasBody(
compoundStmt(forEachDescendant(
declStmt(containsAnyDeclaration(
LocalValDecl.bind("local-value")),
unless(has(decompositionDecl())))
.bind("decl-stmt")))
.bind("scope")))
hasBody(stmt(forEachDescendant(
declStmt(containsAnyDeclaration(
LocalValDecl.bind("local-value")),
unless(has(decompositionDecl())))
.bind("decl-stmt")))
.bind("scope")))
.bind("function-decl");

Finder->addMatcher(FunctionScope, this);
Expand All @@ -109,7 +108,7 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
enum class VariableCategory { Value, Reference, Pointer };

void ConstCorrectnessCheck::check(const MatchFinder::MatchResult &Result) {
const auto *LocalScope = Result.Nodes.getNodeAs<CompoundStmt>("scope");
const auto *LocalScope = Result.Nodes.getNodeAs<Stmt>("scope");
const auto *Variable = Result.Nodes.getNodeAs<VarDecl>("local-value");
const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("function-decl");

Expand Down Expand Up @@ -198,7 +197,7 @@ void ConstCorrectnessCheck::check(const MatchFinder::MatchResult &Result) {
}
}

void ConstCorrectnessCheck::registerScope(const CompoundStmt *LocalScope,
void ConstCorrectnessCheck::registerScope(const Stmt *LocalScope,
ASTContext *Context) {
auto &Analyzer = ScopesCache[LocalScope];
if (!Analyzer)
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ class ConstCorrectnessCheck : public ClangTidyCheck {
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;

private:
void registerScope(const CompoundStmt *LocalScope, ASTContext *Context);
void registerScope(const Stmt *LocalScope, ASTContext *Context);

using MutationAnalyzer = std::unique_ptr<ExprMutationAnalyzer>;
llvm::DenseMap<const CompoundStmt *, MutationAnalyzer> ScopesCache;
llvm::DenseMap<const Stmt *, MutationAnalyzer> ScopesCache;
llvm::DenseSet<SourceLocation> TemplateDiagnosticsCache;

const bool AnalyzeValues;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,65 +119,72 @@ void UnnecessaryValueParamCheck::check(const MatchFinder::MatchResult &Result) {
}
}

const size_t Index = llvm::find(Function->parameters(), Param) -
Function->parameters().begin();
handleConstRefFix(*Function, *Param, *Result.Context);
}

void UnnecessaryValueParamCheck::registerPPCallbacks(
const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
Inserter.registerPreprocessor(PP);
}

void UnnecessaryValueParamCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IncludeStyle", Inserter.getStyle());
Options.store(Opts, "AllowedTypes",
utils::options::serializeStringList(AllowedTypes));
}

void UnnecessaryValueParamCheck::onEndOfTranslationUnit() {
MutationAnalyzerCache.clear();
}

void UnnecessaryValueParamCheck::handleConstRefFix(const FunctionDecl &Function,
const ParmVarDecl &Param,
ASTContext &Context) {
const size_t Index =
llvm::find(Function.parameters(), &Param) - Function.parameters().begin();
const bool IsConstQualified =
Param.getType().getCanonicalType().isConstQualified();

auto Diag =
diag(Param->getLocation(),
diag(Param.getLocation(),
"the %select{|const qualified }0parameter %1 is copied for each "
"invocation%select{ but only used as a const reference|}0; consider "
"making it a %select{const |}0reference")
<< IsConstQualified << paramNameOrIndex(Param->getName(), Index);
<< IsConstQualified << paramNameOrIndex(Param.getName(), Index);
// Do not propose fixes when:
// 1. the ParmVarDecl is in a macro, since we cannot place them correctly
// 2. the function is virtual as it might break overrides
// 3. the function is referenced outside of a call expression within the
// compilation unit as the signature change could introduce build errors.
// 4. the function is an explicit template/ specialization.
const auto *Method = llvm::dyn_cast<CXXMethodDecl>(Function);
if (Param->getBeginLoc().isMacroID() || (Method && Method->isVirtual()) ||
isReferencedOutsideOfCallExpr(*Function, *Result.Context) ||
Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
const auto *Method = llvm::dyn_cast<CXXMethodDecl>(&Function);
if (Param.getBeginLoc().isMacroID() || (Method && Method->isVirtual()) ||
isReferencedOutsideOfCallExpr(Function, Context) ||
Function.getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
return;
for (const auto *FunctionDecl = Function; FunctionDecl != nullptr;
for (const auto *FunctionDecl = &Function; FunctionDecl != nullptr;
FunctionDecl = FunctionDecl->getPreviousDecl()) {
const auto &CurrentParam = *FunctionDecl->getParamDecl(Index);
Diag << utils::fixit::changeVarDeclToReference(CurrentParam,
*Result.Context);
Diag << utils::fixit::changeVarDeclToReference(CurrentParam, Context);
// The parameter of each declaration needs to be checked individually as to
// whether it is const or not as constness can differ between definition and
// declaration.
if (!CurrentParam.getType().getCanonicalType().isConstQualified()) {
if (std::optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
CurrentParam, *Result.Context, DeclSpec::TQ::TQ_const))
CurrentParam, Context, DeclSpec::TQ::TQ_const))
Diag << *Fix;
}
}
}

void UnnecessaryValueParamCheck::registerPPCallbacks(
const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
Inserter.registerPreprocessor(PP);
}

void UnnecessaryValueParamCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IncludeStyle", Inserter.getStyle());
Options.store(Opts, "AllowedTypes",
utils::options::serializeStringList(AllowedTypes));
}

void UnnecessaryValueParamCheck::onEndOfTranslationUnit() {
MutationAnalyzerCache.clear();
}

void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl &Var,
void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl &Param,
const DeclRefExpr &CopyArgument,
const ASTContext &Context) {
ASTContext &Context) {
auto Diag = diag(CopyArgument.getBeginLoc(),
"parameter %0 is passed by value and only copied once; "
"consider moving it to avoid unnecessary copies")
<< &Var;
<< &Param;
// Do not propose fixes in macros since we cannot place them correctly.
if (CopyArgument.getBeginLoc().isMacroID())
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ class UnnecessaryValueParamCheck : public ClangTidyCheck {
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void onEndOfTranslationUnit() override;

private:
void handleMoveFix(const ParmVarDecl &Var, const DeclRefExpr &CopyArgument,
const ASTContext &Context);
protected:
// Create diagnostics. These are virtual so that derived classes can change
// behaviour.
virtual void handleMoveFix(const ParmVarDecl &Param,
const DeclRefExpr &CopyArgument,
ASTContext &Context);
virtual void handleConstRefFix(const FunctionDecl &Function,
const ParmVarDecl &Param, ASTContext &Context);

private:
ExprMutationAnalyzer::Memoized MutationAnalyzerCache;
utils::IncludeInserter Inserter;
const std::vector<StringRef> AllowedTypes;
Expand Down
323 changes: 183 additions & 140 deletions clang-tools-extra/clang-tidy/tool/run-clang-tidy.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ bool areStatementsIdentical(const Stmt *FirstStmt, const Stmt *SecondStmt,
if (FirstStmt == SecondStmt)
return true;

if (FirstStmt->getStmtClass() != FirstStmt->getStmtClass())
if (FirstStmt->getStmtClass() != SecondStmt->getStmtClass())
return false;

if (isa<Expr>(FirstStmt) && isa<Expr>(SecondStmt)) {
Expand Down
10 changes: 5 additions & 5 deletions clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ bool isStandardPointerConvertible(QualType From, QualType To) {
if (RD->isCompleteDefinition() &&
isBaseOf(From->getPointeeType().getTypePtr(),
To->getPointeeType().getTypePtr())) {
return true;
// If B is an inaccessible or ambiguous base class of D, a program
// that necessitates this conversion is ill-formed
return isUnambiguousPublicBaseClass(From->getPointeeType().getTypePtr(),
To->getPointeeType().getTypePtr());
}
}

Expand Down Expand Up @@ -375,10 +378,7 @@ bool ExceptionAnalyzer::ExceptionInfo::filterByCatch(
isPointerOrPointerToMember(ExceptionCanTy->getTypePtr())) {
// A standard pointer conversion not involving conversions to pointers to
// private or protected or ambiguous classes ...
if (isStandardPointerConvertible(ExceptionCanTy, HandlerCanTy) &&
isUnambiguousPublicBaseClass(
ExceptionCanTy->getTypePtr()->getPointeeType().getTypePtr(),
HandlerCanTy->getTypePtr()->getPointeeType().getTypePtr())) {
if (isStandardPointerConvertible(ExceptionCanTy, HandlerCanTy)) {
TypesToDelete.push_back(ExceptionTy);
}
// A function pointer conversion ...
Expand Down
421 changes: 0 additions & 421 deletions clang-tools-extra/docs/ReleaseNotes.rst

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
.. title:: clang-tidy - clang-analyzer-cplusplus.Move
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-move

clang-analyzer-cplusplus.Move
=============================

Find use-after-move bugs in C++.

The clang-analyzer-cplusplus.Move check is an alias of
Clang Static Analyzer cplusplus.Move.
The `clang-analyzer-cplusplus.Move` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-move>`_
for more information.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.. title:: clang-tidy - clang-analyzer-optin.taint.TaintedAlloc
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#optin-taint-taintedalloc

clang-analyzer-optin.taint.TaintedAlloc
=======================================

Check for memory allocations, where the size parameter might be a tainted
(attacker controlled) value.

The `clang-analyzer-optin.taint.TaintedAlloc` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#optin-taint-taintedalloc>`_
for more information.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. title:: clang-tidy - clang-analyzer-security.PutenvStackArray

clang-analyzer-security.PutenvStackArray
========================================

Finds calls to the function 'putenv' which pass a pointer to an automatic
(stack-allocated) array as the argument.

The clang-analyzer-security.PutenvStackArray check is an alias of
Clang Static Analyzer security.PutenvStackArray.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. title:: clang-tidy - clang-analyzer-unix.BlockInCriticalSection
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#unix-blockincriticalsection

clang-analyzer-unix.BlockInCriticalSection
==========================================

Check for calls to blocking functions inside a critical section.

The `clang-analyzer-unix.BlockInCriticalSection` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#unix-blockincriticalsection>`_
for more information.
10 changes: 7 additions & 3 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Clang-Tidy Checks
:doc:`bugprone-not-null-terminated-result <bugprone/not-null-terminated-result>`, "Yes"
:doc:`bugprone-optional-value-conversion <bugprone/optional-value-conversion>`, "Yes"
:doc:`bugprone-parent-virtual-call <bugprone/parent-virtual-call>`, "Yes"
:doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
:doc:`bugprone-posix-return <bugprone/posix-return>`, "Yes"
:doc:`bugprone-redundant-branch-condition <bugprone/redundant-branch-condition>`, "Yes"
:doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
Expand Down Expand Up @@ -158,7 +159,6 @@ Clang-Tidy Checks
:doc:`bugprone-unused-raii <bugprone/unused-raii>`, "Yes"
:doc:`bugprone-unused-return-value <bugprone/unused-return-value>`,
:doc:`bugprone-use-after-move <bugprone/use-after-move>`,
:doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
:doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes"
:doc:`cert-dcl50-cpp <cert/dcl50-cpp>`,
:doc:`cert-dcl58-cpp <cert/dcl58-cpp>`,
Expand Down Expand Up @@ -269,7 +269,7 @@ Clang-Tidy Checks
:doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
:doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
:doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
:doc:`misc-use-internal-linkage <misc/use-internal-linkage>`,
:doc:`misc-use-internal-linkage <misc/use-internal-linkage>`, "Yes"
:doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
:doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
:doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes"
Expand Down Expand Up @@ -409,6 +409,7 @@ Check aliases
:doc:`bugprone-narrowing-conversions <bugprone/narrowing-conversions>`, :doc:`cppcoreguidelines-narrowing-conversions <cppcoreguidelines/narrowing-conversions>`,
:doc:`cert-con36-c <cert/con36-c>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
:doc:`cert-con54-cpp <cert/con54-cpp>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
:doc:`cert-ctr56-cpp <cert/ctr56-cpp>`, :doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
:doc:`cert-dcl03-c <cert/dcl03-c>`, :doc:`misc-static-assert <misc/static-assert>`, "Yes"
:doc:`cert-dcl16-c <cert/dcl16-c>`, :doc:`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>`, "Yes"
:doc:`cert-dcl37-c <cert/dcl37-c>`, :doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
Expand Down Expand Up @@ -448,7 +449,7 @@ Check aliases
:doc:`clang-analyzer-core.uninitialized.UndefReturn <clang-analyzer/core.uninitialized.UndefReturn>`, `Clang Static Analyzer core.uninitialized.UndefReturn <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-undefreturn>`_,
:doc:`clang-analyzer-cplusplus.ArrayDelete <clang-analyzer/cplusplus.ArrayDelete>`, `Clang Static Analyzer cplusplus.ArrayDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-arraydelete>`_,
:doc:`clang-analyzer-cplusplus.InnerPointer <clang-analyzer/cplusplus.InnerPointer>`, `Clang Static Analyzer cplusplus.InnerPointer <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-innerpointer>`_,
:doc:`clang-analyzer-cplusplus.Move <clang-analyzer/cplusplus.Move>`, Clang Static Analyzer cplusplus.Move,
:doc:`clang-analyzer-cplusplus.Move <clang-analyzer/cplusplus.Move>`, `Clang Static Analyzer cplusplus.Move <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-move>`_,
:doc:`clang-analyzer-cplusplus.NewDelete <clang-analyzer/cplusplus.NewDelete>`, `Clang Static Analyzer cplusplus.NewDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-newdelete>`_,
:doc:`clang-analyzer-cplusplus.NewDeleteLeaks <clang-analyzer/cplusplus.NewDeleteLeaks>`, `Clang Static Analyzer cplusplus.NewDeleteLeaks <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-newdeleteleaks>`_,
:doc:`clang-analyzer-cplusplus.PlacementNew <clang-analyzer/cplusplus.PlacementNew>`, `Clang Static Analyzer cplusplus.PlacementNew <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-placementnew>`_,
Expand All @@ -471,6 +472,7 @@ Check aliases
:doc:`clang-analyzer-optin.performance.GCDAntipattern <clang-analyzer/optin.performance.GCDAntipattern>`, `Clang Static Analyzer optin.performance.GCDAntipattern <https://clang.llvm.org/docs/analyzer/checkers.html#optin-performance-gcdantipattern>`_,
:doc:`clang-analyzer-optin.performance.Padding <clang-analyzer/optin.performance.Padding>`, `Clang Static Analyzer optin.performance.Padding <https://clang.llvm.org/docs/analyzer/checkers.html#optin-performance-padding>`_,
:doc:`clang-analyzer-optin.portability.UnixAPI <clang-analyzer/optin.portability.UnixAPI>`, `Clang Static Analyzer optin.portability.UnixAPI <https://clang.llvm.org/docs/analyzer/checkers.html#optin-portability-unixapi>`_,
:doc:`clang-analyzer-optin.taint.TaintedAlloc <clang-analyzer/optin.taint.TaintedAlloc>`, `Clang Static Analyzer optin.taint.TaintedAlloc <https://clang.llvm.org/docs/analyzer/checkers.html#optin-taint-taintedalloc>`_,
:doc:`clang-analyzer-osx.API <clang-analyzer/osx.API>`, `Clang Static Analyzer osx.API <https://clang.llvm.org/docs/analyzer/checkers.html#osx-api>`_,
:doc:`clang-analyzer-osx.MIG <clang-analyzer/osx.MIG>`, Clang Static Analyzer osx.MIG,
:doc:`clang-analyzer-osx.NumberObjectConversion <clang-analyzer/osx.NumberObjectConversion>`, `Clang Static Analyzer osx.NumberObjectConversion <https://clang.llvm.org/docs/analyzer/checkers.html#osx-numberobjectconversion>`_,
Expand Down Expand Up @@ -501,6 +503,7 @@ Check aliases
:doc:`clang-analyzer-osx.coreFoundation.containers.OutOfBounds <clang-analyzer/osx.coreFoundation.containers.OutOfBounds>`, `Clang Static Analyzer osx.coreFoundation.containers.OutOfBounds <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-outofbounds>`_,
:doc:`clang-analyzer-osx.coreFoundation.containers.PointerSizedValues <clang-analyzer/osx.coreFoundation.containers.PointerSizedValues>`, `Clang Static Analyzer osx.coreFoundation.containers.PointerSizedValues <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-pointersizedvalues>`_,
:doc:`clang-analyzer-security.FloatLoopCounter <clang-analyzer/security.FloatLoopCounter>`, `Clang Static Analyzer security.FloatLoopCounter <https://clang.llvm.org/docs/analyzer/checkers.html#security-floatloopcounter>`_,
:doc:`clang-analyzer-security.PutenvStackArray <clang-analyzer/security.PutenvStackArray>`, Clang Static Analyzer security.PutenvStackArray,
:doc:`clang-analyzer-security.SetgidSetuidOrder <clang-analyzer/security.SetgidSetuidOrder>`, Clang Static Analyzer security.SetgidSetuidOrder,
:doc:`clang-analyzer-security.cert.env.InvalidPtr <clang-analyzer/security.cert.env.InvalidPtr>`, `Clang Static Analyzer security.cert.env.InvalidPtr <https://clang.llvm.org/docs/analyzer/checkers.html#security-cert-env-invalidptr>`_,
:doc:`clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling <clang-analyzer/security.insecureAPI.DeprecatedOrUnsafeBufferHandling>`, `Clang Static Analyzer security.insecureAPI.DeprecatedOrUnsafeBufferHandling <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-deprecatedorunsafebufferhandling>`_,
Expand All @@ -517,6 +520,7 @@ Check aliases
:doc:`clang-analyzer-security.insecureAPI.strcpy <clang-analyzer/security.insecureAPI.strcpy>`, `Clang Static Analyzer security.insecureAPI.strcpy <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-strcpy>`_,
:doc:`clang-analyzer-security.insecureAPI.vfork <clang-analyzer/security.insecureAPI.vfork>`, `Clang Static Analyzer security.insecureAPI.vfork <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-vfork>`_,
:doc:`clang-analyzer-unix.API <clang-analyzer/unix.API>`, `Clang Static Analyzer unix.API <https://clang.llvm.org/docs/analyzer/checkers.html#unix-api>`_,
:doc:`clang-analyzer-unix.BlockInCriticalSection <clang-analyzer/unix.BlockInCriticalSection>`, `Clang Static Analyzer unix.BlockInCriticalSection <https://clang.llvm.org/docs/analyzer/checkers.html#unix-blockincriticalsection>`_,
:doc:`clang-analyzer-unix.Errno <clang-analyzer/unix.Errno>`, `Clang Static Analyzer unix.Errno <https://clang.llvm.org/docs/analyzer/checkers.html#unix-errno>`_,
:doc:`clang-analyzer-unix.Malloc <clang-analyzer/unix.Malloc>`, `Clang Static Analyzer unix.Malloc <https://clang.llvm.org/docs/analyzer/checkers.html#unix-malloc>`_,
:doc:`clang-analyzer-unix.MallocSizeof <clang-analyzer/unix.MallocSizeof>`, `Clang Static Analyzer unix.MallocSizeof <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mallocsizeof>`_,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -756,3 +756,21 @@ struct test_implicit_throw {
};

}}

void pointer_exception_can_not_escape_with_const_void_handler() noexcept {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'pointer_exception_can_not_escape_with_const_void_handler' which should not throw exceptions
const int value = 42;
try {
throw &value;
} catch (const void *) {
}
}

void pointer_exception_can_not_escape_with_void_handler() noexcept {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'pointer_exception_can_not_escape_with_void_handler' which should not throw exceptions
int value = 42;
try {
throw &value;
} catch (void *) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// RUN: misc-const-correctness.TransformValues: true, \
// RUN: misc-const-correctness.WarnPointersAsValues: false, \
// RUN: misc-const-correctness.TransformPointersAsValues: false \
// RUN: }}" -- -fno-delayed-template-parsing
// RUN: }}" -- -fno-delayed-template-parsing -fexceptions

// ------- Provide test samples for primitive builtins ---------
// - every 'p_*' variable is a 'potential_const_*' variable
Expand Down Expand Up @@ -56,6 +56,15 @@ void some_function(double np_arg0, wchar_t np_arg1) {
np_local6--;
}

int function_try_block() try {
int p_local0 = 0;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const'
// CHECK-FIXES: int const p_local0
return p_local0;
} catch (...) {
return 0;
}

void nested_scopes() {
int p_local0 = 2;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const'
Expand Down
2 changes: 2 additions & 0 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi)
endforeach()
set(RUNTIMES_${target}_LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_ENABLE_USE_BY_CLANG ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_USE_NEW_HEADER_GEN OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
Expand Down Expand Up @@ -385,6 +386,7 @@ foreach(target riscv32-unknown-elf)
endforeach()
set(RUNTIMES_${target}_LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_ENABLE_USE_BY_CLANG ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_USE_NEW_HEADER_GEN OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
Expand Down
74 changes: 74 additions & 0 deletions clang/docs/ClangNVLinkWrapper.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
====================
Clang nvlink Wrapper
====================

.. contents::
:local:

.. _clang-nvlink-wrapper:

Introduction
============

This tools works as a wrapper around the NVIDIA ``nvlink`` linker. The purpose
of this wrapper is to provide an interface similar to the ``ld.lld`` linker
while still relying on NVIDIA's proprietary linker to produce the final output.

``nvlink`` has a number of known quirks that make it difficult to use in a
unified offloading setting. For example, it does not accept ``.o`` files as they
must be named ``.cubin``. Static archives do not work, so passing a ``.a`` will
provide a linker error. ``nvlink`` also does not support link time optimization
and ignores many standard linker arguments. This tool works around these issues.

Usage
=====

This tool can be used with the following options. Any arguments not intended
only for the linker wrapper will be forwarded to ``nvlink``.

.. code-block:: console
OVERVIEW: A utility that wraps around the NVIDIA 'nvlink' linker.
This enables static linking and LTO handling for NVPTX targets.
USAGE: clang-nvlink-wrapper [options] <options to passed to nvlink>
OPTIONS:
--arch <value> Specify the 'sm_' name of the target architecture.
--cuda-path=<dir> Set the system CUDA path
--dry-run Print generated commands without running.
--feature <value> Specify the '+ptx' freature to use for LTO.
-g Specify that this was a debug compile.
-help-hidden Display all available options
-help Display available options (--help-hidden for more)
-L <dir> Add <dir> to the library search path
-l <libname> Search for library <libname>
-mllvm <arg> Arguments passed to LLVM, including Clang invocations,
for which the '-mllvm' prefix is preserved. Use '-mllvm
--help' for a list of options.
-o <path> Path to file to write output
--plugin-opt=jobs=<value>
Number of LTO codegen partitions
--plugin-opt=lto-partitions=<value>
Number of LTO codegen partitions
--plugin-opt=O<O0, O1, O2, or O3>
Optimization level for LTO
--plugin-opt=thinlto<value>
Enable the thin-lto backend
--plugin-opt=<value> Arguments passed to LLVM, including Clang invocations,
for which the '-mllvm' prefix is preserved. Use '-mllvm
--help' for a list of options.
--save-temps Save intermediate results
--version Display the version number and exit
-v Print verbose information
Example
=======

This tool is intended to be invoked when targeting the NVPTX toolchain directly
as a cross-compiling target. This can be used to create standalone GPU
executables with normal linking semantics similar to standard compilation.

.. code-block:: console
clang --target=nvptx64-nvidia-cuda -march=native -flto=full input.c
5 changes: 2 additions & 3 deletions clang/docs/HLSL/AvailabilityDiagnostics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ If the compilation target is a shader library, only availability based on shader

As a result, availability based on specific shader stage will only be diagnosed in code that is reachable from a shader entry point or library export function. It also means that function bodies might be scanned multiple time. When that happens, care should be taken not to produce duplicated diagnostics.

========
Examples
========

Expand All @@ -62,7 +61,7 @@ For the example below, the ``WaveActiveCountBits`` API function became available
The availability of ``ddx`` function depends on a shader stage. It is available for pixel shaders in shader model 2.1 and higher, for compute, mesh and amplification shaders in shader model 6.6 and higher. For any other shader stages it is not available.

Compute shader example
======================
----------------------

.. code-block:: c++

Expand Down Expand Up @@ -94,7 +93,7 @@ With strict diagnostic mode, in addition to the 2 errors above Clang will also e
<>:7:13: error: 'WaveActiveCountBits' is only available on Shader Model 6.5 or newer
Shader library example
======================
----------------------

.. code-block:: c++

Expand Down
2 changes: 1 addition & 1 deletion clang/docs/HLSL/ExpectedDifferences.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

===================================
Expected Differences vs DXC and FXC
===================================

Expand Down
1,174 changes: 7 additions & 1,167 deletions clang/docs/ReleaseNotes.rst

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions clang/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Using Clang Tools
ClangFormatStyleOptions
ClangFormattedStatus
ClangLinkerWrapper
ClangNVLinkWrapper
ClangOffloadBundler
ClangOffloadPackager
ClangRepl
Expand Down
8 changes: 7 additions & 1 deletion clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
}
void Deallocate(void *Ptr) const {}

llvm::StringRef backupStr(llvm::StringRef S) const {
char *Buf = new (*this) char[S.size()];
std::copy(S.begin(), S.end(), Buf);
return llvm::StringRef(Buf, S.size());
}

/// Allocates a \c DeclListNode or returns one from the \c ListNodeFreeList
/// pool.
DeclListNode *AllocateDeclListNode(clang::NamedDecl *ND) {
Expand Down Expand Up @@ -1287,7 +1293,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD);

/// Return the "other" type-specific discriminator for the given type.
uint16_t getPointerAuthTypeDiscriminator(QualType T) const;
uint16_t getPointerAuthTypeDiscriminator(QualType T);

/// Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol
Expand Down
10 changes: 1 addition & 9 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -4854,15 +4854,7 @@ class CXXFoldExpr : public Expr {
CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee,
SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Opcode,
SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc,
std::optional<unsigned> NumExpansions)
: Expr(CXXFoldExprClass, T, VK_PRValue, OK_Ordinary),
LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc),
NumExpansions(NumExpansions ? *NumExpansions + 1 : 0), Opcode(Opcode) {
SubExprs[SubExpr::Callee] = Callee;
SubExprs[SubExpr::LHS] = LHS;
SubExprs[SubExpr::RHS] = RHS;
setDependence(computeDependence(this));
}
std::optional<unsigned> NumExpansions);

CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {}

Expand Down
24 changes: 3 additions & 21 deletions clang/include/clang/AST/StmtOpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,15 +281,6 @@ class OMPExecutableDirective : public Stmt {
return Data->getClauses();
}

/// Was this directive mapped from an another directive?
/// e.g. 1) omp loop bind(parallel) is mapped to OMPD_for
/// 2) omp loop bind(teams) is mapped to OMPD_distribute
/// 3) omp loop bind(thread) is mapped to OMPD_simd
/// It was necessary to note it down in the Directive because of
/// clang::TreeTransform::TransformOMPExecutableDirective() pass in
/// the frontend.
OpenMPDirectiveKind PrevMappedDirective = llvm::omp::OMPD_unknown;

protected:
/// Data, associated with the directive.
OMPChildren *Data = nullptr;
Expand Down Expand Up @@ -354,10 +345,6 @@ class OMPExecutableDirective : public Stmt {
return Inst;
}

void setMappedDirective(OpenMPDirectiveKind MappedDirective) {
PrevMappedDirective = MappedDirective;
}

public:
/// Iterates over expressions/statements used in the construct.
class used_clauses_child_iterator
Expand Down Expand Up @@ -611,8 +598,6 @@ class OMPExecutableDirective : public Stmt {
"Expected directive with the associated statement.");
return Data->getRawStmt();
}

OpenMPDirectiveKind getMappedDirective() const { return PrevMappedDirective; }
};

/// This represents '#pragma omp parallel' directive.
Expand Down Expand Up @@ -1620,8 +1605,7 @@ class OMPSimdDirective : public OMPLoopDirective {
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt,
const HelperExprs &Exprs,
OpenMPDirectiveKind ParamPrevMappedDirective);
const HelperExprs &Exprs);

/// Creates an empty directive with the place
/// for \a NumClauses clauses.
Expand Down Expand Up @@ -1699,8 +1683,7 @@ class OMPForDirective : public OMPLoopDirective {
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, const HelperExprs &Exprs,
Expr *TaskRedRef, bool HasCancel,
OpenMPDirectiveKind ParamPrevMappedDirective);
Expr *TaskRedRef, bool HasCancel);

/// Creates an empty directive with the place
/// for \a NumClauses clauses.
Expand Down Expand Up @@ -4478,8 +4461,7 @@ class OMPDistributeDirective : public OMPLoopDirective {
static OMPDistributeDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, const HelperExprs &Exprs,
OpenMPDirectiveKind ParamPrevMappedDirective);
Stmt *AssociatedStmt, const HelperExprs &Exprs);

/// Creates an empty directive with the place
/// for \a NumClauses clauses.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,9 @@ def warn_pragma_intrinsic_builtin : Warning<
def warn_pragma_unused_expected_var : Warning<
"expected '#pragma unused' argument to be a variable name">,
InGroup<IgnoredPragmas>;
// - #pragma mc_func
def err_pragma_mc_func_not_supported :
Error<"#pragma mc_func is not supported">;
// - #pragma init_seg
def warn_pragma_init_seg_unsupported_target : Warning<
"'#pragma init_seg' is only supported when targeting a "
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,9 @@ def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
def note_ptrauth_virtual_function_incomplete_arg_ret_type :
Note<"%0 is incomplete">;

def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error<
"%select{subtraction|addition}0 of address-of-label expressions is not "
"supported with ptrauth indirect gotos">;

/// main()
// static main() is not an error in C, just in C++.
Expand Down Expand Up @@ -5165,7 +5168,7 @@ def warn_cxx11_compat_variable_template : Warning<
InGroup<CXXPre14Compat>, DefaultIgnore;
def err_template_variable_noparams : Error<
"extraneous 'template<>' in declaration of variable %0">;
def err_template_member : Error<"member %0 declared as a template">;
def err_template_member : Error<"non-static data member %0 cannot be declared as a template">;
def err_member_with_template_arguments : Error<"member %0 cannot have template arguments">;
def err_template_member_noparams : Error<
"extraneous 'template<>' in declaration of member %0">;
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,11 @@ FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,11 @@ LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library fea
LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
LANGOPT(PointerAuthCalls , 1, 0, "function pointer authentication")
LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication")
LANGOPT(PointerAuthIndirectGotos, 1, 0, "indirect gotos pointer authentication")
LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, "incorporate type and address discrimination in authenticated vtable pointers for std::type_info")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
BENIGN_LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0,
"Use type discrimination when signing function pointers")
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ namespace clang {

constexpr unsigned PointerAuthKeyNone = -1;

/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
/// The value is ptrauth_string_discriminator("_ZTVSt9type_info"), i.e.,
/// the vtable type discriminator for classes derived from std::type_info.
constexpr uint16_t StdTypeInfoVTablePointerConstantDiscrimination = 0xB1EA;

class PointerAuthSchema {
public:
enum class Kind : unsigned {
Expand Down Expand Up @@ -154,6 +159,9 @@ class PointerAuthSchema {
};

struct PointerAuthOptions {
/// Do indirect goto label addresses need to be authenticated?
bool IndirectGotos = false;

/// The ABI for C function pointers.
PointerAuthSchema FunctionPointers;

Expand All @@ -175,6 +183,9 @@ struct PointerAuthOptions {

/// The ABI for variadic C++ virtual function pointers.
PointerAuthSchema CXXVirtualVariadicFunctionPointers;

/// The ABI for C++ member function pointers.
PointerAuthSchema CXXMemberFunctionPointers;
};

} // end namespace clang
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- CodeGen/ObjectFilePCHContainerOperations.h - ------------*- C++ -*-===//
//===-- CodeGen/ObjectFilePCHContainerWriter.h ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down Expand Up @@ -29,14 +29,6 @@ class ObjectFilePCHContainerWriter : public PCHContainerWriter {
std::shared_ptr<PCHBuffer> Buffer) const override;
};

/// A PCHContainerReader implementation that uses LLVM to
/// wraps Clang modules inside a COFF, ELF, or Mach-O container.
class ObjectFilePCHContainerReader : public PCHContainerReader {
ArrayRef<StringRef> getFormats() const override;

/// Returns the serialized AST inside the PCH container Buffer.
StringRef ExtractPCH(llvm::MemoryBufferRef Buffer) const override;
};
}

#endif
11 changes: 11 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4249,9 +4249,13 @@ defm ptrauth_vtable_pointer_address_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">;
defm ptrauth_vtable_pointer_type_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
defm ptrauth_type_info_vtable_pointer_discrimination :
OptInCC1FFlag<"ptrauth-type-info-vtable-pointer-discrimination", "Enable type and address discrimination of vtable pointer of std::type_info">;
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
defm ptrauth_function_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination",
"Enable type discrimination on C function pointers">;
defm ptrauth_indirect_gotos : OptInCC1FFlag<"ptrauth-indirect-gotos",
"Enable signing and authentication of indirect goto targets">;
}

def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
Expand Down Expand Up @@ -8082,6 +8086,13 @@ def source_date_epoch : Separate<["-"], "source-date-epoch">,

} // let Visibility = [CC1Option]

defm err_pragma_mc_func_aix : BoolFOption<"err-pragma-mc-func-aix",
PreprocessorOpts<"ErrorOnPragmaMcfuncOnAIX">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Treat uses of #pragma mc_func as errors">,
NegFlag<SetFalse,[], [ClangOption, CC1Option],
"Ignore uses of #pragma mc_func">>;

//===----------------------------------------------------------------------===//
// CUDA Options
//===----------------------------------------------------------------------===//
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Lex/PreprocessorOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ class PreprocessorOptions {
/// If set, the UNIX timestamp specified by SOURCE_DATE_EPOCH.
std::optional<uint64_t> SourceDateEpoch;

/// If set, the preprocessor reports an error when processing #pragma mc_func
/// on AIX.
bool ErrorOnPragmaMcfuncOnAIX = false;

public:
PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}

Expand Down Expand Up @@ -248,6 +252,7 @@ class PreprocessorOptions {
PrecompiledPreambleBytes.first = 0;
PrecompiledPreambleBytes.second = false;
RetainExcludedConditionalBlocks = false;
ErrorOnPragmaMcfuncOnAIX = false;
}
};

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
std::unique_ptr<PragmaHandler> MCFuncPragmaHandler;

std::unique_ptr<CommentHandler> CommentSemaHandler;

Expand Down
23 changes: 1 addition & 22 deletions clang/include/clang/Sema/SemaOpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,7 @@ class SemaOpenMP : public SemaBase {
StmtResult ActOnOpenMPExecutableDirective(
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc,
OpenMPDirectiveKind PrevMappedDirective = llvm::omp::OMPD_unknown);
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc);
/// Called on well-formed '\#pragma omp parallel' after parsing
/// of the associated statement.
StmtResult ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
Expand Down Expand Up @@ -1430,26 +1429,6 @@ class SemaOpenMP : public SemaBase {

/// All `omp assumes` we encountered so far.
SmallVector<OMPAssumeAttr *, 4> OMPAssumeGlobal;

/// OMPD_loop is mapped to OMPD_for, OMPD_distribute or OMPD_simd depending
/// on the parameter of the bind clause. In the methods for the
/// mapped directives, check the parameters of the lastprivate clause.
bool checkLastPrivateForMappedDirectives(ArrayRef<OMPClause *> Clauses);
/// Depending on the bind clause of OMPD_loop map the directive to new
/// directives.
/// 1) loop bind(parallel) --> OMPD_for
/// 2) loop bind(teams) --> OMPD_distribute
/// 3) loop bind(thread) --> OMPD_simd
/// This is being handled in Sema instead of Codegen because of the need for
/// rigorous semantic checking in the new mapped directives.
bool mapLoopConstruct(llvm::SmallVector<OMPClause *> &ClausesWithoutBind,
ArrayRef<OMPClause *> Clauses,
OpenMPBindClauseKind &BindKind,
OpenMPDirectiveKind &Kind,
OpenMPDirectiveKind &PrevMappedDirective,
SourceLocation StartLoc, SourceLocation EndLoc,
const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion);
};

} // namespace clang
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/Serialization/ObjectFilePCHContainerReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===-- Serialization/ObjectFilePCHContainerReader.h ------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SERIALIZATION_OBJECTFILEPCHCONTAINERREADER_H
#define LLVM_CLANG_SERIALIZATION_OBJECTFILEPCHCONTAINERREADER_H

#include "clang/Frontend/PCHContainerOperations.h"

namespace clang {
/// A PCHContainerReader implementation that uses LLVM to
/// wraps Clang modules inside a COFF, ELF, or Mach-O container.
class ObjectFilePCHContainerReader : public PCHContainerReader {
ArrayRef<StringRef> getFormats() const override;

/// Returns the serialized AST inside the PCH container Buffer.
StringRef ExtractPCH(llvm::MemoryBufferRef Buffer) const override;
};
} // namespace clang

#endif
2 changes: 1 addition & 1 deletion clang/lib/APINotes/APINotesFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
const uint16_t VERSION_MINOR = 27; // SingleDeclTableKey
const uint16_t VERSION_MINOR = 28; // nested tags

const uint8_t kSwiftCopyable = 1;
const uint8_t kSwiftNonCopyable = 2;
Expand Down
15 changes: 13 additions & 2 deletions clang/lib/APINotes/APINotesYAMLCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ template <> struct ScalarEnumerationTraits<EnumConvenienceAliasKind> {
} // namespace llvm

namespace {
struct Tag;
typedef std::vector<Tag> TagsSeq;

struct Tag {
StringRef Name;
AvailabilityItem Availability;
Expand All @@ -421,9 +424,11 @@ struct Tag {
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
std::optional<bool> SwiftCopyable;
FunctionsSeq Methods;
};

typedef std::vector<Tag> TagsSeq;
/// Tags that are declared within the current tag. Only the tags that have
/// corresponding API Notes will be listed.
TagsSeq Tags;
};
} // namespace

LLVM_YAML_IS_SEQUENCE_VECTOR(Tag)
Expand Down Expand Up @@ -456,6 +461,7 @@ template <> struct MappingTraits<Tag> {
IO.mapOptional("EnumKind", T.EnumConvenienceKind);
IO.mapOptional("SwiftCopyable", T.SwiftCopyable);
IO.mapOptional("Methods", T.Methods);
IO.mapOptional("Tags", T.Tags);
}
};
} // namespace yaml
Expand Down Expand Up @@ -958,12 +964,17 @@ class YAMLConverter {
ContextInfo CI;
auto TagCtxID = Writer.addContext(ParentContextID, T.Name, ContextKind::Tag,
CI, SwiftVersion);
Context TagCtx(TagCtxID, ContextKind::Tag);

for (const auto &CXXMethod : T.Methods) {
CXXMethodInfo MI;
convertFunction(CXXMethod, MI);
Writer.addCXXMethod(TagCtxID, CXXMethod.Name, MI, SwiftVersion);
}

// Convert nested tags.
for (const auto &Tag : T.Tags)
convertTagContext(TagCtx, Tag, SwiftVersion);
}

void convertTopLevelItems(std::optional<Context> Ctx,
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/AST/ASTConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ CreateUnsatisfiedConstraintRecord(const ASTContext &C,
else {
auto &SubstitutionDiagnostic =
*Detail.get<std::pair<SourceLocation, StringRef> *>();
unsigned MessageSize = SubstitutionDiagnostic.second.size();
char *Mem = new (C) char[MessageSize];
memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
StringRef Message = C.backupStr(SubstitutionDiagnostic.second);
auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
SubstitutionDiagnostic.first, Message);
new (TrailingObject) UnsatisfiedConstraintRecord(NewSubstDiag);
}
}
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3407,7 +3407,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
}
}

uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) const {
uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) {
assert(!T->isDependentType() &&
"cannot compute type discriminator of a dependent type");

Expand All @@ -3417,11 +3417,13 @@ uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) const {
if (T->isFunctionPointerType() || T->isFunctionReferenceType())
T = T->getPointeeType();

if (T->isFunctionType())
if (T->isFunctionType()) {
encodeTypeForFunctionPointerAuth(*this, Out, T);
else
llvm_unreachable(
"type discrimination of non-function type not implemented yet");
} else {
T = T.getUnqualifiedType();
std::unique_ptr<MangleContext> MC(createMangleContext());
MC->mangleCanonicalTypeName(T, Out);
}

return llvm::getPointerAuthStableSipHash(Str);
}
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2949,7 +2949,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) {
if (!hasSameVisibilityContextAndLinkage(FoundEnum, D))
continue;
if (IsStructuralMatch(D, FoundEnum)) {
if (IsStructuralMatch(D, FoundEnum, !SearchName.isEmpty())) {
EnumDecl *FoundDef = FoundEnum->getDefinition();
if (D->isThisDeclarationADefinition() && FoundDef)
return Importer.MapImported(D, FoundDef);
Expand All @@ -2960,7 +2960,12 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
}
}

if (!ConflictingDecls.empty()) {
// In case of unnamed enums, we try to find an existing similar one, if none
// was found, perform the import always.
// Structural in-equivalence is not detected in this way here, but it may
// be found when the parent decl is imported (if the enum is part of a
// class). To make this totally exact a more difficult solution is needed.
if (SearchName && !ConflictingDecls.empty()) {
ExpectedName NameOrErr = Importer.HandleNameConflict(
SearchName, DC, IDNS, ConflictingDecls.data(),
ConflictingDecls.size());
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,9 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType(
if (!IsFirstField && !FD->isZeroSize(Ctx))
continue;

if (FD->isInvalidDecl())
continue;

// -- If X is n array type, [visit the element type]
QualType T = Ctx.getBaseElementType(FD->getType());
if (auto *RD = T->getAsCXXRecordDecl())
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1944,3 +1944,22 @@ CXXParenListInitExpr *CXXParenListInitExpr::CreateEmpty(ASTContext &C,
alignof(CXXParenListInitExpr));
return new (Mem) CXXParenListInitExpr(Empty, NumExprs);
}

CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee,
SourceLocation LParenLoc, Expr *LHS,
BinaryOperatorKind Opcode,
SourceLocation EllipsisLoc, Expr *RHS,
SourceLocation RParenLoc,
std::optional<unsigned> NumExpansions)
: Expr(CXXFoldExprClass, T, VK_PRValue, OK_Ordinary), LParenLoc(LParenLoc),
EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc),
NumExpansions(NumExpansions ? *NumExpansions + 1 : 0), Opcode(Opcode) {
// We rely on asserted invariant to distinguish left and right folds.
assert(((LHS && LHS->containsUnexpandedParameterPack()) !=
(RHS && RHS->containsUnexpandedParameterPack())) &&
"Exactly one of LHS or RHS should contain an unexpanded pack");
SubExprs[SubExpr::Callee] = Callee;
SubExprs[SubExpr::LHS] = LHS;
SubExprs[SubExpr::RHS] = RHS;
setDependence(computeDependence(this));
}
36 changes: 26 additions & 10 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12949,19 +12949,35 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
Info.Ctx.getTargetInfo().getMaxAtomicInlineWidth();
if (Size <= Info.Ctx.toCharUnitsFromBits(InlineWidthBits)) {
if (BuiltinOp == Builtin::BI__c11_atomic_is_lock_free ||
Size == CharUnits::One() ||
E->getArg(1)->isNullPointerConstant(Info.Ctx,
Expr::NPC_NeverValueDependent))
// OK, we will inline appropriately-aligned operations of this size,
// and _Atomic(T) is appropriately-aligned.
Size == CharUnits::One())
return Success(1, E);

QualType PointeeType = E->getArg(1)->IgnoreImpCasts()->getType()->
castAs<PointerType>()->getPointeeType();
if (!PointeeType->isIncompleteType() &&
Info.Ctx.getTypeAlignInChars(PointeeType) >= Size) {
// OK, we will inline operations on this object.
// If the pointer argument can be evaluated to a compile-time constant
// integer (or nullptr), check if that value is appropriately aligned.
const Expr *PtrArg = E->getArg(1);
Expr::EvalResult ExprResult;
APSInt IntResult;
if (PtrArg->EvaluateAsRValue(ExprResult, Info.Ctx) &&
ExprResult.Val.toIntegralConstant(IntResult, PtrArg->getType(),
Info.Ctx) &&
IntResult.isAligned(Size.getAsAlign()))
return Success(1, E);

// Otherwise, check if the type's alignment against Size.
if (auto *ICE = dyn_cast<ImplicitCastExpr>(PtrArg)) {
// Drop the potential implicit-cast to 'const volatile void*', getting
// the underlying type.
if (ICE->getCastKind() == CK_BitCast)
PtrArg = ICE->getSubExpr();
}

if (auto PtrTy = PtrArg->getType()->getAs<PointerType>()) {
QualType PointeeType = PtrTy->getPointeeType();
if (!PointeeType->isIncompleteType() &&
Info.Ctx.getTypeAlignInChars(PointeeType) >= Size) {
// OK, we will inline operations on this object.
return Success(1, E);
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ using namespace clang::interp;
/// Similar information is available via ASTContext::BuiltinInfo,
/// but that is not correct for our use cases.
static bool isUnevaluatedBuiltin(unsigned BuiltinID) {
return BuiltinID == Builtin::BI__builtin_classify_type;
return BuiltinID == Builtin::BI__builtin_classify_type ||
BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size;
}

Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
}

static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D, unsigned FieldOffset) {
bool IsActive, const Descriptor *D, unsigned FieldOffset,
bool IsVirtualBase) {
assert(D);
assert(D->ElemRecord);

Expand All @@ -172,13 +173,14 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
Desc->Desc = D;
Desc->IsInitialized = D->IsArray;
Desc->IsBase = true;
Desc->IsVirtualBase = IsVirtualBase;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || D->IsConst;
Desc->IsFieldMutable = IsMutable || D->IsMutable;

for (const auto &V : D->ElemRecord->bases())
initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,
V.Offset);
V.Offset, false);
for (const auto &F : D->ElemRecord->fields())
initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion,
F.Desc, F.Offset);
Expand All @@ -187,11 +189,11 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D) {
for (const auto &V : D->ElemRecord->bases())
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset);
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false);
for (const auto &F : D->ElemRecord->fields())
initField(B, Ptr, IsConst, IsMutable, IsActive, D->ElemRecord->isUnion(), F.Desc, F.Offset);
for (const auto &V : D->ElemRecord->virtual_bases())
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset);
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true);
}

static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ struct InlineDescriptor {
/// Flag indicating if the field is an embedded base class.
LLVM_PREFERRED_TYPE(bool)
unsigned IsBase : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsVirtualBase : 1;
/// Flag indicating if the field is the active member of a union.
LLVM_PREFERRED_TYPE(bool)
unsigned IsActive : 1;
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ class FunctionPointer final {
bool Valid;

public:
FunctionPointer(const Function *Func) : Func(Func), Valid(true) {
assert(Func);
}
FunctionPointer() = default;
FunctionPointer(const Function *Func) : Func(Func), Valid(true) {}

FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
FunctionPointer(uintptr_t IntVal, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)), Valid(false) {}

const Function *getFunction() const { return Func; }
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
}

static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (Ptr.isIntegralPointer())
if (!Ptr.isBlockPointer())
return true;
return CheckConstant(S, OpPC, Ptr.getDeclDesc());
}
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,15 @@ template <typename T>
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
if (RHS.isZero()) {
const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
if constexpr (std::is_same_v<T, Floating>) {
S.CCEDiag(Op, diag::note_expr_divide_by_zero)
<< Op->getRHS()->getSourceRange();
return true;
}

S.FFDiag(Op, diag::note_expr_divide_by_zero)
<< Op->getRHS()->getSourceRange();
if constexpr (!std::is_same_v<T, Floating>)
return false;
return false;
}

if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
Expand Down Expand Up @@ -2806,6 +2811,13 @@ inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
using ToT = typename PrimConv<TOut>::T;

const FromT &OldPtr = S.Stk.pop<FromT>();

if constexpr (std::is_same_v<FromT, FunctionPointer> &&
std::is_same_v<ToT, Pointer>) {
S.Stk.push<Pointer>(OldPtr.getFunction());
return true;
}

S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
return true;
}
Expand Down
32 changes: 23 additions & 9 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,15 +942,29 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC,
if (Ptr.isZero())
return returnBool(true);

QualType PointeeType = Call->getArg(1)
->IgnoreImpCasts()
->getType()
->castAs<PointerType>()
->getPointeeType();
// OK, we will inline operations on this object.
if (!PointeeType->isIncompleteType() &&
S.getCtx().getTypeAlignInChars(PointeeType) >= Size)
return returnBool(true);
if (Ptr.isIntegralPointer()) {
uint64_t IntVal = Ptr.getIntegerRepresentation();
if (APSInt(APInt(64, IntVal, false), true).isAligned(Size.getAsAlign()))
return returnBool(true);
}

const Expr *PtrArg = Call->getArg(1);
// Otherwise, check if the type's alignment against Size.
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(PtrArg)) {
// Drop the potential implicit-cast to 'const volatile void*', getting
// the underlying type.
if (ICE->getCastKind() == CK_BitCast)
PtrArg = ICE->getSubExpr();
}

if (auto PtrTy = PtrArg->getType()->getAs<PointerType>()) {
QualType PointeeType = PtrTy->getPointeeType();
if (!PointeeType->isIncompleteType() &&
S.getCtx().getTypeAlignInChars(PointeeType) >= Size) {
// OK, we will inline operations on this object.
return returnBool(true);
}
}
}
}

Expand Down
39 changes: 31 additions & 8 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Pointer::Pointer(Pointer &&P)
}

Pointer::~Pointer() {
if (isIntegralPointer())
if (!isBlockPointer())
return;

if (Block *Pointee = PointeeStorage.BS.Pointee) {
Expand Down Expand Up @@ -87,6 +87,8 @@ void Pointer::operator=(const Pointer &P) {
PointeeStorage.BS.Pointee->addPointer(this);
} else if (P.isIntegralPointer()) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else if (P.isFunctionPointer()) {
PointeeStorage.Fn = P.PointeeStorage.Fn;
} else {
assert(false && "Unhandled storage kind");
}
Expand Down Expand Up @@ -115,6 +117,8 @@ void Pointer::operator=(Pointer &&P) {
PointeeStorage.BS.Pointee->addPointer(this);
} else if (P.isIntegralPointer()) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else if (P.isFunctionPointer()) {
PointeeStorage.Fn = P.PointeeStorage.Fn;
} else {
assert(false && "Unhandled storage kind");
}
Expand All @@ -131,6 +135,8 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
if (isFunctionPointer())
return asFunctionPointer().toAPValue(ASTCtx);

// Build the lvalue base from the block.
const Descriptor *Desc = getDeclDesc();
Expand Down Expand Up @@ -180,18 +186,30 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
Ptr = Ptr.getArray();
} else {
// TODO: figure out if base is virtual
bool IsVirtual = false;

// Create a path entry for the field.
const Descriptor *Desc = Ptr.getFieldDesc();
if (const auto *BaseOrMember = Desc->asDecl()) {
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
Ptr = Ptr.getBase();

if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember))
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
Ptr = Ptr.getBase();
Offset += getFieldOffset(FD);
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
IsVirtual = Ptr.isVirtualBaseClass();
Ptr = Ptr.getBase();
const Record *BaseRecord = Ptr.getRecord();

const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
cast<CXXRecordDecl>(BaseRecord->getDecl()));
if (IsVirtual)
Offset += Layout.getVBaseClassOffset(RD);
else
Offset += Layout.getBaseClassOffset(RD);

} else {
Ptr = Ptr.getBase();
}
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
continue;
}
llvm_unreachable("Invalid field type");
Expand Down Expand Up @@ -251,7 +269,7 @@ std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
}

bool Pointer::isInitialized() const {
if (isIntegralPointer())
if (!isBlockPointer())
return true;

if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
Expand Down Expand Up @@ -287,7 +305,7 @@ bool Pointer::isInitialized() const {
}

void Pointer::initialize() const {
if (isIntegralPointer())
if (!isBlockPointer())
return;

assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
Expand Down Expand Up @@ -356,10 +374,15 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {

if (A.isIntegralPointer() && B.isIntegralPointer())
return true;
if (A.isFunctionPointer() && B.isFunctionPointer())
return true;

if (A.isIntegralPointer() || B.isIntegralPointer())
return A.getSource() == B.getSource();

if (A.StorageKind != B.StorageKind)
return false;

return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
}

Expand Down
45 changes: 36 additions & 9 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_INTERP_POINTER_H

#include "Descriptor.h"
#include "FunctionPointer.h"
#include "InterpBlock.h"
#include "clang/AST/ComparisonCategories.h"
#include "clang/AST/Decl.h"
Expand Down Expand Up @@ -45,7 +46,7 @@ struct IntPointer {
uint64_t Value;
};

enum class Storage { Block, Int };
enum class Storage { Block, Int, Fn };

/// A pointer to a memory block, live or dead.
///
Expand Down Expand Up @@ -96,6 +97,10 @@ class Pointer {
PointeeStorage.Int.Value = Address;
PointeeStorage.Int.Desc = Desc;
}
Pointer(const Function *F, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Fn) {
PointeeStorage.Fn = FunctionPointer(F);
}
~Pointer();

void operator=(const Pointer &P);
Expand Down Expand Up @@ -126,6 +131,8 @@ class Pointer {
uint64_t getIntegerRepresentation() const {
if (isIntegralPointer())
return asIntPointer().Value + (Offset * elemSize());
if (isFunctionPointer())
return asFunctionPointer().getIntegerRepresentation();
return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
}

Expand All @@ -137,6 +144,8 @@ class Pointer {
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
if (isIntegralPointer())
return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);
if (isFunctionPointer())
return Pointer(asFunctionPointer().getFunction(), Idx);

if (asBlockPointer().Base == RootPtrMark)
return Pointer(asBlockPointer().Pointee, RootPtrMark,
Expand Down Expand Up @@ -247,18 +256,20 @@ class Pointer {
bool isZero() const {
if (isBlockPointer())
return asBlockPointer().Pointee == nullptr;
if (isFunctionPointer())
return asFunctionPointer().isZero();
assert(isIntegralPointer());
return asIntPointer().Value == 0 && Offset == 0;
}
/// Checks if the pointer is live.
bool isLive() const {
if (isIntegralPointer())
if (!isBlockPointer())
return true;
return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead;
}
/// Checks if the item is a field in an object.
bool isField() const {
if (isIntegralPointer())
if (!isBlockPointer())
return false;

return !isRoot() && getFieldDesc()->asDecl();
Expand All @@ -268,6 +279,8 @@ class Pointer {
const Descriptor *getDeclDesc() const {
if (isIntegralPointer())
return asIntPointer().Desc;
if (isFunctionPointer())
return nullptr;

assert(isBlockPointer());
assert(asBlockPointer().Pointee);
Expand All @@ -279,7 +292,10 @@ class Pointer {
DeclTy getSource() const {
if (isBlockPointer())
return getDeclDesc()->getSource();

if (isFunctionPointer()) {
const Function *F = asFunctionPointer().getFunction();
return F ? F->getDecl() : DeclTy();
}
assert(isIntegralPointer());
return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy();
}
Expand Down Expand Up @@ -354,6 +370,7 @@ class Pointer {
/// Returns the offset into an array.
unsigned getOffset() const {
assert(Offset != PastEndMark && "invalid offset");
assert(isBlockPointer());
if (asBlockPointer().Base == RootPtrMark)
return Offset;

Expand Down Expand Up @@ -421,8 +438,14 @@ class Pointer {
assert(isIntegralPointer());
return PointeeStorage.Int;
}
[[nodiscard]] const FunctionPointer &asFunctionPointer() const {
assert(isFunctionPointer());
return PointeeStorage.Fn;
}

bool isBlockPointer() const { return StorageKind == Storage::Block; }
bool isIntegralPointer() const { return StorageKind == Storage::Int; }
bool isFunctionPointer() const { return StorageKind == Storage::Fn; }

/// Returns the record descriptor of a class.
const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
Expand All @@ -445,7 +468,7 @@ class Pointer {
}
/// Checks if the storage is static.
bool isStatic() const {
if (isIntegralPointer())
if (!isBlockPointer())
return true;
assert(asBlockPointer().Pointee);
return asBlockPointer().Pointee->isStatic();
Expand All @@ -469,7 +492,7 @@ class Pointer {
}

bool isWeak() const {
if (isIntegralPointer())
if (!isBlockPointer())
return false;

assert(isBlockPointer());
Expand All @@ -487,6 +510,9 @@ class Pointer {
}
/// Checks if a structure is a base class.
bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
bool isVirtualBaseClass() const {
return isField() && getInlineDesc()->IsVirtualBase;
}
/// Checks if the pointer points to a dummy value.
bool isDummy() const {
if (!isBlockPointer())
Expand Down Expand Up @@ -525,8 +551,8 @@ class Pointer {

/// Returns the number of elements.
unsigned getNumElems() const {
if (isIntegralPointer())
return ~unsigned(0);
if (!isBlockPointer())
return ~0u;
return getSize() / elemSize();
}

Expand All @@ -552,7 +578,7 @@ class Pointer {

/// Checks if the index is one past end.
bool isOnePastEnd() const {
if (isIntegralPointer())
if (isIntegralPointer() || isFunctionPointer())
return false;

if (!asBlockPointer().Pointee)
Expand Down Expand Up @@ -689,6 +715,7 @@ class Pointer {
union {
BlockPointer BS;
IntPointer Int;
FunctionPointer Fn;
} PointeeStorage;
Storage StorageKind = Storage::Int;
};
Expand Down
24 changes: 11 additions & 13 deletions clang/lib/AST/StmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,11 @@ OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C,
/*NumChildren=*/1);
}

OMPSimdDirective *OMPSimdDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, OpenMPDirectiveKind ParamPrevMappedDirective) {
OMPSimdDirective *
OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs) {
auto *Dir = createDirective<OMPSimdDirective>(
C, Clauses, AssociatedStmt, numLoopChildren(CollapsedNum, OMPD_simd),
StartLoc, EndLoc, CollapsedNum);
Expand All @@ -320,7 +321,6 @@ OMPSimdDirective *OMPSimdDirective::Create(
Dir->setDependentInits(Exprs.DependentInits);
Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setMappedDirective(ParamPrevMappedDirective);
return Dir;
}

Expand All @@ -336,8 +336,7 @@ OMPSimdDirective *OMPSimdDirective::CreateEmpty(const ASTContext &C,
OMPForDirective *OMPForDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, Expr *TaskRedRef, bool HasCancel,
OpenMPDirectiveKind ParamPrevMappedDirective) {
const HelperExprs &Exprs, Expr *TaskRedRef, bool HasCancel) {
auto *Dir = createDirective<OMPForDirective>(
C, Clauses, AssociatedStmt, numLoopChildren(CollapsedNum, OMPD_for) + 1,
StartLoc, EndLoc, CollapsedNum);
Expand Down Expand Up @@ -367,7 +366,6 @@ OMPForDirective *OMPForDirective::Create(
Dir->setPreInits(Exprs.PreInits);
Dir->setTaskReductionRefExpr(TaskRedRef);
Dir->setHasCancel(HasCancel);
Dir->setMappedDirective(ParamPrevMappedDirective);
return Dir;
}

Expand Down Expand Up @@ -1569,10 +1567,11 @@ OMPParallelMaskedTaskLoopSimdDirective::CreateEmpty(const ASTContext &C,
CollapsedNum);
}

OMPDistributeDirective *OMPDistributeDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, OpenMPDirectiveKind ParamPrevMappedDirective) {
OMPDistributeDirective *
OMPDistributeDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, const HelperExprs &Exprs) {
auto *Dir = createDirective<OMPDistributeDirective>(
C, Clauses, AssociatedStmt,
numLoopChildren(CollapsedNum, OMPD_distribute), StartLoc, EndLoc,
Expand Down Expand Up @@ -1601,7 +1600,6 @@ OMPDistributeDirective *OMPDistributeDirective::Create(
Dir->setDependentInits(Exprs.DependentInits);
Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setMappedDirective(ParamPrevMappedDirective);
return Dir;
}

Expand Down
9 changes: 8 additions & 1 deletion clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
StringRef AArch64TargetInfo::getABI() const { return ABI; }

bool AArch64TargetInfo::setABI(const std::string &Name) {
if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs")
if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs" &&
Name != "pauthtest")
return false;

ABI = Name;
Expand All @@ -218,6 +219,12 @@ bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
Diags.Report(diag::err_target_unsupported_abi_with_fpu) << ABI;
return false;
}
if (getTriple().getEnvironment() == llvm::Triple::PAuthTest &&
getTriple().getOS() != llvm::Triple::Linux) {
Diags.Report(diag::err_target_unsupported_abi_for_triple)
<< getTriple().getEnvironmentName() << getTriple().getTriple();
return false;
}
return true;
}

Expand Down
23 changes: 22 additions & 1 deletion clang/lib/Basic/Targets/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,24 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,

// Define __loongarch_arch.
StringRef ArchName = getCPU();
Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"'));
if (ArchName == "loongarch64") {
if (HasFeatureLSX) {
// TODO: As more features of the V1.1 ISA are supported, a unified "v1.1"
// arch feature set will be used to include all sub-features belonging to
// the V1.1 ISA version.
if (HasFeatureFrecipe)
Builder.defineMacro("__loongarch_arch",
Twine('"') + "la64v1.1" + Twine('"'));
else
Builder.defineMacro("__loongarch_arch",
Twine('"') + "la64v1.0" + Twine('"'));
} else {
Builder.defineMacro("__loongarch_arch",
Twine('"') + ArchName + Twine('"'));
}
} else {
Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"'));
}

// Define __loongarch_tune.
StringRef TuneCPU = getTargetOpts().TuneCPU;
Expand All @@ -216,6 +233,8 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__loongarch_simd_width", "128");
Builder.defineMacro("__loongarch_sx", Twine(1));
}
if (HasFeatureFrecipe)
Builder.defineMacro("__loongarch_frecipe", Twine(1));

StringRef ABI = getABI();
if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
Expand Down Expand Up @@ -291,6 +310,8 @@ bool LoongArchTargetInfo::handleTargetFeatures(
HasFeatureLASX = true;
else if (Feature == "-ual")
HasUnalignedAccess = false;
else if (Feature == "+frecipe")
HasFeatureFrecipe = true;
}
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/LoongArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
bool HasFeatureF;
bool HasFeatureLSX;
bool HasFeatureLASX;
bool HasFeatureFrecipe;

public:
LoongArchTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
Expand All @@ -37,6 +38,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
HasFeatureF = false;
HasFeatureLSX = false;
HasFeatureLASX = false;
HasFeatureFrecipe = false;
LongDoubleWidth = 128;
LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad();
Expand Down
39 changes: 26 additions & 13 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_ARCH_PWR9");
if (ArchDefs & ArchDefinePwr10)
Builder.defineMacro("_ARCH_PWR10");
if (ArchDefs & ArchDefinePwr11)
Builder.defineMacro("_ARCH_PWR11");
if (ArchDefs & ArchDefineA2)
Builder.defineMacro("_ARCH_A2");
if (ArchDefs & ArchDefineE500)
Expand Down Expand Up @@ -622,10 +624,17 @@ bool PPCTargetInfo::initFeatureMap(
addP10SpecificFeatures(Features);
}

// Future CPU should include all of the features of Power 10 as well as any
// Power11 includes all the same features as Power10 plus any features
// specific to the Power11 core.
if (CPU == "pwr11" || CPU == "power11") {
initFeatureMap(Features, Diags, "pwr10", FeaturesVec);
addP11SpecificFeatures(Features);
}

// Future CPU should include all of the features of Power 11 as well as any
// additional features (yet to be determined) specific to it.
if (CPU == "future") {
initFeatureMap(Features, Diags, "pwr10", FeaturesVec);
initFeatureMap(Features, Diags, "pwr11", FeaturesVec);
addFutureSpecificFeatures(Features);
}

Expand Down Expand Up @@ -696,6 +705,10 @@ void PPCTargetInfo::addP10SpecificFeatures(
Features["isa-v31-instructions"] = true;
}

// Add any Power11 specific features.
void PPCTargetInfo::addP11SpecificFeatures(
llvm::StringMap<bool> &Features) const {}

// Add features specific to the "Future" CPU.
void PPCTargetInfo::addFutureSpecificFeatures(
llvm::StringMap<bool> &Features) const {}
Expand Down Expand Up @@ -870,17 +883,17 @@ ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const {
}

static constexpr llvm::StringLiteral ValidCPUNames[] = {
{"generic"}, {"440"}, {"450"}, {"601"}, {"602"},
{"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"},
{"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"},
{"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"},
{"g5"}, {"a2"}, {"e500"}, {"e500mc"}, {"e5500"},
{"power3"}, {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"},
{"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"},
{"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"},
{"pwr8"}, {"power9"}, {"pwr9"}, {"power10"}, {"pwr10"},
{"powerpc"}, {"ppc"}, {"ppc32"}, {"powerpc64"}, {"ppc64"},
{"powerpc64le"}, {"ppc64le"}, {"future"}};
{"generic"}, {"440"}, {"450"}, {"601"}, {"602"},
{"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"},
{"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"},
{"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"},
{"g5"}, {"a2"}, {"e500"}, {"e500mc"}, {"e5500"},
{"power3"}, {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"},
{"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"},
{"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"},
{"pwr8"}, {"power9"}, {"pwr9"}, {"power10"}, {"pwr10"},
{"power11"}, {"pwr11"}, {"powerpc"}, {"ppc"}, {"ppc32"},
{"powerpc64"}, {"ppc64"}, {"powerpc64le"}, {"ppc64le"}, {"future"}};

bool PPCTargetInfo::isValidCPUName(StringRef Name) const {
return llvm::is_contained(ValidCPUNames, Name);
Expand Down
19 changes: 13 additions & 6 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
ArchDefinePwr8 = 1 << 12,
ArchDefinePwr9 = 1 << 13,
ArchDefinePwr10 = 1 << 14,
ArchDefineFuture = 1 << 15,
ArchDefineA2 = 1 << 16,
ArchDefinePwr11 = 1 << 15,
ArchDefineFuture = 1 << 16,
ArchDefineA2 = 1 << 17,
ArchDefineE500 = 1 << 18
} ArchDefineTypes;

Expand Down Expand Up @@ -166,11 +167,16 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x |
ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr |
ArchDefinePpcsq)
.Cases("power11", "pwr11",
ArchDefinePwr11 | ArchDefinePwr10 | ArchDefinePwr9 |
ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 |
ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 |
ArchDefinePpcgr | ArchDefinePpcsq)
.Case("future",
ArchDefineFuture | ArchDefinePwr10 | ArchDefinePwr9 |
ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 |
ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 |
ArchDefinePpcgr | ArchDefinePpcsq)
ArchDefineFuture | ArchDefinePwr11 | ArchDefinePwr10 |
ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 |
ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 |
ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
.Cases("8548", "e500", ArchDefineE500)
.Default(ArchDefineNone);
}
Expand All @@ -192,6 +198,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
const std::vector<std::string> &FeaturesVec) const override;

void addP10SpecificFeatures(llvm::StringMap<bool> &Features) const;
void addP11SpecificFeatures(llvm::StringMap<bool> &Features) const;
void addFutureSpecificFeatures(llvm::StringMap<bool> &Features) const;

bool handleTargetFeatures(std::vector<std::string> &Features,
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,9 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
return CCCR_OK;
}
}

bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
// Only allow extensions we have a known bit position for in the
// __riscv_feature_bits structure.
return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitPosition(Feature);
}
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ class RISCVTargetInfo : public TargetInfo {
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}

bool supportsCpuSupports() const override { return getTriple().isOSLinux(); }
bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
bool validateCpuSupports(StringRef Feature) const override;
};
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
public:
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,15 +513,6 @@ class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
public:
NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}

LangOptions::FPEvalMethodKind getFPEvalMethod() const override {
VersionTuple OsVersion = getTriple().getOSVersion();
// New NetBSD uses the default rounding mode.
if (OsVersion >= VersionTuple(6, 99, 26) || OsVersion.getMajor() == 0)
return X86_32TargetInfo::getFPEvalMethod();
// NetBSD before 6.99.26 defaults to "double" rounding.
return LangOptions::FPEvalMethodKind::FEM_Double;
}
};

class LLVM_LIBRARY_VISIBILITY OpenBSDI386TargetInfo
Expand Down
53 changes: 53 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/TargetParser/AArch64TargetParser.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/X86TargetParser.h"
#include <optional>
#include <sstream>
Expand Down Expand Up @@ -14308,6 +14309,16 @@ Value *CodeGenFunction::EmitAArch64CpuInit() {
return Builder.CreateCall(Func);
}

Value *CodeGenFunction::EmitRISCVCpuInit() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
llvm::FunctionCallee Func =
CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
CalleeGV->setDSOLocal(true);
CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
return Builder.CreateCall(Func);
}

Value *CodeGenFunction::EmitX86CpuInit() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
/*Variadic*/ false);
Expand Down Expand Up @@ -14360,6 +14371,42 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
return Result;
}

Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {

const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
return Builder.getFalse();

// Note: We are making an unchecked assumption that the size of the
// feature array is >= 1. This holds for any version of compiler-rt
// which defines this interface.
llvm::ArrayType *ArrayOfInt64Ty = llvm::ArrayType::get(Int64Ty, 1);
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
llvm::Constant *RISCVFeaturesBits =
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
auto *GV = cast<llvm::GlobalValue>(RISCVFeaturesBits);
GV->setDSOLocal(true);

auto LoadFeatureBit = [&](unsigned Index) {
// Create GEP then load.
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
IndexVal};
Value *Ptr =
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
Value *FeaturesBit =
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
return FeaturesBit;
};

int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(FeatureStr);
assert(BitPos != -1 && "validation should have rejected this feature");
Value *MaskV = Builder.getInt64(1ULL << BitPos);
Value *Bitset = Builder.CreateAnd(LoadFeatureBit(0), MaskV);
return Builder.CreateICmpEQ(Bitset, MaskV);
}

Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
if (BuiltinID == Builtin::BI__builtin_cpu_is)
Expand Down Expand Up @@ -21854,6 +21901,12 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {

if (BuiltinID == Builtin::BI__builtin_cpu_supports)
return EmitRISCVCpuSupports(E);
if (BuiltinID == Builtin::BI__builtin_cpu_init)
return EmitRISCVCpuInit();

SmallVector<Value *, 4> Ops;
llvm::Type *ResultType = ConvertType(E->getType());

Expand Down
213 changes: 115 additions & 98 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5034,7 +5034,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
llvm::CallBase **callOrInvoke, bool IsMustTail,
SourceLocation Loc) {
SourceLocation Loc,
bool IsVirtualFunctionPointerThunk) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.

assert(Callee.isOrdinary() || Callee.isVirtual());
Expand Down Expand Up @@ -5098,7 +5099,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
RawAddress SRetAlloca = RawAddress::invalid();
llvm::Value *UnusedReturnSizePtr = nullptr;
if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) {
if (!ReturnValue.isNull()) {
if (IsVirtualFunctionPointerThunk && RetAI.isIndirect()) {
SRetPtr = makeNaturalAddressForPointer(CurFn->arg_begin() +
IRFunctionArgs.getSRetArgNo(),
RetTy, CharUnits::fromQuantity(1));
} else if (!ReturnValue.isNull()) {
SRetPtr = ReturnValue.getAddress();
} else {
SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca);
Expand Down Expand Up @@ -5877,119 +5882,131 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CallArgs.freeArgumentMemory(*this);

// Extract the return value.
RValue Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::CoerceAndExpand: {
auto coercionType = RetAI.getCoerceAndExpandType();

Address addr = SRetPtr.withElementType(coercionType);

assert(CI->getType() == RetAI.getUnpaddedCoerceAndExpandType());
bool requiresExtract = isa<llvm::StructType>(CI->getType());
RValue Ret;

unsigned unpaddedIndex = 0;
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
llvm::Type *eltType = coercionType->getElementType(i);
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CI;
if (requiresExtract)
elt = Builder.CreateExtractValue(elt, unpaddedIndex++);
else
assert(unpaddedIndex == 0);
Builder.CreateStore(elt, eltAddr);
// If the current function is a virtual function pointer thunk, avoid copying
// the return value of the musttail call to a temporary.
if (IsVirtualFunctionPointerThunk) {
Ret = RValue::get(CI);
} else {
Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::CoerceAndExpand: {
auto coercionType = RetAI.getCoerceAndExpandType();

Address addr = SRetPtr.withElementType(coercionType);

assert(CI->getType() == RetAI.getUnpaddedCoerceAndExpandType());
bool requiresExtract = isa<llvm::StructType>(CI->getType());

unsigned unpaddedIndex = 0;
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
llvm::Type *eltType = coercionType->getElementType(i);
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType))
continue;
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CI;
if (requiresExtract)
elt = Builder.CreateExtractValue(elt, unpaddedIndex++);
else
assert(unpaddedIndex == 0);
Builder.CreateStore(elt, eltAddr);
}
[[fallthrough]];
}
[[fallthrough]];
}

case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
if (UnusedReturnSizePtr)
PopCleanupBlock();
return ret;
}

case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
// construct the appropriate return value for our caller.
return GetUndefRValue(RetTy);
case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
if (UnusedReturnSizePtr)
PopCleanupBlock();
return ret;
}

case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
case TEK_Aggregate: {
Address DestPtr = ReturnValue.getAddress();
bool DestIsVolatile = ReturnValue.isVolatile();
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
// construct the appropriate return value for our caller.
return GetUndefRValue(RetTy);

case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy &&
RetAI.getDirectOffset() == 0) {
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
case TEK_Aggregate: {
Address DestPtr = ReturnValue.getAddress();
bool DestIsVolatile = ReturnValue.isVolatile();

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
EmitAggregateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
}
case TEK_Scalar: {
// If the argument doesn't match, perform a bitcast to coerce it.
// This can happen due to trivial type mismatches.
llvm::Value *V = CI;
if (V->getType() != RetIRTy)
V = Builder.CreateBitCast(V, RetIRTy);
return RValue::get(V);
}
EmitAggregateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
}
llvm_unreachable("bad evaluation kind");
}
case TEK_Scalar: {
// If the argument doesn't match, perform a bitcast to coerce it. This
// can happen due to trivial type mismatches.

// If coercing a fixed vector from a scalable vector for ABI
// compatibility, and the types match, use the llvm.vector.extract
// intrinsic to perform the conversion.
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
llvm::Value *V = CI;
if (V->getType() != RetIRTy)
V = Builder.CreateBitCast(V, RetIRTy);
return RValue::get(V);
}
if (auto *ScalableSrcTy =
dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDstTy->getElementType() ==
ScalableSrcTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
V = Builder.CreateExtractVector(FixedDstTy, V, Zero,
"cast.fixed");
return RValue::get(V);
}
}
}
llvm_unreachable("bad evaluation kind");
}

// If coercing a fixed vector from a scalable vector for ABI
// compatibility, and the types match, use the llvm.vector.extract
// intrinsic to perform the conversion.
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
llvm::Value *V = CI;
if (auto *ScalableSrcTy =
dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDstTy->getElementType() == ScalableSrcTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
V = Builder.CreateExtractVector(FixedDstTy, V, Zero, "cast.fixed");
return RValue::get(V);
}
Address DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
}
}

Address DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
// An empty record can overlap other data (if declared with
// no_unique_address); omit the store for such types - as there is no
// actual data to store.
if (!isEmptyRecord(getContext(), RetTy, true)) {
// If the value is offset in memory, apply the offset now.
Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
}

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}

// An empty record can overlap other data (if declared with
// no_unique_address); omit the store for such types - as there is no
// actual data to store.
if (!isEmptyRecord(getContext(), RetTy, true)) {
// If the value is offset in memory, apply the offset now.
Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
case ABIArgInfo::Expand:
case ABIArgInfo::IndirectAliased:
llvm_unreachable("Invalid ABI kind for return argument");
}

return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}

case ABIArgInfo::Expand:
case ABIArgInfo::IndirectAliased:
llvm_unreachable("Invalid ABI kind for return argument");
}

llvm_unreachable("Unhandled ABIArgInfo::Kind");
} ();
llvm_unreachable("Unhandled ABIArgInfo::Kind");
}();
}

// Emit the assume_aligned check on the return value.
if (Ret.isScalar() && TargetDecl) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,11 @@ static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD,
const CGRecordLayout &Layout = CGF.CGM.getTypes().getCGRecordLayout(RD);
int64_t FieldNo = -1;
for (const FieldDecl *FD : RD->fields()) {
if (!Layout.containsFieldDecl(FD))
// This could happen if the field has a struct type that's empty. I don't
// know why either.
continue;

FieldNo = Layout.getLLVMFieldNo(FD);
if (FD == Field) {
Indices.emplace_back(std::make_pair(RD, CGF.Builder.getInt32(FieldNo)));
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/CodeGen/CGPointerAuth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,40 @@ llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);
}

CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {
assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");
const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
if (!Schema)
return CGPointerAuthInfo();

assert(!Schema.isAddressDiscriminated() &&
"function pointers cannot use address-specific discrimination");

llvm::ConstantInt *Discriminator =
getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT);
return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
/* IsIsaPointer */ false,
/* AuthenticatesNullValues */ false, Discriminator);
}

llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,
QualType FT) {
if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))
return getConstantSignedPointer(
Pointer, PointerAuth.getKey(), nullptr,
cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));

return Pointer;
}

llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
llvm::Type *Ty) {
QualType FT = FD->getType();
FT = getContext().getMemberPointerType(
FT, cast<CXXMethodDecl>(FD)->getParent()->getTypeForDecl());
return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT);
}

std::optional<PointerAuthQualifier>
CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGRecordLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ class CGRecordLayout {
return IsZeroInitializableAsBase;
}

bool containsFieldDecl(const FieldDecl *FD) const {
return FieldInfo.count(FD) != 0;
}

/// Return llvm::StructType element number that corresponds to the
/// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
Expand Down
Loading