Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %check_clang_tidy %s altera-id-dependent-backward-branch %t -- -header-filter=.* "--" -cl-std=CL1.2 -c
// RUN: %check_clang_tidy %s altera-id-dependent-backward-branch %t -- -header-filter=.* "--" -cl-std=CLC++1.0 -c

void error() {
// ==== Conditional Expressions ====
Expand Down Expand Up @@ -80,3 +80,9 @@ void success() {
}
}
}

template<char... STOP>
void gh55408(char const input[], int pos) {
while (((input[pos] != STOP) && ...));
}

39 changes: 39 additions & 0 deletions clang/Maintainers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ Sema
| Sirraide
| aeternalmail\@gmail.com (email), Sirraide (GitHub), Ætérnal (Discord), Sirraide (Discourse)
| Mariya Podchishchaeva
| mariya.podchishchaeva\@intel.com (email), Fznamznon (GitHub), fznamznon (Discord), Fznamznon (Discourse)

Recovery AST
~~~~~~~~~~~~
| Haojian Wu
| hokein.wu\@gmail.com (email), hokein (Phabricator), hokein (GitHub), hokein (Discourse)

Experimental new constant interpreter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -132,6 +141,15 @@ Compiler options
| jan_svoboda\@apple.com (email), jansvoboda11 (Phabricator), jansvoboda11 (GitHub)

API Notes
~~~~~~~~~~~~~~~~
| Egor Zhdan
| e_zhdan\@apple.com (email), egorzhdan (GitHub), egor.zhdan (Discourse)
| Saleem Abdulrasool
| compnerd\@compnerd.org (email), compnerd (GitHub), compnerd (Discourse)

OpenBSD driver
~~~~~~~~~~~~~~
| Brad Smith
Expand All @@ -144,6 +162,12 @@ Driver parts not covered by someone else
| i\@maskray.me (email), MaskRay (Phabricator), MaskRay (GitHub)

Constant Expressions
~~~~~~~~~~~~~~~~~~~~
| Mariya Podchishchaeva
| mariya.podchishchaeva\@intel.com (email), Fznamznon (GitHub), fznamznon (Discord), Fznamznon (Discourse)

Tools
-----
These maintainers are responsible for user-facing tools under the Clang
Expand Down Expand Up @@ -295,6 +319,21 @@ SYCL conformance
| alexey.bader\@intel.com (email), bader (Phabricator), bader (GitHub)

HLSL conformance
~~~~~~~~~~~~~~~~
| Chris Bieneman
| chris.bieneman\@gmail.com (email), llvm-beanz (GitHub), beanz (Discord), beanz (Discourse)

Issue Triage
~~~~~~~~~~~~
| Shafik Yaghmour
| shafik.yaghmour\@intel.com (email), shafik (GitHub), shafik.yaghmour (Discord), shafik (Discourse)
| hstk30
| hanwei62\@huawei.com (email), hstk30-hw (GitHub), hstk30(Discord), hstk30 (Discourse)

Inactive Maintainers
====================
The following people have graciously spent time performing maintainership
Expand Down
2 changes: 1 addition & 1 deletion clang/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ If you're interested in more (including how to build Clang) it is best to read t

* Information on the LLVM project: http://llvm.org/

* If you have questions or comments about Clang, a great place to disucss them is on the Clang forums:    
* If you have questions or comments about Clang, a great place to discuss them is on the Clang forums:    

[Clang Frontend - LLVM Discussion Forums](https://discourse.llvm.org/c/clang/)

Expand Down
18 changes: 18 additions & 0 deletions clang/docs/APINotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,31 @@ declaration kind), all of which are optional:
to ``SWIFT_RETURNS_INDEPENDENT_VALUE``) or ``computed_property`` (equivalent to
``SWIFT_COMPUTED_PROPERTY``).

::

Tags:
- Name: OwnedStorage
SwiftImportAs: owned

:SwiftRetainOp, SwiftReleaseOp:

Controls the lifetime operations of a class which uses custom reference
counting. The class must be annotated as a reference type using
``SwiftImportAs: reference``. The values are either names of global functions,
each taking a single parameter of a pointer type, or ``immortal`` for a type
that is considered alive for the duration of the program.

::

Tags:
- Name: RefCountedStorage
SwiftImportAs: reference
SwiftReleaseOp: RCRelease
SwiftRetainOp: RCRetain
- Name: ImmortalSingleton
SwiftImportAs: reference
SwiftReleaseOp: immortal
SwiftRetainOp: immortal

:SwiftCopyable:

Expand Down
2 changes: 1 addition & 1 deletion clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2259,7 +2259,7 @@ the configuration (without a prefix: ``Auto``).
**BraceWrapping** (``BraceWrappingFlags``) :versionbadge:`clang-format 3.8` :ref:`<BraceWrapping>`
Control of individual brace wrapping cases.

If ``BreakBeforeBraces`` is set to ``BS_Custom``, use this to specify how
If ``BreakBeforeBraces`` is set to ``Custom``, use this to specify how
each individual brace case should be handled. Otherwise, this is ignored.

.. code-block:: yaml
Expand Down
6 changes: 3 additions & 3 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3979,9 +3979,9 @@ standard:
- ``4`` - to nearest, ties away from zero
The effect of passing some other value to ``__builtin_flt_rounds`` is
implementation-defined. ``__builtin_set_flt_rounds`` is currently only supported
to work on x86, x86_64, Arm and AArch64 targets. These builtins read and modify
the floating-point environment, which is not always allowed and may have unexpected
behavior. Please see the section on `Accessing the floating point environment <https://clang.llvm.org/docs/UsersManual.html#accessing-the-floating-point-environment>`_ for more information.
to work on x86, x86_64, powerpc, powerpc64, Arm and AArch64 targets. These builtins
read and modify the floating-point environment, which is not always allowed and may
have unexpected behavior. Please see the section on `Accessing the floating point environment <https://clang.llvm.org/docs/UsersManual.html#accessing-the-floating-point-environment>`_ for more information.

