64 changes: 64 additions & 0 deletions bolt/test/X86/linux-exceptions.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# REQUIRES: system-linux

## Check that BOLT correctly parses the Linux kernel exception table.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr

## Verify exception bindings to instructions.

# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 \
# RUN: --bolt-info=0 | FileCheck %s

## Verify the bindings again on the rewritten binary with nops removed.

# RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized | FileCheck %s

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 exception table entries

.text
.globl _start
.type _start, %function
_start:
# CHECK: Binary Function "_start"
nop
.L0:
mov (%rdi), %rax
# CHECK: mov
# CHECK-SAME: ExceptionEntry: 1 # Fixup: [[FIXUP:[a-zA-Z0-9_]+]]
nop
.L1:
mov (%rsi), %rax
# CHECK: mov
# CHECK-SAME: ExceptionEntry: 2 # Fixup: [[FIXUP]]
nop
ret
.LF0:
# CHECK: Secondary Entry Point: [[FIXUP]]
jmp foo
.size _start, .-_start

.globl foo
.type foo, %function
foo:
ret
.size foo, .-foo


## Exception table.
.section __ex_table,"a",@progbits
.align 4

.long .L0 - . # instruction
.long .LF0 - . # fixup
.long 0 # data

.long .L1 - . # instruction
.long .LF0 - . # fixup
.long 0 # data

## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "ChainedComparisonCheck.h"
#include "ComparePointerToMemberVirtualFunctionCheck.h"
#include "CopyConstructorInitCheck.h"
#include "CrtpConstructorAccessibilityCheck.h"
#include "DanglingHandleCheck.h"
#include "DynamicStaticInitializersCheck.h"
#include "EasilySwappableParametersCheck.h"
Expand Down Expand Up @@ -237,6 +238,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-unhandled-exception-at-new");
CheckFactories.registerCheck<UniquePtrArrayMismatchCheck>(
"bugprone-unique-ptr-array-mismatch");
CheckFactories.registerCheck<CrtpConstructorAccessibilityCheck>(
"bugprone-crtp-constructor-accessibility");
CheckFactories.registerCheck<UnsafeFunctionsCheck>(
"bugprone-unsafe-functions");
CheckFactories.registerCheck<UnusedLocalNonTrivialVariableCheck>(
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ add_clang_library(clangTidyBugproneModule
UnhandledExceptionAtNewCheck.cpp
UnhandledSelfAssignmentCheck.cpp
UniquePtrArrayMismatchCheck.cpp
CrtpConstructorAccessibilityCheck.cpp
UnsafeFunctionsCheck.cpp
UnusedLocalNonTrivialVariableCheck.cpp
UnusedRaiiCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
//===--- CrtpConstructorAccessibilityCheck.cpp - clang-tidy ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "CrtpConstructorAccessibilityCheck.h"
#include "../utils/LexerUtils.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

using namespace clang::ast_matchers;

namespace clang::tidy::bugprone {

static bool hasPrivateConstructor(const CXXRecordDecl *RD) {
return llvm::any_of(RD->ctors(), [](const CXXConstructorDecl *Ctor) {
return Ctor->getAccess() == AS_private;
});
}

static bool isDerivedParameterBefriended(const CXXRecordDecl *CRTP,
const NamedDecl *Param) {
return llvm::any_of(CRTP->friends(), [&](const FriendDecl *Friend) {
const TypeSourceInfo *const FriendType = Friend->getFriendType();
if (!FriendType) {
return false;
}

const auto *const TTPT =
dyn_cast<TemplateTypeParmType>(FriendType->getType());

return TTPT && TTPT->getDecl() == Param;
});
}

static bool isDerivedClassBefriended(const CXXRecordDecl *CRTP,
const CXXRecordDecl *Derived) {
return llvm::any_of(CRTP->friends(), [&](const FriendDecl *Friend) {
const TypeSourceInfo *const FriendType = Friend->getFriendType();
if (!FriendType) {
return false;
}

return FriendType->getType()->getAsCXXRecordDecl() == Derived;
});
}

static const NamedDecl *
getDerivedParameter(const ClassTemplateSpecializationDecl *CRTP,
const CXXRecordDecl *Derived) {
size_t Idx = 0;
const bool AnyOf = llvm::any_of(
CRTP->getTemplateArgs().asArray(), [&](const TemplateArgument &Arg) {
++Idx;
return Arg.getKind() == TemplateArgument::Type &&
Arg.getAsType()->getAsCXXRecordDecl() == Derived;
});

return AnyOf ? CRTP->getSpecializedTemplate()
->getTemplateParameters()
->getParam(Idx - 1)
: nullptr;
}

static std::vector<FixItHint>
hintMakeCtorPrivate(const CXXConstructorDecl *Ctor,
const std::string &OriginalAccess) {
std::vector<FixItHint> Hints;

Hints.emplace_back(FixItHint::CreateInsertion(
Ctor->getBeginLoc().getLocWithOffset(-1), "private:\n"));

const ASTContext &ASTCtx = Ctor->getASTContext();
const SourceLocation CtorEndLoc =
Ctor->isExplicitlyDefaulted()
? utils::lexer::findNextTerminator(Ctor->getEndLoc(),
ASTCtx.getSourceManager(),
ASTCtx.getLangOpts())
: Ctor->getEndLoc();
Hints.emplace_back(FixItHint::CreateInsertion(
CtorEndLoc.getLocWithOffset(1), '\n' + OriginalAccess + ':' + '\n'));

return Hints;
}

void CrtpConstructorAccessibilityCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
classTemplateSpecializationDecl(
decl().bind("crtp"),
hasAnyTemplateArgument(refersToType(recordType(hasDeclaration(
cxxRecordDecl(
isDerivedFrom(cxxRecordDecl(equalsBoundNode("crtp"))))
.bind("derived")))))),
this);
}

void CrtpConstructorAccessibilityCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *CRTPInstantiation =
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("crtp");
const auto *DerivedRecord = Result.Nodes.getNodeAs<CXXRecordDecl>("derived");
const CXXRecordDecl *CRTPDeclaration =
CRTPInstantiation->getSpecializedTemplate()->getTemplatedDecl();

if (!CRTPDeclaration->hasDefinition()) {
return;
}

const auto *DerivedTemplateParameter =
getDerivedParameter(CRTPInstantiation, DerivedRecord);

assert(DerivedTemplateParameter &&
"No template parameter corresponds to the derived class of the CRTP.");

bool NeedsFriend = !isDerivedParameterBefriended(CRTPDeclaration,
DerivedTemplateParameter) &&
!isDerivedClassBefriended(CRTPDeclaration, DerivedRecord);

const FixItHint HintFriend = FixItHint::CreateInsertion(
CRTPDeclaration->getBraceRange().getEnd(),
"friend " + DerivedTemplateParameter->getNameAsString() + ';' + '\n');

if (hasPrivateConstructor(CRTPDeclaration) && NeedsFriend) {
diag(CRTPDeclaration->getLocation(),
"the CRTP cannot be constructed from the derived class; consider "
"declaring the derived class as friend")
<< HintFriend;
}

auto WithFriendHintIfNeeded =
[&](const DiagnosticBuilder &Diag,
bool NeedsFriend) -> const DiagnosticBuilder & {
if (NeedsFriend)
Diag << HintFriend;

return Diag;
};

if (!CRTPDeclaration->hasUserDeclaredConstructor()) {
const bool IsStruct = CRTPDeclaration->isStruct();

WithFriendHintIfNeeded(
diag(CRTPDeclaration->getLocation(),
"the implicit default constructor of the CRTP is publicly "
"accessible; consider making it private%select{| and declaring "
"the derived class as friend}0")
<< NeedsFriend
<< FixItHint::CreateInsertion(
CRTPDeclaration->getBraceRange().getBegin().getLocWithOffset(
1),
(IsStruct ? "\nprivate:\n" : "\n") +
CRTPDeclaration->getNameAsString() + "() = default;\n" +
(IsStruct ? "public:\n" : "")),
NeedsFriend);
}

for (auto &&Ctor : CRTPDeclaration->ctors()) {
if (Ctor->getAccess() == AS_private)
continue;

const bool IsPublic = Ctor->getAccess() == AS_public;
const std::string Access = IsPublic ? "public" : "protected";

WithFriendHintIfNeeded(
diag(Ctor->getLocation(),
"%0 contructor allows the CRTP to be %select{inherited "
"from|constructed}1 as a regular template class; consider making "
"it private%select{| and declaring the derived class as friend}2")
<< Access << IsPublic << NeedsFriend
<< hintMakeCtorPrivate(Ctor, Access),
NeedsFriend);
}
}

