1,213 changes: 1,213 additions & 0 deletions bolt/docs/CommandLineArgumentReference.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions bolt/lib/Rewrite/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
Core
DebugInfoDWARF
DWP
JITLink
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ void SuspiciousEnumUsageCheck::check(const MatchFinder::MatchResult &Result) {
// Skip when one of the parameters is an empty enum. The
// hasDisjointValueRange function could not decide the values properly in
// case of an empty enum.
if (EnumDec->enumerator_begin() == EnumDec->enumerator_end() ||
OtherEnumDec->enumerator_begin() == OtherEnumDec->enumerator_end())
if (EnumDec->enumerators().empty() || OtherEnumDec->enumerators().empty())
return;

if (!hasDisjointValueRange(EnumDec, OtherEnumDec))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ static std::string createReplacementText(const LambdaExpr *Lambda) {
AppendName("this");
}
}
if (!Replacement.empty() &&
Lambda->explicit_capture_begin() != Lambda->explicit_capture_end()) {
if (!Replacement.empty() && !Lambda->explicit_captures().empty()) {
// Add back separator if we are adding explicit capture variables.
Stream << ", ";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,44 @@ SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck(
"AllowMissingMoveFunctions", false)),
AllowSoleDefaultDtor(Options.get("AllowSoleDefaultDtor", false)),
AllowMissingMoveFunctionsWhenCopyIsDeleted(
Options.get("AllowMissingMoveFunctionsWhenCopyIsDeleted", false)) {}
Options.get("AllowMissingMoveFunctionsWhenCopyIsDeleted", false)),
AllowImplicitlyDeletedCopyOrMove(
Options.get("AllowImplicitlyDeletedCopyOrMove", false)) {}

void SpecialMemberFunctionsCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "AllowMissingMoveFunctions", AllowMissingMoveFunctions);
Options.store(Opts, "AllowSoleDefaultDtor", AllowSoleDefaultDtor);
Options.store(Opts, "AllowMissingMoveFunctionsWhenCopyIsDeleted",
AllowMissingMoveFunctionsWhenCopyIsDeleted);
Options.store(Opts, "AllowImplicitlyDeletedCopyOrMove",
AllowImplicitlyDeletedCopyOrMove);
}

std::optional<TraversalKind>
SpecialMemberFunctionsCheck::getCheckTraversalKind() const {
return AllowImplicitlyDeletedCopyOrMove ? TK_AsIs
: TK_IgnoreUnlessSpelledInSource;
}