String builtins
---------------
Expand Down
14 changes: 11 additions & 3 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ Bug Fixes to C++ Support
- Fixed an assertion failure in debug mode, and potential crashes in release mode, when
diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
- Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326)
- Fixed a crash when mixture of designated and non-designated initializers in union. (#GH113855)
- Fixed an issue deducing non-type template arguments of reference type. (#GH73460)
- Fixed an issue in constraint evaluation, where type constraints on the lambda expression
containing outer unexpanded parameters were not correctly expanded. (#GH101754)
Expand All @@ -568,9 +569,6 @@ Bug Fixes to C++ Support
in certain friend declarations. (#GH93099)
- Clang now instantiates the correct lambda call operator when a lambda's class type is
merged across modules. (#GH110401)
- Clang now uses the correct set of template argument lists when comparing the constraints of
out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of
a class template. (#GH102320)
- Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460)
- Fixed an assertion failure when invoking recovery call expressions with explicit attributes
and undeclared templates. (#GH107047), (#GH49093)
Expand All @@ -590,6 +588,7 @@ Bug Fixes to C++ Support
- Clang now correctly ignores previous partial specializations of member templates explicitly specialized for
an implicitly instantiated class template specialization. (#GH51051)
- Fixed an assertion failure caused by invalid enum forward declarations. (#GH112208)
- Name independent data members were not correctly initialized from default member initializers. (#GH114069)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -715,6 +714,7 @@ CUDA Support
^^^^^^^^^^^^
- Clang now supports CUDA SDK up to 12.6
- Added support for sm_100
- Added support for `__grid_constant__` attribute.

AIX Support
^^^^^^^^^^^
Expand Down Expand Up @@ -871,6 +871,13 @@ Sanitizers
This new flag should allow those projects to enable integer sanitizers with
less noise.

- ``-fsanitize=signed-integer-overflow``, ``-fsanitize=unsigned-integer-overflow``,
``-fsanitize=implicit-signed-integer-truncation``, ``-fsanitize=implicit-unsigned-integer-truncation``,
``-fsanitize=enum`` now properly support the
"type" prefix within `Sanitizer Special Case Lists (SSCL)
<https://clang.llvm.org/docs/SanitizerSpecialCaseList.html>`_. See that link
for examples.

Python Binding Changes
----------------------
- Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.
Expand All @@ -879,6 +886,7 @@ OpenMP Support
--------------
- Added support for 'omp assume' directive.
- Added support for 'omp scope' directive.
- Added support for allocator-modifier in 'allocate' clause.

Improvements
^^^^^^^^^^^^
Expand Down
61 changes: 58 additions & 3 deletions clang/docs/SanitizerSpecialCaseList.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ file at compile-time.
Goal and usage
==============

Users of sanitizer tools, such as :doc:`AddressSanitizer`, :doc:`ThreadSanitizer`
or :doc:`MemorySanitizer` may want to disable or alter some checks for
certain source-level entities to:
Users of sanitizer tools, such as :doc:`AddressSanitizer`,
:doc:`HardwareAssistedAddressSanitizerDesign`, :doc:`ThreadSanitizer`,
:doc:`MemorySanitizer` or :doc:`UndefinedBehaviorSanitizer` may want to disable
or alter some checks for certain source-level entities to:

* speedup hot function, which is known to be correct;
* ignore a function that does some low-level magic (e.g. walks through the
Expand Down Expand Up @@ -48,6 +49,60 @@ Example
$ clang -fsanitize=address -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
# No error report here.
Usage with UndefinedBehaviorSanitizer
=====================================

``unsigned-integer-overflow``, ``signed-integer-overflow``,
``implicit-signed-integer-truncation``,
``implicit-unsigned-integer-truncation``, and ``enum`` sanitizers support the
ability to adjust instrumentation based on type.

By default, supported sanitizers will have their instrumentation disabled for
types specified within an ignorelist.

.. code-block:: bash
$ cat foo.c
void foo() {
int a = 2147483647; // INT_MAX
++a; // Normally, an overflow with -fsanitize=signed-integer-overflow
}
$ cat ignorelist.txt
[signed-integer-overflow]
type:int
$ clang -fsanitize=signed-integer-overflow -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
# no signed-integer-overflow error
For example, supplying the above ``ignorelist.txt`` to
``-fsanitize-ignorelist=ignorelist.txt`` disables overflow sanitizer
instrumentation for arithmetic operations containing values of type ``int``.

The ``=sanitize`` category is also supported. Any types assigned to the
``sanitize`` category will have their sanitizer instrumentation remain. If the
same type appears within or across ignorelists with different categories the
``sanitize`` category takes precedence -- regardless of order.

With this, one may disable instrumentation for some or all types and
specifically allow instrumentation for one or many types -- including types
created via ``typedef``. This is a way to achieve a sort of "allowlist" for
supported sanitizers.

.. code-block:: bash
$ cat ignorelist.txt
[implicit-signed-integer-truncation]
type:*
type:T=sanitize
$ cat foo.c
typedef char T;
typedef char U;
void foo(int toobig) {
T a = toobig; // instrumented
U b = toobig; // not instrumented
char c = toobig; // also not instrumented
}
Format
======

Expand Down
4 changes: 2 additions & 2 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3459,8 +3459,8 @@ Raw pointers and references to an object which supports CheckedPtr or CheckedRef
.. code-block:: cpp
struct CheckableObj {
void incrementPtrCount() {}
void decrementPtrCount() {}
void incrementCheckedPtrCount() {}
void decrementCheckedPtrCount() {}
};
struct Foo {
Expand Down
29 changes: 28 additions & 1 deletion clang/include/clang/APINotes/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,14 +425,24 @@ class ParamInfo : public VariableInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned NoEscape : 1;

/// Whether lifetimebound was specified.
LLVM_PREFERRED_TYPE(bool)
unsigned LifetimeboundSpecified : 1;

/// Whether the this parameter has the 'lifetimebound' attribute.
LLVM_PREFERRED_TYPE(bool)
unsigned Lifetimebound : 1;

/// A biased RetainCountConventionKind, where 0 means "unspecified".
///
/// Only relevant for out-parameters.
unsigned RawRetainCountConvention : 3;

public:
ParamInfo()
: NoEscapeSpecified(false), NoEscape(false), RawRetainCountConvention() {}
: NoEscapeSpecified(false), NoEscape(false),
LifetimeboundSpecified(false), Lifetimebound(false),
RawRetainCountConvention() {}

std::optional<bool> isNoEscape() const {
if (!NoEscapeSpecified)
Expand All @@ -444,6 +454,16 @@ class ParamInfo : public VariableInfo {
NoEscape = Value.value_or(false);
}

std::optional<bool> isLifetimebound() const {
if (!LifetimeboundSpecified)
return std::nullopt;
return Lifetimebound;
}
void setLifetimebound(std::optional<bool> Value) {
LifetimeboundSpecified = Value.has_value();
Lifetimebound = Value.value_or(false);
}

std::optional<RetainCountConventionKind> getRetainCountConvention() const {
if (!RawRetainCountConvention)
return std::nullopt;
Expand All @@ -463,6 +483,11 @@ class ParamInfo : public VariableInfo {
NoEscape = RHS.NoEscape;
}

if (!LifetimeboundSpecified && RHS.LifetimeboundSpecified) {
LifetimeboundSpecified = true;
Lifetimebound = RHS.Lifetimebound;
}

if (!RawRetainCountConvention)
RawRetainCountConvention = RHS.RawRetainCountConvention;

Expand All @@ -478,6 +503,8 @@ inline bool operator==(const ParamInfo &LHS, const ParamInfo &RHS) {
return static_cast<const VariableInfo &>(LHS) == RHS &&
LHS.NoEscapeSpecified == RHS.NoEscapeSpecified &&
LHS.NoEscape == RHS.NoEscape &&
LHS.LifetimeboundSpecified == RHS.LifetimeboundSpecified &&
LHS.Lifetimebound == RHS.Lifetimebound &&
LHS.RawRetainCountConvention == RHS.RawRetainCountConvention;
}

Expand Down
19 changes: 18 additions & 1 deletion clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RawCommentList.h"
#include "clang/AST/SYCLKernelInfo.h"
#include "clang/AST/TemplateName.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/PartialDiagnostic.h"
Expand Down Expand Up @@ -838,6 +839,9 @@ class ASTContext : public RefCountedBase<ASTContext> {

const NoSanitizeList &getNoSanitizeList() const { return *NoSanitizeL; }

bool isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
const QualType &Ty) const;

const XRayFunctionFilter &getXRayFilter() const {
return *XRayFilter;
}
Expand Down Expand Up @@ -1037,7 +1041,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
UsingShadowDecl *Pattern);

FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) const;

void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);

Expand Down Expand Up @@ -1236,6 +1240,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// in device compilation.
llvm::DenseSet<const FunctionDecl *> CUDAImplicitHostDeviceFunUsedByDevice;

/// Map of SYCL kernels indexed by the unique type used to name the kernel.
/// Entries are not serialized but are recreated on deserialization of a
/// sycl_kernel_entry_point attributed function declaration.
llvm::DenseMap<CanQualType, SYCLKernelInfo> SYCLKernels;

/// For capturing lambdas with an explicit object parameter whose type is
/// derived from the lambda type, we need to perform derived-to-base
/// conversion so we can access the captures; the cast paths for that
Expand Down Expand Up @@ -3337,6 +3346,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
GlobalDecl GD) const;

/// Generates and stores SYCL kernel metadata for the provided
/// SYCL kernel entry point function. The provided function must have
/// an attached sycl_kernel_entry_point attribute that specifies a unique
/// type for the name of a SYCL kernel. Callers are required to detect
/// conflicting SYCL kernel names and issue a diagnostic prior to calling
/// this function.
void registerSYCLEntryPointFunction(FunctionDecl *FD);

//===--------------------------------------------------------------------===//
// Statistics
//===--------------------------------------------------------------------===//
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ class DeclaratorDecl : public ValueDecl {
// qualifier, to be used for the (uncommon) case of out-of-line declarations
// and constrained function decls.
struct ExtInfo : public QualifierInfo {
TypeSourceInfo *TInfo;
TypeSourceInfo *TInfo = nullptr;
Expr *TrailingRequiresClause = nullptr;
};

Expand Down
95 changes: 36 additions & 59 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -787,11 +787,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
EntryType *Entry, void *InsertPos);

struct CommonBase {
CommonBase() {}
CommonBase() : InstantiatedFromMember(nullptr, false) {}

/// The template from which this was most
/// directly instantiated (or null).
RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
///
/// The boolean value indicates whether this template
/// was explicitly specialized.
llvm::PointerIntPair<RedeclarableTemplateDecl *, 1, bool>
InstantiatedFromMember;

/// If non-null, points to an array of specializations (including
/// partial specializations) known only by their external declaration IDs.
Expand All @@ -802,19 +806,14 @@ class RedeclarableTemplateDecl : public TemplateDecl,
};

/// Pointer to the common data shared by all declarations of this
/// template, and a flag indicating if the template is a member
/// specialization.
mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;

CommonBase *getCommonPtrInternal() const { return Common.getPointer(); }
/// template.
mutable CommonBase *Common = nullptr;

/// Retrieves the "common" pointer shared by all (re-)declarations of
/// the same template. Calling this routine may implicitly allocate memory
/// for the common pointer.
CommonBase *getCommonPtr() const;

void setCommonPtr(CommonBase *C) const { Common.setPointer(C); }

virtual CommonBase *newCommon(ASTContext &C) const = 0;

// Construct a template decl with name, parameters, and templated element.
Expand Down Expand Up @@ -855,22 +854,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// template<> template<typename T>
/// struct X<int>::Inner { /* ... */ };
/// \endcode
bool isMemberSpecialization() const { return Common.getInt(); }

/// Determines whether any redeclaration of this template was
/// a specialization of a member template.
bool hasMemberSpecialization() const {
for (const auto *D : redecls()) {
if (D->isMemberSpecialization())
return true;
}
return false;
bool isMemberSpecialization() const {
return getCommonPtr()->InstantiatedFromMember.getInt();
}

/// Note that this member template is a specialization.
void setMemberSpecialization() {
assert(!isMemberSpecialization() && "already a member specialization");
Common.setInt(true);
assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
getCommonPtr()->InstantiatedFromMember.setInt(true);
}

/// Retrieve the member template from which this template was
Expand Down Expand Up @@ -910,12 +902,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// void X<T>::f(T, U);
/// \endcode
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
return getCommonPtr()->InstantiatedFromMember;
return getCommonPtr()->InstantiatedFromMember.getPointer();
}

void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
assert(!getCommonPtr()->InstantiatedFromMember);
getCommonPtr()->InstantiatedFromMember = TD;
assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
getCommonPtr()->InstantiatedFromMember.setPointer(TD);
}

/// Retrieve the "injected" template arguments that correspond to the
Expand Down Expand Up @@ -1997,8 +1989,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// template arguments have been deduced.
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgumentList *TemplateArgs) {
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Already set to a class template partial specialization!");
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
Expand All @@ -2010,8 +2000,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// Note that this class template specialization is an instantiation
/// of the given class template.
void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Previously set to a class template partial specialization!");
SpecializedTemplate = TemplDecl;
Expand Down Expand Up @@ -2205,22 +2193,18 @@ class ClassTemplatePartialSpecializationDecl
/// struct X<int>::Inner<T*> { /* ... */ };
/// \endcode
bool isMemberSpecialization() const {
return InstantiatedFromMember.getInt();
}

/// Determines whether any redeclaration of this this class template partial
/// specialization was a specialization of a member partial specialization.
bool hasMemberSpecialization() const {
for (const auto *D : redecls()) {
if (cast<ClassTemplatePartialSpecializationDecl>(D)
->isMemberSpecialization())
return true;
}
return false;
const auto *First =
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
}

/// Note that this member template is a specialization.
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
void setMemberSpecialization() {
auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
assert(First->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true);
}

/// Retrieves the injected specialization type for this partial
/// specialization. This is not the same as the type-decl-type for
Expand Down Expand Up @@ -2290,6 +2274,8 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}

void setCommonPtr(Common *C) { RedeclarableTemplateDecl::Common = C; }

public:

friend class ASTDeclReader;
Expand Down Expand Up @@ -2772,8 +2758,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// template arguments have been deduced.
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgumentList *TemplateArgs) {
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Already set to a variable template partial specialization!");
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
Expand All @@ -2785,8 +2769,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// Note that this variable template specialization is an instantiation
/// of the given variable template.
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Previously set to a variable template partial specialization!");
SpecializedTemplate = TemplDecl;
Expand Down Expand Up @@ -2977,23 +2959,18 @@ class VarTemplatePartialSpecializationDecl
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
/// \endcode
bool isMemberSpecialization() const {
return InstantiatedFromMember.getInt();
}

/// Determines whether any redeclaration of this this variable template
/// partial specialization was a specialization of a member partial
/// specialization.
bool hasMemberSpecialization() const {
for (const auto *D : redecls()) {
if (cast<VarTemplatePartialSpecializationDecl>(D)
->isMemberSpecialization())
return true;
}
return false;
const auto *First =
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
}

/// Note that this member template is a specialization.
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
void setMemberSpecialization() {
auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
assert(First->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true);
}

SourceRange getSourceRange() const override LLVM_READONLY;

Expand Down
276 changes: 276 additions & 0 deletions clang/include/clang/AST/DynamicRecursiveASTVisitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
//===--- DynamicRecursiveASTVisitor.h - Virtual AST Visitor -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the DynamicRecursiveASTVisitor interface, which acts
// identically to RecursiveASTVisitor, except that it uses virtual dispatch
// instead of CRTP, which greatly improves compile times and binary size.
//
// Prefer to use this over RecursiveASTVisitor whenever possible.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H
#define LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H

#include "clang/AST/Attr.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/TypeLoc.h"

namespace clang {
class ASTContext;

/// Recursive AST visitor that supports extension via dynamic dispatch.
///
/// Like RecursiveASTVisitor, this class allows for traversal of arbitrarily
/// complex ASTs. The main difference is that this uses virtual functions
/// instead of CRTP, which greatly improves compile times of Clang itself,
/// as well as binary size.
///
/// Instead of functions (e.g. shouldVisitImplicitCode()), this class
/// uses member variables (e.g. ShouldVisitImplicitCode) to control
/// visitation behaviour.
///
/// However, there is no support for overriding some of the less commonly
/// used features of the RAV, such as WalkUpFromX or attribute traversal
/// (attributes can still be traversed, but you can't change what happens
/// when we traverse one).
///
/// The following is a list of RAV features that are NOT customisable:
///
/// - Visiting attributes,
/// - Overriding WalkUpFromX,
/// - Overriding getStmtChildren().
///
/// Furthermore, post-order traversal is not supported at all.
///
/// Prefer to use this over RecursiveASTVisitor unless you absolutely
/// need to use one of the features listed above (e.g. overriding
/// WalkUpFromX or post-order traversal).
///
/// \see RecursiveASTVisitor.
class DynamicRecursiveASTVisitor {
public:
/// Whether this visitor should recurse into template instantiations.
bool ShouldVisitTemplateInstantiations = false;

/// Whether this visitor should recurse into the types of TypeLocs.
bool ShouldWalkTypesOfTypeLocs = true;

/// Whether this visitor should recurse into implicit code, e.g.
/// implicit constructors and destructors.
bool ShouldVisitImplicitCode = false;

/// Whether this visitor should recurse into lambda body.
bool ShouldVisitLambdaBody = true;

protected:
DynamicRecursiveASTVisitor() = default;
DynamicRecursiveASTVisitor(DynamicRecursiveASTVisitor &&) = default;
DynamicRecursiveASTVisitor(const DynamicRecursiveASTVisitor &) = default;
DynamicRecursiveASTVisitor &
operator=(DynamicRecursiveASTVisitor &&) = default;
DynamicRecursiveASTVisitor &
operator=(const DynamicRecursiveASTVisitor &) = default;

public:
virtual void anchor();
virtual ~DynamicRecursiveASTVisitor() = default;

/// Recursively visits an entire AST, starting from the TranslationUnitDecl.
/// \returns false if visitation was terminated early.
virtual bool TraverseAST(ASTContext &AST);

/// Recursively visit an attribute, by dispatching to
/// Traverse*Attr() based on the argument's dynamic type.
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is a Null type location).
virtual bool TraverseAttr(Attr *At);

/// Recursively visit a constructor initializer. This
/// automatically dispatches to another visitor for the initializer
/// expression, but not for the name of the initializer, so may
/// be overridden for clients that need access to the name.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseConstructorInitializer(CXXCtorInitializer *Init);

/// Recursively visit a base specifier. This can be overridden by a
/// subclass.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base);

/// Recursively visit a declaration, by dispatching to
/// Traverse*Decl() based on the argument's dynamic type.
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is NULL).
virtual bool TraverseDecl(Decl *D);

/// Recursively visit a name with its location information.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo);

/// Recursively visit a lambda capture. \c Init is the expression that
/// will be used to initialize the capture.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
Expr *Init);

/// Recursively visit a C++ nested-name-specifier.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);

/// Recursively visit a C++ nested-name-specifier with location
/// information.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);

/// Recursively visit a statement or expression, by
/// dispatching to Traverse*() based on the argument's dynamic type.
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is nullptr).
virtual bool TraverseStmt(Stmt *S);

/// Recursively visit a template argument and dispatch to the
/// appropriate method for the argument type.
///
/// \returns false if the visitation was terminated early, true otherwise.
// FIXME: migrate callers to TemplateArgumentLoc instead.
virtual bool TraverseTemplateArgument(const TemplateArgument &Arg);

/// Recursively visit a template argument location and dispatch to the
/// appropriate method for the argument type.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc);

/// Recursively visit a set of template arguments.
///
/// \returns false if the visitation was terminated early, true otherwise.
// FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead.
// Not virtual for now because no-one overrides it.
bool TraverseTemplateArguments(ArrayRef<TemplateArgument> Args);

/// Recursively visit a template name and dispatch to the
/// appropriate method.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseTemplateName(TemplateName Template);

/// Recursively visit a type, by dispatching to
/// Traverse*Type() based on the argument's getTypeClass() property.
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is a Null type).
virtual bool TraverseType(QualType T);

/// Recursively visit a type with location, by dispatching to
/// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is a Null type location).
virtual bool TraverseTypeLoc(TypeLoc TL);

/// Recursively visit an Objective-C protocol reference with location
/// information.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc);

/// Traverse a concept (requirement).
virtual bool TraverseTypeConstraint(const TypeConstraint *C);
virtual bool TraverseConceptRequirement(concepts::Requirement *R);
virtual bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R);
virtual bool TraverseConceptExprRequirement(concepts::ExprRequirement *R);
virtual bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R);
virtual bool TraverseConceptReference(ConceptReference *CR);
virtual bool VisitConceptReference(ConceptReference *CR) { return true; }

/// Visit a node.
virtual bool VisitAttr(Attr *A) { return true; }
virtual bool VisitDecl(Decl *D) { return true; }
virtual bool VisitStmt(Stmt *S) { return true; }
virtual bool VisitType(Type *T) { return true; }
virtual bool VisitTypeLoc(TypeLoc TL) { return true; }

/// Walk up from a node.
bool WalkUpFromDecl(Decl *D) { return VisitDecl(D); }
bool WalkUpFromStmt(Stmt *S) { return VisitStmt(S); }
bool WalkUpFromType(Type *T) { return VisitType(T); }
bool WalkUpFromTypeLoc(TypeLoc TL) { return VisitTypeLoc(TL); }

/// Invoked before visiting a statement or expression via data recursion.
///
/// \returns false to skip visiting the node, true otherwise.
virtual bool dataTraverseStmtPre(Stmt *S) { return true; }

/// Invoked after visiting a statement or expression via data recursion.
/// This is not invoked if the previously invoked \c dataTraverseStmtPre
/// returned false.
///
/// \returns false if the visitation was terminated early, true otherwise.
virtual bool dataTraverseStmtPost(Stmt *S) { return true; }
virtual bool dataTraverseNode(Stmt *S);

#define DEF_TRAVERSE_TMPL_INST(kind) \
virtual bool TraverseTemplateInstantiations(kind##TemplateDecl *D);
DEF_TRAVERSE_TMPL_INST(Class)
DEF_TRAVERSE_TMPL_INST(Var)
DEF_TRAVERSE_TMPL_INST(Function)
#undef DEF_TRAVERSE_TMPL_INST

// Decls.
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) virtual bool Traverse##CLASS##Decl(CLASS##Decl *D);
#include "clang/AST/DeclNodes.inc"

#define DECL(CLASS, BASE) \
bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D); \
virtual bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; }
#include "clang/AST/DeclNodes.inc"

