10 changes: 10 additions & 0 deletions clang-tools-extra/clangd/unittests/XRefsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,15 @@ TEST(LocateSymbol, All) {
void *Value;
void *getPointer() const { return Info::get^Pointer(Value); }
};
)cpp",
R"cpp(// Deducing this
struct S {
int bar(this S&);
};
void foo() {
S [[waldo]];
int x = wa^ldo.bar();
}
)cpp"};
for (const char *Test : Tests) {
Annotations T(Test);
Expand All @@ -1035,6 +1044,7 @@ TEST(LocateSymbol, All) {
TU.Code = std::string(T.code());

TU.ExtraArgs.push_back("-xobjective-c++");
TU.ExtraArgs.push_back("-std=c++23");

auto AST = TU.build();
auto Results = locateSymbolAt(AST, T.point());
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/modularize/ModuleAssistant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class Module {
public:
Module(llvm::StringRef Name, bool Problem);
~Module();
Module(const Module &other) = delete;
Module &operator=(const Module &other) = delete;
bool output(llvm::raw_fd_ostream &OS, int Indent);
Module *findSubModule(llvm::StringRef SubName);

Expand Down
17 changes: 17 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,20 @@ Improvements to Clang's diagnostics

- Clang now diagnoses dangling references for C++20's parenthesized aggregate initialization (#101957).

- Fixed a bug where Clang would not emit ``-Wunused-private-field`` warnings when an unrelated class
defined a defaulted comparison operator (#GH116270).

.. code-block:: c++

class A {
private:
int a; // warning: private field 'a' is not used, no diagnostic previously
};

class C {
bool operator==(const C&) = default;
};

Improvements to Clang's time-trace
----------------------------------

Expand All @@ -663,6 +677,9 @@ Bug Fixes in This Version
- Fixed a crash when GNU statement expression contains invalid statement (#GH113468).
- Fixed a failed assertion when using ``__attribute__((noderef))`` on an
``_Atomic``-qualified type (#GH116124).
- No longer return ``false`` for ``noexcept`` expressions involving a
``delete`` which resolves to a destroying delete but the type of the object
being deleted has a potentially throwing destructor (#GH118660).

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
25 changes: 25 additions & 0 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3438,6 +3438,31 @@ alpha.WebKit
.. _alpha-webkit-NoUncheckedPtrMemberChecker:
alpha.webkit.MemoryUnsafeCastChecker
""""""""""""""""""""""""""""""""""""""
Check for all casts from a base type to its derived type as these might be memory-unsafe.
Example:
.. code-block:: cpp
class Base { };
class Derived : public Base { };
void f(Base* base) {
Derived* derived = static_cast<Derived*>(base); // ERROR
}
For all cast operations (C-style casts, static_cast, reinterpret_cast, dynamic_cast), if the source type a `Base*` and the destination type is `Derived*`, where `Derived` inherits from `Base`, the static analyzer should signal an error.
This applies to:
- C structs, C++ structs and classes, and Objective-C classes and protocols.
- Pointers and references.
- Inside template instantiations and macro expansions that are visible to the compiler.
For types like this, instead of using built in casts, the programmer will use helper functions that internally perform the appropriate type check and disable static analysis.
alpha.webkit.NoUncheckedPtrMemberChecker
""""""""""""""""""""""""""""""""""""""""
Raw pointers and references to an object which supports CheckedPtr or CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, or Ref are allowed.
Expand Down
11 changes: 10 additions & 1 deletion clang/docs/tools/dump_format_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# A tool to parse the output of `clang-format --help` and update the
# documentation in ../ClangFormat.rst automatically.

import argparse
import os
import re
import subprocess
Expand All @@ -26,7 +27,7 @@ def indent(text, columns, indent_first_line=True):


def get_help_output():
args = ["clang-format", "--help"]
args = [binary, "--help"]
cmd = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = cmd.communicate()
out = out.decode(sys.stdout.encoding)
Expand Down Expand Up @@ -54,6 +55,14 @@ def validate(text, columns):
print("warning: line too long:\n", line, file=sys.stderr)


p = argparse.ArgumentParser()
p.add_argument("-d", "--directory", help="directory of clang-format")
opts = p.parse_args()

binary = "clang-format"
if opts.directory:
binary = opts.directory + "/" + binary

help_text = get_help_text()
validate(help_text, 100)

Expand Down
2 changes: 1 addition & 1 deletion clang/docs/tools/dump_format_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
PLURALS_FILE = os.path.join(os.path.dirname(__file__), "plurals.txt")

plurals: Set[str] = set()
with open(PLURALS_FILE, "a+") as f:
with open(PLURALS_FILE) as f:
f.seek(0)
plurals = set(f.read().splitlines())

Expand Down
23 changes: 13 additions & 10 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
}

void anchor() override;

protected:
template <typename EntryType> struct SpecEntryTraits {
using DeclType = EntryType;
Expand Down Expand Up @@ -775,13 +776,22 @@ class RedeclarableTemplateDecl : public TemplateDecl,
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
}

void loadLazySpecializationsImpl() const;
void loadLazySpecializationsImpl(bool OnlyPartial = false) const;

bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
TemplateParameterList *TPL = nullptr) const;

template <class EntryType, typename ...ProfileArguments>
typename SpecEntryTraits<EntryType>::DeclType*
findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
void *&InsertPos, ProfileArguments &&...ProfileArgs);

template <class EntryType, typename... ProfileArguments>
typename SpecEntryTraits<EntryType>::DeclType *
findSpecializationLocally(llvm::FoldingSetVector<EntryType> &Specs,
void *&InsertPos,
ProfileArguments &&...ProfileArgs);

template <class Derived, class EntryType>
void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
EntryType *Entry, void *InsertPos);
Expand All @@ -796,13 +806,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// 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.
///
/// The first value in the array is the number of specializations/partial
/// specializations that follow.
GlobalDeclID *LazySpecializations = nullptr;
};

/// Pointer to the common data shared by all declarations of this
Expand Down Expand Up @@ -2283,7 +2286,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
friend class TemplateDeclInstantiator;

/// Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
void LoadLazySpecializations(bool OnlyPartial = false) const;

/// Get the underlying class declarations of the template.
CXXRecordDecl *getTemplatedDecl() const {
Expand Down Expand Up @@ -3033,7 +3036,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
friend class ASTDeclWriter;

/// Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
void LoadLazySpecializations(bool OnlyPartial = false) const;

/// Get the underlying variable declarations of the template.
VarDecl *getTemplatedDecl() const {
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/AST/ExternalASTSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,21 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
virtual bool
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);

/// Load all the external specializations for the Decl \param D if \param
/// OnlyPartial is false. Otherwise, load all the external **partial**
/// specializations for the \param D.
///
/// Return true if any new specializations get loaded. Return false otherwise.
virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial);

/// Load all the specializations for the Decl \param D with the same template
/// args specified by \param TemplateArgs.
///
/// Return true if any new specializations get loaded. Return false otherwise.
virtual bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
///
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/AST/OpenACCClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,14 @@ class OpenACCGangClause final
return {getGangKind(I), getExprs()[I]};
}

bool hasExprOfKind(OpenACCGangKind GK) const {
for (unsigned I = 0; I < getNumExprs(); ++I) {
if (getGangKind(I) == GK)
return true;
}
return false;
}

static OpenACCGangClause *
Create(const ASTContext &Ctx, SourceLocation BeginLoc,
SourceLocation LParenLoc, ArrayRef<OpenACCGangKind> GangKinds,
Expand Down
19 changes: 10 additions & 9 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12755,21 +12755,22 @@ def err_acc_gang_multiple_elt
: Error<"OpenACC 'gang' clause may have at most one %select{unnamed or "
"'num'|'dim'|'static'}0 argument">;
def err_acc_int_arg_invalid
: Error<"'%1' argument on '%0' clause is not permitted on a%select{n "
"orphaned|||}2 'loop' construct %select{|associated with a "
"'parallel' compute construct|associated with a 'kernels' compute "
"construct|associated with a 'serial' compute construct}2">;
: Error<"'%0' argument on '%1' clause is not permitted on a%select{|n "
"orphaned}2 '%3' construct%select{| associated with a '%5' compute "
"construct}4">;
def err_acc_gang_dim_value
: Error<"argument to 'gang' clause dimension must be %select{a constant "
"expression|1, 2, or 3: evaluated to %1}0">;
def err_acc_num_arg_conflict
: Error<"'num' argument to '%0' clause not allowed on a 'loop' construct "
"associated with a 'kernels' construct that has a "
"'%select{num_gangs|num_workers|vector_length}1' "
"clause">;
: Error<"'num' argument to '%0' clause not allowed on a '%1' "
"construct%select{| associated with a '%3' construct}2 that has a "
"'%4' clause">;
def err_acc_num_arg_conflict_reverse
: Error<"'%0' clause not allowed on a 'kernels loop' construct that "
"has a '%1' clause with a%select{n| 'num'}2 argument">;
def err_acc_clause_in_clause_region
: Error<"loop with a '%0' clause may not exist in the region of a '%1' "
"clause%select{| on a 'kernels' compute construct}2">;
"clause%select{| on a '%3' construct}2">;
def err_acc_gang_reduction_conflict
: Error<"%select{OpenACC 'gang' clause with a 'dim' value greater than "
"1|OpenACC 'reduction' clause}0 cannot "
Expand Down
10 changes: 5 additions & 5 deletions clang/include/clang/Basic/arm_mve.td
Original file line number Diff line number Diff line change
Expand Up @@ -1270,13 +1270,13 @@ defm sqrshr: ScalarSaturatingShiftReg<s32, s64>;
def lsll: LongScalarShift<u64, (args s32:$sh), (IRInt<"lsll"> $lo, $hi, $sh)>;
def asrl: LongScalarShift<s64, (args s32:$sh), (IRInt<"asrl"> $lo, $hi, $sh)>;

multiclass vadcsbc {
multiclass vadcsbc<dag initial_carry_in> {
def q: Intrinsic<Vector, (args Vector:$a, Vector:$b, Ptr<uint>:$carry),
(seq (IRInt<NAME, [Vector]> $a, $b, (shl (load $carry), 29)):$pair,
(store (and 1, (lshr (xval $pair, 1), 29)), $carry),
(xval $pair, 0))>;
def iq: Intrinsic<Vector, (args Vector:$a, Vector:$b, Ptr<uint>:$carry),
(seq (IRInt<NAME, [Vector]> $a, $b, 0):$pair,
(seq (IRInt<NAME, [Vector]> $a, $b, initial_carry_in):$pair,
(store (and 1, (lshr (xval $pair, 1), 29)), $carry),
(xval $pair, 0))>;
def q_m: Intrinsic<Vector, (args Vector:$inactive, Vector:$a, Vector:$b,
Expand All @@ -1288,13 +1288,13 @@ multiclass vadcsbc {
def iq_m: Intrinsic<Vector, (args Vector:$inactive, Vector:$a, Vector:$b,
Ptr<uint>:$carry, Predicate:$pred),
(seq (IRInt<NAME # "_predicated", [Vector, Predicate]> $inactive, $a, $b,
0, $pred):$pair,
initial_carry_in, $pred):$pair,
(store (and 1, (lshr (xval $pair, 1), 29)), $carry),
(xval $pair, 0))>;
}
let params = T.Int32 in {
defm vadc: vadcsbc;
defm vsbc: vadcsbc;
defm vadc: vadcsbc<(u32 0)>;
defm vsbc: vadcsbc<(shl 1, 29)>;
}

let params = T.Int in {
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/MultiplexExternalSemaSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;

bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;

bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
void completeVisibleDeclsMap(const DeclContext *DC) override;
Expand Down
17 changes: 12 additions & 5 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,14 @@ class SemaOpenACC : public SemaBase {
}

/// If there is a current 'active' loop construct with a 'gang' clause on a
/// 'kernel' construct, this will have the source location for it. This
/// permits us to implement the restriction of no further 'gang' clauses.
SourceLocation LoopGangClauseOnKernelLoc;
/// 'kernel' construct, this will have the source location for it, and the
/// 'kernel kind'. This permits us to implement the restriction of no further
/// 'gang' clauses.
struct LoopGangOnKernelTy {
SourceLocation Loc;
OpenACCDirectiveKind DirKind = OpenACCDirectiveKind::Invalid;
} LoopGangClauseOnKernel;

/// If there is a current 'active' loop construct with a 'worker' clause on it
/// (on any sort of construct), this has the source location for it. This
/// permits us to implement the restriction of no further 'gang' or 'worker'
Expand Down Expand Up @@ -705,7 +710,9 @@ class SemaOpenACC : public SemaBase {
ExprResult CheckTileSizeExpr(Expr *SizeExpr);

// Check a single expression on a gang clause.
ExprResult CheckGangExpr(OpenACCGangKind GK, Expr *E);
ExprResult CheckGangExpr(ArrayRef<const OpenACCClause *> ExistingClauses,
OpenACCDirectiveKind DK, OpenACCGangKind GK,
Expr *E);

// Does the checking for a 'gang' clause that needs to be done in dependent
// and not dependent cases.
Expand Down Expand Up @@ -771,7 +778,7 @@ class SemaOpenACC : public SemaBase {
SemaOpenACC &SemaRef;
ComputeConstructInfo OldActiveComputeConstructInfo;
OpenACCDirectiveKind DirKind;
SourceLocation OldLoopGangClauseOnKernelLoc;
LoopGangOnKernelTy OldLoopGangClauseOnKernel;
SourceLocation OldLoopWorkerClauseLoc;
SourceLocation OldLoopVectorClauseLoc;
LoopWithoutSeqCheckingInfo OldLoopWithoutSeqInfo;
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,13 @@ enum ASTRecordTypes {
/// Record code for Sema's vector of functions/blocks with effects to
/// be verified.
DECLS_WITH_EFFECTS_TO_VERIFY = 72,

/// Record code for updated specialization
UPDATE_SPECIALIZATION = 73,

CXX_ADDED_TEMPLATE_SPECIALIZATION = 74,

CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION = 75,
};

/// Record types used within a source manager block.
Expand Down Expand Up @@ -1502,6 +1509,12 @@ enum DeclCode {
/// An ImplicitConceptSpecializationDecl record.
DECL_IMPLICIT_CONCEPT_SPECIALIZATION,

// A decls specilization record.
DECL_SPECIALIZATIONS,

// A decls specilization record.
DECL_PARTIAL_SPECIALIZATIONS,

DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
};

Expand Down
48 changes: 45 additions & 3 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ class ASTIdentifierLookupTrait;
/// The on-disk hash table(s) used for DeclContext name lookup.
struct DeclContextLookupTable;

/// The on-disk hash table(s) used for specialization decls.
struct LazySpecializationInfoLookupTable;

} // namespace reader

} // namespace serialization
Expand Down Expand Up @@ -632,20 +635,40 @@ class ASTReader
llvm::DenseMap<const DeclContext *,
serialization::reader::DeclContextLookupTable> Lookups;

using SpecLookupTableTy =
llvm::DenseMap<const Decl *,
serialization::reader::LazySpecializationInfoLookupTable>;
/// Map from decls to specialized decls.
SpecLookupTableTy SpecializationsLookups;
/// Split partial specialization from specialization to speed up lookups.
SpecLookupTableTy PartialSpecializationsLookups;

bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
const Decl *D);
bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);

// Updates for visible decls can occur for other contexts than just the
// TU, and when we read those update records, the actual context may not
// be available yet, so have this pending map using the ID as a key. It
// will be realized when the context is actually loaded.
struct PendingVisibleUpdate {
// will be realized when the data is actually loaded.
struct UpdateData {
ModuleFile *Mod;
const unsigned char *Data;
};
using DeclContextVisibleUpdates = SmallVector<PendingVisibleUpdate, 1>;
using DeclContextVisibleUpdates = SmallVector<UpdateData, 1>;

/// Updates to the visible declarations of declaration contexts that
/// haven't been loaded yet.
llvm::DenseMap<GlobalDeclID, DeclContextVisibleUpdates> PendingVisibleUpdates;

using SpecializationsUpdate = SmallVector<UpdateData, 1>;
using SpecializationsUpdateMap =
llvm::DenseMap<GlobalDeclID, SpecializationsUpdate>;
SpecializationsUpdateMap PendingSpecializationsUpdates;
SpecializationsUpdateMap PendingPartialSpecializationsUpdates;

/// The set of C++ or Objective-C classes that have forward
/// declarations that have not yet been linked to their definitions.
llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
Expand Down Expand Up @@ -678,6 +701,11 @@ class ASTReader
llvm::BitstreamCursor &Cursor,
uint64_t Offset, GlobalDeclID ID);

bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor,
uint64_t Offset, Decl *D, bool IsPartial);
void AddSpecializations(const Decl *D, const unsigned char *Data,
ModuleFile &M, bool IsPartial);

/// A vector containing identifiers that have already been
/// loaded.
///
Expand Down Expand Up @@ -1419,6 +1447,14 @@ class ASTReader
const serialization::reader::DeclContextLookupTable *
getLoadedLookupTables(DeclContext *Primary) const;

/// Get the loaded specializations lookup tables for \p D,
/// if any.
serialization::reader::LazySpecializationInfoLookupTable *
getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial);

/// If we have any unloaded specialization for \p D
bool haveUnloadedSpecializations(const Decl *D) const;

private:
struct ImportedModule {
ModuleFile *Mod;
Expand Down Expand Up @@ -2076,6 +2112,12 @@ class ASTReader
unsigned BlockID,
uint64_t *StartOfBlockOffset = nullptr);

bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;

bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;

/// Finds all the visible declarations with a given name.
/// The current implementation of this method just loads the entire
/// lookup table as unmaterialized references.
Expand Down
17 changes: 17 additions & 0 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ class ASTWriter : public ASTDeserializationListener,
/// Only meaningful for reduced BMI.
DeclUpdateMap DeclUpdatesFromGMF;

/// Mapping from decl templates and its new specialization in the
/// current TU.
using SpecializationUpdateMap =
llvm::MapVector<const NamedDecl *, SmallVector<const Decl *>>;
SpecializationUpdateMap SpecializationsUpdates;
SpecializationUpdateMap PartialSpecializationsUpdates;

using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>;

/// Map of first declarations from a chained PCH that point to the
Expand Down Expand Up @@ -575,6 +582,12 @@ class ASTWriter : public ASTDeserializationListener,

bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);

void GenerateSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial);
uint64_t WriteSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
bool IsPartial);
void GenerateNameLookupTable(ASTContext &Context, const DeclContext *DC,
llvm::SmallVectorImpl<char> &LookupTable);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context,
Expand All @@ -590,6 +603,7 @@ class ASTWriter : public ASTDeserializationListener,
void WriteDeclAndTypes(ASTContext &Context);
void PrepareWritingSpecialDecls(Sema &SemaRef);
void WriteSpecialDeclRecords(Sema &SemaRef);
void WriteSpecializationsUpdates(bool IsPartial);
void WriteDeclUpdatesBlocks(ASTContext &Context,
RecordDataImpl &OffsetsRecord);
void WriteDeclContextVisibleUpdate(ASTContext &Context,
Expand Down Expand Up @@ -619,6 +633,9 @@ class ASTWriter : public ASTDeserializationListener,
unsigned DeclEnumAbbrev = 0;
unsigned DeclObjCIvarAbbrev = 0;
unsigned DeclCXXMethodAbbrev = 0;
unsigned DeclSpecializationsAbbrev = 0;
unsigned DeclPartialSpecializationsAbbrev = 0;

unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0;
unsigned DeclTemplateCXXMethodAbbrev = 0;
unsigned DeclMemberSpecializedCXXMethodAbbrev = 0;
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -1749,6 +1749,10 @@ def UncountedLambdaCapturesChecker : Checker<"UncountedLambdaCapturesChecker">,

let ParentPackage = WebKitAlpha in {

def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
HelpText<"Check for memory unsafe casts from base type to derived type.">,
Documentation<HasDocumentation>;

def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
HelpText<"Check for no unchecked member variables.">,
Documentation<HasDocumentation>;
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,13 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
}

assert(P.isInitialized());
// nullptr_t is a PT_Ptr for us, but it's still not std::is_pointer_v.
if (T == PT_Ptr)
assert(false && "Implement casting to pointer types");
if (T == PT_Ptr) {
assert(P.getType()->isNullPtrType());
// Clang treats nullptr_t has having NO bits in its value
// representation. So, we accept it here and leave its bits
// uninitialized.
return true;
}

auto Buff =
std::make_unique<std::byte[]>(ObjectReprChars.getQuantity());
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/CommentLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/CommentDiagnostic.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DiagnosticComment.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ConvertUTF.h"
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/CommentParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

#include "clang/AST/CommentParser.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/CommentSema.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DiagnosticComment.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/ErrorHandling.h"

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/CommentSema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
#include "clang/AST/CommentSema.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/DiagnosticComment.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
Expand Down
108 changes: 77 additions & 31 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/ODRHash.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
Expand Down Expand Up @@ -348,26 +350,39 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
return Common;
}

void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
// Grab the most recent declaration to ensure we've loaded any lazy
// redeclarations of this template.
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
if (CommonBasePtr->LazySpecializations) {
ASTContext &Context = getASTContext();
GlobalDeclID *Specs = CommonBasePtr->LazySpecializations;
CommonBasePtr->LazySpecializations = nullptr;
unsigned SpecSize = (*Specs++).getRawValue();
for (unsigned I = 0; I != SpecSize; ++I)
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
}
void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
bool OnlyPartial /*=false*/) const {
auto *ExternalSource = getASTContext().getExternalSource();
if (!ExternalSource)
return;

ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
OnlyPartial);
return;
}

template<class EntryType, typename... ProfileArguments>
bool RedeclarableTemplateDecl::loadLazySpecializationsImpl(
ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
auto *ExternalSource = getASTContext().getExternalSource();
if (!ExternalSource)
return false;

// If TPL is not null, it implies that we're loading specializations for
// partial templates. We need to load all specializations in such cases.
if (TPL)
return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
/*OnlyPartial=*/false);

return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
Args);
}

template <class EntryType, typename... ProfileArguments>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
RedeclarableTemplateDecl::findSpecializationImpl(
RedeclarableTemplateDecl::findSpecializationLocally(
llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
ProfileArguments&&... ProfileArgs) {
using SETraits = SpecEntryTraits<EntryType>;
ProfileArguments &&...ProfileArgs) {
using SETraits = RedeclarableTemplateDecl::SpecEntryTraits<EntryType>;

llvm::FoldingSetNodeID ID;
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
Expand All @@ -376,6 +391,24 @@ RedeclarableTemplateDecl::findSpecializationImpl(
return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr;
}

template <class EntryType, typename... ProfileArguments>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
RedeclarableTemplateDecl::findSpecializationImpl(
llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
ProfileArguments &&...ProfileArgs) {

if (auto *Found = findSpecializationLocally(
Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...))
return Found;

if (!loadLazySpecializationsImpl(
std::forward<ProfileArguments>(ProfileArgs)...))
return nullptr;

return findSpecializationLocally(
Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...);
}

template<class Derived, class EntryType>
void RedeclarableTemplateDecl::addSpecializationImpl(
llvm::FoldingSetVector<EntryType> &Specializations, EntryType *Entry,
Expand All @@ -384,10 +417,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl(

if (InsertPos) {
#ifndef NDEBUG
auto Args = SETraits::getTemplateArgs(Entry);
// Due to hash collisions, it can happen that we load another template
// specialization with the same hash. This is fine, as long as the next
// call to findSpecializationImpl does not find a matching Decl for the
// template arguments.
loadLazySpecializationsImpl(Args);
void *CorrectInsertPos;
assert(!findSpecializationImpl(Specializations,
CorrectInsertPos,
SETraits::getTemplateArgs(Entry)) &&
assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) &&
InsertPos == CorrectInsertPos &&
"given incorrect InsertPos for specialization");
#endif
Expand Down Expand Up @@ -445,12 +482,14 @@ FunctionTemplateDecl::getSpecializations() const {
FunctionDecl *
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
auto *Common = getCommonPtr();
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
}

void FunctionTemplateDecl::addSpecialization(
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
auto *Common = getCommonPtr();
addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
InsertPos);
}

Expand Down Expand Up @@ -510,8 +549,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
DeclarationName(), nullptr, nullptr);
}

void ClassTemplateDecl::LoadLazySpecializations() const {
loadLazySpecializationsImpl();
void ClassTemplateDecl::LoadLazySpecializations(
bool OnlyPartial /*=false*/) const {
loadLazySpecializationsImpl(OnlyPartial);
}

llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
Expand All @@ -522,7 +562,7 @@ ClassTemplateDecl::getSpecializations() const {

llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
ClassTemplateDecl::getPartialSpecializations() const {
LoadLazySpecializations();
LoadLazySpecializations(/*PartialOnly = */ true);
return getCommonPtr()->PartialSpecializations;
}

Expand All @@ -536,12 +576,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
ClassTemplateSpecializationDecl *
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
auto *Common = getCommonPtr();
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
}

void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
void *InsertPos) {
addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
auto *Common = getCommonPtr();
addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
InsertPos);
}

ClassTemplatePartialSpecializationDecl *
Expand Down Expand Up @@ -1259,8 +1302,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
DeclarationName(), nullptr, nullptr);
}

void VarTemplateDecl::LoadLazySpecializations() const {
loadLazySpecializationsImpl();
void VarTemplateDecl::LoadLazySpecializations(
bool OnlyPartial /*=false*/) const {
loadLazySpecializationsImpl(OnlyPartial);
}

llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
Expand All @@ -1271,7 +1315,7 @@ VarTemplateDecl::getSpecializations() const {

llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
VarTemplateDecl::getPartialSpecializations() const {
LoadLazySpecializations();
LoadLazySpecializations(/*PartialOnly = */ true);
return getCommonPtr()->PartialSpecializations;
}

Expand All @@ -1285,12 +1329,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
VarTemplateSpecializationDecl *
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
auto *Common = getCommonPtr();
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
}

void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
void *InsertPos) {
addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
auto *Common = getCommonPtr();
addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
}

VarTemplatePartialSpecializationDecl *
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1639,11 +1639,19 @@ SourceLocation CallExpr::getBeginLoc() const {
if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this))
return OCE->getBeginLoc();

if (const auto *Method =
dyn_cast_if_present<const CXXMethodDecl>(getCalleeDecl());
Method && Method->isExplicitObjectMemberFunction()) {
assert(getNumArgs() > 0 && getArg(0));
return getArg(0)->getBeginLoc();
}

SourceLocation begin = getCallee()->getBeginLoc();
if (begin.isInvalid() && getNumArgs() > 0 && getArg(0))
begin = getArg(0)->getBeginLoc();
return begin;
}

SourceLocation CallExpr::getEndLoc() const {
if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this))
return OCE->getEndLoc();
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/ExternalASTSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
return false;
}

bool ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {
return false;
}

bool ExternalASTSource::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument>) {
return false;
}

void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {}

void ExternalASTSource::FindExternalLexicalDecls(
Expand Down
23 changes: 14 additions & 9 deletions clang/lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -818,15 +818,20 @@ void ODRHash::AddDecl(const Decl *D) {

AddDeclarationName(ND->getDeclName());

const auto *Specialization =
dyn_cast<ClassTemplateSpecializationDecl>(D);
AddBoolean(Specialization);
if (Specialization) {
const TemplateArgumentList &List = Specialization->getTemplateArgs();
ID.AddInteger(List.size());
for (const TemplateArgument &TA : List.asArray())
AddTemplateArgument(TA);
}
// If this was a specialization we should take into account its template
// arguments. This helps to reduce collisions coming when visiting template
// specialization types (eg. when processing type template arguments).
ArrayRef<TemplateArgument> Args;
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
Args = CTSD->getTemplateArgs().asArray();
else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
Args = VTSD->getTemplateArgs().asArray();
else if (auto *FD = dyn_cast<FunctionDecl>(D))
if (FD->getTemplateSpecializationArgs())
Args = FD->getTemplateSpecializationArgs()->asArray();

for (auto &TA : Args)
AddTemplateArgument(TA);
}

namespace {
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10646,7 +10646,7 @@ Value *CodeGenFunction::EmitSMELd1St1(const SVETypeFlags &TypeFlags,
NewOps.push_back(Ops[2]);

llvm::Value *BasePtr = Ops[3];

llvm::Value *RealSlice = Ops[1];
// If the intrinsic contains the vnum parameter, multiply it with the vector
// size in bytes.
if (Ops.size() == 5) {
Expand All @@ -10658,10 +10658,13 @@ Value *CodeGenFunction::EmitSMELd1St1(const SVETypeFlags &TypeFlags,
Builder.CreateMul(StreamingVectorLengthCall, Ops[4], "mulvl");
// The type of the ptr parameter is void *, so use Int8Ty here.
BasePtr = Builder.CreateGEP(Int8Ty, Ops[3], Mulvl);
RealSlice = Builder.CreateZExt(RealSlice, Int64Ty);
RealSlice = Builder.CreateAdd(RealSlice, Ops[4]);
RealSlice = Builder.CreateTrunc(RealSlice, Int32Ty);
}
NewOps.push_back(BasePtr);
NewOps.push_back(Ops[0]);
NewOps.push_back(Ops[1]);
NewOps.push_back(RealSlice);
Function *F = CGM.getIntrinsic(IntID);
return Builder.CreateCall(F, NewOps);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4529,7 +4529,7 @@ void CodeGenFunction::EmitCallArgs(
ArgTypes.assign(MD->param_type_begin() + ParamsToSkip,
MD->param_type_end());
} else {
const auto *FPT = Prototype.P.get<const FunctionProtoType *>();
const auto *FPT = cast<const FunctionProtoType *>(Prototype.P);
IsVariadic = FPT->isVariadic();
ExplicitCC = FPT->getExtInfo().getCC();
ArgTypes.assign(FPT->param_type_begin() + ParamsToSkip,
Expand Down
14 changes: 7 additions & 7 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7770,7 +7770,7 @@ class MappableExprsHandler {
if (const auto *Base = Data.dyn_cast<const CXXRecordDecl *>())
getPlainLayout(Base, Layout, /*AsBase=*/true);
else
Layout.push_back(Data.get<const FieldDecl *>());
Layout.push_back(cast<const FieldDecl *>(Data));
}
}

Expand Down Expand Up @@ -8333,9 +8333,9 @@ class MappableExprsHandler {
MapCombinedInfoTy &CombinedInfo, llvm::OpenMPIRBuilder &OMPBuilder,
const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet =
llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const {
assert(CurDir.is<const OMPExecutableDirective *>() &&
assert(isa<const OMPExecutableDirective *>(CurDir) &&
"Expect a executable directive");
const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
generateAllInfoForClauses(CurExecDir->clauses(), CombinedInfo, OMPBuilder,
SkipVarSet);
}
Expand All @@ -8345,9 +8345,9 @@ class MappableExprsHandler {
/// in \a CombinedInfo).
void generateAllInfoForMapper(MapCombinedInfoTy &CombinedInfo,
llvm::OpenMPIRBuilder &OMPBuilder) const {
assert(CurDir.is<const OMPDeclareMapperDecl *>() &&
assert(isa<const OMPDeclareMapperDecl *>(CurDir) &&
"Expect a declare mapper directive");
const auto *CurMapperDir = CurDir.get<const OMPDeclareMapperDecl *>();
const auto *CurMapperDir = cast<const OMPDeclareMapperDecl *>(CurDir);
generateAllInfoForClauses(CurMapperDir->clauses(), CombinedInfo,
OMPBuilder);
}
Expand Down Expand Up @@ -8519,9 +8519,9 @@ class MappableExprsHandler {
DeclComponentLists.emplace_back(MCL, OMPC_MAP_tofrom, Unknown,
/*IsImpicit = */ true, nullptr,
nullptr);
assert(CurDir.is<const OMPExecutableDirective *>() &&
assert(isa<const OMPExecutableDirective *>(CurDir) &&
"Expect a executable directive");
const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
bool HasMapBasePtr = false;
bool HasMapArraySec = false;
for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/CodeGen/ConstantInitBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ using namespace CodeGen;

llvm::Type *ConstantInitFuture::getType() const {
assert(Data && "dereferencing null future");
if (Data.is<llvm::Constant*>()) {
return Data.get<llvm::Constant*>()->getType();
if (const auto *C = dyn_cast<llvm::Constant *>(Data)) {
return C->getType();
} else {
return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
return cast<ConstantInitBuilderBase *>(Data)->Buffer[0]->getType();
}
}

Expand All @@ -37,10 +37,10 @@ void ConstantInitFuture::abandon() {

void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
assert(Data && "installing null future");
if (Data.is<llvm::Constant*>()) {
GV->setInitializer(Data.get<llvm::Constant*>());
if (auto *C = dyn_cast<llvm::Constant *>(Data)) {
GV->setInitializer(C);
} else {
auto &builder = *Data.get<ConstantInitBuilderBase*>();
auto &builder = *cast<ConstantInitBuilderBase *>(Data);
assert(builder.Buffer.size() == 1);
builder.setGlobalInitializer(GV, builder.Buffer[0]);
builder.Buffer.clear();
Expand Down
27 changes: 15 additions & 12 deletions clang/lib/Format/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,18 @@ endforeach ()

add_custom_target(clang-format-check-format DEPENDS ${check_format_depends})

set(style_options_depends ${CLANG_SOURCE_DIR}/docs/ClangFormatStyleOptions.rst)
set(docs_tools_dir ${CLANG_SOURCE_DIR}/docs/tools)
add_custom_command(OUTPUT ${style_options_depends}
COMMAND ${Python3_EXECUTABLE} dump_format_style.py
WORKING_DIRECTORY ${docs_tools_dir}
DEPENDS ${CLANG_SOURCE_DIR}/include/clang/Format/Format.h
${CLANG_SOURCE_DIR}/include/clang/Tooling/Inclusions/IncludeStyle.h
${docs_tools_dir}/plurals.txt
${docs_tools_dir}/dump_format_style.py
)
add_custom_target(clang-format-style-options DEPENDS ${style_options_depends})
add_dependencies(clangFormat clang-format-style-options)
if(CLANG_INCLUDE_DOCS)
set(style_options_depends ${CMAKE_CURRENT_BINARY_DIR}/dummy_output)
set(docs_tools_dir ${CLANG_SOURCE_DIR}/docs/tools)
add_custom_command(OUTPUT ${style_options_depends}
COMMAND ${Python3_EXECUTABLE} dump_format_style.py &&
touch ${style_options_depends}
WORKING_DIRECTORY ${docs_tools_dir}
DEPENDS ${CLANG_SOURCE_DIR}/include/clang/Format/Format.h
${CLANG_SOURCE_DIR}/include/clang/Tooling/Inclusions/IncludeStyle.h
${CLANG_SOURCE_DIR}/docs/ClangFormatStyleOptions.rst
${docs_tools_dir}/plurals.txt
${docs_tools_dir}/dump_format_style.py
)
add_custom_target(clang-format-style-options DEPENDS ${style_options_depends})
endif()
2 changes: 1 addition & 1 deletion clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
if (LangOpts.getSYCLVersion() == LangOptions::SYCL_2017)
Builder.defineMacro("CL_SYCL_LANGUAGE_VERSION", "121");
else if (LangOpts.getSYCLVersion() == LangOptions::SYCL_2020)
Builder.defineMacro("SYCL_LANGUAGE_VERSION", "202001");
Builder.defineMacro("SYCL_LANGUAGE_VERSION", "202012L");
}

// Not "standard" per se, but available even with the -undef flag.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ IncrementalCompilerBuilder::CreateCpp() {
#ifdef __EMSCRIPTEN__
Argv.push_back("-target");
Argv.push_back("wasm32-unknown-emscripten");
Argv.push_back("-shared");
Argv.push_back("-fvisibility=default");
#endif
Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Lex/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ bool Lexer::getRawToken(SourceLocation Loc, Token &Result,

const char *StrData = Buffer.data()+LocInfo.second;

if (!IgnoreWhiteSpace && isWhitespace(StrData[0]))
if (!IgnoreWhiteSpace && isWhitespace(SkipEscapedNewLines(StrData)[0]))
return true;

// Create a lexer starting at the beginning of this token.
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Sema/MultiplexExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,23 @@ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
return AnyDeclsFound;
}

bool MultiplexExternalSemaSource::LoadExternalSpecializations(
const Decl *D, bool OnlyPartial) {
bool Loaded = false;
for (size_t i = 0; i < Sources.size(); ++i)
Loaded |= Sources[i]->LoadExternalSpecializations(D, OnlyPartial);
return Loaded;
}

bool MultiplexExternalSemaSource::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
bool AnyNewSpecsLoaded = false;
for (size_t i = 0; i < Sources.size(); ++i)
AnyNewSpecsLoaded |=
Sources[i]->LoadExternalSpecializations(D, TemplateArgs);
return AnyNewSpecsLoaded;
}

void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
for(size_t i = 0; i < Sources.size(); ++i)
Sources[i]->completeVisibleDeclsMap(DC);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "clang/AST/ASTLambda.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
Expand All @@ -30,6 +29,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/Type.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticComment.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
Expand Down
11 changes: 9 additions & 2 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7535,8 +7535,15 @@ void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) {
return;
}

if (DefKind.isComparison())
UnusedPrivateFields.clear();
if (DefKind.isComparison()) {
auto PT = FD->getParamDecl(0)->getType();
if (const CXXRecordDecl *RD =
PT.getNonReferenceType()->getAsCXXRecordDecl()) {
for (FieldDecl *Field : RD->fields()) {
UnusedPrivateFields.remove(Field);
}
}
}

if (DefKind.isSpecialMember()
? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD),
Expand Down
17 changes: 9 additions & 8 deletions clang/lib/Sema/SemaExceptionSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1205,15 +1205,16 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
if (DTy.isNull() || DTy->isDependentType()) {
CT = CT_Dependent;
} else {
CT = canCalleeThrow(*this, DE, DE->getOperatorDelete());
if (const RecordType *RT = DTy->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
const CXXDestructorDecl *DD = RD->getDestructor();
if (DD)
CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));
const FunctionDecl *OperatorDelete = DE->getOperatorDelete();
CT = canCalleeThrow(*this, DE, OperatorDelete);
if (!OperatorDelete->isDestroyingOperatorDelete()) {
if (const auto *RD = DTy->getAsCXXRecordDecl()) {
if (const CXXDestructorDecl *DD = RD->getDestructor())
CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));
}
if (CT == CT_Can)
return CT;
}
if (CT == CT_Can)
return CT;
}
return mergeCanThrow(CT, canSubStmtsThrow(*this, DE));
}
Expand Down
587 changes: 360 additions & 227 deletions clang/lib/Sema/SemaOpenACC.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15575,7 +15575,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Build the actual expression node.
ExprResult FnExpr =
CreateFunctionRefExpr(*this, Method, FoundDecl, MemExpr,
HadMultipleCandidates, MemExpr->getBeginLoc());
HadMultipleCandidates, MemExpr->getExprLoc());
if (FnExpr.isInvalid())
return ExprError();

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -12027,7 +12027,9 @@ void OpenACCClauseTransform<Derived>::VisitGangClause(
if (!ER.isUsable())
continue;

ER = Self.getSema().OpenACC().CheckGangExpr(C.getExpr(I).first, ER.get());
ER = Self.getSema().OpenACC().CheckGangExpr(ExistingClauses,
ParsedClause.getDirectiveKind(),
C.getExpr(I).first, ER.get());
if (!ER.isUsable())
continue;
TransformedGangKinds.push_back(C.getExpr(I).first);
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/ASTCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ namespace serialization {

enum DeclUpdateKind {
UPD_CXX_ADDED_IMPLICIT_MEMBER,
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_ADDED_VAR_DEFINITION,
Expand Down
237 changes: 228 additions & 9 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "TemplateArgumentHasher.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
Expand Down Expand Up @@ -1295,6 +1296,42 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type,
}
}

ModuleFile *
LazySpecializationInfoLookupTrait::ReadFileRef(const unsigned char *&d) {
using namespace llvm::support;

uint32_t ModuleFileID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
return Reader.getLocalModuleFile(F, ModuleFileID);
}

LazySpecializationInfoLookupTrait::internal_key_type
LazySpecializationInfoLookupTrait::ReadKey(const unsigned char *d, unsigned) {
using namespace llvm::support;
return endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
}

std::pair<unsigned, unsigned>
LazySpecializationInfoLookupTrait::ReadKeyDataLength(const unsigned char *&d) {
return readULEBKeyDataLength(d);
}

void LazySpecializationInfoLookupTrait::ReadDataInto(internal_key_type,
const unsigned char *d,
unsigned DataLen,
data_type_builder &Val) {
using namespace llvm::support;

for (unsigned NumDecls =
DataLen / sizeof(serialization::reader::LazySpecializationInfo);
NumDecls; --NumDecls) {
LocalDeclID LocalID = LocalDeclID::get(
Reader, F,
endian::readNext<DeclID, llvm::endianness::little, unaligned>(d));
Val.insert(Reader.getGlobalDeclID(F, LocalID));
}
}

bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M,
BitstreamCursor &Cursor,
uint64_t Offset,
Expand Down Expand Up @@ -1379,7 +1416,52 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M,
// We can't safely determine the primary context yet, so delay attaching the
// lookup table until we're done with recursive deserialization.
auto *Data = (const unsigned char*)Blob.data();
PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data});
PendingVisibleUpdates[ID].push_back(UpdateData{&M, Data});
return false;
}

void ASTReader::AddSpecializations(const Decl *D, const unsigned char *Data,
ModuleFile &M, bool IsPartial) {
D = D->getCanonicalDecl();
auto &SpecLookups =
IsPartial ? PartialSpecializationsLookups : SpecializationsLookups;
SpecLookups[D].Table.add(&M, Data,
reader::LazySpecializationInfoLookupTrait(*this, M));
}

bool ASTReader::ReadSpecializations(ModuleFile &M, BitstreamCursor &Cursor,
uint64_t Offset, Decl *D, bool IsPartial) {
assert(Offset != 0);

SavedStreamPosition SavedPosition(Cursor);
if (llvm::Error Err = Cursor.JumpToBit(Offset)) {
Error(std::move(Err));
return true;
}

RecordData Record;
StringRef Blob;
Expected<unsigned> MaybeCode = Cursor.ReadCode();
if (!MaybeCode) {
Error(MaybeCode.takeError());
return true;
}
unsigned Code = MaybeCode.get();

Expected<unsigned> MaybeRecCode = Cursor.readRecord(Code, Record, &Blob);
if (!MaybeRecCode) {
Error(MaybeRecCode.takeError());
return true;
}
unsigned RecCode = MaybeRecCode.get();
if (RecCode != DECL_SPECIALIZATIONS &&
RecCode != DECL_PARTIAL_SPECIALIZATIONS) {
Error("Expected decl specs block");
return true;
}

auto *Data = (const unsigned char *)Blob.data();
AddSpecializations(D, Data, M, IsPartial);
return false;
}

Expand Down Expand Up @@ -3458,7 +3540,33 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
unsigned Idx = 0;
GlobalDeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char*)Blob.data();
PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data});
PendingVisibleUpdates[ID].push_back(UpdateData{&F, Data});
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
PendingUpdateRecords.push_back(
PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
break;
}

case CXX_ADDED_TEMPLATE_SPECIALIZATION: {
unsigned Idx = 0;
GlobalDeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char *)Blob.data();
PendingSpecializationsUpdates[ID].push_back(UpdateData{&F, Data});
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
PendingUpdateRecords.push_back(
PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
break;
}

case CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION: {
unsigned Idx = 0;
GlobalDeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char *)Blob.data();
PendingPartialSpecializationsUpdates[ID].push_back(UpdateData{&F, Data});
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
Expand Down Expand Up @@ -7654,13 +7762,28 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
}
}

if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
CTSD->getSpecializedTemplate()->LoadLazySpecializations();
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
VTSD->getSpecializedTemplate()->LoadLazySpecializations();
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
if (auto *Template = FD->getPrimaryTemplate())
Template->LoadLazySpecializations();
RedeclarableTemplateDecl *Template = nullptr;
ArrayRef<TemplateArgument> Args;
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
Template = CTSD->getSpecializedTemplate();
Args = CTSD->getTemplateArgs().asArray();
} else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
Template = VTSD->getSpecializedTemplate();
Args = VTSD->getTemplateArgs().asArray();
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
if (auto *Tmplt = FD->getPrimaryTemplate()) {
Template = Tmplt;
Args = FD->getTemplateSpecializationArgs()->asArray();
}
}

if (Template) {
// For partitial specialization, load all the specializations for safety.
if (isa<ClassTemplatePartialSpecializationDecl,
VarTemplatePartialSpecializationDecl>(D))
Template->loadLazySpecializationsImpl();
else
Template->loadLazySpecializationsImpl(Args);
}
}

Expand Down Expand Up @@ -8042,6 +8165,86 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
return ReadStmtFromStream(*Loc.F);
}

bool ASTReader::LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
const Decl *D) {
assert(D);

auto It = SpecLookups.find(D);
if (It == SpecLookups.end())
return false;

// Get Decl may violate the iterator from SpecializationsLookups so we store
// the DeclIDs in ahead.
llvm::SmallVector<serialization::reader::LazySpecializationInfo, 8> Infos =
It->second.Table.findAll();

// Since we've loaded all the specializations, we can erase it from
// the lookup table.
SpecLookups.erase(It);

bool NewSpecsFound = false;
Deserializing LookupResults(this);
for (auto &Info : Infos) {
if (GetExistingDecl(Info))
continue;
NewSpecsFound = true;
GetDecl(Info);
}

return NewSpecsFound;
}

bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
assert(D);

bool NewSpecsFound =
LoadExternalSpecializationsImpl(PartialSpecializationsLookups, D);
if (OnlyPartial)
return NewSpecsFound;

NewSpecsFound |= LoadExternalSpecializationsImpl(SpecializationsLookups, D);
return NewSpecsFound;
}

bool ASTReader::LoadExternalSpecializationsImpl(
SpecLookupTableTy &SpecLookups, const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) {
assert(D);

auto It = SpecLookups.find(D);
if (It == SpecLookups.end())
return false;

Deserializing LookupResults(this);
auto HashValue = StableHashForTemplateArguments(TemplateArgs);

// Get Decl may violate the iterator from SpecLookups
llvm::SmallVector<serialization::reader::LazySpecializationInfo, 8> Infos =
It->second.Table.find(HashValue);

bool NewSpecsFound = false;
for (auto &Info : Infos) {
if (GetExistingDecl(Info))
continue;
NewSpecsFound = true;
GetDecl(Info);
}

return NewSpecsFound;
}

bool ASTReader::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
assert(D);

bool NewDeclsFound = LoadExternalSpecializationsImpl(
PartialSpecializationsLookups, D, TemplateArgs);
NewDeclsFound |=
LoadExternalSpecializationsImpl(SpecializationsLookups, D, TemplateArgs);

return NewDeclsFound;
}

void ASTReader::FindExternalLexicalDecls(
const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
SmallVectorImpl<Decl *> &Decls) {
Expand Down Expand Up @@ -8221,6 +8424,22 @@ ASTReader::getLoadedLookupTables(DeclContext *Primary) const {
return I == Lookups.end() ? nullptr : &I->second;
}

serialization::reader::LazySpecializationInfoLookupTable *
ASTReader::getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial) {
assert(D->isCanonicalDecl());
auto &LookupTable =
IsPartial ? PartialSpecializationsLookups : SpecializationsLookups;
auto I = LookupTable.find(D);
return I == LookupTable.end() ? nullptr : &I->second;
}

bool ASTReader::haveUnloadedSpecializations(const Decl *D) const {
assert(D->isCanonicalDecl());
return (PartialSpecializationsLookups.find(D) !=
PartialSpecializationsLookups.end()) ||
(SpecializationsLookups.find(D) != SpecializationsLookups.end());
}

/// Under non-PCH compilation the consumer receives the objc methods
/// before receiving the implementation, and codegen depends on this.
/// We simulate this by deserializing and passing to consumer the methods of the
Expand Down
104 changes: 43 additions & 61 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,6 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {

std::string readString() { return Record.readString(); }

void readDeclIDList(SmallVectorImpl<GlobalDeclID> &IDs) {
for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I)
IDs.push_back(readDeclID());
}

Decl *readDecl() { return Record.readDecl(); }

template <typename T> T *readDeclAs() { return Record.readDeclAs<T>(); }
Expand Down Expand Up @@ -284,30 +279,6 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
: Reader(Reader), MergeImpl(Reader), Record(Record), Loc(Loc),
ThisDeclID(thisDeclID), ThisDeclLoc(ThisDeclLoc) {}

template <typename T>
static void AddLazySpecializations(T *D, SmallVectorImpl<GlobalDeclID> &IDs) {
if (IDs.empty())
return;

// FIXME: We should avoid this pattern of getting the ASTContext.
ASTContext &C = D->getASTContext();

auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;

if (auto &Old = LazySpecializations) {
IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].getRawValue());
llvm::sort(IDs);
IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
}

auto *Result = new (C) GlobalDeclID[1 + IDs.size()];
*Result = GlobalDeclID(IDs.size());

std::copy(IDs.begin(), IDs.end(), Result + 1);

LazySpecializations = Result;
}

template <typename DeclT>
static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
static Decl *getMostRecentDeclImpl(...);
Expand All @@ -332,10 +303,13 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
static void markIncompleteDeclChainImpl(Redeclarable<DeclT> *D);
static void markIncompleteDeclChainImpl(...);

void ReadSpecializations(ModuleFile &M, Decl *D,
llvm::BitstreamCursor &DeclsCursor, bool IsPartial);

void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);

void UpdateDecl(Decl *D, SmallVectorImpl<GlobalDeclID> &);
void UpdateDecl(Decl *D);

static void setNextObjCCategory(ObjCCategoryDecl *Cat,
ObjCCategoryDecl *Next) {
Expand Down Expand Up @@ -2418,6 +2392,16 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
}

void ASTDeclReader::ReadSpecializations(ModuleFile &M, Decl *D,
llvm::BitstreamCursor &DeclsCursor,
bool IsPartial) {
uint64_t Offset = ReadLocalOffset();
bool Failed =
Reader.ReadSpecializations(M, DeclsCursor, Offset, D, IsPartial);
(void)Failed;
assert(!Failed);
}

RedeclarableResult
ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
Expand Down Expand Up @@ -2456,9 +2440,8 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
SmallVector<GlobalDeclID, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true);
}

if (D->getTemplatedDecl()->TemplateOrInstantiation) {
Expand All @@ -2484,9 +2467,8 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
SmallVector<GlobalDeclID, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true);
}
}

Expand Down Expand Up @@ -2585,9 +2567,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {

if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
SmallVector<GlobalDeclID, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
}
}

Expand Down Expand Up @@ -3877,6 +3857,8 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
switch ((DeclCode)MaybeDeclCode.get()) {
case DECL_CONTEXT_LEXICAL:
case DECL_CONTEXT_VISIBLE:
case DECL_SPECIALIZATIONS:
case DECL_PARTIAL_SPECIALIZATIONS:
llvm_unreachable("Record cannot be de-serialized with readDeclRecord");
case DECL_TYPEDEF:
D = TypedefDecl::CreateDeserialized(Context, ID);
Expand Down Expand Up @@ -4286,8 +4268,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);

SmallVector<GlobalDeclID, 8> PendingLazySpecializationIDs;

if (UpdI != DeclUpdateOffsets.end()) {
auto UpdateOffsets = std::move(UpdI->second);
DeclUpdateOffsets.erase(UpdI);
Expand Down Expand Up @@ -4324,7 +4304,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {

ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID,
SourceLocation());
Reader.UpdateDecl(D, PendingLazySpecializationIDs);
Reader.UpdateDecl(D);

// We might have made this declaration interesting. If so, remember that
// we need to hand it off to the consumer.
Expand All @@ -4334,17 +4314,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
}
}
}
// Add the lazy specializations to the template.
assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) ||
isa<FunctionTemplateDecl, VarTemplateDecl>(D)) &&
"Must not have pending specializations");
if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs);
else if (auto *VTD = dyn_cast<VarTemplateDecl>(D))
ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs);
PendingLazySpecializationIDs.clear();

// Load the pending visible updates for this decl context, if it has any.
auto I = PendingVisibleUpdates.find(ID);
Expand All @@ -4369,6 +4338,26 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
FunctionToLambdasMap.erase(IT);
}
}

// Load the pending specializations update for this decl, if it has any.
if (auto I = PendingSpecializationsUpdates.find(ID);
I != PendingSpecializationsUpdates.end()) {
auto SpecializationUpdates = std::move(I->second);
PendingSpecializationsUpdates.erase(I);

for (const auto &Update : SpecializationUpdates)
AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/false);
}

// Load the pending specializations update for this decl, if it has any.
if (auto I = PendingPartialSpecializationsUpdates.find(ID);
I != PendingPartialSpecializationsUpdates.end()) {
auto SpecializationUpdates = std::move(I->second);
PendingPartialSpecializationsUpdates.erase(I);

for (const auto &Update : SpecializationUpdates)
AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/true);
}
}

void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) {
Expand Down Expand Up @@ -4561,9 +4550,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
}
}

void ASTDeclReader::UpdateDecl(
Decl *D,
llvm::SmallVectorImpl<GlobalDeclID> &PendingLazySpecializationIDs) {
void ASTDeclReader::UpdateDecl(Decl *D) {
while (Record.getIdx() < Record.size()) {
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
Expand All @@ -4574,11 +4561,6 @@ void ASTDeclReader::UpdateDecl(
break;
}

case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's lazy specialization set.
PendingLazySpecializationIDs.push_back(readDeclID());
break;

case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
auto *Anon = readDeclAs<NamespaceDecl>();

Expand Down
82 changes: 82 additions & 0 deletions clang/lib/Serialization/ASTReaderInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,88 @@ struct DeclContextLookupTable {
MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table;
};

using LazySpecializationInfo = GlobalDeclID;

/// Class that performs lookup to specialized decls.
class LazySpecializationInfoLookupTrait {
ASTReader &Reader;
ModuleFile &F;

public:
// Maximum number of lookup tables we allow before condensing the tables.
static const int MaxTables = 4;

/// The lookup result is a list of global declaration IDs.
using data_type = SmallVector<LazySpecializationInfo, 4>;

struct data_type_builder {
data_type &Data;
llvm::DenseSet<LazySpecializationInfo> Found;

data_type_builder(data_type &D) : Data(D) {}

void insert(LazySpecializationInfo Info) {
// Just use a linear scan unless we have more than a few IDs.
if (Found.empty() && !Data.empty()) {
if (Data.size() <= 4) {
for (auto I : Found)
if (I == Info)
return;
Data.push_back(Info);
return;
}

// Switch to tracking found IDs in the set.
Found.insert(Data.begin(), Data.end());
}

if (Found.insert(Info).second)
Data.push_back(Info);
}
};
using hash_value_type = unsigned;
using offset_type = unsigned;
using file_type = ModuleFile *;

using external_key_type = unsigned;
using internal_key_type = unsigned;

explicit LazySpecializationInfoLookupTrait(ASTReader &Reader, ModuleFile &F)
: Reader(Reader), F(F) {}

static bool EqualKey(const internal_key_type &a, const internal_key_type &b) {
return a == b;
}

static hash_value_type ComputeHash(const internal_key_type &Key) {
return Key;
}

static internal_key_type GetInternalKey(const external_key_type &Name) {
return Name;
}

static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char *&d);

internal_key_type ReadKey(const unsigned char *d, unsigned);

void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen,
data_type_builder &Val);

static void MergeDataInto(const data_type &From, data_type_builder &To) {
To.Data.reserve(To.Data.size() + From.size());
for (LazySpecializationInfo Info : From)
To.insert(Info);
}

file_type ReadFileRef(const unsigned char *&d);
};

struct LazySpecializationInfoLookupTable {
MultiOnDiskHashTable<LazySpecializationInfoLookupTrait> Table;
};

/// Base class for the trait describing the on-disk hash table for the
/// identifiers in an AST file.
///
Expand Down
256 changes: 239 additions & 17 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "MultiOnDiskHashTable.h"
#include "TemplateArgumentHasher.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/AbstractTypeWriter.h"
Expand Down Expand Up @@ -184,14 +185,30 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
const SourceManager &SM = PP.getSourceManager();
const ModuleMap &MM = HS.getModuleMap();

llvm::DenseSet<FileID> ModuleMaps;

llvm::DenseSet<const Module *> ProcessedModules;
auto CollectModuleMapsForHierarchy = [&](const Module *M) {
// Module maps used only by textual headers are special. Their FileID is
// non-affecting, but their FileEntry is (i.e. must be written as InputFile).
enum AffectedReason : bool {
AR_TextualHeader = 0,
AR_ImportOrTextualHeader = 1,
};
auto AssignMostImportant = [](AffectedReason &LHS, AffectedReason RHS) {
LHS = std::max(LHS, RHS);
};
llvm::DenseMap<FileID, AffectedReason> ModuleMaps;
llvm::DenseMap<const Module *, AffectedReason> ProcessedModules;
auto CollectModuleMapsForHierarchy = [&](const Module *M,
AffectedReason Reason) {
M = M->getTopLevelModule();

if (!ProcessedModules.insert(M).second)
// We need to process the header either when it was not present or when we
// previously flagged module map as textual headers and now we found a
// proper import.
if (auto [It, Inserted] = ProcessedModules.insert({M, Reason});
!Inserted && Reason <= It->second) {
return;
} else {
It->second = Reason;
}

std::queue<const Module *> Q;
Q.push(M);
Expand All @@ -202,12 +219,12 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
// The containing module map is affecting, because it's being pointed
// into by Module::DefinitionLoc.
if (auto F = MM.getContainingModuleMapFileID(Mod); F.isValid())
ModuleMaps.insert(F);
AssignMostImportant(ModuleMaps[F], Reason);
// For inferred modules, the module map that allowed inferring is not
// related to the virtual containing module map file. It did affect the
// compilation, though.
if (auto UniqF = MM.getModuleMapFileIDForUniquing(Mod); UniqF.isValid())
ModuleMaps.insert(UniqF);
AssignMostImportant(ModuleMaps[UniqF], Reason);

for (auto *SubM : Mod->submodules())
Q.push(SubM);
Expand All @@ -216,7 +233,7 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {

// Handle all the affecting modules referenced from the root module.

CollectModuleMapsForHierarchy(RootModule);
CollectModuleMapsForHierarchy(RootModule, AR_ImportOrTextualHeader);

std::queue<const Module *> Q;
Q.push(RootModule);
Expand All @@ -225,9 +242,9 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
Q.pop();

for (const Module *ImportedModule : CurrentModule->Imports)
CollectModuleMapsForHierarchy(ImportedModule);
CollectModuleMapsForHierarchy(ImportedModule, AR_ImportOrTextualHeader);
for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses)
CollectModuleMapsForHierarchy(UndeclaredModule);
CollectModuleMapsForHierarchy(UndeclaredModule, AR_ImportOrTextualHeader);

for (auto *M : CurrentModule->submodules())
Q.push(M);
Expand Down Expand Up @@ -256,7 +273,7 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {

for (const auto &KH : HS.findResolvedModulesForHeader(*File))
if (const Module *M = KH.getModule())
CollectModuleMapsForHierarchy(M);
CollectModuleMapsForHierarchy(M, AR_TextualHeader);
}

// FIXME: This algorithm is not correct for module map hierarchies where
Expand All @@ -278,13 +295,16 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
// includes a module map defining a module that's not a submodule of X.

llvm::DenseSet<const FileEntry *> ModuleFileEntries;
for (FileID MM : ModuleMaps) {
if (auto *FE = SM.getFileEntryForID(MM))
llvm::DenseSet<FileID> ModuleFileIDs;
for (auto [FID, Reason] : ModuleMaps) {
if (Reason == AR_ImportOrTextualHeader)
ModuleFileIDs.insert(FID);
if (auto *FE = SM.getFileEntryForID(FID))
ModuleFileEntries.insert(FE);
}

AffectingModuleMaps R;
R.DefinitionFileIDs = std::move(ModuleMaps);
R.DefinitionFileIDs = std::move(ModuleFileIDs);
R.DefinitionFiles = std::move(ModuleFileEntries);
return std::move(R);
}
Expand Down Expand Up @@ -4148,6 +4168,175 @@ class ASTDeclContextNameLookupTrait {

} // namespace

namespace {
class LazySpecializationInfoLookupTrait {
ASTWriter &Writer;
llvm::SmallVector<serialization::reader::LazySpecializationInfo, 64> Specs;

public:
using key_type = unsigned;
using key_type_ref = key_type;

/// A start and end index into Specs, representing a sequence of decls.
using data_type = std::pair<unsigned, unsigned>;
using data_type_ref = const data_type &;

using hash_value_type = unsigned;
using offset_type = unsigned;

explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer)
: Writer(Writer) {}

template <typename Col, typename Col2>
data_type getData(Col &&C, Col2 &ExistingInfo) {
unsigned Start = Specs.size();
for (auto *D : C) {
NamedDecl *ND = getDeclForLocalLookup(Writer.getLangOpts(),
const_cast<NamedDecl *>(D));
Specs.push_back(GlobalDeclID(Writer.GetDeclRef(ND).getRawValue()));
}
for (const serialization::reader::LazySpecializationInfo &Info :
ExistingInfo)
Specs.push_back(Info);
return std::make_pair(Start, Specs.size());
}

data_type ImportData(
const reader::LazySpecializationInfoLookupTrait::data_type &FromReader) {
unsigned Start = Specs.size();
for (auto ID : FromReader)
Specs.push_back(ID);
return std::make_pair(Start, Specs.size());
}

static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; }

hash_value_type ComputeHash(key_type Name) { return Name; }

void EmitFileRef(raw_ostream &Out, ModuleFile *F) const {
assert(Writer.hasChain() &&
"have reference to loaded module file but no chain?");

using namespace llvm::support;
endian::write<uint32_t>(Out, Writer.getChain()->getModuleFileID(F),
llvm::endianness::little);
}

std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out,
key_type HashValue,
data_type_ref Lookup) {
// 4 bytes for each slot.
unsigned KeyLen = 4;
unsigned DataLen = sizeof(serialization::reader::LazySpecializationInfo) *
(Lookup.second - Lookup.first);

return emitULEBKeyDataLength(KeyLen, DataLen, Out);
}

void EmitKey(raw_ostream &Out, key_type HashValue, unsigned) {
using namespace llvm::support;

endian::Writer LE(Out, llvm::endianness::little);
LE.write<uint32_t>(HashValue);
}

void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup,
unsigned DataLen) {
using namespace llvm::support;

endian::Writer LE(Out, llvm::endianness::little);
uint64_t Start = Out.tell();
(void)Start;
for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) {
LE.write<DeclID>(Specs[I].getRawValue());
}
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
};

unsigned CalculateODRHashForSpecs(const Decl *Spec) {
ArrayRef<TemplateArgument> Args;
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec))
Args = CTSD->getTemplateArgs().asArray();
else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec))
Args = VTSD->getTemplateArgs().asArray();
else if (auto *FD = dyn_cast<FunctionDecl>(Spec))
Args = FD->getTemplateSpecializationArgs()->asArray();
else
llvm_unreachable("New Specialization Kind?");

return StableHashForTemplateArguments(Args);
}
} // namespace

void ASTWriter::GenerateSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial) {
assert(D->isFirstDecl());

// Create the on-disk hash table representation.
MultiOnDiskHashTableGenerator<reader::LazySpecializationInfoLookupTrait,
LazySpecializationInfoLookupTrait>
Generator;
LazySpecializationInfoLookupTrait Trait(*this);

llvm::DenseMap<unsigned, llvm::SmallVector<const NamedDecl *, 4>>
SpecializationMaps;

for (auto *Specialization : Specializations) {
unsigned HashedValue = CalculateODRHashForSpecs(Specialization);

auto Iter = SpecializationMaps.find(HashedValue);
if (Iter == SpecializationMaps.end())
Iter = SpecializationMaps
.try_emplace(HashedValue,
llvm::SmallVector<const NamedDecl *, 4>())
.first;

Iter->second.push_back(cast<NamedDecl>(Specialization));
}

auto *Lookups =
Chain ? Chain->getLoadedSpecializationsLookupTables(D, IsPartial)
: nullptr;

for (auto &[HashValue, Specs] : SpecializationMaps) {
SmallVector<serialization::reader::LazySpecializationInfo, 16>
ExisitingSpecs;
// We have to merge the lookup table manually here. We can't depend on the
// merge mechanism offered by
// clang::serialization::MultiOnDiskHashTableGenerator since that generator
// assumes the we'll get the same value with the same key.
// And also underlying llvm::OnDiskChainedHashTableGenerator assumes that we
// won't insert the values with the same key twice. So we have to merge the
// lookup table here manually.
if (Lookups)
ExisitingSpecs = Lookups->Table.find(HashValue);

Generator.insert(HashValue, Trait.getData(Specs, ExisitingSpecs), Trait);
}

Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr);
}

uint64_t ASTWriter::WriteSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
bool IsPartial) {

llvm::SmallString<4096> LookupTable;
GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable,
IsPartial);

uint64_t Offset = Stream.GetCurrentBitNo();
RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS
: DECL_SPECIALIZATIONS};
Stream.EmitRecordWithBlob(IsPartial ? DeclPartialSpecializationsAbbrev
: DeclSpecializationsAbbrev,
Record, LookupTable);

return Offset;
}

bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
DeclContext *DC) {
return Result.hasExternalDecls() &&
Expand Down Expand Up @@ -5729,7 +5918,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
// Keep writing types, declarations, and declaration update records
// until we've emitted all of them.
RecordData DeclUpdatesOffsetsRecord;
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5);
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/ 6);
DeclTypesBlockStartOffset = Stream.GetCurrentBitNo();
WriteTypeAbbrevs();
WriteDeclAbbrevs();
Expand Down Expand Up @@ -5803,6 +5992,16 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
FunctionToLambdaMapAbbrev);
}

if (!SpecializationsUpdates.empty()) {
WriteSpecializationsUpdates(/*IsPartial=*/false);
SpecializationsUpdates.clear();
}

if (!PartialSpecializationsUpdates.empty()) {
WriteSpecializationsUpdates(/*IsPartial=*/true);
PartialSpecializationsUpdates.clear();
}

const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
Expand Down Expand Up @@ -5846,6 +6045,31 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
WriteDeclContextVisibleUpdate(Context, DC);
}

void ASTWriter::WriteSpecializationsUpdates(bool IsPartial) {
auto RecordType = IsPartial ? CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION
: CXX_ADDED_TEMPLATE_SPECIALIZATION;

auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
Abv->Add(llvm::BitCodeAbbrevOp(RecordType));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv));

auto &SpecUpdates =
IsPartial ? PartialSpecializationsUpdates : SpecializationsUpdates;
for (auto &SpecializationUpdate : SpecUpdates) {
const NamedDecl *D = SpecializationUpdate.first;

llvm::SmallString<4096> LookupTable;
GenerateSpecializationInfoLookupTable(D, SpecializationUpdate.second,
LookupTable, IsPartial);

// Write the lookup table
RecordData::value_type Record[] = {RecordType, getDeclID(D).getRawValue()};
Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable);
}
}

void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,
RecordDataImpl &OffsetsRecord) {
if (DeclUpdates.empty())
Expand Down Expand Up @@ -5875,12 +6099,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,

switch (Kind) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
assert(Update.getDecl() && "no decl to add?");
Record.AddDeclRef(Update.getDecl());
break;

case UPD_CXX_ADDED_FUNCTION_DEFINITION:
case UPD_CXX_ADDED_VAR_DEFINITION:
break;
Expand Down
110 changes: 79 additions & 31 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,22 +177,54 @@ namespace clang {
Record.AddSourceLocation(typeParams->getRAngleLoc());
}

/// Add to the record the first declaration from each module file that
/// provides a declaration of D. The intent is to provide a sufficient
/// set such that reloading this set will load all current redeclarations.
void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) {
llvm::MapVector<ModuleFile*, const Decl*> Firsts;
/// Collect the first declaration from each module file that provides a
/// declaration of D.
void CollectFirstDeclFromEachModule(
const Decl *D, bool IncludeLocal,
llvm::MapVector<ModuleFile *, const Decl *> &Firsts) {

// FIXME: We can skip entries that we know are implied by others.
for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) {
if (R->isFromASTFile())
Firsts[Writer.Chain->getOwningModuleFile(R)] = R;
else if (IncludeLocal)
Firsts[nullptr] = R;
}
}

/// Add to the record the first declaration from each module file that
/// provides a declaration of D. The intent is to provide a sufficient
/// set such that reloading this set will load all current redeclarations.
void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) {
llvm::MapVector<ModuleFile *, const Decl *> Firsts;
CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts);

for (const auto &F : Firsts)
Record.AddDeclRef(F.second);
}

/// Add to the record the first template specialization from each module
/// file that provides a declaration of D. We store the DeclId and an
/// ODRHash of the template arguments of D which should provide enough
/// information to load D only if the template instantiator needs it.
void AddFirstSpecializationDeclFromEachModule(
const Decl *D, llvm::SmallVectorImpl<const Decl *> &SpecsInMap,
llvm::SmallVectorImpl<const Decl *> &PartialSpecsInMap) {
assert((isa<ClassTemplateSpecializationDecl>(D) ||
isa<VarTemplateSpecializationDecl>(D) || isa<FunctionDecl>(D)) &&
"Must not be called with other decls");
llvm::MapVector<ModuleFile *, const Decl *> Firsts;
CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts);

for (const auto &F : Firsts) {
if (isa<ClassTemplatePartialSpecializationDecl,
VarTemplatePartialSpecializationDecl>(F.second))
PartialSpecsInMap.push_back(F.second);
else
SpecsInMap.push_back(F.second);
}
}

/// Get the specialization decl from an entry in the specialization list.
template <typename EntryType>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
Expand All @@ -205,8 +237,9 @@ namespace clang {
decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) {
return Common->PartialSpecializations;
}
ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) {
return {};
MutableArrayRef<FunctionTemplateSpecializationInfo>
getPartialSpecializations(FunctionTemplateDecl::Common *) {
return std::nullopt;
}

template<typename DeclTy>
Expand All @@ -217,37 +250,37 @@ namespace clang {
// our chained AST reader, we can just write out the DeclIDs. Otherwise,
// we need to resolve them to actual declarations.
if (Writer.Chain != Record.getASTContext().getExternalSource() &&
Common->LazySpecializations) {
Writer.Chain && Writer.Chain->haveUnloadedSpecializations(D)) {
D->LoadLazySpecializations();
assert(!Common->LazySpecializations);
assert(!Writer.Chain->haveUnloadedSpecializations(D));
}

ArrayRef<GlobalDeclID> LazySpecializations;
if (auto *LS = Common->LazySpecializations)
LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].getRawValue());

// Add a slot to the record for the number of specializations.
unsigned I = Record.size();
Record.push_back(0);

// AddFirstDeclFromEachModule might trigger deserialization, invalidating
// *Specializations iterators.
llvm::SmallVector<const Decl*, 16> Specs;
// AddFirstSpecializationDeclFromEachModule might trigger deserialization,
// invalidating *Specializations iterators.
llvm::SmallVector<const Decl *, 16> AllSpecs;
for (auto &Entry : Common->Specializations)
Specs.push_back(getSpecializationDecl(Entry));
AllSpecs.push_back(getSpecializationDecl(Entry));
for (auto &Entry : getPartialSpecializations(Common))
Specs.push_back(getSpecializationDecl(Entry));
AllSpecs.push_back(getSpecializationDecl(Entry));

for (auto *D : Specs) {
llvm::SmallVector<const Decl *, 16> Specs;
llvm::SmallVector<const Decl *, 16> PartialSpecs;
for (auto *D : AllSpecs) {
assert(D->isCanonicalDecl() && "non-canonical decl in set");
AddFirstDeclFromEachModule(D, /*IncludeLocal*/true);
AddFirstSpecializationDeclFromEachModule(D, Specs, PartialSpecs);
}

Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
D, Specs, /*IsPartial=*/false));

// Function Template Decl doesn't have partial decls.
if (isa<FunctionTemplateDecl>(D)) {
assert(PartialSpecs.empty());
return;
}
Record.append(
DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.begin()),
DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.end()));

// Update the size entry we added earlier.
Record[I] = Record.size() - I - 1;
Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
D, PartialSpecs, /*IsPartial=*/true));
}

/// Ensure that this template specialization is associated with the specified
Expand All @@ -268,8 +301,13 @@ namespace clang {
if (Writer.getFirstLocalDecl(Specialization) != Specialization)
return;

Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate(
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization));
if (isa<ClassTemplatePartialSpecializationDecl,
VarTemplatePartialSpecializationDecl>(Specialization))
Writer.PartialSpecializationsUpdates[cast<NamedDecl>(Template)]
.push_back(cast<NamedDecl>(Specialization));
else
Writer.SpecializationsUpdates[cast<NamedDecl>(Template)].push_back(
cast<NamedDecl>(Specialization));
}
};
}
Expand Down Expand Up @@ -2774,6 +2812,16 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(std::move(Abv));

Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_SPECIALIZATIONS));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
DeclSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv));

Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARTIAL_SPECIALIZATIONS));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
DeclPartialSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv));
}

/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_clang_library(clangSerialization
ModuleManager.cpp
PCHContainerOperations.cpp
ObjectFilePCHContainerReader.cpp
TemplateArgumentHasher.cpp

ADDITIONAL_HEADERS
ASTCommon.h
Expand Down
Loading