void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) {
auto IsNotImplicitOrDeleted = anyOf(unless(isImplicit()), isDeleted());

Finder->addMatcher(
cxxRecordDecl(
eachOf(has(cxxDestructorDecl().bind("dtor")),
has(cxxConstructorDecl(isCopyConstructor()).bind("copy-ctor")),
has(cxxMethodDecl(isCopyAssignmentOperator())
unless(isImplicit()),
eachOf(has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")),
has(cxxConstructorDecl(isCopyConstructor(),
IsNotImplicitOrDeleted)
.bind("copy-ctor")),
has(cxxMethodDecl(isCopyAssignmentOperator(),
IsNotImplicitOrDeleted)
.bind("copy-assign")),
has(cxxConstructorDecl(isMoveConstructor()).bind("move-ctor")),
has(cxxMethodDecl(isMoveAssignmentOperator())
has(cxxConstructorDecl(isMoveConstructor(),
IsNotImplicitOrDeleted)
.bind("move-ctor")),
has(cxxMethodDecl(isMoveAssignmentOperator(),
IsNotImplicitOrDeleted)
.bind("move-assign"))))
.bind("class-def"),
this);
Expand Down Expand Up @@ -127,7 +146,8 @@ void SpecialMemberFunctionsCheck::check(
for (const auto &KV : Matchers)
if (const auto *MethodDecl =
Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first)) {
StoreMember({KV.second, MethodDecl->isDeleted()});
StoreMember(
{KV.second, MethodDecl->isDeleted(), MethodDecl->isImplicit()});
}
}

Expand All @@ -144,7 +164,13 @@ void SpecialMemberFunctionsCheck::checkForMissingMembers(

auto HasMember = [&](SpecialMemberFunctionKind Kind) {
return llvm::any_of(DefinedMembers, [Kind](const auto &Data) {
return Data.FunctionKind == Kind;
return Data.FunctionKind == Kind && !Data.IsImplicit;
});
};

auto HasImplicitDeletedMember = [&](SpecialMemberFunctionKind Kind) {
return llvm::any_of(DefinedMembers, [Kind](const auto &Data) {
return Data.FunctionKind == Kind && Data.IsImplicit && Data.IsDeleted;
});
};

Expand All @@ -154,9 +180,17 @@ void SpecialMemberFunctionsCheck::checkForMissingMembers(
});
};

auto RequireMember = [&](SpecialMemberFunctionKind Kind) {
if (!HasMember(Kind))
MissingMembers.push_back(Kind);
auto RequireMembers = [&](SpecialMemberFunctionKind Kind1,
SpecialMemberFunctionKind Kind2) {
if (AllowImplicitlyDeletedCopyOrMove && HasImplicitDeletedMember(Kind1) &&
HasImplicitDeletedMember(Kind2))
return;

if (!HasMember(Kind1))
MissingMembers.push_back(Kind1);

if (!HasMember(Kind2))
MissingMembers.push_back(Kind2);
};

bool RequireThree =
Expand All @@ -180,23 +214,25 @@ void SpecialMemberFunctionsCheck::checkForMissingMembers(
!HasMember(SpecialMemberFunctionKind::NonDefaultDestructor))
MissingMembers.push_back(SpecialMemberFunctionKind::Destructor);

RequireMember(SpecialMemberFunctionKind::CopyConstructor);
RequireMember(SpecialMemberFunctionKind::CopyAssignment);
RequireMembers(SpecialMemberFunctionKind::CopyConstructor,
SpecialMemberFunctionKind::CopyAssignment);
}

if (RequireFive &&
!(AllowMissingMoveFunctionsWhenCopyIsDeleted &&
(IsDeleted(SpecialMemberFunctionKind::CopyConstructor) &&
IsDeleted(SpecialMemberFunctionKind::CopyAssignment)))) {
assert(RequireThree);
RequireMember(SpecialMemberFunctionKind::MoveConstructor);
RequireMember(SpecialMemberFunctionKind::MoveAssignment);
RequireMembers(SpecialMemberFunctionKind::MoveConstructor,
SpecialMemberFunctionKind::MoveAssignment);
}

if (!MissingMembers.empty()) {
llvm::SmallVector<SpecialMemberFunctionKind, 5> DefinedMemberKinds;
llvm::transform(DefinedMembers, std::back_inserter(DefinedMemberKinds),
[](const auto &Data) { return Data.FunctionKind; });
for (const auto &Data : DefinedMembers) {
if (!Data.IsImplicit)
DefinedMemberKinds.push_back(Data.FunctionKind);
}
diag(ID.first, "class '%0' defines %1 but does not define %2")
<< ID.second << cppcoreguidelines::join(DefinedMemberKinds, " and ")
<< cppcoreguidelines::join(MissingMembers, " or ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ class SpecialMemberFunctionsCheck : public ClangTidyCheck {
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void onEndOfTranslationUnit() override;
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}
std::optional<TraversalKind> getCheckTraversalKind() const override;

enum class SpecialMemberFunctionKind : uint8_t {
Destructor,
DefaultDestructor,
Expand All @@ -46,6 +45,7 @@ class SpecialMemberFunctionsCheck : public ClangTidyCheck {
struct SpecialMemberFunctionData {
SpecialMemberFunctionKind FunctionKind;
bool IsDeleted;
bool IsImplicit = false;

bool operator==(const SpecialMemberFunctionData &Other) const {
return (Other.FunctionKind == FunctionKind) &&
Expand All @@ -67,6 +67,7 @@ class SpecialMemberFunctionsCheck : public ClangTidyCheck {
const bool AllowMissingMoveFunctions;
const bool AllowSoleDefaultDtor;
const bool AllowMissingMoveFunctionsWhenCopyIsDeleted;
const bool AllowImplicitlyDeletedCopyOrMove;
ClassDefiningSpecialMembersMap ClassWithSpecialMembers;
};

Expand Down
4 changes: 1 addition & 3 deletions clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,7 @@ void UnusedParametersCheck::check(const MatchFinder::MatchResult &Result) {

// In non-strict mode ignore function definitions with empty bodies
// (constructor initializer counts for non-empty body).
if (StrictMode ||
(Function->getBody()->child_begin() !=
Function->getBody()->child_end()) ||
if (StrictMode || !Function->getBody()->children().empty() ||
(isa<CXXConstructorDecl>(Function) &&
cast<CXXConstructorDecl>(Function)->getNumCtorInitializers() > 0))
warnOnUnusedParameter(Result, Function, I);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,17 @@ generateReplacements(const MatchFinder::MatchResult &Match,
continue;
}

// if the nested call is not the same as the top call
if (InnerCall->getDirectCallee()->getQualifiedNameAsString() !=
TopCall->getDirectCallee()->getQualifiedNameAsString())
continue;

const FindArgsResult InnerResult = findArgs(InnerCall);

// if the nested call doesn't have arguments skip it
if (!InnerResult.First || !InnerResult.Last)
continue;

// if the nested call is not the same as the top call
if (InnerCall->getDirectCallee()->getQualifiedNameAsString() !=
TopCall->getDirectCallee()->getQualifiedNameAsString())
continue;

// if the nested call doesn't have the same compare function
if ((Result.Compare || InnerResult.Compare) &&
!utils::areStatementsIdentical(Result.Compare, InnerResult.Compare,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ AST_MATCHER(FunctionDecl, hasOtherDeclarations) {
void UseConstraintsCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
functionTemplateDecl(
// Skip external libraries included as system headers
unless(isExpansionInSystemHeader()),
has(functionDecl(unless(hasOtherDeclarations()), isDefinition(),
hasReturnTypeLoc(typeLoc().bind("return")))
.bind("function")))
Expand All @@ -57,6 +59,8 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) {
return std::nullopt;
}
TheType = Dep.getQualifierLoc().getTypeLoc();
if (TheType.isNull())
return std::nullopt;
}

if (const auto SpecializationLoc =
Expand Down Expand Up @@ -254,7 +258,7 @@ findInsertionForConstraint(const FunctionDecl *Function, ASTContext &Context) {
return utils::lexer::findPreviousTokenKind(Init->getSourceLocation(),
SM, LangOpts, tok::colon);
}
if (Constructor->init_begin() != Constructor->init_end())
if (!Constructor->inits().empty())
return std::nullopt;
}
if (Function->isDeleted()) {
Expand Down
10 changes: 10 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ Changes in existing checks
<clang-tidy/checks/cppcoreguidelines/use-default-member-init>`. Fixed
incorrect hints when using list-initialization.

- Improved :doc:`cppcoreguidelines-special-member-functions
<clang-tidy/checks/cppcoreguidelines/special-member-functions>` check with a
new option `AllowImplicitlyDeletedCopyOrMove`, which removes the requirement
for explicit copy or move special member functions when they are already
implicitly deleted.

- Improved :doc:`google-build-namespaces
<clang-tidy/checks/google/build-namespaces>` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.
Expand Down Expand Up @@ -322,6 +328,10 @@ Changes in existing checks
don't remove parentheses used in ``sizeof`` calls when they have array index
accesses as arguments.

- Improved :doc:`modernize-use-constraints
<clang-tidy/checks/modernize/use-constraints>` check by fixing a crash that
occurred in some scenarios and excluding system headers from analysis.

- Improved :doc:`modernize-use-nullptr
<clang-tidy/checks/modernize/use-nullptr>` check to include support for C23,
which also has introduced the ``nullptr`` keyword.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ Options

.. option:: AllowMissingMoveFunctions

When set to `true` (default is `false`), this check doesn't flag classes which define no move
operations at all. It still flags classes which define only one of either
move constructor or move assignment operator. With this option enabled, the following class won't be flagged:
When set to `true` (default is `false`), this check doesn't flag classes
which define no move operations at all. It still flags classes which define
only one of either move constructor or move assignment operator. With this
option enabled, the following class won't be flagged:

.. code-block:: c++

Expand All @@ -59,10 +60,11 @@ Options

.. option:: AllowMissingMoveFunctionsWhenCopyIsDeleted

When set to `true` (default is `false`), this check doesn't flag classes which define deleted copy
operations but don't define move operations. This flag is related to Google C++ Style Guide
https://google.github.io/styleguide/cppguide.html#Copyable_Movable_Types. With this option enabled, the
following class won't be flagged:
When set to `true` (default is `false`), this check doesn't flag classes
which define deleted copy operations but don't define move operations. This
flag is related to Google C++ Style Guide `Copyable and Movable Types
<https://google.github.io/styleguide/cppguide.html#Copyable_Movable_Types>`_.
With this option enabled, the following class won't be flagged:

.. code-block:: c++

Expand All @@ -71,3 +73,15 @@ Options
A& operator=(const A&) = delete;
~A();
};

.. option:: AllowImplicitlyDeletedCopyOrMove

When set to `true` (default is `false`), this check doesn't flag classes
which implicitly delete copy or move operations.
With this option enabled, the following class won't be flagged:

.. code-block:: c++

struct A : boost::noncopyable {
~A() { std::cout << "dtor\n"; }
};
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,7 @@ The tool will replace the above code with,
// The tool will not emit a diagnostic or attempt to replace the code.
template <typename T, std::enable_if_t<T::some_trait, int> = 0>
struct my_class {};

.. note::

System headers are not analyzed by this check.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t -- -config="{CheckOptions: {cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions: true, cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor: true}}" --
// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t -- -config="{CheckOptions: {cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions: true, cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor: true, cppcoreguidelines-special-member-functions.AllowImplicitlyDeletedCopyOrMove: true}}" --

// Don't warn on destructors without definitions, they might be defaulted in another TU.
class DeclaresDestructor {
Expand Down Expand Up @@ -34,12 +34,13 @@ class DefinesCopyAssignment {
class DefinesMoveConstructor {
DefinesMoveConstructor(DefinesMoveConstructor &&);
};
// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor, a copy constructor, a copy assignment operator or a move assignment operator [cppcoreguidelines-special-member-functions]
// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor or a move assignment operator [cppcoreguidelines-special-member-functions]

class DefinesMoveAssignment {
DefinesMoveAssignment &operator=(DefinesMoveAssignment &&);
};
// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor, a copy constructor, a copy assignment operator or a move constructor [cppcoreguidelines-special-member-functions]
// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor or a move constructor [cppcoreguidelines-special-member-functions]

class DefinesNothing {
};

Expand Down Expand Up @@ -81,3 +82,22 @@ struct TemplateClass {
// This should not cause problems.
TemplateClass<int> InstantiationWithInt;
TemplateClass<double> InstantiationWithDouble;

struct NoCopy
{
NoCopy() = default;
~NoCopy() = default;

NoCopy(const NoCopy&) = delete;
NoCopy(NoCopy&&) = delete;

NoCopy& operator=(const NoCopy&) = delete;
NoCopy& operator=(NoCopy&&) = delete;
};

// CHECK-MESSAGES: [[@LINE+1]]:8: warning: class 'NonCopyable' defines a copy constructor but does not define a destructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
struct NonCopyable : NoCopy
{
NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
};
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,27 @@ B maxTT2 = std::max(B(), std::max(B(), B()));
B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; });
// CHECK-FIXES: B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; });

struct GH91982 {
int fun0Args();
int fun1Arg(int a);
int fun2Args(int a, int b);
int fun3Args(int a, int b, int c);
int fun4Args(int a, int b, int c, int d);

int foo() {
return std::max(
fun0Args(),
std::max(fun1Arg(0),
std::max(fun2Args(0, 1),
std::max(fun3Args(0, 1, 2), fun4Args(0, 1, 2, 3)))));
// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: return std::max(
// CHECK-FIXES-NEXT: {fun0Args(),
// CHECK-FIXES-NEXT: fun1Arg(0),
// CHECK-FIXES-NEXT: fun2Args(0, 1),
// CHECK-FIXES-NEXT: fun3Args(0, 1, 2), fun4Args(0, 1, 2, 3)});
}
};

} // namespace

Original file line number Diff line number Diff line change
Expand Up @@ -724,3 +724,35 @@ void not_last_param() {
}

} // namespace enable_if_trailing_type_parameter


// Issue fixes:

namespace PR91872 {

enum expression_template_option { value1, value2 };

template <typename T> struct number_category {
static const int value = 0;
};

constexpr int number_kind_complex = 1;

template <typename T, expression_template_option ExpressionTemplates>
struct number {
using type = T;
};

template <typename T> struct component_type {
using type = T;
};

template <class T, expression_template_option ExpressionTemplates>
inline typename std::enable_if<
number_category<T>::value == number_kind_complex,
component_type<number<T, ExpressionTemplates>>>::type::type
abs(const number<T, ExpressionTemplates> &v) {
return {};
}

}
12 changes: 11 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,14 @@ C++ Specific Potentially Breaking Changes
- The behavior controlled by the `-frelaxed-template-template-args` flag is now
on by default, and the flag is deprecated. Until the flag is finally removed,
it's negative spelling can be used to obtain compatibility with previous
versions of clang.
versions of clang. The deprecation warning for the negative spelling can be
disabled with `-Wno-deprecated-no-relaxed-template-template-args`.

- Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906).

- Clang now performs semantic analysis for unary operators with dependent operands
that are known to be of non-class non-enumeration type prior to instantiation.

ABI Changes in This Version
---------------------------
- Fixed Microsoft name mangling of implicitly defined variables used for thread
Expand Down Expand Up @@ -566,6 +570,9 @@ Bug Fixes in This Version
- Clang will no longer emit a duplicate -Wunused-value warning for an expression
`(A, B)` which evaluates to glvalue `B` that can be converted to non ODR-use. (#GH45783)

- Clang now correctly disallows VLA type compound literals, e.g. ``(int[size]){}``,
as the C standard mandates. (#GH89835)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -713,6 +720,9 @@ Bug Fixes to C++ Support
- Correctly treat the compound statement of an ``if consteval`` as an immediate context. Fixes (#GH91509).
- When partial ordering alias templates against template template parameters,
allow pack expansions when the alias has a fixed-size parameter list. Fixes (#GH62529).
- Clang now ignores template parameters only used within the exception specification of candidate function
templates during partial ordering when deducing template arguments from a function declaration or when
taking the address of a function template.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -8044,7 +8044,10 @@ inline bool Type::isUndeducedType() const {
/// Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {
return isDependentType() || isRecordType() || isEnumeralType();
if (!CanonicalType->isDependentType())
return isRecordType() || isEnumeralType();
return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
!isMemberPointerType();
}

/// Determines whether this type is written as a typedef-name.
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/AST/VTTBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class VTTBuilder {
using AddressPointsMapTy = llvm::DenseMap<BaseSubobject, uint64_t>;

/// The sub-VTT indices for the bases of the most derived class.
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndices;

/// The secondary virtual pointer indices of all subobjects of
/// the most derived class.
Expand Down Expand Up @@ -148,8 +148,8 @@ class VTTBuilder {
}

/// Returns a reference to the sub-VTT indices.
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
return SubVTTIndicies;
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndices() const {
return SubVTTIndices;
}

/// Returns a reference to the secondary virtual pointer indices.
Expand Down
118 changes: 73 additions & 45 deletions clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/Formula.h"
Expand All @@ -30,9 +31,11 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>

namespace clang {
namespace dataflow {
Expand Down Expand Up @@ -155,32 +158,40 @@ class Environment {

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
explicit Environment(DataflowAnalysisContext &DACtx);
explicit Environment(DataflowAnalysisContext &DACtx)
: DACtx(&DACtx),
FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program, with `S` as the statement to analyze.
Environment(DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) {
InitialTargetStmt = &S;
}

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program, with `FD` as the function to analyze.
///
/// Requirements:
///
/// The function must have a body, i.e.
/// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD)
: Environment(DACtx, *FD.getBody()) {
assert(FD.doesThisDeclarationHaveABody());
InitialTargetFunc = &FD;
}

// Copy-constructor is private, Environments should not be copied. See fork().
Environment &operator=(const Environment &Other) = delete;

Environment(Environment &&Other) = default;
Environment &operator=(Environment &&Other) = default;

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
///
/// If `DeclCtx` is a function, initializes the environment with symbolic
/// representations of the function parameters.
///
/// If `DeclCtx` is a non-static member function, initializes the environment
/// with a symbolic representation of the `this` pointee.
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);

/// Assigns storage locations and values to all parameters, captures, global
/// variables, fields and functions referenced in the function currently being
/// analyzed.
///
/// Requirements:
/// variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
/// passed to the constructor.
///
/// The function must have a body, i.e.
/// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
/// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
void initialize();

/// Returns a new environment that is a copy of this one.
Expand All @@ -193,7 +204,7 @@ class Environment {
/// forked flow condition references the original).
Environment fork() const;

/// Creates and returns an environment to use for an inline analysis of the
/// Creates and returns an environment to use for an inline analysis of the
/// callee. Uses the storage location from each argument in the `Call` as the
/// storage location for the corresponding parameter in the callee.
///
Expand Down Expand Up @@ -365,46 +376,51 @@ class Environment {
RecordStorageLocation &
getResultObjectLocation(const Expr &RecordPRValue) const;

/// Returns the return value of the current function. This can be null if:
/// Returns the return value of the function currently being analyzed.
/// This can be null if:
/// - The function has a void return type
/// - No return value could be determined for the function, for example
/// because it calls a function without a body.
///
/// Requirements:
/// The current function must have a non-reference return type.
/// The current analysis target must be a function and must have a
/// non-reference return type.
Value *getReturnValue() const {
assert(getCurrentFunc() != nullptr &&
!getCurrentFunc()->getReturnType()->isReferenceType());
return ReturnVal;
}

/// Returns the storage location for the reference returned by the current
/// function. This can be null if function doesn't return a single consistent
/// reference.
/// Returns the storage location for the reference returned by the function
/// currently being analyzed. This can be null if the function doesn't return
/// a single consistent reference.
///
/// Requirements:
/// The current function must have a reference return type.
/// The current analysis target must be a function and must have a reference
/// return type.
StorageLocation *getReturnStorageLocation() const {
assert(getCurrentFunc() != nullptr &&
getCurrentFunc()->getReturnType()->isReferenceType());
return ReturnLoc;
}

/// Sets the return value of the current function.
/// Sets the return value of the function currently being analyzed.
///
/// Requirements:
/// The current function must have a non-reference return type.
/// The current analysis target must be a function and must have a
/// non-reference return type.
void setReturnValue(Value *Val) {
assert(getCurrentFunc() != nullptr &&
!getCurrentFunc()->getReturnType()->isReferenceType());
ReturnVal = Val;
}

/// Sets the storage location for the reference returned by the current
/// function.
/// Sets the storage location for the reference returned by the function
/// currently being analyzed.
///
/// Requirements:
/// The current function must have a reference return type.
/// The current analysis target must be a function and must have a reference
/// return type.
void setReturnStorageLocation(StorageLocation *Loc) {
assert(getCurrentFunc() != nullptr &&
getCurrentFunc()->getReturnType()->isReferenceType());
Expand Down Expand Up @@ -641,23 +657,21 @@ class Environment {
/// (or the flow condition is overly constraining) or if the solver times out.
bool allows(const Formula &) const;

/// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
/// returns null.
const DeclContext *getDeclCtx() const { return CallStack.back(); }

/// Returns the function currently being analyzed, or null if the code being
/// analyzed isn't part of a function.
const FunctionDecl *getCurrentFunc() const {
return dyn_cast<FunctionDecl>(getDeclCtx());
return CallStack.empty() ? InitialTargetFunc : CallStack.back();
}

/// Returns the size of the call stack.
/// Returns the size of the call stack, not counting the initial analysis
/// target.
size_t callStackSize() const { return CallStack.size(); }

/// Returns whether this `Environment` can be extended to analyze the given
/// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
/// given `MaxDepth`.
bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
/// `Callee` (i.e. if `pushCall` can be used).
/// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
/// (i.e. the maximum value that `callStackSize()` may assume after the call).
bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const;

/// Returns the `DataflowAnalysisContext` used by the environment.
DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
Expand Down Expand Up @@ -719,15 +733,20 @@ class Environment {
ArrayRef<const Expr *> Args);

/// Assigns storage locations and values to all global variables, fields
/// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
/// and functions in `Referenced`.
void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced);

static PrValueToResultObject
buildResultObjectMap(DataflowAnalysisContext *DACtx,
const FunctionDecl *FuncDecl,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal);

static PrValueToResultObject
buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal);

// `DACtx` is not null and not owned by this object.
DataflowAnalysisContext *DACtx;

Expand All @@ -736,11 +755,20 @@ class Environment {
// shared between environments in the same call.
// https://github.com/llvm/llvm-project/issues/59005

// `DeclContext` of the block being analysed if provided.
std::vector<const DeclContext *> CallStack;
// The stack of functions called from the initial analysis target.
std::vector<const FunctionDecl *> CallStack;

// Initial function to analyze, if a function was passed to the constructor.
// Null otherwise.
const FunctionDecl *InitialTargetFunc = nullptr;
// Top-level statement of the initial analysis target.
// If a function was passed to the constructor, this is its body.
// If a statement was passed to the constructor, this is that statement.
// Null if no analysis target was passed to the constructor.
Stmt *InitialTargetStmt = nullptr;

// Maps from prvalues of record type to their result objects. Shared between
// all environments for the same function.
// all environments for the same analysis target.
// FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
// here, though the cost is acceptable: The overhead of a `shared_ptr` is
// incurred when it is copied, and this happens only relatively rarely (when
Expand All @@ -749,7 +777,7 @@ class Environment {
std::shared_ptr<PrValueToResultObject> ResultObjectMap;

// The following three member variables handle various different types of
// return values.
// return values when the current analysis target is a function.
// - If the return type is not a reference and not a record: Value returned
// by the function.
Value *ReturnVal = nullptr;
Expand All @@ -762,7 +790,7 @@ class Environment {
RecordStorageLocation *LocForRecordReturnVal = nullptr;

// The storage location of the `this` pointee. Should only be null if the
// function being analyzed is only a function and not a method.
// analysis target is not a method.
RecordStorageLocation *ThisPointeeLoc = nullptr;

// Maps from declarations and glvalue expression to storage locations that are
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
def warn_drv_deprecated_arg : Warning<
"argument '%0' is deprecated%select{|, use '%2' instead}1">, InGroup<Deprecated>;
def warn_drv_deprecated_arg_no_relaxed_template_template_args : Warning<
"argument '-fno-relaxed-template-template-args' is deprecated">,
InGroup<DeprecatedNoRelaxedTemplateTemplateArgs>;
def warn_drv_deprecated_custom : Warning<
"argument '%0' is deprecated, %1">, InGroup<Deprecated>;
def warn_drv_assuming_mfloat_abi_is : Warning<
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def EnumConversion : DiagGroup<"enum-conversion",
[EnumEnumConversion,
EnumFloatConversion,
EnumCompareConditional]>;
def DeprecatedNoRelaxedTemplateTemplateArgs : DiagGroup<"deprecated-no-relaxed-template-template-args">;
def ObjCSignedCharBoolImplicitIntConversion :
DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
def Shorten64To32 : DiagGroup<"shorten-64-to-32">;
Expand Down Expand Up @@ -228,6 +229,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedLiteralOperator,
DeprecatedPragma,
DeprecatedRegister,
DeprecatedNoRelaxedTemplateTemplateArgs,
DeprecatedThisCapture,
DeprecatedType,
DeprecatedVolatile,
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3371,6 +3371,8 @@ def err_field_with_address_space : Error<
"field may not be qualified with an address space">;
def err_compound_literal_with_address_space : Error<
"compound literal in function scope may not be qualified with an address space">;
def err_compound_literal_with_vla_type : Error<
"compound literal cannot be of variable-length array type">;
def err_address_space_mismatch_templ_inst : Error<
"conflicting address space qualifiers are provided between types %0 and %1">;
def err_attr_objc_ownership_redundant : Error<
Expand Down
8 changes: 7 additions & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -6550,6 +6550,10 @@ def flang_deprecated_no_hlfir : Flag<["-"], "flang-deprecated-no-hlfir">,
Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
HelpText<"Do not use HLFIR lowering (deprecated)">;

def flang_experimental_integer_overflow : Flag<["-"], "flang-experimental-integer-overflow">,
Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
HelpText<"Add nsw flag to internal operations such as do-variable increment (experimental)">;

//===----------------------------------------------------------------------===//
// FLangOption + CoreOption + NoXarchOption
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -6647,7 +6651,9 @@ def fdebug_unparse : Flag<["-"], "fdebug-unparse">, Group<Action_Group>,
DocBrief<[{Run the parser and the semantic checks. Then unparse the
parse-tree and output the generated Fortran source file.}]>;
def fdebug_unparse_with_symbols : Flag<["-"], "fdebug-unparse-with-symbols">, Group<Action_Group>,
HelpText<"Unparse and stop.">;
HelpText<"Unparse with symbols and stop.">;
def fdebug_unparse_with_modules : Flag<["-"], "fdebug-unparse-with-modules">, Group<Action_Group>,
HelpText<"Unparse with dependent modules and stop.">;
def fdebug_dump_symbols : Flag<["-"], "fdebug-dump-symbols">, Group<Action_Group>,
HelpText<"Dump symbols after the semantic analysis">;
def fdebug_dump_parse_tree : Flag<["-"], "fdebug-dump-parse-tree">, Group<Action_Group>,
Expand Down
88 changes: 88 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2498,6 +2498,84 @@ bool ByteCodeExprGen<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) {
return this->emitGetLocal(PT_Ptr, Offset, E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitConvertVectorExpr(
const ConvertVectorExpr *E) {
assert(Initializing);
const auto *VT = E->getType()->castAs<VectorType>();
QualType ElemType = VT->getElementType();
PrimType ElemT = classifyPrim(ElemType);
const Expr *Src = E->getSrcExpr();
PrimType SrcElemT =
classifyPrim(Src->getType()->castAs<VectorType>()->getElementType());

unsigned SrcOffset = this->allocateLocalPrimitive(Src, PT_Ptr, true, false);
if (!this->visit(Src))
return false;
if (!this->emitSetLocal(PT_Ptr, SrcOffset, E))
return false;

for (unsigned I = 0; I != VT->getNumElements(); ++I) {
if (!this->emitGetLocal(PT_Ptr, SrcOffset, E))
return false;
if (!this->emitArrayElemPop(SrcElemT, I, E))
return false;
if (SrcElemT != ElemT) {
if (!this->emitPrimCast(SrcElemT, ElemT, ElemType, E))
return false;
}
if (!this->emitInitElem(ElemT, I, E))
return false;
}

return true;
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitShuffleVectorExpr(
const ShuffleVectorExpr *E) {
assert(Initializing);
assert(E->getNumSubExprs() > 2);

const Expr *Vecs[] = {E->getExpr(0), E->getExpr(1)};
assert(Vecs[0]->getType() == Vecs[1]->getType());

const VectorType *VT = Vecs[0]->getType()->castAs<VectorType>();
PrimType ElemT = classifyPrim(VT->getElementType());
unsigned NumInputElems = VT->getNumElements();
unsigned NumOutputElems = E->getNumSubExprs() - 2;
assert(NumOutputElems > 0);

// Save both input vectors to a local variable.
unsigned VectorOffsets[2];
for (unsigned I = 0; I != 2; ++I) {
VectorOffsets[I] = this->allocateLocalPrimitive(
Vecs[I], PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false);
if (!this->visit(Vecs[I]))
return false;
if (!this->emitSetLocal(PT_Ptr, VectorOffsets[I], E))
return false;
}
for (unsigned I = 0; I != NumOutputElems; ++I) {
APSInt ShuffleIndex = E->getShuffleMaskIdx(Ctx.getASTContext(), I);
if (ShuffleIndex == -1)
return this->emitInvalid(E); // FIXME: Better diagnostic.

assert(ShuffleIndex < (NumInputElems * 2));
if (!this->emitGetLocal(PT_Ptr,
VectorOffsets[ShuffleIndex >= NumInputElems], E))
return false;
unsigned InputVectorIndex = ShuffleIndex.getZExtValue() % NumInputElems;
if (!this->emitArrayElemPop(ElemT, InputVectorIndex, E))
return false;

if (!this->emitInitElem(ElemT, I, E))
return false;
}

return true;
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true,
/*NewInitializing=*/false);
Expand Down Expand Up @@ -3685,12 +3763,22 @@ bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
return this->emitCastFP(ToSem, getRoundingMode(E), E);
}

if (ToT == PT_IntAP)
return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(ToQT), E);
if (ToT == PT_IntAPS)
return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(ToQT), E);

// Float to integral.
if (isIntegralType(ToT) || ToT == PT_Bool)
return this->emitCastFloatingIntegral(ToT, E);
}

if (isIntegralType(FromT) || FromT == PT_Bool) {
if (ToT == PT_IntAP)
return this->emitCastAP(FromT, Ctx.getBitWidth(ToQT), E);
if (ToT == PT_IntAPS)
return this->emitCastAPS(FromT, Ctx.getBitWidth(ToQT), E);

// Integral to integral.
if (isIntegralType(ToT) || ToT == PT_Bool)
return FromT != ToT ? this->emitCast(FromT, ToT, E) : true;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitPackIndexingExpr(const PackIndexingExpr *E);
bool VisitRecoveryExpr(const RecoveryExpr *E);
bool VisitAddrLabelExpr(const AddrLabelExpr *E);
bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ template <bool Signed> class IntegralAP final {

IntegralAP(APInt V) : V(V) {}
/// Arbitrary value for uninitialized variables.
IntegralAP() : IntegralAP(-1, 1024) {}
IntegralAP() : IntegralAP(-1, 3) {}

IntegralAP operator-() const { return IntegralAP(-V); }
IntegralAP operator-(const IntegralAP &Other) const {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/VTTBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {

if (!IsPrimaryVTT) {
// Remember the sub-VTT index.
SubVTTIndicies[Base] = VTTComponents.size();
SubVTTIndices[Base] = VTTComponents.size();
}

uint64_t VTableIndex = VTTVTables.size();
Expand Down
107 changes: 57 additions & 50 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <memory>
#include <utility>

#define DEBUG_TYPE "dataflow"
Expand Down Expand Up @@ -290,15 +295,14 @@ widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
namespace {

// Visitor that builds a map from record prvalues to result objects.
// This traverses the body of the function to be analyzed; for each result
// object that it encounters, it propagates the storage location of the result
// object to all record prvalues that can initialize it.
// For each result object that it encounters, it propagates the storage location
// of the result object to all record prvalues that can initialize it.
class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
public:
// `ResultObjectMap` will be filled with a map from record prvalues to result
// object. If the function being analyzed returns a record by value,
// `LocForRecordReturnVal` is the location to which this record should be
// written; otherwise, it is null.
// object. If this visitor will traverse a function that returns a record by
// value, `LocForRecordReturnVal` is the location to which this record should
// be written; otherwise, it is null.
explicit ResultObjectVisitor(
llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
RecordStorageLocation *LocForRecordReturnVal,
Expand Down Expand Up @@ -514,39 +518,31 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {

} // namespace

Environment::Environment(DataflowAnalysisContext &DACtx)
: DACtx(&DACtx),
FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}

Environment::Environment(DataflowAnalysisContext &DACtx,
const DeclContext &DeclCtx)
: Environment(DACtx) {
CallStack.push_back(&DeclCtx);
}

void Environment::initialize() {
const DeclContext *DeclCtx = getDeclCtx();
if (DeclCtx == nullptr)
if (InitialTargetStmt == nullptr)
return;

const auto *FuncDecl = dyn_cast<FunctionDecl>(DeclCtx);
if (FuncDecl == nullptr)
if (InitialTargetFunc == nullptr) {
initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt));
ResultObjectMap =
std::make_shared<PrValueToResultObject>(buildResultObjectMap(
DACtx, InitialTargetStmt, getThisPointeeStorageLocation(),
/*LocForRecordReturnValue=*/nullptr));
return;
}

assert(FuncDecl->doesThisDeclarationHaveABody());

initFieldsGlobalsAndFuncs(FuncDecl);
initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc));

for (const auto *ParamDecl : FuncDecl->parameters()) {
for (const auto *ParamDecl : InitialTargetFunc->parameters()) {
assert(ParamDecl != nullptr);
setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));
}

if (FuncDecl->getReturnType()->isRecordType())
if (InitialTargetFunc->getReturnType()->isRecordType())
LocForRecordReturnVal = &cast<RecordStorageLocation>(
createStorageLocation(FuncDecl->getReturnType()));
createStorageLocation(InitialTargetFunc->getReturnType()));

if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(DeclCtx)) {
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
auto *Parent = MethodDecl->getParent();
assert(Parent != nullptr);

Expand All @@ -558,7 +554,7 @@ void Environment::initialize() {
setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
} else if (Capture.capturesThis()) {
const auto *SurroundingMethodDecl =
cast<CXXMethodDecl>(DeclCtx->getNonClosureAncestor());
cast<CXXMethodDecl>(InitialTargetFunc->getNonClosureAncestor());
QualType ThisPointeeType =
SurroundingMethodDecl->getFunctionObjectParameterType();
setThisPointeeStorageLocation(
Expand All @@ -580,18 +576,16 @@ void Environment::initialize() {

// We do this below the handling of `CXXMethodDecl` above so that we can
// be sure that the storage location for `this` has been set.
ResultObjectMap = std::make_shared<PrValueToResultObject>(
buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(),
LocForRecordReturnVal));
ResultObjectMap =
std::make_shared<PrValueToResultObject>(buildResultObjectMap(
DACtx, InitialTargetFunc, getThisPointeeStorageLocation(),
LocForRecordReturnVal));
}

// FIXME: Add support for resetting globals after function calls to enable
// the implementation of sound analyses.
void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
assert(FuncDecl->doesThisDeclarationHaveABody());

ReferencedDecls Referenced = getReferencedDecls(*FuncDecl);
// FIXME: Add support for resetting globals after function calls to enable the
// implementation of sound analyses.

void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {
// These have to be added before the lines that follow to ensure that
// `create*` work correctly for structs.
DACtx->addModeledFields(Referenced.Fields);
Expand All @@ -602,9 +596,9 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {

// We don't run transfer functions on the initializers of global variables,
// so they won't be associated with a value or storage location. We
// therefore intentionally don't pass an initializer to `createObject()`;
// in particular, this ensures that `createObject()` will initialize the
// fields of record-type variables with values.
// therefore intentionally don't pass an initializer to `createObject()`; in
// particular, this ensures that `createObject()` will initialize the fields
// of record-type variables with values.
setStorageLocation(*D, createObject(*D, nullptr));
}

Expand All @@ -623,8 +617,8 @@ Environment Environment::fork() const {
}

bool Environment::canDescend(unsigned MaxDepth,
const DeclContext *Callee) const {
return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
const FunctionDecl *Callee) const {
return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
}

Environment Environment::pushCall(const CallExpr *Call) const {
Expand Down Expand Up @@ -671,7 +665,7 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl,

CallStack.push_back(FuncDecl);

initFieldsGlobalsAndFuncs(FuncDecl);
initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl));

const auto *ParamIt = FuncDecl->param_begin();

Expand Down Expand Up @@ -755,6 +749,8 @@ LatticeEffect Environment::widen(const Environment &PrevEnv,
assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
assert(CallStack == PrevEnv.CallStack);
assert(ResultObjectMap == PrevEnv.ResultObjectMap);
assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);

auto Effect = LatticeEffect::Unchanged;

Expand Down Expand Up @@ -790,21 +786,22 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
assert(EnvA.CallStack == EnvB.CallStack);
assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);

Environment JoinedEnv(*EnvA.DACtx);

JoinedEnv.CallStack = EnvA.CallStack;
JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;

if (EnvA.CallStack.empty()) {
const FunctionDecl *Func = EnvA.getCurrentFunc();
if (!Func) {
JoinedEnv.ReturnVal = nullptr;
} else {
// FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
// cast.
auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
assert(Func != nullptr);
JoinedEnv.ReturnVal =
joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
EnvB, JoinedEnv, Model);
Expand Down Expand Up @@ -1229,16 +1226,26 @@ Environment::PrValueToResultObject Environment::buildResultObjectMap(
RecordStorageLocation *LocForRecordReturnVal) {
assert(FuncDecl->doesThisDeclarationHaveABody());

PrValueToResultObject Map;
PrValueToResultObject Map = buildResultObjectMap(
DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);

ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
Visitor.TraverseConstructorInits(Ctor, ThisPointeeLoc);
Visitor.TraverseStmt(FuncDecl->getBody());

return Map;
}

Environment::PrValueToResultObject Environment::buildResultObjectMap(
DataflowAnalysisContext *DACtx, Stmt *S,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal) {
PrValueToResultObject Map;
ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
Visitor.TraverseStmt(S);
return Map;
}

RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
const Environment &Env) {
Expr *ImplicitObject = MCE.getImplicitObjectArgument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ runTypeErasedDataflowAnalysis(
PrettyStackTraceAnalysis CrashInfo(ACFG, "runTypeErasedDataflowAnalysis");

std::optional<Environment> MaybeStartingEnv;
if (InitEnv.callStackSize() == 1) {
if (InitEnv.callStackSize() == 0) {
MaybeStartingEnv = InitEnv.fork();
MaybeStartingEnv->initialize();
}
Expand Down
11 changes: 6 additions & 5 deletions clang/lib/CodeGen/CGCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,11 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co

llvm::Function *AwaitSuspendIntrinsic = CGF.CGM.getIntrinsic(AwaitSuspendIID);

const auto AwaitSuspendCanThrow = StmtCanThrow(S.getSuspendExpr());
// SuspendHandle might throw since it also resumes the returned handle.
const bool AwaitSuspendCanThrow =
SuspendReturnType ==
CoroutineSuspendExpr::SuspendReturnType::SuspendHandle ||
StmtCanThrow(S.getSuspendExpr());

llvm::CallBase *SuspendRet = nullptr;
// FIXME: add call attributes?
Expand Down Expand Up @@ -307,10 +311,7 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
break;
}
case CoroutineSuspendExpr::SuspendReturnType::SuspendHandle: {
assert(SuspendRet->getType()->isPointerTy());

auto ResumeIntrinsic = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_resume);
Builder.CreateCall(ResumeIntrinsic, SuspendRet);
assert(SuspendRet->getType()->isVoidTy());
break;
}
}
Expand Down
37 changes: 28 additions & 9 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6830,7 +6830,8 @@ class MappableExprsHandler {
const ValueDecl *Mapper = nullptr, bool ForDeviceAddr = false,
const ValueDecl *BaseDecl = nullptr, const Expr *MapExpr = nullptr,
ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
OverlappedElements = std::nullopt) const {
OverlappedElements = std::nullopt,
bool AreBothBasePtrAndPteeMapped = false) const {
// The following summarizes what has to be generated for each map and the
// types below. The generated information is expressed in this order:
// base pointer, section pointer, size, flags
Expand Down Expand Up @@ -7006,6 +7007,10 @@ class MappableExprsHandler {
// &(ps->p), &(ps->p[0]), 33*sizeof(double), MEMBER_OF(4) | PTR_AND_OBJ | TO
// (*) the struct this entry pertains to is the 4th element in the list
// of arguments, hence MEMBER_OF(4)
//
// map(p, p[:100])
// ===> map(p[:100])
// &p, &p[0], 100*sizeof(float), TARGET_PARAM | PTR_AND_OBJ | TO | FROM

// Track if the map information being generated is the first for a capture.
bool IsCaptureFirstInfo = IsFirstComponentList;
Expand All @@ -7029,6 +7034,8 @@ class MappableExprsHandler {
const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
const auto *OAShE = dyn_cast<OMPArrayShapingExpr>(AssocExpr);

if (AreBothBasePtrAndPteeMapped && std::next(I) == CE)
return;
if (isa<MemberExpr>(AssocExpr)) {
// The base is the 'this' pointer. The content of the pointer is going
// to be the base of the field being mapped.
Expand Down Expand Up @@ -7071,8 +7078,9 @@ class MappableExprsHandler {
// can be associated with the combined storage if shared memory mode is
// active or the base declaration is not global variable.
const auto *VD = dyn_cast<VarDecl>(I->getAssociatedDeclaration());
if (CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
!VD || VD->hasLocalStorage())
if (!AreBothBasePtrAndPteeMapped &&
(CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
!VD || VD->hasLocalStorage()))
BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
else
FirstPointerInComplexData = true;
Expand Down Expand Up @@ -7394,11 +7402,13 @@ class MappableExprsHandler {
// same expression except for the first one. We also need to signal
// this map is the first one that relates with the current capture
// (there is a set of entries for each capture).
OpenMPOffloadMappingFlags Flags = getMapTypeBits(
MapType, MapModifiers, MotionModifiers, IsImplicit,
!IsExpressionFirstInfo || RequiresReference ||
FirstPointerInComplexData || IsMemberReference,
IsCaptureFirstInfo && !RequiresReference, IsNonContiguous);
OpenMPOffloadMappingFlags Flags =
getMapTypeBits(MapType, MapModifiers, MotionModifiers, IsImplicit,
!IsExpressionFirstInfo || RequiresReference ||
FirstPointerInComplexData || IsMemberReference,
AreBothBasePtrAndPteeMapped ||
(IsCaptureFirstInfo && !RequiresReference),
IsNonContiguous);

if (!IsExpressionFirstInfo || IsMemberReference) {
// If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
Expand Down Expand Up @@ -8492,6 +8502,8 @@ class MappableExprsHandler {
assert(CurDir.is<const OMPExecutableDirective *>() &&
"Expect a executable directive");
const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
bool HasMapBasePtr = false;
bool HasMapArraySec = false;
for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
const auto *EI = C->getVarRefs().begin();
for (const auto L : C->decl_component_lists(VD)) {
Expand All @@ -8503,6 +8515,11 @@ class MappableExprsHandler {
assert(VDecl == VD && "We got information for the wrong declaration??");
assert(!Components.empty() &&
"Not expecting declaration with no component lists.");
if (VD && E && VD->getType()->isAnyPointerType() && isa<DeclRefExpr>(E))
HasMapBasePtr = true;
if (VD && E && VD->getType()->isAnyPointerType() &&
(isa<ArraySectionExpr>(E) || isa<ArraySubscriptExpr>(E)))
HasMapArraySec = true;
DeclComponentLists.emplace_back(Components, C->getMapType(),
C->getMapTypeModifiers(),
C->isImplicit(), Mapper, E);
Expand Down Expand Up @@ -8685,7 +8702,9 @@ class MappableExprsHandler {
MapType, MapModifiers, std::nullopt, Components, CombinedInfo,
StructBaseCombinedInfo, PartialStruct, IsFirstComponentList,
IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper,
/*ForDeviceAddr=*/false, VD, VarRef);
/*ForDeviceAddr=*/false, VD, VarRef,
/*OverlappedElements*/ std::nullopt,
HasMapBasePtr && HasMapArraySec);
IsFirstComponentList = false;
}
}
Expand Down
17 changes: 9 additions & 8 deletions clang/lib/CodeGen/CGVTT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,24 @@ uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
BaseSubobject Base) {
BaseSubobjectPairTy ClassSubobjectPair(RD, Base);

SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair);
if (I != SubVTTIndicies.end())
SubVTTIndicesMapTy::iterator I = SubVTTIndices.find(ClassSubobjectPair);
if (I != SubVTTIndices.end())
return I->second;

VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);

for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
Builder.getSubVTTIndicies().begin(),
E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator
I = Builder.getSubVTTIndices().begin(),
E = Builder.getSubVTTIndices().end();
I != E; ++I) {
// Insert all indices.
BaseSubobjectPairTy ClassSubobjectPair(RD, I->first);

SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second));
SubVTTIndices.insert(std::make_pair(ClassSubobjectPair, I->second));
}

I = SubVTTIndicies.find(ClassSubobjectPair);
assert(I != SubVTTIndicies.end() && "Did not find index!");
I = SubVTTIndices.find(ClassSubobjectPair);
assert(I != SubVTTIndices.end() && "Did not find index!");

return I->second;
}
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/CodeGen/CGVTables.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class CodeGenVTables {
typedef VTableLayout::AddressPointsMapTy VTableAddressPointsMapTy;

typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy;
typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy;
typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndicesMapTy;

/// SubVTTIndicies - Contains indices into the various sub-VTTs.
SubVTTIndiciesMapTy SubVTTIndicies;
/// SubVTTIndices - Contains indices into the various sub-VTTs.
SubVTTIndicesMapTy SubVTTIndices;

typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t>
SecondaryVirtualPointerIndicesMapTy;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,10 @@ struct CounterCoverageMappingBuilder
terminateRegion(S);
}

void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *E) {
Visit(E->getOperand());
}

void VisitCXXThrowExpr(const CXXThrowExpr *E) {
extendRegion(E);
if (E->getSubExpr())
Expand Down Expand Up @@ -2173,6 +2177,10 @@ struct CounterCoverageMappingBuilder
// propagate counts into them.
}

void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *AILE) {
Visit(AILE->getCommonExpr()->getSourceExpr());
}

void VisitPseudoObjectExpr(const PseudoObjectExpr *POE) {
// Just visit syntatic expression as this is what users actually write.
VisitStmt(POE->getSyntacticForm());
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/Targets/Sparc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,11 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {

CoerceBuilder CB(getVMContext(), getDataLayout());
CB.addStruct(0, StrTy);
CB.pad(llvm::alignTo(CB.DL.getTypeSizeInBits(StrTy), 64));
// All structs, even empty ones, should take up a register argument slot,
// so pin the minimum struct size to one bit.
CB.pad(llvm::alignTo(
std::max(CB.DL.getTypeSizeInBits(StrTy).getKnownMinValue(), uint64_t(1)),
64));

// Try to use the original type for coercion.
llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7253,10 +7253,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A =
Args.getLastArg(options::OPT_frelaxed_template_template_args,
options::OPT_fno_relaxed_template_template_args)) {
D.Diag(diag::warn_drv_deprecated_arg)
<< A->getAsString(Args) << /*hasReplacement=*/false;
if (A->getOption().matches(options::OPT_fno_relaxed_template_template_args))
if (A->getOption().matches(
options::OPT_fno_relaxed_template_template_args)) {
D.Diag(diag::warn_drv_deprecated_arg_no_relaxed_template_template_args);
CmdArgs.push_back("-fno-relaxed-template-template-args");
} else {
D.Diag(diag::warn_drv_deprecated_arg)
<< A->getAsString(Args) << /*hasReplacement=*/false;
}
}

// -fsized-deallocation is off by default, as it is an ABI-breaking change for
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ void Flang::addCodegenOptions(const ArgList &Args,

Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir,
options::OPT_flang_deprecated_no_hlfir,
options::OPT_flang_experimental_integer_overflow,
options::OPT_fno_ppc_native_vec_elem_order,
options::OPT_fppc_native_vec_elem_order});
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Driver/ToolChains/OpenBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,8 @@ std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component,
if (Component == "builtins") {
SmallString<128> Path(getDriver().SysRoot);
llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
return std::string(Path);
if (getVFS().exists(Path))
return std::string(Path);
}
SmallString<128> P(getDriver().ResourceDir);
std::string CRTBasename =
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line,
OS << Prefix;
NewLine = false;
}
OS << I->Tok->Tok.getName() << "[" << "T=" << (unsigned)I->Tok->getType()
OS << I->Tok->Tok.getName() << "["
<< "T=" << (unsigned)I->Tok->getType()
<< ", OC=" << I->Tok->OriginalColumn << ", \"" << I->Tok->TokenText
<< "\"] ";
for (SmallVectorImpl<UnwrappedLine>::const_iterator
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
}
}

Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);

// Tell the actions module that we have entered a function definition with the
// specified Declarator for the function.
SkipBodyInfo SkipBody;
Expand Down Expand Up @@ -1497,8 +1499,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
}

Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);

if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res, BodyScope);

Expand Down
382 changes: 190 additions & 192 deletions clang/lib/Sema/SemaExpr.cpp

Large diffs are not rendered by default.

36 changes: 28 additions & 8 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5453,7 +5453,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
// is used.
if (DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced,
TDF_None,
TDF_AllowCompatibleFunctionType,
/*PartialOrdering=*/true) != TemplateDeductionResult::Success)
return false;
break;
Expand Down Expand Up @@ -5485,20 +5485,40 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
switch (TPOC) {
case TPOC_Call:
for (unsigned I = 0, N = Args2.size(); I != N; ++I)
::MarkUsedTemplateParameters(S.Context, Args2[I], false,
TemplateParams->getDepth(),
UsedParameters);
::MarkUsedTemplateParameters(S.Context, Args2[I], /*OnlyDeduced=*/false,
TemplateParams->getDepth(), UsedParameters);
break;

case TPOC_Conversion:
::MarkUsedTemplateParameters(S.Context, Proto2->getReturnType(), false,
::MarkUsedTemplateParameters(S.Context, Proto2->getReturnType(),
/*OnlyDeduced=*/false,
TemplateParams->getDepth(), UsedParameters);
break;

case TPOC_Other:
::MarkUsedTemplateParameters(S.Context, FD2->getType(), false,
TemplateParams->getDepth(),
UsedParameters);
// We do not deduce template arguments from the exception specification
// when determining the primary template of a function template
// specialization or when taking the address of a function template.
// Therefore, we do not mark template parameters in the exception
// specification as used during partial ordering to prevent the following
// from being ambiguous:
//
// template<typename T, typename U>
// void f(U) noexcept(noexcept(T())); // #1
//
// template<typename T>
// void f(T*) noexcept; // #2
//
// template<>
// void f<int>(int*) noexcept; // explicit specialization of #2
//
// Although there is no corresponding wording in the standard, this seems
// to be the intended behavior given the definition of
// 'deduction substitution loci' in [temp.deduct].
::MarkUsedTemplateParameters(
S.Context,
S.Context.getFunctionTypeWithExceptionSpec(FD2->getType(), EST_None),
/*OnlyDeduced=*/false, TemplateParams->getDepth(), UsedParameters);
break;
}

Expand Down
17 changes: 7 additions & 10 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -16236,10 +16236,11 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, First);
}
} else {
if (!First->getType()->isOverloadableType() &&
if (!First->isTypeDependent() && !Second->isTypeDependent() &&
!First->getType()->isOverloadableType() &&
!Second->getType()->isOverloadableType()) {
// Neither of the arguments is an overloadable type, so try to
// create a built-in binary operation.
// Neither of the arguments is type-dependent or has an overloadable
// type, so try to create a built-in binary operation.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
ExprResult Result
= SemaRef.CreateBuiltinBinOp(OpLoc, Opc, First, Second);
Expand All @@ -16250,12 +16251,8 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
}
}

// Add any functions found via argument-dependent lookup.
Expr *Args[2] = { First, Second };
unsigned NumArgs = 1 + (Second != nullptr);

// Create the overloaded operator invocation for unary operators.
if (NumArgs == 1 || isPostIncDec) {
if (!Second || isPostIncDec) {
UnaryOperatorKind Opc
= UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First,
Expand All @@ -16264,8 +16261,8 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(

// Create the overloaded operator invocation for binary operators.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
ExprResult Result = SemaRef.CreateOverloadedBinOp(
OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL);
ExprResult Result = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions,
First, Second, RequiresADL);
if (Result.isInvalid())
return ExprError();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,8 @@ class RAIIMutexDescriptor {
// this function is called instead of early returning it. To avoid this, a
// bool variable (IdentifierInfoInitialized) is used and the function will
// be run only once.
Guard = &Call.getCalleeAnalysisDeclContext()->getASTContext().Idents.get(
GuardName);
IdentifierInfoInitialized = true;
const auto &ASTCtx = Call.getState()->getStateManager().getContext();
Guard = &ASTCtx.Idents.get(GuardName);
}
}

Expand Down
10 changes: 9 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,19 @@ bool TrivialFunctionAnalysis::isTrivialImpl(
if (!IsNew)
return It->second;

TrivialFunctionAnalysisVisitor V(Cache);

if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
for (auto *CtorInit : CtorDecl->inits()) {
if (!V.Visit(CtorInit->getInit()))
return false;
}
}

const Stmt *Body = D->getBody();
if (!Body)
return false;

TrivialFunctionAnalysisVisitor V(Cache);
bool Result = V.Visit(Body);
if (Result)
Cache[D] = true;
Expand Down
267 changes: 267 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions clang/test/AST/ast-dump-expr-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4261,9 +4261,9 @@ void TestNonADLCall3() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "<dependent type>"
// CHECK-NEXT: "qualType": "V"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "prvalue",
// CHECK-NEXT: "valueCategory": "lvalue",
// CHECK-NEXT: "isPostfix": false,
// CHECK-NEXT: "opcode": "*",
// CHECK-NEXT: "canOverflow": false,
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/ast-dump-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ void PrimaryExpressions(Ts... a) {
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:8> col:8 implicit 'V'
// CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} <col:8> 'NULL TYPE'
// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> '<dependent type>' prefix '*' cannot overflow
// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> 'V' lvalue prefix '*' cannot overflow
// CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' this
}
};
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/ast-dump-lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ template <typename... Ts> void test(Ts... a) {
// CHECK-NEXT: | | | `-CompoundStmt {{.*}} <col:15, col:16>
// CHECK-NEXT: | | `-FieldDecl {{.*}} <col:8> col:8{{( imported)?}} implicit 'V'
// CHECK-NEXT: | |-ParenListExpr {{.*}} <col:8> 'NULL TYPE'
// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> '<dependent type>' prefix '*' cannot overflow
// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> 'V' lvalue prefix '*' cannot overflow
// CHECK-NEXT: | | `-CXXThisExpr {{.*}} <col:8> 'V *' this
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:15, col:16>
// CHECK-NEXT: |-DeclStmt {{.*}} <line:22:3, col:11>
Expand Down
21 changes: 21 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,13 @@ template<typename E> class OptionSet {
StorageType m_storage { 0 };
};

int atoi(const char* str);

class Number {
public:
Number(int v) : v(v) { }
Number(double);
Number(const char* str) : v(atoi(str)) { }
Number operator+(const Number&);
Number& operator++() { ++v; return *this; }
Number operator++(int) { Number returnValue(v); ++v; return returnValue; }
Expand All @@ -173,9 +176,16 @@ class Number {
int v;
};

class DerivedNumber : public Number {
public:
DerivedNumber(char c) : Number(c - '0') { }
DerivedNumber(const char* str) : Number(atoi(str)) { }
};

class ComplexNumber {
public:
ComplexNumber() : realPart(0), complexPart(0) { }
ComplexNumber(int real, const char* str) : realPart(real), complexPart(str) { }
ComplexNumber(const ComplexNumber&);
ComplexNumber& operator++() { realPart.someMethod(); return *this; }
ComplexNumber operator++(int);
Expand Down Expand Up @@ -311,6 +321,7 @@ class RefCounted {
return;
}
unsigned trivial60() { return ObjectWithNonTrivialDestructor { 5 }.value(); }
unsigned trivial61() { return DerivedNumber('7').value(); }

static RefCounted& singleton() {
static RefCounted s_RefCounted;
Expand Down Expand Up @@ -391,6 +402,9 @@ class RefCounted {
ComplexNumber nonTrivial18() { return +complex; }
ComplexNumber* nonTrivial19() { return new ComplexNumber(complex); }
unsigned nonTrivial20() { return ObjectWithMutatingDestructor { 7 }.value(); }
unsigned nonTrivial21() { return Number("123").value(); }
unsigned nonTrivial22() { return ComplexNumber(123, "456").real().value(); }
unsigned nonTrivial23() { return DerivedNumber("123").value(); }

static unsigned s_v;
unsigned v { 0 };
Expand Down Expand Up @@ -479,6 +493,7 @@ class UnrelatedClass {
getFieldTrivial().trivial58(); // no-warning
getFieldTrivial().trivial59(); // no-warning
getFieldTrivial().trivial60(); // no-warning
getFieldTrivial().trivial61(); // no-warning

RefCounted::singleton().trivial18(); // no-warning
RefCounted::singleton().someFunction(); // no-warning
Expand Down Expand Up @@ -525,6 +540,12 @@ class UnrelatedClass {
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial20();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial21();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial22();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial23();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
}
};

Expand Down
6 changes: 6 additions & 0 deletions clang/test/Analysis/block-in-critical-section.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.BlockInCriticalSection -verify %s
// expected-no-diagnostics

// This should not crash
int (*a)(void);
void b(void) { a(); }
8 changes: 7 additions & 1 deletion clang/test/C/C2x/n2900_n3011.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ void test(void) {
compat-warning {{use of an empty initializer is incompatible with C standards before C23}}
int vla[i] = {}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \
pedantic-warning {{use of an empty initializer is a C23 extension}}
// C99 6.5.2.5 Compound literals constraint 1: The type name shall specify an
// object type or an array of unknown size, but not a variable length array
// type.
int *compound_literal_vla = (int[i]){}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \
pedantic-warning {{use of an empty initializer is a C23 extension}}
pedantic-warning {{use of an empty initializer is a C23 extension}}\
compat-error {{compound literal cannot be of variable-length array type}} \
pedantic-error {{compound literal cannot be of variable-length array type}}\


struct T {
int i;
Expand Down
16 changes: 0 additions & 16 deletions clang/test/C/C2x/n2900_n3011_2.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,6 @@ void test_zero_size_vla() {
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false)
}

void test_compound_literal_vla() {
int num_elts = 12;
int *compound_literal_vla = (int[num_elts]){};
// CHECK: define {{.*}} void @test_compound_literal_vla
// CHECK-NEXT: entry:
// CHECK-NEXT: %[[NUM_ELTS_PTR:.+]] = alloca i32
// CHECK-NEXT: %[[COMP_LIT_VLA:.+]] = alloca ptr
// CHECK-NEXT: %[[COMP_LIT:.+]] = alloca i32
// CHECK-NEXT: store i32 12, ptr %[[NUM_ELTS_PTR]]
// CHECK-NEXT: %[[NUM_ELTS:.+]] = load i32, ptr %[[NUM_ELTS_PTR]]
// CHECK-NEXT: %[[NUM_ELTS_EXT:.+]] = zext i32 %[[NUM_ELTS]] to i64
// CHECK-NEXT: %[[BYTES_TO_COPY:.+]] = mul nuw i64 %[[NUM_ELTS_EXT]], 4
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[COMP_LIT]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false)
// CHECK-NEXT: store ptr %[[COMP_LIT]], ptr %[[COMP_LIT_VLA]]
}

void test_nested_structs() {
struct T t1 = { 1, {} };
struct T t2 = { 1, { 2, {} } };
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CXX/drs/cwg11xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@
// RUN: %clang_cc1 -std=c++17 %s -verify=expected -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++2a %s -verify=expected -fexceptions -fcxx-exceptions -pedantic-errors

namespace cwg1110 { // cwg1110: 3.1
#if __cplusplus >= 201103L
template <typename T>
T return_T();

struct A;

template <typename>
struct B;

decltype(return_T<A>())* a;
decltype(return_T<B<int>>())* b;
#endif
} // namespace cwg1110

namespace cwg1111 { // cwg1111: 3.2
namespace example1 {
template <typename> struct set; // #cwg1111-struct-set
Expand Down
31 changes: 31 additions & 0 deletions clang/test/CXX/drs/cwg13xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,18 @@ namespace cwg1330 { // cwg1330: 4 c++11

// cwg1334: sup 1719

namespace cwg1340 { // cwg1340: 2.9
struct A;
struct B;

void f(B* a, A B::* p) {
(*a).*p;
// expected-warning@-1 {{expression result unused}}
a->*p;
// expected-warning@-1 {{expression result unused}}
}
} // namespace cwg1340

namespace cwg1341 { // cwg1341: sup P0683R1
#if __cplusplus >= 202002L
int a;
Expand Down Expand Up @@ -451,6 +463,25 @@ static_assert(!__is_nothrow_constructible(D4, int), "");
#endif
} // namespace cwg1350

namespace cwg1352 { // cwg1352: 3.0
struct A {
#if __cplusplus >= 201103L
int a = sizeof(A);
#endif
void f(int b = sizeof(A));
};

template <typename T>
struct B {
#if __cplusplus >= 201103L
int a = sizeof(B) + sizeof(T);
#endif
void f(int b = sizeof(B) + sizeof(T));
};

template class B<int>;
} // namespace cwg1352

namespace cwg1358 { // cwg1358: 3.1
#if __cplusplus >= 201103L
struct Lit { constexpr operator int() const { return 0; } };
Expand Down
17 changes: 17 additions & 0 deletions clang/test/CXX/drs/cwg14xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ struct A {
};
}

namespace cwg1458 { // cwg1458: 3.1
#if __cplusplus >= 201103L
struct A;

void f() {
constexpr A* a = nullptr;
constexpr int p = &*a;
// expected-error@-1 {{cannot initialize a variable of type 'const int' with an rvalue of type 'A *'}}
constexpr A *p2 = &*a;
}

struct A {
int operator&();
};
#endif
} // namespace cwg1458

namespace cwg1460 { // cwg1460: 3.5
#if __cplusplus >= 201103L
namespace DRExample {
Expand Down
28 changes: 27 additions & 1 deletion clang/test/CXX/drs/cwg18xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ namespace cwg1814 { // cwg1814: yes
#endif
}

namespace cwg1815 { // cwg1815: yes
namespace cwg1815 { // cwg1815: 19
#if __cplusplus >= 201402L
struct A { int &&r = 0; };
A a = {};
Expand Down Expand Up @@ -303,6 +303,32 @@ namespace cwg1822 { // cwg1822: yes
#endif
}

namespace cwg1824 { // cwg1824: 2.7
template<typename T>
struct A {
T t;
};

struct S {
A<S> f() { return A<S>(); }
};
} // namespace cwg1824

namespace cwg1832 { // cwg1832: 3.0
enum E { // #cwg1832-E
a = static_cast<int>(static_cast<E>(0))
// expected-error@-1 {{'E' is an incomplete type}}
// expected-note@#cwg1832-E {{definition of 'cwg1832::E' is not complete until the closing '}'}}
};

#if __cplusplus >= 201103L
enum E2: decltype(static_cast<E2>(0), 0) {};
// expected-error@-1 {{unknown type name 'E2'}}
enum class E3: decltype(static_cast<E3>(0), 0) {};
// expected-error@-1 {{unknown type name 'E3'}}
#endif
} // namespace cwg1832

namespace cwg1837 { // cwg1837: 3.3
#if __cplusplus >= 201103L
template <typename T>
Expand Down
48 changes: 46 additions & 2 deletions clang/test/CXX/drs/cwg23xx.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++98 %s -verify=expected -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11-14,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,cxx11-14,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
Expand Down Expand Up @@ -47,6 +47,50 @@ void g() {
} // namespace cwg2303
#endif

namespace cwg2304 { // cwg2304: 2.8
template<typename T> void foo(T, int);
template<typename T> void foo(T&, ...);
struct Q; // #cwg2304-Q
void fn1(Q &data_vectors) {
foo(data_vectors, 0);
// expected-error@-1 {{argument type 'cwg2304::Q' is incomplete}}
// expected-note@#cwg2304-Q {{forward declaration of 'cwg2304::Q'}}
}
} // namespace cwg2304

namespace cwg2310 { // cwg2310: partial
#if __cplusplus >= 201103L
template<typename A, typename B>
struct check_derived_from {
static A a;
// FIXME: all 3 examples should be rejected in all language modes.
// FIXME: we should test this in 98 mode.
// FIXME: we accept this when MSVC triple is used
static constexpr B *p = &a;
#if !defined(_WIN32) || defined(__MINGW32__)
// cxx11-14-error@-2 {{cannot initialize a variable of type 'cwg2310::X *const' with an rvalue of type 'cwg2310::Z *'}}
// cxx11-14-note@#cwg2310-X {{in instantiation of template class 'cwg2310::check_derived_from<cwg2310::Z, cwg2310::X>' requested here}}
// cxx11-14-error@-4 {{cannot initialize a variable of type 'cwg2310::Y *const' with an rvalue of type 'cwg2310::Z *'}}
// cxx11-14-note@#cwg2310-Y {{in instantiation of template class 'cwg2310::check_derived_from<cwg2310::Z, cwg2310::Y>' requested here}}
#endif
};

struct W {};
struct X {};
struct Y {};
struct Z : W,
X, check_derived_from<Z, X>, // #cwg2310-X
check_derived_from<Z, Y>, Y // #cwg2310-Y
{
// FIXME: It was properly rejected before, but we're crashing since Clang 11 in C++11 and C++14 modes.
// See https://github.com/llvm/llvm-project/issues/59920
#if __cplusplus >= 201703L
check_derived_from<Z, W> cdf;
#endif
};
#endif
} // namespace cwg2310

// cwg2331: na
// cwg2335 is in cwg2335.cxx

Expand Down
6 changes: 6 additions & 0 deletions clang/test/CXX/drs/cwg24xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ void fallthrough(int n) {
#endif
}

namespace cwg2430 { // cwg2430: 2.7
struct S {
S f(S s) { return s; }
};
} // namespace cwg2430

namespace cwg2450 { // cwg2450: 18
#if __cplusplus >= 202302L
struct S {int a;};
Expand Down
15 changes: 12 additions & 3 deletions clang/test/CXX/drs/cwg25xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 -fexceptions -fcxx-exceptions -pedantic-errors

#if __cplusplus == 199711L
// expected-no-diagnostics
#endif
namespace std {
struct type_info{};
} // namespace std

// cwg2504 is in cwg2504.cpp

namespace cwg2512 { // cwg2512: 2.7
struct A; // #cwg2512-A
void foo(A* p) {
typeid(*p);
// expected-error@-1 {{'typeid' of incomplete type 'A'}}
// expected-note@#cwg2512-A {{forward declaration of 'cwg2512::A'}}
}
} // namespace cwg2512

namespace cwg2516 { // cwg2516: 3.0
// NB: reusing 1482 test
#if __cplusplus >= 201103L
Expand Down
23 changes: 23 additions & 0 deletions clang/test/CXX/drs/cwg2630.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: split-file --leading-lines %s %t
// RUN: %clang_cc1 -std=c++20 -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++20 -verify -fmodule-file=A=%t/module.pcm %t/main.cpp
// RUN: %clang_cc1 -std=c++23 -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++23 -verify -fmodule-file=A=%t/module.pcm %t/main.cpp
// RUN: %clang_cc1 -std=c++2c -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++2c -verify -fmodule-file=A=%t/module.pcm %t/main.cpp

//--- module.cppm
// expected-no-diagnostics
export module A;

namespace cwg2630 {
export class X {};
} // namespace cwg2630

//--- main.cpp
// expected-no-diagnostics
import A;

namespace cwg2630 { // cwg2630: 9
X x;
} // namespace cwg2630
2 changes: 2 additions & 0 deletions clang/test/CXX/drs/cwg26xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ void f() {
#endif
}

// cwg2630 is in cwg2630.cpp

namespace cwg2631 { // cwg2631: 16
#if __cplusplus >= 202002L
constexpr int g();
Expand Down
14 changes: 11 additions & 3 deletions clang/test/CXX/drs/cwg27xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -verify=expected,since-cxx23 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -verify=expected,since-cxx23,since-cxx26 %s

#if __cplusplus <= 202002L
// expected-no-diagnostics
#endif
namespace cwg2718 { // cwg2718: 2.7
struct B {};
struct D;

void f(B b) {
static_cast<D&>(b);
// expected-error@-1 {{non-const lvalue reference to type 'D' cannot bind to a value of unrelated type 'B'}}
}

struct D : B {};
} // namespace cwg2718

namespace cwg2759 { // cwg2759: 19
#if __cplusplus >= 201103L
Expand Down
28 changes: 24 additions & 4 deletions clang/test/CXX/drs/cwg28xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
// RUN: %clang_cc1 -std=c++23 -verify=expected,since-cxx20,since-cxx23 %s
// RUN: %clang_cc1 -std=c++2c -verify=expected,since-cxx20,since-cxx23,since-cxx26 %s

#if __cplusplus < 202002L
// expected-no-diagnostics
#endif

namespace cwg2819 { // cwg2819: 19 tentatively ready 2023-12-01
#if __cpp_constexpr >= 202306L
constexpr void* p = nullptr;
Expand Down Expand Up @@ -67,6 +63,30 @@ void B<int>::g() requires true;

} // namespace cwg2847

namespace cwg2857 { // cwg2857: no
struct A {};
template <typename>
struct D;
namespace N {
struct B {};
void adl_only(A*, D<int>*); // #cwg2857-adl_only
}

void f(A* a, D<int>* d) {
adl_only(a, d);
// expected-error@-1 {{use of undeclared identifier 'adl_only'; did you mean 'N::adl_only'?}}
// expected-note@#cwg2857-adl_only {{'N::adl_only' declared here}}
}

#if __cplusplus >= 201103L
template <typename>
struct D : N::B {
// FIXME: ADL shouldn't associate it's base B and N since D is not complete here
decltype(adl_only((A*) nullptr, (D*) nullptr)) f;
};
#endif
} // namespace cwg2857

namespace cwg2858 { // cwg2858: 19 tentatively ready 2024-04-05

#if __cplusplus > 202302L
Expand Down
7 changes: 7 additions & 0 deletions clang/test/CXX/drs/cwg9xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ namespace std {
};
}

namespace cwg930 { // cwg930: 2.7
#if __cplusplus >= 201103L
static_assert(alignof(int[]) == alignof(int), "");
static_assert(alignof(int[][2]) == alignof(int[2]), "");
#endif
} // namespace cwg930

namespace cwg948 { // cwg948: 3.7
#if __cplusplus >= 201103L
class A {
Expand Down
65 changes: 65 additions & 0 deletions clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// RUN: %clang_cc1 -Wno-unused -fsyntax-only %s -verify

struct A {
void operator*();
void operator+();
void operator-();
void operator!();
void operator~();
void operator&();
void operator++();
void operator--();
};

struct B { };

template<typename T, typename U>
void dependent(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) {
*t;
+t;
-t;
!t;
~t;
&t;
++t;
--t;

*pt;
+pt;
-pt; // expected-error {{invalid argument type 'T *' to unary expression}}
!pt;
~pt; // expected-error {{invalid argument type 'T *' to unary expression}}
&pt;
++pt;
--pt;

*mpt; // expected-error {{indirection requires pointer operand ('T U::*' invalid)}}
+mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}}
-mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}}
!mpt;
~mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}}
&mpt;
++mpt; // expected-error {{cannot increment value of type 'T U::*'}}
--mpt; // expected-error {{cannot decrement value of type 'T U::*'}}

*ft;
+ft;
-ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}}
!ft;
~ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}}
&ft;
++ft; // expected-error {{cannot increment value of type 'T ()'}}
--ft; // expected-error {{cannot decrement value of type 'T ()'}}

*at;
+at;
-at; // expected-error {{invalid argument type 'T *' to unary expression}}
!at;
~at; // expected-error {{invalid argument type 'T *' to unary expression}}
&at;
++at; // expected-error {{cannot increment value of type 'T[4]'}}
--at; // expected-error {{cannot decrement value of type 'T[4]'}}
}

// Make sure we only emit diagnostics once.
template void dependent(A t, A* pt, A B::* mpt, A(&ft)(), A(&at)[4]);
158 changes: 128 additions & 30 deletions clang/test/CXX/over/over.built/ast.cpp
Original file line number Diff line number Diff line change
@@ -1,41 +1,139 @@
// RUN: %clang_cc1 -std=c++17 -ast-dump %s -ast-dump-filter Test | FileCheck %s
// RUN: %clang_cc1 -std=c++17 -Wno-unused -ast-dump %s -ast-dump-filter Test | FileCheck %s

struct A{};
namespace Test {
template<typename T, typename U>
void Unary(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) {
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
*t;

template <typename T, typename U>
auto Test(T* pt, U* pu) {
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)*pt;
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '+' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
+t;

// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)(++pt);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '-' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
-t;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '+'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)(+pt);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '!' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
!t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '+'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
(void)(pt + 3);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '~' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
~t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)(pt - pt);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
&t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
(void)(pt - pu);
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
++t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '=='
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
(void)(pt == pu);
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '--' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
--t;

}
// CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
*pt;

// CHECK: UnaryOperator {{.*}} 'T *' prefix '+' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+pt;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
!pt;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
&pt;

// CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '++' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
++pt;

// CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '--' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
--pt;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <MemberPointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T U::*' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T U::*' lvalue ParmVar {{.*}} 'mpt' 'T U::*'
!mpt;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T U::*' lvalue ParmVar {{.*}} 'mpt' 'T U::*'
&mpt;

// CHECK: UnaryOperator {{.*}} 'T ()' lvalue prefix '*' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
*ft;

// CHECK: UnaryOperator {{.*}} 'T (*)()' prefix '+' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
+ft;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
!ft;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
&ft;

// CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
*at;

// CHECK: UnaryOperator {{.*}} 'T *' prefix '+' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
+at;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
!at;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
&at;
}

template<typename T, typename U>
void Binary(T* pt, U* pu) {
// CHECK: BinaryOperator {{.*}} '<dependent type>' '+'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
pt + 3;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
pt - pt;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
pt - pu;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '=='
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
pt == pu;
}
} // namespace Test
2 changes: 1 addition & 1 deletion clang/test/CXX/over/over.built/p10.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ void f(int i, float f, bool b, char c, int* pi, A* pa, T* pt) {

(void)-pi; // expected-error {{invalid argument type}}
(void)-pa; // expected-error {{invalid argument type}}
(void)-pt; // FIXME: we should be able to give an error here.
(void)-pt; // expected-error {{invalid argument type}}
}

2 changes: 1 addition & 1 deletion clang/test/CXX/over/over.built/p11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ void f(int i, float f, bool b, char c, int* pi, T* pt) {
(void)~b;
(void)~c;
(void)~pi; // expected-error {{invalid argument type}}
(void)~pt; // FIXME: we should be able to give an error here.
(void)~pt; // expected-error {{invalid argument type}}
}

173 changes: 173 additions & 0 deletions clang/test/CXX/over/over.oper/over.oper.general/p1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// RUN: %clang_cc1 -std=c++20 -verify -Wno-unused %s

template<typename T, typename U>
void operator->*(T, U);

template<typename T, typename U>
void operator+(T, U);

template<typename T, typename U>
void operator-(T, U);

template<typename T, typename U>
void operator*(T, U);

template<typename T, typename U>
void operator/(T, U);

template<typename T, typename U>
void operator%(T, U);

template<typename T, typename U>
void operator^(T, U);

template<typename T, typename U>
void operator&(T, U);

template<typename T, typename U>
void operator|(T, U);

template<typename T, typename U>
void operator+=(T, U);

template<typename T, typename U>
void operator-=(T, U);

template<typename T, typename U>
void operator*=(T, U);

template<typename T, typename U>
void operator/=(T, U);

template<typename T, typename U>
void operator%=(T, U);

template<typename T, typename U>
void operator^=(T, U);

template<typename T, typename U>
void operator&=(T, U);

template<typename T, typename U>
void operator|=(T, U);

template<typename T, typename U>
void operator==(T, U);

template<typename T, typename U>
void operator!=(T, U);

template<typename T, typename U>
void operator<(T, U);

template<typename T, typename U>
void operator>(T, U);

template<typename T, typename U>
void operator<=(T, U);

template<typename T, typename U>
void operator>=(T, U);

template<typename T, typename U>
void operator<=>(T, U);

template<typename T, typename U>
void operator&&(T, U);

template<typename T, typename U>
void operator||(T, U);

template<typename T, typename U>
void operator<<(T, U);

template<typename T, typename U>
void operator>>(T, U);

template<typename T, typename U>
void operator<<=(T, U);

template<typename T, typename U>
void operator>>=(T, U);

template<typename T, typename U>
void operator,(T, U);

template<typename T>
void operator*(T);

template<typename T>
void operator&(T);

template<typename T>
void operator+(T);

template<typename T>
void operator-(T);

template<typename T>
void operator!(T);

template<typename T>
void operator~(T);

template<typename T>
void operator++(T);

template<typename T>
void operator--(T);

template<typename T>
void operator++(T, int);

template<typename T>
void operator--(T, int);

template<typename T>
void f(int *x) {
[&](auto *y) {
*y;
&y;
+y;
-y; // expected-error {{invalid argument type 'auto *' to unary expression}}
!y;
~y; // expected-error {{invalid argument type 'auto *' to unary expression}}
++y;
--y;
y++;
y--;
y->*x;
y + x;
y - x;
y * x;
y / x;
y % x;
y ^ x;
y & x;
y | x;
y += x;
y -= x;
y *= x;
y /= x;
y %= x;
y ^= x;
y &= x;
y |= x;
y == x;
y != x;
y < x;
y > x;
y <= x;
y >= x;
y <=> x;
y && x;
y || x;
y << x;
y >> x;
y <<= x;
y >>= x;
y, x;
};
}

template void f<int>(int*);
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// expected-no-diagnostics

template<bool B>
struct A { };

constexpr A<false> a;
constexpr A<false> b;

constexpr int* x = nullptr;
constexpr short* y = nullptr;

namespace ExplicitArgs {
template<typename T, typename U>
constexpr int f(U) noexcept(noexcept(T())) {
return 0;
}

template<typename T>
constexpr int f(T*) noexcept {
return 1;
}

template<>
constexpr int f<int>(int*) noexcept {
return 2;
}

static_assert(f<int>(1) == 0);
static_assert(f<short>(y) == 1);
static_assert(f<int>(x) == 2);

template<typename T, typename U>
constexpr int g(U*) noexcept(noexcept(T())) {
return 3;
}

template<typename T>
constexpr int g(T) noexcept {
return 4;
}

template<>
constexpr int g<int>(int*) noexcept {
return 5;
}

static_assert(g<int>(y) == 3);
static_assert(g<short>(1) == 4);
static_assert(g<int>(x) == 5);
} // namespace ExplicitArgs

namespace DeducedArgs {
template<typename T, bool B>
constexpr int f(T, A<B>) noexcept(B) {
return 0;
}

template<typename T, bool B>
constexpr int f(T*, A<B>) noexcept(B && B) {
return 1;
}

template<>
constexpr int f(int*, A<false>) {
return 2;
}

static_assert(f<int*>(x, a) == 0);
static_assert(f<short>(y, a) == 1);
static_assert(f<int>(x, a) == 2);
} // namespace DeducedArgs
Loading