// Stmts.
#define ABSTRACT_STMT(STMT)
#define STMT(CLASS, PARENT) virtual bool Traverse##CLASS(CLASS *S);
#include "clang/AST/StmtNodes.inc"

#define STMT(CLASS, PARENT) \
bool WalkUpFrom##CLASS(CLASS *S); \
virtual bool Visit##CLASS(CLASS *S) { return true; }
#include "clang/AST/StmtNodes.inc"

// Types.
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) virtual bool Traverse##CLASS##Type(CLASS##Type *T);
#include "clang/AST/TypeNodes.inc"

#define TYPE(CLASS, BASE) \
bool WalkUpFrom##CLASS##Type(CLASS##Type *T); \
virtual bool Visit##CLASS##Type(CLASS##Type *T) { return true; }
#include "clang/AST/TypeNodes.inc"

// TypeLocs.
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
#include "clang/AST/TypeLocNodes.def"

#define TYPELOC(CLASS, BASE) \
bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL); \
virtual bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; }
#include "clang/AST/TypeLocNodes.def"
};
} // namespace clang

#endif // LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H
39 changes: 32 additions & 7 deletions clang/include/clang/AST/OpenMPClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,8 @@ class OMPAlignClause final
/// #pragma omp parallel private(a) allocate(omp_default_mem_alloc :a)
/// \endcode
/// In this example directive '#pragma omp parallel' has clause 'private'
/// and clause 'allocate' for the variable 'a'.
/// and clause 'allocate' for the variable 'a', which specifies an explicit
/// memory allocator.
class OMPAllocateClause final
: public OMPVarListClause<OMPAllocateClause>,
private llvm::TrailingObjects<OMPAllocateClause, Expr *> {
Expand All @@ -499,6 +500,10 @@ class OMPAllocateClause final
Expr *Allocator = nullptr;
/// Position of the ':' delimiter in the clause;
SourceLocation ColonLoc;
/// Modifier of 'allocate' clause.
OpenMPAllocateClauseModifier AllocatorModifier = OMPC_ALLOCATE_unknown;
/// Location of allocator modifier if any.
SourceLocation AllocatorModifierLoc;

/// Build clause with number of variables \a N.
///
Expand All @@ -510,10 +515,14 @@ class OMPAllocateClause final
/// \param N Number of the variables in the clause.
OMPAllocateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
Expr *Allocator, SourceLocation ColonLoc,
SourceLocation EndLoc, unsigned N)
OpenMPAllocateClauseModifier AllocatorModifier,
SourceLocation AllocatorModifierLoc, SourceLocation EndLoc,
unsigned N)
: OMPVarListClause<OMPAllocateClause>(llvm::omp::OMPC_allocate, StartLoc,
LParenLoc, EndLoc, N),
Allocator(Allocator), ColonLoc(ColonLoc) {}
Allocator(Allocator), ColonLoc(ColonLoc),
AllocatorModifier(AllocatorModifier),
AllocatorModifierLoc(AllocatorModifierLoc) {}