bool CrtpConstructorAccessibilityCheck::isLanguageVersionSupported(
const LangOptions &LangOpts) const {
return LangOpts.CPlusPlus11;
}
} // namespace clang::tidy::bugprone
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===--- CrtpConstructorAccessibilityCheck.h - clang-tidy -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CRTPCONSTRUCTORACCESSIBILITYCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CRTPCONSTRUCTORACCESSIBILITYCHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::bugprone {

/// Detects error-prone Curiously Recurring Template Pattern usage, when the
/// CRTP can be constructed outside itself and the derived class.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/crtp-constructor-accessibility.html
class CrtpConstructorAccessibilityCheck : public ClangTidyCheck {
public:
CrtpConstructorAccessibilityCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
};

} // namespace clang::tidy::bugprone

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CRTPCONSTRUCTORACCESSIBILITYCHECK_H
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/refactor/Rename.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,10 @@ llvm::Expected<RenameResult> rename(const RenameInputs &RInputs) {
return makeError(ReasonToReject::AmbiguousSymbol);

const auto &RenameDecl = **DeclsUnderCursor.begin();
static constexpr trace::Metric RenameTriggerCounter(
"rename_trigger_count", trace::Metric::Counter, "decl_kind");
RenameTriggerCounter.record(1, RenameDecl.getDeclKindName());

std::string Placeholder = getName(RenameDecl);
auto Invalid = checkName(RenameDecl, RInputs.NewName, Placeholder);
if (Invalid)
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ Improvements to clang-tidy
New checks
^^^^^^^^^^

- New :doc:`bugprone-crtp-constructor-accessibility
<clang-tidy/checks/bugprone/crtp-constructor-accessibility>` check.

Detects error-prone Curiously Recurring Template Pattern usage, when the CRTP
can be constructed outside itself and the derived class.

- New :doc:`modernize-use-designated-initializers
<clang-tidy/checks/modernize/use-designated-initializers>` check.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
.. title:: clang-tidy - bugprone-crtp-constructor-accessibility

bugprone-crtp-constructor-accessibility
=======================================

Detects error-prone Curiously Recurring Template Pattern usage, when the CRTP
can be constructed outside itself and the derived class.

The CRTP is an idiom, in which a class derives from a template class, where
itself is the template argument. It should be ensured that if a class is
intended to be a base class in this idiom, it can only be instantiated if
the derived class is it's template argument.

Example:

.. code-block:: c++

template <typename T> class CRTP {
private:
CRTP() = default;
friend T;
};

class Derived : CRTP<Derived> {};

Below can be seen some common mistakes that will allow the breaking of the
idiom.

If the constructor of a class intended to be used in a CRTP is public, then
it allows users to construct that class on its own.

Example:

.. code-block:: c++

template <typename T> class CRTP {
public:
CRTP() = default;
};

class Good : CRTP<Good> {};
Good GoodInstance;

CRTP<int> BadInstance;

If the constructor is protected, the possibility of an accidental instantiation
is prevented, however it can fade an error, when a different class is used as
the template parameter instead of the derived one.

Example:

.. code-block:: c++

template <typename T> class CRTP {
protected:
CRTP() = default;
};

class Good : CRTP<Good> {};
Good GoodInstance;

class Bad : CRTP<Good> {};
Bad BadInstance;

To ensure that no accidental instantiation happens, the best practice is to
make the constructor private and declare the derived class as friend. Note
that as a tradeoff, this also gives the derived class access to every other
private members of the CRTP.

Example:

.. code-block:: c++

template <typename T> class CRTP {
CRTP() = default;
friend T;
};

class Good : CRTP<Good> {};
Good GoodInstance;

class Bad : CRTP<Good> {};
Bad CompileTimeError;

CRTP<int> AlsoCompileTimeError;

Limitations:

* The check is not supported below C++11

* The check does not handle when the derived class is passed as a variadic
template argument

* Accessible functions that can construct the CRTP, like factory functions
are not checked

The check also suggests a fix-its in some cases.

1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Clang-Tidy Checks
:doc:`bugprone-chained-comparison <bugprone/chained-comparison>`,
:doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
:doc:`bugprone-crtp-constructor-accessibility <bugprone/crtp-constructor-accessibility>`, "Yes"
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
:doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
:doc:`bugprone-easily-swappable-parameters <bugprone/easily-swappable-parameters>`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-crtp-constructor-accessibility %t -- -- -fno-delayed-template-parsing

namespace class_implicit_ctor {
template <typename T>
class CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
// CHECK-FIXES: friend T;

class A : CRTP<A> {};
} // namespace class_implicit_ctor

namespace class_unconstructible {
template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
};

class A : CRTP<A> {};
} // namespace class_unconstructible