/// Build an empty clause.
///
Expand All @@ -527,6 +536,9 @@ class OMPAllocateClause final
void setColonLoc(SourceLocation CL) { ColonLoc = CL; }

void setAllocator(Expr *A) { Allocator = A; }
void setAllocatorModifier(OpenMPAllocateClauseModifier AM) {
AllocatorModifier = AM;
}

public:
/// Creates clause with a list of variables \a VL.
Expand All @@ -536,18 +548,31 @@ class OMPAllocateClause final
/// \param LParenLoc Location of '('.
/// \param Allocator Allocator expression.
/// \param ColonLoc Location of ':' delimiter.
/// \param AllocatorModifier Allocator modifier.
/// \param SourceLocation Allocator modifier location.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
static OMPAllocateClause *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, Expr *Allocator,
SourceLocation ColonLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL);
static OMPAllocateClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
Expr *Allocator, SourceLocation ColonLoc,
OpenMPAllocateClauseModifier AllocatorModifier,
SourceLocation AllocatorModifierLoc, SourceLocation EndLoc,
ArrayRef<Expr *> VL);

/// Returns the allocator expression or nullptr, if no allocator is specified.
Expr *getAllocator() const { return Allocator; }

/// Return 'allocate' modifier.
OpenMPAllocateClauseModifier getAllocatorModifier() const {
return AllocatorModifier;
}

/// Returns the location of the ':' delimiter.
SourceLocation getColonLoc() const { return ColonLoc; }
/// Return the location of the modifier.
SourceLocation getAllocatorModifierLoc() const {
return AllocatorModifierLoc;
}

/// Creates an empty clause with the place for \a N variables.
///
Expand Down
41 changes: 41 additions & 0 deletions clang/include/clang/AST/SYCLKernelInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===--- SYCLKernelInfo.h --- Information about SYCL kernels --------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares types used to describe SYCL kernels.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_SYCLKERNELINFO_H
#define LLVM_CLANG_AST_SYCLKERNELINFO_H

#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"

namespace clang {

class SYCLKernelInfo {
public:
SYCLKernelInfo(CanQualType KernelNameType,
const FunctionDecl *KernelEntryPointDecl)
: KernelNameType(KernelNameType),
KernelEntryPointDecl(KernelEntryPointDecl) {}

CanQualType getKernelNameType() const { return KernelNameType; }

const FunctionDecl *getKernelEntryPointDecl() const {
return KernelEntryPointDecl;
}

private:
CanQualType KernelNameType;
const FunctionDecl *KernelEntryPointDecl;
};

} // namespace clang

#endif // LLVM_CLANG_AST_SYCLKERNELINFO_H
2 changes: 1 addition & 1 deletion clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -3226,7 +3226,7 @@ AST_MATCHER_P(CXXDependentScopeMemberExpr, memberHasSameNameAsBoundNode,

return Builder->removeBindings(
[this, MemberName](const BoundNodesMap &Nodes) {
const auto &BN = Nodes.getNode(this->BindingID);
const DynTypedNode &BN = Nodes.getNode(this->BindingID);
if (const auto *ND = BN.get<NamedDecl>()) {
if (!isa<FieldDecl, CXXMethodDecl, VarDecl>(ND))
return true;
Expand Down
23 changes: 20 additions & 3 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,8 @@ def MicrosoftExt : LangOpt<"MicrosoftExt">;
def Borland : LangOpt<"Borland">;
def CUDA : LangOpt<"CUDA">;
def HIP : LangOpt<"HIP">;
def SYCL : LangOpt<"SYCLIsDevice">;
def SYCLHost : LangOpt<"SYCLIsHost">;
def SYCLDevice : LangOpt<"SYCLIsDevice">;
def COnly : LangOpt<"", "!LangOpts.CPlusPlus">;
def CPlusPlus : LangOpt<"CPlusPlus">;
def OpenCL : LangOpt<"OpenCL">;
Expand Down Expand Up @@ -1450,6 +1451,13 @@ def CUDAHost : InheritableAttr {
}
def : MutualExclusions<[CUDAGlobal, CUDAHost]>;

def CUDAGridConstant : InheritableAttr {
let Spellings = [GNU<"grid_constant">, Declspec<"__grid_constant__">];
let Subjects = SubjectList<[ParmVar]>;
let LangOpts = [CUDA];
let Documentation = [CUDAGridConstantAttrDocs];
}

def NVPTXKernel : InheritableAttr, TargetSpecificAttr<TargetNVPTX> {
let Spellings = [Clang<"nvptx_kernel">];
let Subjects = SubjectList<[Function]>;
Expand Down Expand Up @@ -1493,14 +1501,23 @@ def : MutualExclusions<[CUDAConstant, CUDAShared, HIPManaged]>;
def SYCLKernel : InheritableAttr {
let Spellings = [Clang<"sycl_kernel">];
let Subjects = SubjectList<[FunctionTmpl]>;
let LangOpts = [SYCL];
let LangOpts = [SYCLDevice];
let Documentation = [SYCLKernelDocs];
}

def SYCLKernelEntryPoint : InheritableAttr {
let Spellings = [Clang<"sycl_kernel_entry_point">];
let Args = [TypeArgument<"KernelName">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let TemplateDependent = 1;
let LangOpts = [SYCLHost, SYCLDevice];
let Documentation = [SYCLKernelEntryPointDocs];
}

def SYCLSpecialClass: InheritableAttr {
let Spellings = [Clang<"sycl_special_class">];
let Subjects = SubjectList<[CXXRecord]>;
let LangOpts = [SYCL];
let LangOpts = [SYCLDevice];
let Documentation = [SYCLSpecialClassDocs];
}

Expand Down
184 changes: 184 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,180 @@ The SYCL kernel in the previous code sample meets these expectations.
}];
}

def SYCLKernelEntryPointDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``sycl_kernel_entry_point`` attribute facilitates the generation of an
offload kernel entry point, sometimes called a SYCL kernel caller function,
suitable for invoking a SYCL kernel on an offload device. The attribute is
intended for use in the implementation of SYCL kernel invocation functions
like the ``single_task`` and ``parallel_for`` member functions of the
``sycl::handler`` class specified in section 4.9.4, "Command group ``handler``
class", of the SYCL 2020 specification.

The attribute requires a single type argument that specifies a class type that
meets the requirements for a SYCL kernel name as described in section 5.2,
"Naming of kernels", of the SYCL 2020 specification. A unique kernel name type
is required for each function declared with the attribute. The attribute may
not first appear on a declaration that follows a definition of the function.

The attribute only appertains to functions and only those that meet the
following requirements.

* Has a ``void`` return type.
* Is not a non-static member function, constructor, or destructor.
* Is not a C variadic function.
* Is not a coroutine.
* Is not defined as deleted or as defaulted.
* Is not declared with the ``constexpr`` or ``consteval`` specifiers.
* Is not declared with the ``[[noreturn]]`` attribute.

Use in the implementation of a SYCL kernel invocation function might look as
follows.

.. code-block:: c++

namespace sycl {
class handler {
template<typename KernelNameType, typename KernelType>
[[ clang::sycl_kernel_entry_point(KernelNameType) ]]
static void kernel_entry_point(KernelType kernel) {
kernel();
}

public:
template<typename KernelNameType, typename KernelType>
void single_task(KernelType kernel) {
// Call kernel_entry_point() to trigger generation of an offload
// kernel entry point.
kernel_entry_point<KernelNameType>(kernel);
// Call functions appropriate for the desired offload backend
// (OpenCL, CUDA, HIP, Level Zero, etc...).
}
};
} // namespace sycl

A SYCL kernel is a callable object of class type that is constructed on a host,
often via a lambda expression, and then passed to a SYCL kernel invocation
function to be executed on an offload device. A SYCL kernel invocation function
is responsible for copying the provided SYCL kernel object to an offload
device and initiating a call to it. The SYCL kernel object and its data members
constitute the parameters of an offload kernel.

A SYCL kernel type is required to satisfy the device copyability requirements
specified in section 3.13.1, "Device copyable", of the SYCL 2020 specification.
Additionally, any data members of the kernel object type are required to satisfy
section 4.12.4, "Rules for parameter passing to kernels". For most types, these
rules require that the type is trivially copyable. However, the SYCL
specification mandates that certain special SYCL types, such as
``sycl::accessor`` and ``sycl::stream`` be device copyable even if they are not
trivially copyable. These types require special handling because they cannot
be copied to device memory as if by ``memcpy()``. Additionally, some offload
backends, OpenCL for example, require objects of some of these types to be
passed as individual arguments to the offload kernel.

An offload kernel consists of an entry point function that declares the
parameters of the offload kernel and the set of all functions and variables that
are directly or indirectly used by the entry point function.

A SYCL kernel invocation function invokes a SYCL kernel on a device by
performing the following tasks (likely with the help of an offload backend
like OpenCL):

#. Identifying the offload kernel entry point to be used for the SYCL kernel.

#. Deconstructing the SYCL kernel object, if necessary, to produce the set of
offload kernel arguments required by the offload kernel entry point.

#. Copying the offload kernel arguments to device memory.

#. Initiating execution of the offload kernel entry point.

The offload kernel entry point for a SYCL kernel performs the following tasks:

#. Reconstituting the SYCL kernel object, if necessary, using the offload
kernel parameters.

#. Calling the ``operator()`` member function of the (reconstituted) SYCL kernel
object.

The ``sycl_kernel_entry_point`` attribute automates generation of an offload
kernel entry point that performs those latter tasks. The parameters and body of
a function declared with the ``sycl_kernel_entry_point`` attribute specify a
pattern from which the parameters and body of the entry point function are
derived. Consider the following call to a SYCL kernel invocation function.

.. code-block:: c++

struct S { int i; };
void f(sycl::handler &handler, sycl::stream &sout, S s) {
handler.single_task<struct KN>([=] {
sout << "The value of s.i is " << s.i << "\n";
});
}

The SYCL kernel object is the result of the lambda expression. It has two
data members corresponding to the captures of ``sout`` and ``s``. Since one
of these data members corresponds to a special SYCL type that must be passed
individually as an offload kernel parameter, it is necessary to decompose the
SYCL kernel object into its constituent parts; the offload kernel will have
two kernel parameters. Given a SYCL implementation that uses a
``sycl_kernel_entry_point`` attributed function like the one shown above, an
offload kernel entry point function will be generated that looks approximately
as follows.

.. code-block:: c++

void sycl-kernel-caller-for-KN(sycl::stream sout, S s) {
kernel-type kernel = { sout, s );
kernel();
}

There are a few items worthy of note:

#. The name of the generated function incorporates the SYCL kernel name,
``KN``, that was passed as the ``KernelNameType`` template parameter to
``kernel_entry_point()`` and provided as the argument to the
``sycl_kernel_entry_point`` attribute. There is a one-to-one correspondence
between SYCL kernel names and offload kernel entry points.

#. The SYCL kernel is a lambda closure type and therefore has no name;
``kernel-type`` is substituted above and corresponds to the ``KernelType``
template parameter deduced in the call to ``kernel_entry_point()``.
Lambda types cannot be declared and initialized using the aggregate
initialization syntax used above, but the intended behavior should be clear.

#. ``S`` is a device copyable type that does not directly or indirectly contain
a data member of a SYCL special type. It therefore does not need to be
decomposed into its constituent members to be passed as a kernel argument.

#. The depiction of the ``sycl::stream`` parameter as a single self contained
kernel parameter is an oversimplification. SYCL special types may require
additional decomposition such that the generated function might have three
or more parameters depending on how the SYCL library implementation defines
these types.

#. The call to ``kernel_entry_point()`` has no effect other than to trigger
emission of the entry point function. The statments that make up the body
of the function are not executed when the function is called; they are
only used in the generation of the entry point function.

It is not necessary for a function declared with the ``sycl_kernel_entry_point``
attribute to be called for the offload kernel entry point to be emitted. For
inline functions and function templates, any ODR-use will suffice. For other
functions, an ODR-use is not required; the offload kernel entry point will be
emitted if the function is defined.

Functions declared with the ``sycl_kernel_entry_point`` attribute are not
limited to the simple example shown above. They may have additional template
parameters, declare additional function parameters, and have complex control
flow in the function body. Function parameter decomposition and reconstitution
is performed for all function parameters. The function must abide by the
language feature restrictions described in section 5.4, "Language restrictions
for device functions" in the SYCL 2020 specification.
}];
}

def SYCLSpecialClassDocs : Documentation {
let Category = DocCatStmt;
let Content = [{
Expand Down Expand Up @@ -6620,6 +6794,16 @@ unbind runtime APIs.
}];
}

def CUDAGridConstantAttrDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
The ``__grid_constant__`` attribute can be applied to a ``const``-qualified kernel
function argument and allows compiler to take the address of that argument without
making a copy. The argument applies to sm_70 or newer GPUs, during compilation
with CUDA-11.7(PTX 7.7) or newer, and is ignored otherwise.
}];
}

def HIPManagedAttrDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4792,6 +4792,18 @@ def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLDot4AddI8Packed : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_dot4add_i8packed"];
let Attributes = [NoThrow, Const];
let Prototype = "int(unsigned int, unsigned int, int)";
}

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

def HLSLFrac : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_frac"];
let Attributes = [NoThrow, Const];
Expand Down
146 changes: 73 additions & 73 deletions clang/include/clang/Basic/BuiltinsLoongArchLASX.def

Large diffs are not rendered by default.

132 changes: 66 additions & 66 deletions clang/include/clang/Basic/BuiltinsLoongArchLSX.def

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -389,13 +389,14 @@ def remark_sloc_usage : Remark<
"source manager location address space usage:">,
InGroup<DiagGroup<"sloc-usage">>, DefaultRemark, ShowInSystemHeader;
def note_total_sloc_usage : Note<
"%0B in local locations, %1B in locations loaded from AST files, for a total "
"of %2B (%3%% of available space)">;
"%0B (%1B) in local locations, %2B (%3B) "
"in locations loaded from AST files, for a total of %4B (%5B) "
"(%6%% of available space)">;
def note_file_sloc_usage : Note<
"file entered %0 time%s0 using %1B of space"
"%plural{0:|: plus %2B for macro expansions}2">;
"file entered %0 time%s0 using %1B (%2B) of space"
"%plural{0:|: plus %3B (%4B) for macro expansions}3">;
def note_file_misc_sloc_usage : Note<
"%0 additional files entered using a total of %1B of space">;
"%0 additional files entered using a total of %1B (%2B) of space">;

// Modules
def err_module_format_unhandled : Error<
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 @@ -9100,6 +9100,8 @@ def err_cuda_host_shared : Error<
"%select{__device__|__global__|__host__|__host__ __device__}0 functions">;
def err_cuda_nonstatic_constdev: Error<"__constant__, __device__, and "
"__managed__ are not allowed on non-static local variables">;
def err_cuda_grid_constant_not_allowed : Error<
"__grid_constant__ is only allowed on const-qualified kernel parameters">;
def err_cuda_ovl_target : Error<
"%select{__device__|__global__|__host__|__host__ __device__}0 function %1 "
"cannot overload %select{__device__|__global__|__host__|__host__ __device__}2 function %3">;
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/OpenMPKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
#ifndef OPENMP_DOACROSS_MODIFIER
#define OPENMP_DOACROSS_MODIFIER(Name)
#endif
#ifndef OPENMP_ALLOCATE_MODIFIER
#define OPENMP_ALLOCATE_MODIFIER(Name)
#endif

// Static attributes for 'schedule' clause.
OPENMP_SCHEDULE_KIND(static)
Expand Down Expand Up @@ -214,6 +217,9 @@ OPENMP_GRAINSIZE_MODIFIER(strict)
// Modifiers for the 'num_tasks' clause.
OPENMP_NUMTASKS_MODIFIER(strict)

// Modifiers for 'allocate' clause.
OPENMP_ALLOCATE_MODIFIER(allocator)

// Modifiers for the 'doacross' clause.
OPENMP_DOACROSS_MODIFIER(source)
OPENMP_DOACROSS_MODIFIER(sink)
Expand Down Expand Up @@ -245,4 +251,5 @@ OPENMP_DOACROSS_MODIFIER(source_omp_cur_iteration)
#undef OPENMP_DEFAULTMAP_KIND
#undef OPENMP_DEFAULTMAP_MODIFIER
#undef OPENMP_DOACROSS_MODIFIER
#undef OPENMP_ALLOCATE_MODIFIER

7 changes: 7 additions & 0 deletions clang/include/clang/Basic/OpenMPKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ enum OpenMPDoacrossClauseModifier {
OMPC_DOACROSS_unknown
};

/// OpenMP modifiers for 'allocate' clause.
enum OpenMPAllocateClauseModifier {
#define OPENMP_ALLOCATE_MODIFIER(Name) OMPC_ALLOCATE_##Name,
#include "clang/Basic/OpenMPKinds.def"
OMPC_ALLOCATE_unknown
};

/// Contains 'interop' data for 'append_args' and 'init' clauses.
class Expr;
struct OMPInteropInfo final {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ KEYWORD(out , KEYHLSL)
// HLSL Type traits
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
TYPE_TRAIT_1(__builtin_hlsl_is_typed_resource_element_compatible, IsTypedResourceElementCompatible, KEYHLSL)

// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/CIR/CIRGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class CIRGenerator : public clang::ASTConsumer {
~CIRGenerator() override;
void Initialize(clang::ASTContext &astCtx) override;
bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
mlir::ModuleOp getModule() const;
};

} // namespace cir
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRDialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,25 @@
#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
#define LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H

#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/Interfaces/CallInterfaces.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
#include "mlir/Interfaces/LoopLikeInterface.h"
#include "mlir/Interfaces/MemorySlotInterfaces.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

#include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"