namespace class_public_default_ctor {
template <typename T>
class CRTP {
public:
CRTP() = default;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_public_default_ctor

namespace class_public_user_provided_ctor {
template <typename T>
class CRTP {
public:
CRTP(int) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_public_user_provided_ctor

namespace class_public_multiple_user_provided_ctors {
template <typename T>
class CRTP {
public:
CRTP(int) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}public:
CRTP(float) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(float) {}{{[[:space:]]*}}public:

// CHECK-FIXES: friend T;
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_public_multiple_user_provided_ctors

namespace class_protected_ctors {
template <typename T>
class CRTP {
protected:
CRTP(int) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}protected:
CRTP() = default;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}protected:
CRTP(float) {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP(float) {}{{[[:space:]]*}}protected:

// CHECK-FIXES: friend T;
// CHECK-FIXES: friend T;
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace class_protected_ctors

namespace struct_implicit_ctor {
template <typename T>
struct CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;

class A : CRTP<A> {};
} // namespace struct_implicit_ctor

namespace struct_default_ctor {
template <typename T>
struct CRTP {
CRTP() = default;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;
};

class A : CRTP<A> {};
} // namespace struct_default_ctor

namespace same_class_multiple_crtps {
template <typename T>
struct CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;

template <typename T>
struct CRTP2 {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: private:{{[[:space:]]*}}CRTP2() = default;{{[[:space:]]*}}public:
// CHECK-FIXES: friend T;

class A : CRTP<A>, CRTP2<A> {};
} // namespace same_class_multiple_crtps

namespace same_crtp_multiple_classes {
template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
};

class A : CRTP<A> {};
class B : CRTP<B> {};
} // namespace same_crtp_multiple_classes

namespace crtp_template {
template <typename T, typename U>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend U;
CRTP() = default;
};

class A : CRTP<int, A> {};
} // namespace crtp_template

namespace crtp_template2 {
template <typename T, typename U>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
};

class A : CRTP<A, A> {};
} // namespace crtp_template2

namespace template_derived {
template <typename T>
class CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
// CHECK-FIXES: friend T;

template<typename T>
class A : CRTP<A<T>> {};

// FIXME: Ideally the warning should be triggered without instantiation.
void foo() {
A<int> A;
(void) A;
}
} // namespace template_derived

namespace template_derived_explicit_specialization {
template <typename T>
class CRTP {};
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
// CHECK-FIXES: friend T;

template<typename T>
class A : CRTP<A<T>> {};

template<>
class A<int> : CRTP<A<int>> {};
} // namespace template_derived_explicit_specialization

namespace explicit_derived_friend {
class A;

template <typename T>
class CRTP {
CRTP() = default;
friend A;
};

class A : CRTP<A> {};
} // namespace explicit_derived_friend

namespace explicit_derived_friend_multiple {
class A;

template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class; consider declaring the derived class as friend [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: friend T;
CRTP() = default;
friend A;
};

class A : CRTP<A> {};
class B : CRTP<B> {};
} // namespace explicit_derived_friend_multiple

namespace no_need_for_friend {
class A;

template <typename T>
class CRTP {
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible; consider making it private [bugprone-crtp-constructor-accessibility]
// CHECK-FIXES: CRTP() = default;
friend A;
};

class A : CRTP<A> {};
} // namespace no_need_for_friend

namespace no_warning {
template <typename T>
class CRTP
{
CRTP() = default;
friend T;
};

class A : CRTP<A> {};
} // namespace no_warning

namespace no_warning_unsupported {
template<typename... Types>
class CRTP
{};

class A : CRTP<A> {};

void foo() {
A A;
(void) A;
}
} // namespace no_warning_unsupported
33 changes: 33 additions & 0 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,39 @@ if(FUCHSIA_SDK)
set(LLVM_RUNTIME_MULTILIB_hwasan+noexcept_TARGETS "aarch64-unknown-fuchsia;riscv64-unknown-fuchsia" CACHE STRING "")
endif()

foreach(target armv6m-unknown-eabi)
list(APPEND BUILTIN_TARGETS "${target}")
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT "" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
foreach(lang C;CXX;ASM)
set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mcpu=cortex-m0plus -mthumb" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(BUILTINS_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
endforeach()
set(BUILTINS_${target}_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "")

list(APPEND RUNTIME_TARGETS "${target}")
set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSROOT "" CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
foreach(lang C;CXX;ASM)
set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mcpu=cortex-m0plus -mthumb" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
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}_LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES "libc" CACHE STRING "")
endforeach()

foreach(target riscv32-unknown-elf)
list(APPEND BUILTIN_TARGETS "${target}")
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
Expand Down
13 changes: 13 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ Non-comprehensive list of changes in this release
New Compiler Flags
------------------

- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave
like it did before Clang 18.x. Fixes (`#56628 <https://github.com/llvm/llvm-project/issues/68933>`_)

Deprecated Compiler Flags
-------------------------

Expand Down Expand Up @@ -177,6 +181,9 @@ Improvements to Clang's diagnostics
- The ``-Wshorten-64-to-32`` diagnostic is now grouped under ``-Wimplicit-int-conversion`` instead
of ``-Wconversion``. Fixes #GH69444.

- Clang now uses thousand separators when printing large numbers in integer overflow diagnostics.
Fixes #GH80939.

- Clang now diagnoses friend declarations with an ``enum`` elaborated-type-specifier in language modes after C++98.

- Added diagnostics for C11 keywords being incompatible with language standards
Expand Down Expand Up @@ -265,6 +272,8 @@ Bug Fixes to C++ Support
- Fix a crash when trying to call a varargs function that also has an explicit object parameter. (#GH80971)
- Fixed a bug where abbreviated function templates would append their invented template parameters to
an empty template parameter lists.
- Fix parsing of abominable function types inside type traits.
Fixes (`#77585 <https://github.com/llvm/llvm-project/issues/77585>`_)
- Clang now classifies aggregate initialization in C++17 and newer as constant
or non-constant more accurately. Previously, only a subset of the initializer
elements were considered, misclassifying some initializers as constant. Partially fixes
Expand Down Expand Up @@ -298,6 +307,10 @@ Bug Fixes to C++ Support
- Fixed an issue where an attribute on a declarator would cause the attribute to
be destructed prematurely. This fixes a pair of Chromium that were brought to
our attention by an attempt to fix in (#GH77703). Fixes (#GH83385).
- Fix evaluation of some immediate calls in default arguments.
Fixes (#GH80630)
- Fix a crash when an explicit template argument list is used with a name for which lookup
finds a non-template function and a dependent using declarator.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
98 changes: 70 additions & 28 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ class FPMathTemplate : Template<["float", "double", "long double"],
["f", "", "l"]>;

class FPMathWithF16Template :
Template<["float", "double", "long double", "__fp16", "__float128"],
["f", "", "l", "f16", "f128"]>;
Template<["float", "double", "long double", "__fp16"],
["f", "", "l", "f16"]>;

class FPMathWithF16F128Template :
Template<["float", "double", "long double", "__fp16", "__float128"],
["f", "", "l", "f16", "f128"]>;

class FPMathWithF128Template :
Template<["float", "double", "long double", "__float128"],
["f", "", "l", "f128"]>;

class F16F128MathTemplate : Template<["__fp16", "__float128"],
["f16", "f128"]>;

Expand Down Expand Up @@ -253,18 +257,30 @@ def FrexpF16F128 : F16F128MathTemplate, Builtin {
let Prototype = "T(T, int*)";
}

def HugeVal : Builtin, FPMathWithF16F128Template {
def HugeVal : Builtin, FPMathWithF128Template {
let Spellings = ["__builtin_huge_val"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T()";
}

def Inf : Builtin, FPMathWithF16F128Template {
def HugeValF16 : Builtin {
let Spellings = ["__builtin_huge_valf16"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "_Float16()";
}

def Inf : Builtin, FPMathWithF128Template {
let Spellings = ["__builtin_inf"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "T()";
}

def InfF16 : Builtin {
let Spellings = ["__builtin_inff16"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "_Float16()";
}

def LdexpF16F128 : F16F128MathTemplate, Builtin {
let Spellings = ["__builtin_ldexp"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
Expand Down Expand Up @@ -1550,7 +1566,7 @@ def SyncBoolCompareAndSwap : Builtin {
def SyncBoolCompareAndSwapN : Builtin, SyncBuiltinsTemplate {
let Spellings = ["__sync_bool_compare_and_swap_"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "T(T volatile*, T, ...)";
let Prototype = "bool(T volatile*, T, T, ...)";
}

def SyncValCompareAndSwap : Builtin {
Expand All @@ -1562,7 +1578,7 @@ def SyncValCompareAndSwap : Builtin {
def SynLockValCompareAndSwapN : Builtin, SyncBuiltinsTemplate {
let Spellings = ["__sync_val_compare_and_swap_"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "T(T volatile*, T, ...)";
let Prototype = "T(T volatile*, T, T, ...)";
}

def SyncLockTestAndSet : Builtin {
Expand All @@ -1577,16 +1593,16 @@ def SynLockLockTestAndSetN : Builtin, SyncBuiltinsTemplate {
let Prototype = "T(T volatile*, T, ...)";
}

def SyncLockReleaseN : Builtin {
def SyncLockRelease : Builtin {
let Spellings = ["__sync_lock_release"];
let Attributes = [CustomTypeChecking];
let Prototype = "void(...)";
}

def SynLockReleaseN : Builtin, SyncBuiltinsTemplate {
def SyncLockReleaseN : Builtin, SyncBuiltinsTemplate {
let Spellings = ["__sync_lock_release_"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "T(T volatile*, T, ...)";
let Prototype = "void(T volatile*, ...)";
}

def SyncSwap : Builtin {
Expand Down Expand Up @@ -2569,6 +2585,13 @@ def Abort : LibBuiltin<"stdlib.h"> {
let AddBuiltinPrefixedAlias = 1;
}

def Abs : IntMathTemplate, LibBuiltin<"stdlib.h"> {
let Spellings = ["abs"];
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
}

def Calloc : LibBuiltin<"stdlib.h"> {
let Spellings = ["calloc"];
let Prototype = "void*(size_t, size_t)";
Expand Down Expand Up @@ -3085,38 +3108,38 @@ def MemAlign : GNULibBuiltin<"malloc.h"> {

// POSIX string.h

def MemcCpy : GNULibBuiltin<"stdlib.h"> {
def MemcCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["memccpy"];
let Prototype = "void*(void*, void const*, int, size_t)";
}

def MempCpy : GNULibBuiltin<"stdlib.h"> {
def MempCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["mempcpy"];
let Prototype = "void*(void*, void const*, size_t)";
}

def StpCpy : GNULibBuiltin<"stdlib.h"> {
def StpCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["stpcpy"];
let Attributes = [NoThrow];
let Prototype = "char*(char*, char const*)";
let AddBuiltinPrefixedAlias = 1;
}

def StpnCpy : GNULibBuiltin<"stdlib.h"> {
def StpnCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["stpncpy"];
let Attributes = [NoThrow];
let Prototype = "char*(char*, char const*, size_t)";
let AddBuiltinPrefixedAlias = 1;
}

def StrDup : GNULibBuiltin<"stdlib.h"> {
def StrDup : GNULibBuiltin<"string.h"> {
let Spellings = ["strdup"];
let Attributes = [NoThrow];
let Prototype = "char*(char const*)";
let AddBuiltinPrefixedAlias = 1;
}

def StrnDup : GNULibBuiltin<"stdlib.h"> {
def StrnDup : GNULibBuiltin<"string.h"> {
let Spellings = ["strndup"];
let Attributes = [NoThrow];
let Prototype = "char*(char const*, size_t)";
Expand Down Expand Up @@ -3286,22 +3309,22 @@ def ObjcEnumerationMutation : ObjCLibBuiltin<"objc/runtime.h"> {
let Prototype = "void(id)";
}

def ObjcReadWeak : ObjCLibBuiltin<"objc/message.h"> {
def ObjcReadWeak : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_read_weak"];
let Prototype = "id(id*)";
}

def ObjcAssignWeak : ObjCLibBuiltin<"objc/message.h"> {
def ObjcAssignWeak : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_assign_weak"];
let Prototype = "id(id, id*)";
}

def ObjcAssignIvar : ObjCLibBuiltin<"objc/message.h"> {
def ObjcAssignIvar : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_assign_ivar"];
let Prototype = "id(id, id, ptrdiff_t)";
}

def ObjcAssignGlobal : ObjCLibBuiltin<"objc/message.h"> {
def ObjcAssignGlobal : ObjCLibBuiltin<"objc/objc-auto.h"> {
let Spellings = ["objc_assign_global"];
let Prototype = "id(id, id*)";
}
Expand Down Expand Up @@ -3371,13 +3394,6 @@ def Atan2 : FPMathTemplate, LibBuiltin<"math.h"> {
let AddBuiltinPrefixedAlias = 1;
}

def Abs : IntMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["abs"];
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
}

def Copysign : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["copysign"];
let Attributes = [NoThrow, Const];
Expand Down Expand Up @@ -3996,8 +4012,16 @@ def BlockObjectDispose : LibBuiltin<"blocks.h"> {
}
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.

def __Addressof : LangBuiltin<"CXX_LANG"> {
let Spellings = ["__addressof"];
let Attributes = [FunctionWithoutBuiltinPrefix, NoThrow, Const,
IgnoreSignature, Constexpr];
let Prototype = "void*(void&)";
let Namespace = "std";
}

def Addressof : CxxLibBuiltin<"memory"> {
let Spellings = ["addressof", "__addressof"];
let Spellings = ["addressof"];
let Attributes = [NoThrow, Const, IgnoreSignature, RequireDeclaration,
Constexpr];
let Prototype = "void*(void&)";
Expand Down Expand Up @@ -4036,7 +4060,7 @@ def Move : CxxLibBuiltin<"utility"> {
let Namespace = "std";
}

def MoveIfNsoexcept : CxxLibBuiltin<"memory"> {
def MoveIfNsoexcept : CxxLibBuiltin<"utility"> {
let Spellings = ["move_if_noexcept"];
let Attributes = [NoThrow, Const, IgnoreSignature, RequireDeclaration,
Constexpr];
Expand Down Expand Up @@ -4518,6 +4542,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
}

// HLSL
def HLSLAny : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_any"];
let Attributes = [NoThrow, Const];
let Prototype = "bool(...)";
}

def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_wave_active_count_bits"];
let Attributes = [NoThrow, Const];
Expand Down Expand Up @@ -4548,6 +4578,18 @@ def HLSLLerp : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLMad : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_mad"];
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}

def HLSLRcp : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_rcp"];
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}

// Builtins for XRay.
def XRayCustomEvent : Builtin {
let Spellings = ["__xray_customevent"];
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/BuiltinsBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ def UnevaluatedArguments : Attribute<"u">;
// is required for a builtin.
def FunctionWithBuiltinPrefix : Attribute<"F">;

def FunctionWithoutBuiltinPrefix : Attribute<"f">;

// const, but only when -fno-math-errno and FP exceptions are ignored.
def ConstIgnoringErrnoAndExceptions : Attribute<"e">;

Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">;
def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{
code Documentation = [{
Warn about designated initializers with some fields missing (only in C++).
}];
}
// Default -Wmissing-field-initializers matches gcc behavior,
// but missing-designated-field-initializers can be turned off to match old clang behavior.
def MissingFieldInitializers : DiagGroup<"missing-field-initializers",
[MissingDesignatedFieldInitializers]>;
def ModuleLock : DiagGroup<"module-lock">;
def ModuleBuild : DiagGroup<"module-build">;
def ModuleImport : DiagGroup<"module-import">;
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -6170,6 +6170,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn<
def warn_missing_field_initializers : Warning<
"missing field %0 initializer">,
InGroup<MissingFieldInitializers>, DefaultIgnore;
// The same warning, but another group is needed to disable it separately.
def warn_missing_designated_field_initializers : Warning<
warn_missing_field_initializers.Summary>,
InGroup<MissingDesignatedFieldInitializers>, DefaultIgnore;
def warn_braces_around_init : Warning<
"braces around %select{scalar |}0initializer">,
InGroup<DiagGroup<"braced-scalar-init">>;
Expand Down Expand Up @@ -9901,7 +9905,7 @@ def err_lifetimebound_ctor_dtor : Error<
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr_ref : Warning<
"%select{address of|reference to}0 stack memory associated with "
"%select{local variable|parameter}2 %1 returned">,
"%select{local variable|parameter|compound literal}2 %1 returned">,
InGroup<ReturnStackAddress>;
def warn_ret_local_temp_addr_ref : Warning<
"returning %select{address of|reference to}0 local temporary object">,
Expand Down
35 changes: 35 additions & 0 deletions clang/include/clang/InstallAPI/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ namespace installapi {
using SymbolFlags = llvm::MachO::SymbolFlags;
using RecordLinkage = llvm::MachO::RecordLinkage;
using GlobalRecord = llvm::MachO::GlobalRecord;
using ObjCContainerRecord = llvm::MachO::ObjCContainerRecord;
using ObjCInterfaceRecord = llvm::MachO::ObjCInterfaceRecord;
using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord;
using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;

// Represents a collection of frontend records for a library that are tied to a
// darwin target triple.
Expand Down Expand Up @@ -69,6 +72,38 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
const Decl *D, HeaderType Access,
bool IsEHType);

/// Add ObjC Category record with attributes from AST.
///
/// \param ClassToExtend The name of class that is extended by category, not
/// symbol.
/// \param CategoryName The name of category, not symbol.
/// \param Avail The availability information tied
/// to the active target triple.
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \return The non-owning pointer to added record in slice.
ObjCCategoryRecord *addObjCCategory(StringRef ClassToExtend,
StringRef CategoryName,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access);

/// Add ObjC IVar record with attributes from AST.
///
/// \param Container The owning pointer for instance variable.
/// \param Name The name of ivar, not symbol.
/// \param Linkage The linkage of symbol.
/// \param Avail The availability information tied to the active target
/// triple.
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param AC The access control tied to the ivar declaration.
/// \return The non-owning pointer to added record in slice.
ObjCIVarRecord *addObjCIVar(ObjCContainerRecord *Container,
StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC);

private:
/// Frontend information captured about records.
struct FrontendAttrs {
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/InstallAPI/Visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,22 @@ class InstallAPIVisitor final : public ASTConsumer,
/// ivars, properties, and methods of the class.
bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);

/// Collect Objective-C Category/Extension declarations.
///
/// The class that is being extended might come from a different library and
/// is therefore itself not collected.
bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D);

private:
std::string getMangledName(const NamedDecl *D) const;
std::string getBackendMangledName(llvm::Twine Name) const;
std::optional<HeaderType> getAccessForDecl(const NamedDecl *D) const;
void recordObjCInstanceVariables(
const ASTContext &ASTCtx, llvm::MachO::ObjCContainerRecord *Record,
StringRef SuperClass,
const llvm::iterator_range<
DeclContext::specific_decl_iterator<ObjCIvarDecl>>
Ivars);

InstallAPIContext &Ctx;
SourceManager &SrcMgr;
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -14146,7 +14146,8 @@ class Sema final {
bool SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res);
bool SemaBuiltinVectorToScalarMath(CallExpr *TheCall);
bool SemaBuiltinElementwiseMath(CallExpr *TheCall);
bool SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall);
bool SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall,
bool CheckForFloatArgs = true);
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall);
bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall);

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,10 @@ def StdCLibraryFunctionsTesterChecker : Checker<"StdCLibraryFunctionsTester">,
WeakDependencies<[StdCLibraryFunctionsChecker]>,
Documentation<NotDocumented>;

def CheckerDocumentationChecker : Checker<"CheckerDocumentation">,
HelpText<"Defines an empty checker callback for all possible handlers.">,
Documentation<NotDocumented>;

} // end "debug"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,6 @@ class CoreEngine {
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
ProgramStateRef InitState);

/// Returns true if there is still simulation state on the worklist.
bool ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps,
ProgramStateRef InitState,
ExplodedNodeSet &Dst);

/// Dispatch the work list item based on the given location information.
/// Use Pred parameter as the predecessor state.
void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
Expand Down
10 changes: 0 additions & 10 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,16 +190,6 @@ class ExprEngine {
return Engine.ExecuteWorkList(L, Steps, nullptr);
}

/// Execute the work list with an initial state. Nodes that reaches the exit
/// of the function are added into the Dst set, which represent the exit
/// state of the function call. Returns true if there is still simulation
/// state on the worklist.
bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
ProgramStateRef InitState,
ExplodedNodeSet &Dst) {
return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}

/// getContext - Return the ASTContext associated with this analysis.
ASTContext &getContext() const { return AMgr.getASTContext(); }

Expand Down
8 changes: 6 additions & 2 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2778,7 +2778,9 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
<< toString(Result, 10) << E->getType() << E->getSourceRange();
<< toString(Result, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true)
<< E->getType() << E->getSourceRange();
return HandleOverflow(Info, E, Value, E->getType());
}
return true;
Expand Down Expand Up @@ -13910,7 +13912,9 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
<< toString(Value, 10) << E->getType() << E->getSourceRange();
<< toString(Value, 10, Value.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true)
<< E->getType() << E->getSourceRange();

if (!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
E->getType()))
Expand Down
23 changes: 20 additions & 3 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
QualType Type = E->getType();
if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
Value.trunc(Result.bitWidth()).toString(Trunc, 10);
Value.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand Down Expand Up @@ -499,7 +501,9 @@ bool Neg(InterpState &S, CodePtr OpPC) {

if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
NegatedValue.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand Down Expand Up @@ -561,7 +565,9 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
QualType Type = E->getType();
if (S.checkingForUndefinedBehavior()) {
SmallString<32> Trunc;
APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
APResult.trunc(Result.bitWidth())
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
/*UpperCase=*/true, /*InsertSeparators=*/true);
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
Expand Down Expand Up @@ -746,6 +752,17 @@ inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
CompareFn Fn) {
const auto &RHS = S.Stk.pop<FunctionPointer>();
const auto &LHS = S.Stk.pop<FunctionPointer>();

// We cannot compare against weak declarations at compile time.
for (const auto &FP : {LHS, RHS}) {
if (!FP.isZero() && FP.getFunction()->getDecl()->isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< FP.toDiagnosticString(S.getCtx());
return false;
}
}

S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/StmtOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
// This file implements the subclesses of Stmt class declared in StmtOpenACC.h
// This file implements the subclasses of Stmt class declared in StmtOpenACC.h
//
//===----------------------------------------------------------------------===//

Expand Down
39 changes: 36 additions & 3 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17963,6 +17963,12 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return nullptr;

switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_elementwise_any: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
/*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
Intrinsic::dx_any, ArrayRef<Value *>{Op0}, nullptr, "dx.any");
}
case Builtin::BI__builtin_hlsl_dot: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
Expand Down Expand Up @@ -17996,7 +18002,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
"Dot product requires vectors to be of the same size.");

return Builder.CreateIntrinsic(
/*ReturnType*/ T0->getScalarType(), Intrinsic::dx_dot,
/*ReturnType=*/T0->getScalarType(), Intrinsic::dx_dot,
ArrayRef<Value *>{Op0, Op1}, nullptr, "dx.dot");
} break;
case Builtin::BI__builtin_hlsl_lerp: {
Expand Down Expand Up @@ -18033,17 +18039,44 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
XVecTy->getElementType() == SVecTy->getElementType() &&
"Lerp requires float vectors to be of the same type.");
return Builder.CreateIntrinsic(
/*ReturnType*/ Xty, Intrinsic::dx_lerp, ArrayRef<Value *>{X, Y, S},
/*ReturnType=*/Xty, Intrinsic::dx_lerp, ArrayRef<Value *>{X, Y, S},
nullptr, "dx.lerp");
}
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("frac operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType*/ Op0->getType(), Intrinsic::dx_frac,
/*ReturnType=*/Op0->getType(), Intrinsic::dx_frac,
ArrayRef<Value *>{Op0}, nullptr, "dx.frac");
}
case Builtin::BI__builtin_hlsl_mad: {
Value *M = EmitScalarExpr(E->getArg(0));
Value *A = EmitScalarExpr(E->getArg(1));
Value *B = EmitScalarExpr(E->getArg(2));
if (E->getArg(0)->getType()->hasFloatingRepresentation()) {
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::fmuladd,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.fmad");
}
if (E->getArg(0)->getType()->hasSignedIntegerRepresentation()) {
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
}
assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation());
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
}
case Builtin::BI__builtin_hlsl_elementwise_rcp: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("rcp operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/Op0->getType(), Intrinsic::dx_rcp,
ArrayRef<Value *>{Op0}, nullptr, "dx.rcp");
}
}
return nullptr;
}
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/IntrinsicsSPIRV.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FormatVariadic.h"
Expand Down Expand Up @@ -342,8 +343,19 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
return B.CreateCall(FunctionCallee(DxGroupIndex));
}
if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
llvm::Function *DxThreadID = CGM.getIntrinsic(Intrinsic::dx_thread_id);
return buildVectorInput(B, DxThreadID, Ty);
llvm::Function *ThreadIDIntrinsic;
switch (CGM.getTarget().getTriple().getArch()) {
case llvm::Triple::dxil:
ThreadIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_thread_id);
break;
case llvm::Triple::spirv:
ThreadIDIntrinsic = CGM.getIntrinsic(Intrinsic::spv_thread_id);
break;
default:
llvm_unreachable("Input semantic not supported by target");
break;
}
return buildVectorInput(B, ThreadIDIntrinsic, Ty);
}
assert(false && "Unhandled parameter attribute");
return nullptr;
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1593,12 +1593,20 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
}

bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
// NSObject is a fixed size. If we can see the @implementation of a class
// which inherits from NSObject then we know that all it's offsets also must
// be fixed. FIXME: Can we do this if see a chain of super classes with
// implementations leading to NSObject?
return ID->getImplementation() && ID->getSuperClass() &&
ID->getSuperClass()->getName() == "NSObject";
// Test a class by checking its superclasses up to
// its base class if it has one.
for (; ID; ID = ID->getSuperClass()) {
// The layout of base class NSObject
// is guaranteed to be statically known
if (ID->getIdentifier()->getName() == "NSObject")
return true;

// If we cannot see the @implementation of a class,
// we cannot statically know the class layout.
if (!ID->getImplementation())
return false;
}
return false;
}

public:
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/Driver/ToolChains/FreeBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = ToolChain.getTriple();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
Expand Down Expand Up @@ -165,8 +166,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld-elf.so.1");
}
const llvm::Triple &T = ToolChain.getTriple();
if (Arch == llvm::Triple::arm || T.isX86())
if (Arch == llvm::Triple::arm || Triple.isX86())
CmdArgs.push_back("--hash-style=both");
CmdArgs.push_back("--enable-new-dtags");
}
Expand Down Expand Up @@ -212,12 +212,17 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::riscv64:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf64lriscv");
CmdArgs.push_back("-X");
break;
default:
break;
}

if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

if (Arg *A = Args.getLastArg(options::OPT_G)) {
if (ToolChain.getTriple().isMIPS()) {
StringRef v = A->getValue();
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Driver/ToolChains/Fuchsia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,11 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Dyld));
}

if (ToolChain.getArch() == llvm::Triple::riscv64)
if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Driver/ToolChains/Haiku.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const auto &ToolChain = static_cast<const Haiku &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const llvm::Triple &Triple = ToolChain.getTriple();
const bool Static = Args.hasArg(options::OPT_static);
const bool Shared = Args.hasArg(options::OPT_shared);
ArgStringList CmdArgs;
Expand Down Expand Up @@ -61,8 +61,11 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Shared)
CmdArgs.push_back("--no-undefined");