// TableGen'erated files for MLIR dialects require that a macro be defined when
// they are included. GET_OP_CLASSES tells the file to define the classes for
// the operations of that dialect.
#define GET_OP_CLASSES
#include "clang/CIR/Dialect/IR/CIROps.h.inc"

#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
82 changes: 82 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,86 @@

include "clang/CIR/Dialect/IR/CIRDialect.td"

include "mlir/IR/BuiltinAttributeInterfaces.td"
include "mlir/IR/EnumAttr.td"
include "mlir/IR/SymbolInterfaces.td"
include "mlir/IR/CommonAttrConstraints.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/FunctionInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/Interfaces/LoopLikeInterface.td"
include "mlir/Interfaces/MemorySlotInterfaces.td"
include "mlir/Interfaces/SideEffectInterfaces.td"

//===----------------------------------------------------------------------===//
// CIR Ops
//===----------------------------------------------------------------------===//

// LLVMLoweringInfo is used by cir-tablegen to generate LLVM lowering logic
// automatically for CIR operations. The `llvmOp` field gives the name of the
// LLVM IR dialect operation that the CIR operation will be lowered to. The
// input arguments of the CIR operation will be passed in the same order to the
// lowered LLVM IR operation.
//
// Example:
//
// For the following CIR operation definition:
//
// def FooOp : CIR_Op<"foo"> {
// // ...
// let arguments = (ins CIR_AnyType:$arg1, CIR_AnyType:$arg2);
// let llvmOp = "BarOp";
// }
//
// cir-tablegen will generate LLVM lowering code for the FooOp similar to the
// following:
//
// class CIRFooOpLowering
// : public mlir::OpConversionPattern<mlir::cir::FooOp> {
// public:
// using OpConversionPattern<mlir::cir::FooOp>::OpConversionPattern;
//
// mlir::LogicalResult matchAndRewrite(
// mlir::cir::FooOp op,
// OpAdaptor adaptor,
// mlir::ConversionPatternRewriter &rewriter) const override {
// rewriter.replaceOpWithNewOp<mlir::LLVM::BarOp>(
// op, adaptor.getOperands()[0], adaptor.getOperands()[1]);
// return mlir::success();
// }
// }
//
// If you want fully customized LLVM IR lowering logic, simply exclude the
// `llvmOp` field from your CIR operation definition.
class LLVMLoweringInfo {
string llvmOp = "";
}

class CIR_Op<string mnemonic, list<Trait> traits = []> :
Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;

//===----------------------------------------------------------------------===//
// FuncOp
//===----------------------------------------------------------------------===//

// TODO(CIR): For starters, cir.func has only name, nothing else. The other
// properties of a function will be added over time as more of ClangIR is
// upstreamed.

def FuncOp : CIR_Op<"func"> {
let summary = "Declare or define a function";
let description = [{
... lots of text to be added later ...
}];

let arguments = (ins SymbolNameAttr:$sym_name);

let skipDefaultBuilders = 1;

let builders = [OpBuilder<(ins "StringRef":$name)>];

let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;
}

#endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS
2 changes: 1 addition & 1 deletion clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1569,7 +1569,7 @@ struct FormatStyle {

/// Control of individual brace wrapping cases.
///
/// If ``BreakBeforeBraces`` is set to ``BS_Custom``, use this to specify how
/// If ``BreakBeforeBraces`` is set to ``Custom``, use this to specify how
/// each individual brace case should be handled. Otherwise, this is ignored.
/// \code{.yaml}
/// # Example of usage:
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,19 @@ class Preprocessor {
/// \#pragma GCC poison/system_header/dependency and \#pragma once.
void RegisterBuiltinPragmas();

/// RegisterBuiltinMacro - Register the specified identifier in the identifier
/// table and mark it as a builtin macro to be expanded.
IdentifierInfo *RegisterBuiltinMacro(const char *Name) {
// Get the identifier.
IdentifierInfo *Id = getIdentifierInfo(Name);

// Mark it as being a macro that is builtin.
MacroInfo *MI = AllocateMacroInfo(SourceLocation());
MI->setIsBuiltinMacro();
appendDefMacroDirective(Id, MI);
return Id;
}

/// Register builtin macros such as __LINE__ with the identifier table.
void RegisterBuiltinMacros();

Expand Down
25 changes: 19 additions & 6 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -11328,9 +11328,9 @@ class Sema final : public SemaBase {
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
SourceLocation FriendLoc,
ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
TemplateParameterList **OuterTemplateParamLists,
SkipBodyInfo *SkipBody = nullptr);

/// Translates template arguments as provided by the parser
/// into template arguments used by semantic analysis.
Expand Down Expand Up @@ -11369,8 +11369,7 @@ class Sema final : public SemaBase {
DeclResult ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
StorageClass SC, bool IsPartialSpecialization,
bool IsMemberSpecialization);
StorageClass SC, bool IsPartialSpecialization);

/// Get the specialization of the given variable template corresponding to
/// the specified argument list, or a null-but-valid result if the arguments
Expand Down Expand Up @@ -13012,14 +13011,28 @@ class Sema final : public SemaBase {
/// dealing with a specialization. This is only relevant for function
/// template specializations.
///
/// \param Pattern If non-NULL, indicates the pattern from which we will be
/// instantiating the definition of the given declaration, \p ND. This is
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
///
/// \param ForConstraintInstantiation when collecting arguments,
/// ForConstraintInstantiation indicates we should continue looking when
/// encountering a lambda generic call operator, and continue looking for
/// arguments on an enclosing class template.
///
/// \param SkipForSpecialization when specified, any template specializations
/// in a traversal would be ignored.
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
/// when encountering a specialized member function template, rather than
/// returning immediately.
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false,
bool SkipForSpecialization = false,
bool ForDefaultArgumentSubstitution = false);

/// RAII object to handle the state changes required to synthesize
/// a function body.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class SemaHLSL : public SemaBase {

// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
bool IsTypedResourceElementCompatible(QualType T1);

bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);

Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Sema/SemaOpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,7 @@ class SemaOpenMP : public SemaBase {
SourceLocation OmpAllMemoryLoc;
SourceLocation
StepModifierLoc; /// 'step' modifier location for linear clause
OpenMPAllocateClauseModifier AllocClauseModifier = OMPC_ALLOCATE_unknown;
};

OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
Expand All @@ -1165,10 +1166,10 @@ class SemaOpenMP : public SemaBase {
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-formed 'allocate' clause.
OMPClause *
ActOnOpenMPAllocateClause(Expr *Allocator, ArrayRef<Expr *> VarList,
SourceLocation StartLoc, SourceLocation ColonLoc,
SourceLocation LParenLoc, SourceLocation EndLoc);
OMPClause *ActOnOpenMPAllocateClause(
Expr *Allocator, OpenMPAllocateClauseModifier ACModifier,
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc);
/// Called on well-formed 'private' clause.
OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/SemaSYCL.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class SemaSYCL : public SemaBase {
ParsedType ParsedTy);

void handleKernelAttr(Decl *D, const ParsedAttr &AL);
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
};

} // namespace clang
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/APINotes/APINotesFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
const uint16_t VERSION_MINOR = 30; // fields
const uint16_t VERSION_MINOR = 31; // lifetimebound

const uint8_t kSwiftCopyable = 1;
const uint8_t kSwiftNonCopyable = 2;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/APINotes/APINotesReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ void ReadParamInfo(const uint8_t *&Data, ParamInfo &Info) {
Info.setRetainCountConvention(Convention);
}
Payload >>= 3;
if (Payload & 0x01)
Info.setLifetimebound(Payload & 0x02);
Payload >>= 2;
if (Payload & 0x01)
Info.setNoEscape(Payload & 0x02);
Payload >>= 2;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/APINotes/APINotesTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ LLVM_DUMP_METHOD void ParamInfo::dump(llvm::raw_ostream &OS) const {
static_cast<const VariableInfo &>(*this).dump(OS);
if (NoEscapeSpecified)
OS << (NoEscape ? "[NoEscape] " : "");
if (LifetimeboundSpecified)
OS << (Lifetimebound ? "[Lifetimebound] " : "");
OS << "RawRetainCountConvention: " << RawRetainCountConvention << ' ';
OS << '\n';
}
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/APINotes/APINotesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,12 @@ void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
if (*noescape)
flags |= 0x02;
}
flags <<= 2;
if (auto lifetimebound = PI.isLifetimebound()) {
flags |= 0x01;
if (*lifetimebound)
flags |= 0x02;
}
flags <<= 3;
if (auto RCC = PI.getRetainCountConvention())
flags |= static_cast<uint8_t>(RCC.value()) + 1;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/APINotes/APINotesYAMLCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ namespace {
struct Param {
unsigned Position;
std::optional<bool> NoEscape = false;
std::optional<bool> Lifetimebound = false;
std::optional<NullabilityKind> Nullability;
std::optional<RetainCountConventionKind> RetainCountConvention;
StringRef Type;
Expand Down Expand Up @@ -121,6 +122,7 @@ template <> struct MappingTraits<Param> {
IO.mapOptional("Nullability", P.Nullability, std::nullopt);
IO.mapOptional("RetainCountConvention", P.RetainCountConvention);
IO.mapOptional("NoEscape", P.NoEscape);
IO.mapOptional("Lifetimebound", P.Lifetimebound);
IO.mapOptional("Type", P.Type, StringRef(""));
}
};
Expand Down Expand Up @@ -734,6 +736,7 @@ class YAMLConverter {
if (P.Nullability)
PI.setNullabilityAudited(*P.Nullability);
PI.setNoEscape(P.NoEscape);
PI.setLifetimebound(P.Lifetimebound);
PI.setType(std::string(P.Type));
PI.setRetainCountConvention(P.RetainCountConvention);
if (OutInfo.Params.size() <= P.Position)
Expand Down
45 changes: 42 additions & 3 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,15 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
return CanonTTP;
}

/// Check if a type can have its sanitizer instrumentation elided based on its
/// presence within an ignorelist.
bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
const QualType &Ty) const {
std::string TyName = Ty.getUnqualifiedType().getAsString(getPrintingPolicy());
return NoSanitizeL->containsType(Mask, TyName) &&
!NoSanitizeL->containsType(Mask, TyName, "sanitize");
}

TargetCXXABI::Kind ASTContext::getCXXABIKind() const {
auto Kind = getTargetInfo().getCXXABI().getKind();
return getLangOpts().CXXABI.value_or(Kind);
Expand Down Expand Up @@ -1583,14 +1592,17 @@ ASTContext::setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
InstantiatedFromUsingShadowDecl[Inst] = Pattern;
}

FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
FieldDecl *
ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) const {
return InstantiatedFromUnnamedFieldDecl.lookup(Field);
}

void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
FieldDecl *Tmpl) {
assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed");
assert(!Tmpl->getDeclName() && "Template field decl is not unnamed");
assert((!Inst->getDeclName() || Inst->isPlaceholderVar(getLangOpts())) &&
"Instantiated field decl is not unnamed");
assert((!Inst->getDeclName() || Inst->isPlaceholderVar(getLangOpts())) &&
"Template field decl is not unnamed");
assert(!InstantiatedFromUnnamedFieldDecl[Inst] &&
"Already noted what unnamed field was instantiated from");

Expand Down Expand Up @@ -14402,6 +14414,33 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
}
}

static SYCLKernelInfo BuildSYCLKernelInfo(CanQualType KernelNameType,
const FunctionDecl *FD) {
return {KernelNameType, FD};
}

void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) {
// If the function declaration to register is invalid or dependent, the
// registration attempt is ignored.
if (FD->isInvalidDecl() || FD->isTemplated())
return;

const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");

// Be tolerant of multiple registration attempts so long as each attempt
// is for the same entity. Callers are obligated to detect and diagnose
// conflicting kernel names prior to calling this function.
CanQualType KernelNameType = getCanonicalType(SKEPAttr->getKernelName());
auto IT = SYCLKernels.find(KernelNameType);
assert((IT == SYCLKernels.end() ||
declaresSameEntity(FD, IT->second.getKernelEntryPointDecl())) &&
"SYCL kernel name conflict");
(void)IT;
SYCLKernels.insert(
std::make_pair(KernelNameType, BuildSYCLKernelInfo(KernelNameType, FD)));
}

OMPTraitInfo &ASTContext::getNewOMPTraitInfo() {
OMPTraitInfoVector.emplace_back(new OMPTraitInfo());
return *OMPTraitInfoVector.back();
Expand Down
18 changes: 13 additions & 5 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2735,7 +2735,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
return this->visitInitializer(SubExpr);
return this->visitInitializer(SubExpr) && this->emitFinishInit(E);
}
}
return false;
Expand Down Expand Up @@ -6446,8 +6446,6 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
QualType ToType = E->getType();
std::optional<PrimType> ToT = classify(ToType);

assert(!DiscardResult && "Implement DiscardResult mode for bitcasts.");

if (ToType->isNullPtrType()) {
if (!this->discard(SubExpr))
return false;
Expand All @@ -6463,13 +6461,23 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
}
assert(!ToType->isReferenceType());

// Prepare storage for the result in case we discard.
if (DiscardResult && !Initializing && !ToT) {
std::optional<unsigned> LocalIndex = allocateLocal(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}

// Get a pointer to the value-to-cast on the stack.
if (!this->visit(SubExpr))
return false;

if (!ToT || ToT == PT_Ptr) {
// Conversion to an array or record type.
assert(false && "Implement bitcast to pointers.");
if (!this->emitBitCastPtr(E))
return false;
return DiscardResult ? this->emitPopPtr(E) : true;
}
assert(ToT);

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class Floating final {
return Floating(APFloat(Sem, API));
}

void bitcastToMemory(std::byte *Buff) {
void bitcastToMemory(std::byte *Buff) const {
llvm::APInt API = F.bitcastToAPInt();
llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
}
Expand Down
21 changes: 20 additions & 1 deletion clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -3063,14 +3063,33 @@ inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,

if constexpr (std::is_same_v<T, Floating>) {
assert(Sem);
S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
ptrdiff_t Offset = 0;

if (llvm::sys::IsBigEndianHost) {
unsigned NumBits = llvm::APFloatBase::getSizeInBits(*Sem);
assert(NumBits % 8 == 0);
assert(NumBits <= ResultBitWidth);
Offset = (ResultBitWidth - NumBits) / 8;
}

S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data() + Offset, *Sem));
} else {
assert(!Sem);
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
}
return true;
}

inline bool BitCastPtr(InterpState &S, CodePtr OpPC) {
const Pointer &FromPtr = S.Stk.pop<Pointer>();
Pointer &ToPtr = S.Stk.peek<Pointer>();

if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
return false;

return true;
}

//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
169 changes: 122 additions & 47 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ using namespace clang;
using namespace clang::interp;

/// Used to iterate over pointer fields.
using DataFunc =
llvm::function_ref<bool(const Pointer &P, PrimType Ty, size_t BitOffset)>;
using DataFunc = llvm::function_ref<bool(const Pointer &P, PrimType Ty,
size_t BitOffset, bool PackedBools)>;

#define BITCAST_TYPE_SWITCH(Expr, B) \
do { \
Expand All @@ -48,9 +48,7 @@ using DataFunc =
} \
} while (0)