if (Arch == llvm::Triple::riscv64)
if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Driver/ToolChains/NetBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,11 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
break;
}

if (Triple.isRISCV())
if (Triple.isRISCV()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Driver/ToolChains/OpenBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = ToolChain.getTriple();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool Static = Args.hasArg(options::OPT_static);
const bool Shared = Args.hasArg(options::OPT_shared);
Expand Down Expand Up @@ -160,8 +161,11 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Nopie || Profiling)
CmdArgs.push_back("-nopie");

if (Arch == llvm::Triple::riscv64)
if (Triple.isRISCV64()) {
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_mno_relax))
CmdArgs.push_back("--no-relax");
}

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
Expand Down
35 changes: 27 additions & 8 deletions clang/lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,14 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
}
}

static void checkConfigMacros(Preprocessor &PP, Module *M,
SourceLocation ImportLoc) {
clang::Module *TopModule = M->getTopLevelModule();
for (const StringRef ConMacro : TopModule->ConfigMacros) {
checkConfigMacro(PP, ConMacro, M, ImportLoc);
}
}

/// Write a new timestamp file with the given path.
static void writeTimestampFile(StringRef TimestampFile) {
std::error_code EC;
Expand Down Expand Up @@ -1829,6 +1837,13 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST(
Module *M =
HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective);

// Check for any configuration macros that have changed. This is done
// immediately before potentially building a module in case this module
// depends on having one of its configuration macros defined to successfully
// build. If this is not done the user will never see the warning.
if (M)
checkConfigMacros(getPreprocessor(), M, ImportLoc);

// Select the source and filename for loading the named module.
std::string ModuleFilename;
ModuleSource Source =
Expand Down Expand Up @@ -2006,12 +2021,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
if (auto MaybeModule = MM.getCachedModuleLoad(*Path[0].first)) {
// Use the cached result, which may be nullptr.
Module = *MaybeModule;
// Config macros are already checked before building a module, but they need
// to be checked at each import location in case any of the config macros
// have a new value at the current `ImportLoc`.
if (Module)
checkConfigMacros(getPreprocessor(), Module, ImportLoc);
} else if (ModuleName == getLangOpts().CurrentModule) {
// This is the module we're building.
Module = PP->getHeaderSearchInfo().lookupModule(
ModuleName, ImportLoc, /*AllowSearch*/ true,
/*AllowExtraModuleMapSearch*/ !IsInclusionDirective);

// Config macros do not need to be checked here for two reasons.
// * This will always be textual inclusion, and thus the config macros
// actually do impact the content of the header.
// * `Preprocessor::HandleHeaderIncludeOrImport` will never call this
// function as the `#include` or `#import` is textual.

MM.cacheModuleLoad(*Path[0].first, Module);
} else {
ModuleLoadResult Result = findOrCompileModuleAndReadAST(
Expand Down Expand Up @@ -2146,18 +2172,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
TheASTReader->makeModuleVisible(Module, Visibility, ImportLoc);
}

// Check for any configuration macros that have changed.
clang::Module *TopModule = Module->getTopLevelModule();
for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) {
checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I],
Module, ImportLoc);
}