/// Float is a special case that sometimes needs the floating point semantics
/// to be available.
#define BITCAST_TYPE_SWITCH_WITH_FLOAT(Expr, B) \
#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \
do { \
switch (Expr) { \
TYPE_SWITCH_CASE(PT_Sint8, B) \
Expand All @@ -61,10 +59,7 @@ using DataFunc =
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
TYPE_SWITCH_CASE(PT_IntAP, B) \
TYPE_SWITCH_CASE(PT_IntAPS, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
TYPE_SWITCH_CASE(PT_Float, B) \
default: \
llvm_unreachable("Unhandled bitcast type"); \
} \
Expand All @@ -83,39 +78,38 @@ static void swapBytes(std::byte *M, size_t N) {
/// have indeterminate value.
/// All offsets are in bits.
struct BitcastBuffer {
llvm::BitVector Data;
size_t SizeInBits = 0;
llvm::SmallVector<std::byte> Data;

BitcastBuffer() = default;

size_t size() const { return Data.size(); }
size_t size() const { return SizeInBits; }

const std::byte *data() const {
unsigned NBytes = Data.size() / 8;
unsigned BitVectorWordSize = sizeof(uintptr_t);
bool FullWord = (NBytes % BitVectorWordSize == 0);
const std::byte *data() const { return Data.data(); }

// llvm::BitVector uses 64-bit fields internally, so when we have
// fewer bytes than that, we need to compensate for that on
// big endian hosts.
unsigned DataPlus;
if (llvm::sys::IsBigEndianHost)
DataPlus = BitVectorWordSize - (NBytes % BitVectorWordSize);
else
DataPlus = 0;

return reinterpret_cast<const std::byte *>(Data.getData().data()) +
(FullWord ? 0 : DataPlus);
std::byte *getBytes(unsigned BitOffset) const {
assert(BitOffset % 8 == 0);
assert(BitOffset < SizeInBits);
return const_cast<std::byte *>(data() + (BitOffset / 8));
}

bool allInitialized() const {
// FIXME: Implement.
return true;
}

void pushData(const std::byte *data, size_t BitOffset, size_t BitWidth,
bool BigEndianTarget) {
Data.reserve(BitOffset + BitWidth);
bool atByteBoundary() const { return (Data.size() * 8) == SizeInBits; }

void pushBit(bool Value) {
if (atByteBoundary())
Data.push_back(std::byte{0});

if (Value)
Data.back() |= (std::byte{1} << (SizeInBits % 8));
++SizeInBits;
}

void pushData(const std::byte *data, size_t BitWidth, bool BigEndianTarget) {
bool OnlyFullBytes = BitWidth % 8 == 0;
unsigned NBytes = BitWidth / 8;

Expand All @@ -125,7 +119,7 @@ struct BitcastBuffer {
std::byte B =
BigEndianTarget ? data[NBytes - OnlyFullBytes - I] : data[I];
for (unsigned X = 0; X != 8; ++X) {
Data.push_back(bitof(B, X));
pushBit(bitof(B, X));
++BitsHandled;
}
}
Expand All @@ -137,7 +131,7 @@ struct BitcastBuffer {
assert((BitWidth - BitsHandled) < 8);
std::byte B = BigEndianTarget ? data[0] : data[NBytes];
for (size_t I = 0, E = (BitWidth - BitsHandled); I != E; ++I) {
Data.push_back(bitof(B, I));
pushBit(bitof(B, I));
++BitsHandled;
}

Expand All @@ -154,18 +148,20 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset,

// Primitives.
if (FieldDesc->isPrimitive())
return F(P, FieldDesc->getPrimType(), Offset);
return F(P, FieldDesc->getPrimType(), Offset, false);

// Primitive arrays.
if (FieldDesc->isPrimitiveArray()) {
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
QualType ElemType = FieldDesc->getElemQualType();
size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType);
PrimType ElemT = *Ctx.classify(ElemType);
// Special case, since the bools here are packed.
bool PackedBools = FieldDesc->getType()->isExtVectorBoolType();
bool Ok = true;
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
unsigned Index = BigEndianTarget ? (FieldDesc->getNumElems() - 1 - I) : I;
Ok = Ok && F(P.atIndex(Index), ElemT, Offset);
Ok = Ok && F(P.atIndex(Index), ElemT, Offset, PackedBools);
Offset += ElemSizeInBits;
}
return Ok;
Expand Down Expand Up @@ -309,7 +305,8 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,

return enumeratePointerFields(
FromPtr, Ctx,
[&](const Pointer &P, PrimType T, size_t BitOffset) -> bool {
[&](const Pointer &P, PrimType T, size_t BitOffset,
bool PackedBools) -> bool {
if (!P.isInitialized()) {
assert(false && "Implement uninitialized value tracking");
return ReturnOnUninit;
Expand All @@ -321,25 +318,42 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
assert(false && "Implement casting to pointer types");

CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
unsigned BitWidth;
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
BitWidth = FD->getBitWidthValue(ASTCtx);
else
BitWidth = ASTCtx.toBits(ObjectReprChars);

unsigned BitWidth = ASTCtx.toBits(ObjectReprChars);
llvm::SmallVector<std::byte> Buff(ObjectReprChars.getQuantity());
BITCAST_TYPE_SWITCH_WITH_FLOAT(T, {
T Val = P.deref<T>();
Val.bitcastToMemory(Buff.data());
});
if (SwapData)
swapBytes(Buff.data(), ObjectReprChars.getQuantity());
// Work around floating point types that contain unused padding bytes.
// This is really just `long double` on x86, which is the only
// fundamental type with padding bytes.
if (T == PT_Float) {
const Floating &F = P.deref<Floating>();
unsigned NumBits =
llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics());
assert(NumBits % 8 == 0);
assert(NumBits <= (ObjectReprChars.getQuantity() * 8));
F.bitcastToMemory(Buff.data());
// Now, only (maybe) swap the actual size of the float, excluding the
// padding bits.
if (SwapData)
swapBytes(Buff.data(), NumBits / 8);

} else {
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
BitWidth = FD->getBitWidthValue(ASTCtx);
else if (T == PT_Bool && PackedBools)
BitWidth = 1;

BITCAST_TYPE_SWITCH(T, {
T Val = P.deref<T>();
Val.bitcastToMemory(Buff.data());
});
if (SwapData)
swapBytes(Buff.data(), ObjectReprChars.getQuantity());
}

if (BitWidth != (Buff.size() * 8) && BigEndianTarget) {
Buffer.pushData(Buff.data() + (Buff.size() - 1 - (BitWidth / 8)),
BitOffset, BitWidth, BigEndianTarget);
BitWidth, BigEndianTarget);
} else {
Buffer.pushData(Buff.data(), BitOffset, BitWidth, BigEndianTarget);
Buffer.pushData(Buff.data(), BitWidth, BigEndianTarget);
}
return true;
});
Expand All @@ -363,5 +377,66 @@ bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
HasIndeterminateBits = !Buffer.allInitialized();
std::memcpy(Buff, Buffer.data(), BuffSize);

if (llvm::sys::IsBigEndianHost)
swapBytes(Buff, BuffSize);

return Success;
}

bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
const Pointer &FromPtr, Pointer &ToPtr) {
assert(FromPtr.isLive());
assert(FromPtr.isBlockPointer());
assert(ToPtr.isBlockPointer());

QualType FromType = FromPtr.getType();
QualType ToType = ToPtr.getType();

if (!CheckBitcastType(S, OpPC, FromType, /*IsToType=*/false))
return false;

if (!CheckBitcastType(S, OpPC, ToType, /*IsToType=*/true))
return false;

BitcastBuffer Buffer;
readPointerToBuffer(S.getContext(), FromPtr, Buffer,
/*ReturnOnUninit=*/false);

// Now read the values out of the buffer again and into ToPtr.
const ASTContext &ASTCtx = S.getASTContext();
size_t BitOffset = 0;
bool Success = enumeratePointerFields(
ToPtr, S.getContext(),
[&](const Pointer &P, PrimType T, size_t _, bool PackedBools) -> bool {
if (T == PT_Float) {
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
const auto &Semantics = ASTCtx.getFloatTypeSemantics(P.getType());
unsigned NumBits = llvm::APFloatBase::getSizeInBits(Semantics);
assert(NumBits % 8 == 0);
assert(NumBits <= ASTCtx.toBits(ObjectReprChars));
std::byte *M = Buffer.getBytes(BitOffset);

if (llvm::sys::IsBigEndianHost)
swapBytes(M, NumBits / 8);

P.deref<Floating>() = Floating::bitcastFromMemory(M, Semantics);
P.initialize();
BitOffset += ASTCtx.toBits(ObjectReprChars);
return true;
}

BITCAST_TYPE_SWITCH_FIXED_SIZE(T, {
std::byte *M = Buffer.getBytes(BitOffset);

if (llvm::sys::IsBigEndianHost)
swapBytes(M, T::bitWidth() / 8);

P.deref<T>() = T::bitcastFromMemory(M, T::bitWidth());
P.initialize();
BitOffset += T::bitWidth();
});
return true;
});

return Success;
}
2 changes: 2 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class CodePtr;

bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
std::byte *Buff, size_t BuffSize, bool &HasIndeterminateBits);
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,
Pointer &ToPtr);

} // namespace interp
} // namespace clang
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -847,3 +847,5 @@ def BitCast : Opcode {
let Args = [ArgBool, ArgUint32, ArgFltSemantics];
let HasGroup = 1;
}

def BitCastPtr : Opcode;
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ add_clang_library(clangAST
DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
DynamicRecursiveASTVisitor.cpp
ParentMapContext.cpp
Expr.cpp
ExprClassification.cpp
Expand Down
37 changes: 19 additions & 18 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2708,21 +2708,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
auto From = VDTemplSpec->getInstantiatedFrom();
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
while (!VTD->hasMemberSpecialization()) {
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
VTD = NewVTD;
else
while (!VTD->isMemberSpecialization()) {
auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
if (!NewVTD)
break;
VTD = NewVTD;
}
return getDefinitionOrSelf(VTD->getTemplatedDecl());
}
if (auto *VTPSD =
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
while (!VTPSD->hasMemberSpecialization()) {
if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
VTPSD = NewVTPSD;
else
while (!VTPSD->isMemberSpecialization()) {
auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
if (!NewVTPSD)
break;
VTPSD = NewVTPSD;
}
return getDefinitionOrSelf<VarDecl>(VTPSD);
}
Expand All @@ -2731,14 +2731,15 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {

// If this is the pattern of a variable template, find where it was
// instantiated from. FIXME: Is this necessary?
if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
while (!VTD->hasMemberSpecialization()) {
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
VTD = NewVTD;
else
if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
while (!VarTemplate->isMemberSpecialization()) {
auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
if (!NewVT)
break;
VarTemplate = NewVT;
}
return getDefinitionOrSelf(VTD->getTemplatedDecl());

return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
}

if (VD == this)
Expand Down Expand Up @@ -4153,11 +4154,11 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
// If we hit a point where the user provided a specialization of this
// template, we're done looking.
while (!ForDefinition || !Primary->hasMemberSpecialization()) {
if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
Primary = NewPrimary;
else
while (!ForDefinition || !Primary->isMemberSpecialization()) {
auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
if (!NewPrimary)
break;
Primary = NewPrimary;
}

return getDefinitionOrSelf(Primary->getTemplatedDecl());
Expand Down
14 changes: 6 additions & 8 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2030,21 +2030,19 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
auto From = TD->getInstantiatedFrom();
if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
while (!CTD->hasMemberSpecialization()) {
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
CTD = NewCTD;
else
while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
if (NewCTD->isMemberSpecialization())
break;
CTD = NewCTD;
}
return GetDefinitionOrSelf(CTD->getTemplatedDecl());
}
if (auto *CTPSD =
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
while (!CTPSD->hasMemberSpecialization()) {
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
CTPSD = NewCTPSD;
else
while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
if (NewCTPSD->isMemberSpecialization())
break;
CTPSD = NewCTPSD;
}
return GetDefinitionOrSelf(CTPSD);
}
Expand Down
30 changes: 16 additions & 14 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,35 +320,35 @@ bool TemplateDecl::isTypeAlias() const {
void RedeclarableTemplateDecl::anchor() {}

RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
if (CommonBase *C = getCommonPtrInternal())
return C;
if (Common)
return Common;

// Walk the previous-declaration chain until we either find a declaration
// with a common pointer or we run out of previous declarations.
SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
Prev = Prev->getPreviousDecl()) {
if (CommonBase *C = Prev->getCommonPtrInternal()) {
setCommonPtr(C);
if (Prev->Common) {
Common = Prev->Common;
break;
}

PrevDecls.push_back(Prev);
}

// If we never found a common pointer, allocate one now.
if (!getCommonPtrInternal()) {
if (!Common) {
// FIXME: If any of the declarations is from an AST file, we probably
// need an update record to add the common data.

setCommonPtr(newCommon(getASTContext()));
Common = newCommon(getASTContext());
}

// Update any previous declarations we saw with the common pointer.
for (const RedeclarableTemplateDecl *Prev : PrevDecls)
Prev->setCommonPtr(getCommonPtrInternal());
Prev->Common = Common;

return getCommonPtrInternal();
return Common;
}

void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
Expand Down Expand Up @@ -458,17 +458,19 @@ void FunctionTemplateDecl::addSpecialization(
}

void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
using Base = RedeclarableTemplateDecl;

// If we haven't created a common pointer yet, then it can just be created
// with the usual method.
if (!getCommonPtrInternal())
if (!Base::Common)
return;

Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal());
Common *ThisCommon = static_cast<Common *>(Base::Common);
Common *PrevCommon = nullptr;
SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
for (; Prev; Prev = Prev->getPreviousDecl()) {
if (CommonBase *C = Prev->getCommonPtrInternal()) {
PrevCommon = static_cast<Common *>(C);
if (Prev->Base::Common) {
PrevCommon = static_cast<Common *>(Prev->Base::Common);
break;
}
PreviousDecls.push_back(Prev);
Expand All @@ -478,15 +480,15 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
// use this common pointer.
if (!PrevCommon) {
for (auto *D : PreviousDecls)
D->setCommonPtr(ThisCommon);
D->Base::Common = ThisCommon;
return;
}

// Ensure we don't leak any important state.
assert(ThisCommon->Specializations.size() == 0 &&
"Can't merge incompatible declarations!");

setCommonPtr(PrevCommon);
Base::Common = PrevCommon;
}

//===----------------------------------------------------------------------===//
Expand Down
Loading