// Resolve any remaining module using export_as for this one.
getPreprocessor()
.getHeaderSearchInfo()
.getModuleMap()
.resolveLinkAsDependencies(TopModule);
.resolveLinkAsDependencies(Module->getTopLevelModule());

LastModuleImportLoc = ImportLoc;
LastModuleImportResult = ModuleLoadResult(Module);
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Headers/hlsl/hlsl_basic_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ typedef vector<uint16_t, 2> uint16_t2;
typedef vector<uint16_t, 3> uint16_t3;
typedef vector<uint16_t, 4> uint16_t4;
#endif

typedef vector<bool, 2> bool2;
typedef vector<bool, 3> bool3;
typedef vector<bool, 4> bool4;
typedef vector<int, 2> int2;
typedef vector<int, 3> int3;
typedef vector<int, 4> int4;
Expand Down
322 changes: 322 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,118 @@ double3 abs(double3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
double4 abs(double4);

//===----------------------------------------------------------------------===//
// any builtins
//===----------------------------------------------------------------------===//

/// \fn bool any(T x)
/// \brief Returns True if any components of the \a x parameter are non-zero;
/// otherwise, false. \param x The input value.

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int16_t4);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint16_t4);
#endif

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(half4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(bool);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(bool2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(bool3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(bool4);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(float4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(int64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(uint64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(double);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(double2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_any)
bool any(double4);

//===----------------------------------------------------------------------===//
// ceil builtins
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -277,6 +389,70 @@ uint64_t dot(uint64_t3, uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t4, uint64_t4);

//===----------------------------------------------------------------------===//
// exp builtins
//===----------------------------------------------------------------------===//

/// \fn T exp(T x)
/// \brief Returns the base-e exponential, or \a e**x, of the specified value.
/// \param x The specified input value.
///
/// The return value is the base-e exponential of the \a x parameter.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
half exp(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
half2 exp(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
half3 exp(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
half4 exp(half4);

_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
float exp(float);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
float2 exp(float2);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
float3 exp(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp)
float4 exp(float4);

//===----------------------------------------------------------------------===//
// exp2 builtins
//===----------------------------------------------------------------------===//

/// \fn T exp2(T x)
/// \brief Returns the base 2 exponential, or \a 2**x, of the specified value.
/// \param x The specified input value.
///
/// The base 2 exponential of the \a x parameter.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
half exp2(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
half2 exp2(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
half3 exp2(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
half4 exp2(half4);

_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
float exp2(float);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
float2 exp2(float2);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
float3 exp2(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_exp2)
float4 exp2(float4);

//===----------------------------------------------------------------------===//
// floor builtins
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -511,6 +687,111 @@ double3 log2(double3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log2)
double4 log2(double4);

//===----------------------------------------------------------------------===//
// mad builtins
//===----------------------------------------------------------------------===//

/// \fn T mad(T M, T A, T B)
/// \brief The result of \a M * \a A + \a B.
/// \param M The multiplication value.
/// \param A The first addition value.
/// \param B The second addition value.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
half mad(half, half, half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
half2 mad(half2, half2, half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
half3 mad(half3, half3, half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
half4 mad(half4, half4, half4);

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int16_t mad(int16_t, int16_t, int16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int16_t2 mad(int16_t2, int16_t2, int16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int16_t3 mad(int16_t3, int16_t3, int16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int16_t4 mad(int16_t4, int16_t4, int16_t4);

_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint16_t mad(uint16_t, uint16_t, uint16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint16_t2 mad(uint16_t2, uint16_t2, uint16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint16_t3 mad(uint16_t3, uint16_t3, uint16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint16_t4 mad(uint16_t4, uint16_t4, uint16_t4);
#endif

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int mad(int, int, int);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int2 mad(int2, int2, int2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int3 mad(int3, int3, int3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int4 mad(int4, int4, int4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint mad(uint, uint, uint);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint2 mad(uint2, uint2, uint2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint3 mad(uint3, uint3, uint3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint4 mad(uint4, uint4, uint4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int64_t mad(int64_t, int64_t, int64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int64_t2 mad(int64_t2, int64_t2, int64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int64_t3 mad(int64_t3, int64_t3, int64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
int64_t4 mad(int64_t4, int64_t4, int64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint64_t mad(uint64_t, uint64_t, uint64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint64_t2 mad(uint64_t2, uint64_t2, uint64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint64_t3 mad(uint64_t3, uint64_t3, uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
uint64_t4 mad(uint64_t4, uint64_t4, uint64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
float mad(float, float, float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
float2 mad(float2, float2, float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
float3 mad(float3, float3, float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
float4 mad(float4, float4, float4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
double mad(double, double, double);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
double2 mad(double2, double2, double2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
double3 mad(double3, double3, double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_mad)
double4 mad(double4, double4, double4);

//===----------------------------------------------------------------------===//
// max builtins
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -831,6 +1112,47 @@ uint64_t3 reversebits(uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse)
uint64_t4 reversebits(uint64_t4);

//===----------------------------------------------------------------------===//
// rcp builtins
//===----------------------------------------------------------------------===//

/// \fn T rcp(T x)
/// \brief Calculates a fast, approximate, per-component reciprocal ie 1 / \a x.
/// \param x The specified input value.
///
/// The return value is the reciprocal of the \a x parameter.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
half rcp(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
half2 rcp(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
half3 rcp(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
half4 rcp(half4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
float rcp(float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
float2 rcp(float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
float3 rcp(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
float4 rcp(float4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
double rcp(double);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
double2 rcp(double2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
double3 rcp(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
double4 rcp(double4);

//===----------------------------------------------------------------------===//
// round builtins
//===----------------------------------------------------------------------===//
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/InstallAPI/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ ObjCInterfaceRecord *FrontendRecordsSlice::addObjCInterface(
return ObjCR;
}

ObjCCategoryRecord *FrontendRecordsSlice::addObjCCategory(
StringRef ClassToExtend, StringRef CategoryName,
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access) {
auto *ObjCR =
llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
return ObjCR;
}

ObjCIVarRecord *FrontendRecordsSlice::addObjCIVar(
ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC) {
// If the decl otherwise would have been exported, check their access control.
// Ivar's linkage is also determined by this.
if ((Linkage == RecordLinkage::Exported) &&
((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package)))
Linkage = RecordLinkage::Internal;
auto *ObjCR =
llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});

return nullptr;
}

std::optional<HeaderType>
InstallAPIContext::findAndRecordFile(const FileEntry *FE,
const Preprocessor &PP) {
Expand Down
51 changes: 50 additions & 1 deletion clang/lib/InstallAPI/Visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,29 @@ static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *D) {

return false;
}
void InstallAPIVisitor::recordObjCInstanceVariables(
const ASTContext &ASTCtx, ObjCContainerRecord *Record, StringRef SuperClass,
const llvm::iterator_range<
DeclContext::specific_decl_iterator<ObjCIvarDecl>>
Ivars) {
RecordLinkage Linkage = RecordLinkage::Exported;
const RecordLinkage ContainerLinkage = Record->getLinkage();
// If fragile, set to unknown.
if (ASTCtx.getLangOpts().ObjCRuntime.isFragile())
Linkage = RecordLinkage::Unknown;
// Linkage should be inherited from container.
else if (ContainerLinkage != RecordLinkage::Unknown)
Linkage = ContainerLinkage;
for (const auto *IV : Ivars) {
auto Access = getAccessForDecl(IV);
if (!Access)
continue;
StringRef Name = IV->getName();
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV);
auto AC = IV->getCanonicalAccessControl();
Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
}
}

bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
// Skip forward declaration for classes (@class)
Expand All @@ -118,7 +141,33 @@ bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
(!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
hasObjCExceptionAttribute(D));

Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
ObjCInterfaceRecord *Class =
Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);

// Get base class.
StringRef SuperClassName;
if (const auto *SuperClass = D->getSuperClass())
SuperClassName = SuperClass->getObjCRuntimeNameAsString();

recordObjCInstanceVariables(D->getASTContext(), Class, SuperClassName,
D->ivars());
return true;
}

bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
StringRef CategoryName = D->getName();
// Skip over declarations that access could not be collected for.
auto Access = getAccessForDecl(D);
if (!Access)
return true;
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
const StringRef InterfaceName = InterfaceD->getName();

ObjCCategoryRecord *Category = Ctx.Slice->addObjCCategory(
InterfaceName, CategoryName, Avail, D, *Access);
recordObjCInstanceVariables(D->getASTContext(), Category, InterfaceName,
D->ivars());
return true;
}

Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3908,7 +3908,10 @@ ExprResult Parser::ParseTypeTrait() {
SmallVector<ParsedType, 2> Args;
do {
// Parse the next type.
TypeResult Ty = ParseTypeName();
TypeResult Ty =
ParseTypeName(/*SourceRange=*/nullptr,
getLangOpts().CPlusPlus ? DeclaratorContext::TemplateArg
: DeclaratorContext::TypeName);
if (Ty.isInvalid()) {
Parens.skipToEnd();
return ExprError();
Expand Down Expand Up @@ -3950,7 +3953,8 @@ ExprResult Parser::ParseArrayTypeTrait() {
if (T.expectAndConsume())
return ExprError();

TypeResult Ty = ParseTypeName();
TypeResult Ty =
ParseTypeName(/*SourceRange=*/nullptr, DeclaratorContext::TemplateArg);
if (Ty.isInvalid()) {
SkipUntil(tok::comma, StopAtSemi);
SkipUntil(tok::r_paren, StopAtSemi);
Expand Down
64 changes: 43 additions & 21 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5271,6 +5271,11 @@ bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) {
// returning an ExprError
bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_elementwise_any: {
if (checkArgCount(*this, TheCall, 1))
return true;
break;
}
case Builtin::BI__builtin_hlsl_dot: {
if (checkArgCount(*this, TheCall, 2))
return true;
Expand All @@ -5280,6 +5285,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_rcp:
case Builtin::BI__builtin_hlsl_elementwise_frac: {
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
Expand All @@ -5298,6 +5304,14 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_mad: {
if (checkArgCount(*this, TheCall, 3))
return true;
if (CheckVectorElementCallArgs(this, TheCall))
return true;
if (SemaBuiltinElementwiseTernaryMath(TheCall, /*CheckForFloatArgs*/ false))
return true;
}
}
return false;
}
Expand Down Expand Up @@ -17624,31 +17638,29 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
return VisitExpr(CCE);

// In C++11, list initializations are sequenced.
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
E = CCE->arg_end();
I != E; ++I) {
Region = Tree.allocate(Parent);
Elts.push_back(Region);
Visit(*I);
}

// Forget that the initializers are sequenced.
Region = Parent;
for (unsigned I = 0; I < Elts.size(); ++I)
Tree.merge(Elts[I]);
SequenceExpressionsInOrder(
llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs()));
}

void VisitInitListExpr(const InitListExpr *ILE) {
if (!SemaRef.getLangOpts().CPlusPlus11)
return VisitExpr(ILE);

// In C++11, list initializations are sequenced.
SequenceExpressionsInOrder(ILE->inits());
}

void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) {
// C++20 parenthesized list initializations are sequenced. See C++20
// [decl.init.general]p16.5 and [decl.init.general]p16.6.2.2.
SequenceExpressionsInOrder(PLIE->getInitExprs());
}

private:
void SequenceExpressionsInOrder(ArrayRef<const Expr *> ExpressionList) {
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
const Expr *E = ILE->getInit(I);
for (const Expr *E : ExpressionList) {
if (!E)
continue;
Region = Tree.allocate(Parent);
Expand Down Expand Up @@ -19800,7 +19812,8 @@ bool Sema::SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res) {
return false;
}

bool Sema::SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall) {
bool Sema::SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall,
bool CheckForFloatArgs) {
if (checkArgCount(*this, TheCall, 3))
return true;

Expand All @@ -19812,11 +19825,20 @@ bool Sema::SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall) {
Args[I] = Converted.get();
}

int ArgOrdinal = 1;
for (Expr *Arg : Args) {
if (checkFPMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
if (CheckForFloatArgs) {
int ArgOrdinal = 1;
for (Expr *Arg : Args) {
if (checkFPMathBuiltinElementType(*this, Arg->getBeginLoc(),
Arg->getType(), ArgOrdinal++))
return true;
}
} else {
int ArgOrdinal = 1;
for (Expr *Arg : Args) {
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
ArgOrdinal++))
return true;
return true;
}
}

for (int I = 1; I < 3; ++I) {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,9 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
// unqualified-id followed by a < and name lookup finds either one
// or more functions or finds nothing.
if (!IsFilteredTemplateName)
FilterAcceptableTemplateNames(Result);
FilterAcceptableTemplateNames(Result,
/*AllowFunctionTemplates=*/true,
/*AllowDependent=*/true);

bool IsFunctionTemplate;
bool IsVarTemplate;
Expand All @@ -1120,6 +1122,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
Template = Context.getOverloadedTemplateName(Result.begin(),
Result.end());
} else if (!Result.empty()) {
assert(!Result.isUnresolvableResult());
auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(
*Result.begin(), /*AllowFunctionTemplates=*/true,
/*AllowDependent=*/false));
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6227,12 +6227,6 @@ struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> {
return VisitCXXMethodDecl(E->getCallOperator());
}

// Blocks don't support default parameters, and, as for lambdas,
// we don't consider their body a subexpression.
bool VisitBlockDecl(BlockDecl *B) { return false; }

bool VisitCompoundStmt(CompoundStmt *B) { return false; }

bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
return TraverseStmt(E->getExpr());
}
Expand Down
37 changes: 24 additions & 13 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes(
size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
return isa<FieldDecl>(D) || isa<RecordDecl>(D);
});
bool CheckForMissingFields =
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
bool HasDesignatedInit = false;

llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;
Expand Down Expand Up @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes(
}

InitializedSomething = true;

// Disable check for missing fields when designators are used.
// This matches gcc behaviour.
if (!SemaRef.getLangOpts().CPlusPlus)
CheckForMissingFields = false;
continue;
}

Expand All @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes(
// These are okay for randomized structures. [C99 6.7.8p19]
//
// Also, if there is only one element in the structure, we allow something
// like this, because it's really not randomized in the tranditional sense.
// like this, because it's really not randomized in the traditional sense.
//
// struct foo h = {bar};
auto IsZeroInitializer = [&](const Expr *I) {
Expand Down Expand Up @@ -2363,8 +2356,13 @@ void InitListChecker::CheckStructUnionTypes(
}

// Emit warnings for missing struct field initializers.
if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
!RD->isUnion()) {
// This check is disabled for designated initializers in C.
// This matches gcc behaviour.
bool IsCDesignatedInitializer =
HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus;
if (!VerifyOnly && InitializedSomething && !RD->isUnion() &&
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
!IsCDesignatedInitializer) {
// It is possible we have one or more unnamed bitfields remaining.
// Find first (if any) named field and emit warning.
for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
Expand All @@ -2376,9 +2374,10 @@ void InitListChecker::CheckStructUnionTypes(

if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
!it->getType()->isIncompleteArrayType()) {
SemaRef.Diag(IList->getSourceRange().getEnd(),
diag::warn_missing_field_initializers)
<< *it;
auto Diag = HasDesignatedInit
? diag::warn_missing_designated_field_initializers
: diag::warn_missing_field_initializers;
SemaRef.Diag(IList->getSourceRange().getEnd(), Diag) << *it;
break;
}
}
Expand Down Expand Up @@ -7734,6 +7733,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
break;
}

case Stmt::CompoundLiteralExprClass: {
if (auto *CLE = dyn_cast<CompoundLiteralExpr>(Init)) {
if (!CLE->isFileScope())
Visit(Path, Local(CLE), RK);
}
break;
}

// FIXME: Visit the left-hand side of an -> or ->*.

default:
Expand Down Expand Up @@ -8289,6 +8296,10 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (LK == LK_StmtExprResult)
return false;
Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange;
} else if (auto *CLE = dyn_cast<CompoundLiteralExpr>(L)) {
Diag(DiagLoc, diag::warn_ret_stack_addr_ref)
<< Entity.getType()->isReferenceType() << CLE->getInitializer() << 2
<< DiagRange;
} else {
Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)
<< Entity.getType()->isReferenceType() << DiagRange;
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,18 +491,20 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// To keep our behavior consistent, we apply the "finds nothing" part in
// all language modes, and diagnose the empty lookup in ActOnCallExpr if we
// successfully form a call to an undeclared template-id.
bool AllFunctions =
getLangOpts().CPlusPlus20 && llvm::all_of(Found, [](NamedDecl *ND) {
bool AnyFunctions =
getLangOpts().CPlusPlus20 && llvm::any_of(Found, [](NamedDecl *ND) {
return isa<FunctionDecl>(ND->getUnderlyingDecl());
});
if (AllFunctions || (Found.empty() && !IsDependent)) {
if (AnyFunctions || (Found.empty() && !IsDependent)) {
// If lookup found any functions, or if this is a name that can only be
// used for a function, then strongly assume this is a function
// template-id.
*ATK = (Found.empty() && Found.getLookupName().isIdentifier())
? AssumedTemplateKind::FoundNothing
: AssumedTemplateKind::FoundFunctions;
Found.clear();
FilterAcceptableTemplateNames(Found,
/*AllowFunctionTemplates*/ true,
/*AllowDependent*/ true);
return false;
}
}
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,7 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
/// (2) and (3). Post-call for the allocator is called after step (1).
/// Pre-statement for the new-expression is called on step (4) when the value
/// of the expression is evaluated.
/// \param NE The C++ new-expression that triggered the allocation.
/// \param Target The allocated region, casted to the class type.
void checkNewAllocator(const CXXNewExpr *NE, SVal Target,
CheckerContext &) const {}
void checkNewAllocator(const CXXAllocatorCall &, CheckerContext &) const {}

/// Called on a load from and a store to a location.
///
Expand Down Expand Up @@ -330,5 +327,13 @@ void CheckerDocumentation::checkPostStmt(const DeclStmt *DS,
CheckerContext &C) const {
}

void registerCheckerDocumentationChecker(CheckerManager &Mgr) {
Mgr.registerChecker<CheckerDocumentation>();
}

bool shouldRegisterCheckerDocumentationChecker(const CheckerManager &) {
return false;
}

} // end namespace ento
} // end namespace clang
12 changes: 0 additions & 12 deletions clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,18 +222,6 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
}
}

bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps,
ProgramStateRef InitState,
ExplodedNodeSet &Dst) {
bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
for (ExplodedGraph::eop_iterator I = G.eop_begin(), E = G.eop_end(); I != E;
++I) {
Dst.Add(*I);
}
return DidNotFinish;
}

void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
const CFGBlock *Blk = L.getDst();
NodeBuilderContext BuilderCtx(*this, Blk, Pred);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/Interp/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ int chooseexpr[__builtin_choose_expr(1, 1, expr)];

int somefunc(int i) {
return (i, 65537) * 65537; // all-warning {{left operand of comma operator has no effect}} \
// all-warning {{overflow in expression; result is 131073}}
// all-warning {{overflow in expression; result is 131'073 with type 'int'}}
}

/// FIXME: The following test is incorrect in the new interpreter.
Expand Down
10 changes: 10 additions & 0 deletions clang/test/AST/Interp/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,13 @@ namespace VariadicOperator {
float &fr = c(10);
}
}

namespace WeakCompare {
[[gnu::weak]]void weak_method();
static_assert(weak_method != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}

constexpr auto A = &weak_method;
static_assert(A != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
}
4 changes: 2 additions & 2 deletions clang/test/Analysis/stack-addr-ps.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ int* f3(int x, int *y) {

void* compound_literal(int x, int y) {
if (x)
return &(unsigned short){((unsigned short)0x22EF)}; // expected-warning{{Address of stack memory}}
return &(unsigned short){((unsigned short)0x22EF)}; // expected-warning{{Address of stack memory}} expected-warning{{address of stack memory}}

int* array[] = {};
struct s { int z; double y; int w; };

if (y)
return &((struct s){ 2, 0.4, 5 * 8 }); // expected-warning{{Address of stack memory}}
return &((struct s){ 2, 0.4, 5 * 8 }); // expected-warning{{Address of stack memory}} expected-warning{{address of stack memory}}


void* p = &((struct s){ 42, 0.4, x ? 42 : 0 });
Expand Down
2 changes: 1 addition & 1 deletion clang/test/C/drs/dr0xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ _Static_assert(__builtin_types_compatible_p(struct S { int a; }, union U { int a
*/
void dr031(int i) {
switch (i) {
case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */
case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch"
/* Silence the targets which issue:
Expand Down
2 changes: 1 addition & 1 deletion clang/test/C/drs/dr2xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ void dr258(void) {
void dr261(void) {
/* This is still an integer constant expression despite the overflow. */
enum e1 {
ex1 = __INT_MAX__ + 1 /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */
ex1 = __INT_MAX__ + 1 /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */
};

/* This is not an integer constant expression, because of the comma operator,
Expand Down
Loading