131 changes: 98 additions & 33 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,85 @@ using IdentifierID = uint32_t;
/// discovery), with values below NUM_PREDEF_DECL_IDS being reserved.
/// At the start of a chain of precompiled headers, declaration ID 1 is
/// used for the translation unit declaration.
///
/// FIXME: Merge with Decl::DeclID
using DeclID = uint32_t;

// FIXME: Turn these into classes so we can have some type safety when
// we go from local ID to global and vice-versa.
using LocalDeclID = DeclID;
using GlobalDeclID = DeclID;
class LocalDeclID {
public:
explicit LocalDeclID(DeclID ID) : ID(ID) {}

DeclID get() const { return ID; }

private:
DeclID ID;
};

/// Wrapper class for DeclID. This is helpful to not mix the use of LocalDeclID
/// and GlobalDeclID to improve the type safety.
class GlobalDeclID {
public:
GlobalDeclID() : ID(0) {}
explicit GlobalDeclID(DeclID ID) : ID(ID) {}

DeclID get() const { return ID; }

explicit operator DeclID() const { return ID; }

friend bool operator==(const GlobalDeclID &LHS, const GlobalDeclID &RHS) {
return LHS.ID == RHS.ID;
}
friend bool operator!=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) {
return LHS.ID != RHS.ID;
}
// We may sort the global decl ID.
friend bool operator<(const GlobalDeclID &LHS, const GlobalDeclID &RHS) {
return LHS.ID < RHS.ID;
}
friend bool operator>(const GlobalDeclID &LHS, const GlobalDeclID &RHS) {
return LHS.ID > RHS.ID;
}
friend bool operator<=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) {
return LHS.ID <= RHS.ID;
}
friend bool operator>=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) {
return LHS.ID >= RHS.ID;
}

private:
DeclID ID;
};

/// A helper iterator adaptor to convert the iterators to `SmallVector<DeclID>`
/// to the iterators to `SmallVector<GlobalDeclID>`.
class GlobalDeclIDIterator
: public llvm::iterator_adaptor_base<GlobalDeclIDIterator, const DeclID *,
std::forward_iterator_tag,
GlobalDeclID> {
public:
GlobalDeclIDIterator() : iterator_adaptor_base(nullptr) {}

GlobalDeclIDIterator(const DeclID *ID) : iterator_adaptor_base(ID) {}

value_type operator*() const { return GlobalDeclID(*I); }

bool operator==(const GlobalDeclIDIterator &RHS) const { return I == RHS.I; }
};

/// A helper iterator adaptor to convert the iterators to
/// `SmallVector<GlobalDeclID>` to the iterators to `SmallVector<DeclID>`.
class DeclIDIterator
: public llvm::iterator_adaptor_base<DeclIDIterator, const GlobalDeclID *,
std::forward_iterator_tag, DeclID> {
public:
DeclIDIterator() : iterator_adaptor_base(nullptr) {}

DeclIDIterator(const GlobalDeclID *ID) : iterator_adaptor_base(ID) {}

value_type operator*() const { return DeclID(*I); }

bool operator==(const DeclIDIterator &RHS) const { return I == RHS.I; }
};

/// An ID number that refers to a type in an AST file.
///
Expand Down Expand Up @@ -2056,35 +2129,6 @@ enum CtorInitializerType {
/// Kinds of cleanup objects owned by ExprWithCleanups.
enum CleanupObjectKind { COK_Block, COK_CompoundLiteral };

/// Describes the redeclarations of a declaration.
struct LocalRedeclarationsInfo {
// The ID of the first declaration
DeclID FirstID;

// Offset into the array of redeclaration chains.
unsigned Offset;

friend bool operator<(const LocalRedeclarationsInfo &X,
const LocalRedeclarationsInfo &Y) {
return X.FirstID < Y.FirstID;
}

friend bool operator>(const LocalRedeclarationsInfo &X,
const LocalRedeclarationsInfo &Y) {
return X.FirstID > Y.FirstID;
}

friend bool operator<=(const LocalRedeclarationsInfo &X,
const LocalRedeclarationsInfo &Y) {
return X.FirstID <= Y.FirstID;
}

friend bool operator>=(const LocalRedeclarationsInfo &X,
const LocalRedeclarationsInfo &Y) {
return X.FirstID >= Y.FirstID;
}
};

/// Describes the categories of an Objective-C class.
struct ObjCCategoriesInfo {
// The ID of the definition
Expand Down Expand Up @@ -2187,6 +2231,27 @@ template <> struct DenseMapInfo<clang::serialization::DeclarationNameKey> {
}
};

template <> struct DenseMapInfo<clang::serialization::GlobalDeclID> {
using DeclID = clang::serialization::DeclID;
using GlobalDeclID = clang::serialization::GlobalDeclID;

static GlobalDeclID getEmptyKey() {
return GlobalDeclID(DenseMapInfo<DeclID>::getEmptyKey());
}

static GlobalDeclID getTombstoneKey() {
return GlobalDeclID(DenseMapInfo<DeclID>::getTombstoneKey());
}

static unsigned getHashValue(const GlobalDeclID &Key) {
return DenseMapInfo<DeclID>::getHashValue(Key.get());
}

static bool isEqual(const GlobalDeclID &L, const GlobalDeclID &R) {
return L == R;
}
};

} // namespace llvm

#endif // LLVM_CLANG_SERIALIZATION_ASTBITCODES_H
98 changes: 59 additions & 39 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ class ASTReader
static_assert(std::is_same_v<serialization::DeclID, Decl::DeclID>);

using GlobalDeclMapType =
ContinuousRangeMap<serialization::DeclID, ModuleFile *, 4>;
ContinuousRangeMap<serialization::GlobalDeclID, ModuleFile *, 4>;

/// Mapping from global declaration IDs to the module in which the
/// declaration resides.
Expand All @@ -513,14 +513,14 @@ class ASTReader
using FileOffset = std::pair<ModuleFile *, uint64_t>;
using FileOffsetsTy = SmallVector<FileOffset, 2>;
using DeclUpdateOffsetsMap =
llvm::DenseMap<serialization::DeclID, FileOffsetsTy>;
llvm::DenseMap<serialization::GlobalDeclID, FileOffsetsTy>;

/// Declarations that have modifications residing in a later file
/// in the chain.
DeclUpdateOffsetsMap DeclUpdateOffsets;

using DelayedNamespaceOffsetMapTy = llvm::DenseMap<
serialization::DeclID,
serialization::GlobalDeclID,
std::pair</*LexicalOffset*/ uint64_t, /*VisibleOffset*/ uint64_t>>;

/// Mapping from global declaration IDs to the lexical and visible block
Expand Down Expand Up @@ -606,7 +606,11 @@ class ASTReader

/// An array of lexical contents of a declaration context, as a sequence of
/// Decl::Kind, DeclID pairs.
using LexicalContents = ArrayRef<llvm::support::unaligned_uint32_t>;
using unalighed_decl_id_t =
llvm::support::detail::packed_endian_specific_integral<
serialization::DeclID, llvm::endianness::native,
llvm::support::unaligned>;
using LexicalContents = ArrayRef<unalighed_decl_id_t>;

/// Map from a DeclContext to its lexical contents.
llvm::DenseMap<const DeclContext*, std::pair<ModuleFile*, LexicalContents>>
Expand All @@ -631,7 +635,7 @@ class ASTReader

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

/// The set of C++ or Objective-C classes that have forward
Expand All @@ -658,7 +662,8 @@ class ASTReader
/// Read the record that describes the visible contents of a DC.
bool ReadVisibleDeclContextStorage(ModuleFile &M,
llvm::BitstreamCursor &Cursor,
uint64_t Offset, serialization::DeclID ID);
uint64_t Offset,
serialization::GlobalDeclID ID);

/// A vector containing identifiers that have already been
/// loaded.
Expand Down Expand Up @@ -811,29 +816,38 @@ class ASTReader
/// This contains the data loaded from all EAGERLY_DESERIALIZED_DECLS blocks
/// in the chain. The referenced declarations are deserialized and passed to
/// the consumer eagerly.
SmallVector<serialization::DeclID, 16> EagerlyDeserializedDecls;
SmallVector<serialization::GlobalDeclID, 16> EagerlyDeserializedDecls;

/// The IDs of all tentative definitions stored in the chain.
///
/// Sema keeps track of all tentative definitions in a TU because it has to
/// complete them and pass them on to CodeGen. Thus, tentative definitions in
/// the PCH chain must be eagerly deserialized.
SmallVector<serialization::DeclID, 16> TentativeDefinitions;
SmallVector<serialization::GlobalDeclID, 16> TentativeDefinitions;

/// The IDs of all CXXRecordDecls stored in the chain whose VTables are
/// used.
///
/// CodeGen has to emit VTables for these records, so they have to be eagerly
/// deserialized.
SmallVector<serialization::DeclID, 64> VTableUses;
struct VTableUse {
serialization::GlobalDeclID ID;
SourceLocation::UIntTy RawLoc;
bool Used;
};
SmallVector<VTableUse> VTableUses;

/// A snapshot of the pending instantiations in the chain.
///
/// This record tracks the instantiations that Sema has to perform at the
/// end of the TU. It consists of a pair of values for every pending
/// instantiation where the first value is the ID of the decl and the second
/// is the instantiation location.
SmallVector<serialization::DeclID, 64> PendingInstantiations;
struct PendingInstantiation {
serialization::GlobalDeclID ID;
SourceLocation::UIntTy RawLoc;
};
SmallVector<PendingInstantiation, 64> PendingInstantiations;

//@}

Expand All @@ -843,11 +857,11 @@ class ASTReader

/// A snapshot of Sema's unused file-scoped variable tracking, for
/// generating warnings.
SmallVector<serialization::DeclID, 16> UnusedFileScopedDecls;
SmallVector<serialization::GlobalDeclID, 16> UnusedFileScopedDecls;

/// A list of all the delegating constructors we've seen, to diagnose
/// cycles.
SmallVector<serialization::DeclID, 4> DelegatingCtorDecls;
SmallVector<serialization::GlobalDeclID, 4> DelegatingCtorDecls;

/// Method selectors used in a @selector expression. Used for
/// implementation of -Wselector.
Expand All @@ -860,7 +874,7 @@ class ASTReader
/// The IDs of type aliases for ext_vectors that exist in the chain.
///
/// Used by Sema for finding sugared names for ext_vectors in diagnostics.
SmallVector<serialization::DeclID, 4> ExtVectorDecls;
SmallVector<serialization::GlobalDeclID, 4> ExtVectorDecls;

//@}

Expand All @@ -871,7 +885,7 @@ class ASTReader
/// The IDs of all potentially unused typedef names in the chain.
///
/// Sema tracks these to emit warnings.
SmallVector<serialization::DeclID, 16> UnusedLocalTypedefNameCandidates;
SmallVector<serialization::GlobalDeclID, 16> UnusedLocalTypedefNameCandidates;

/// Our current depth in #pragma cuda force_host_device begin/end
/// macros.
Expand All @@ -880,7 +894,7 @@ class ASTReader
/// The IDs of the declarations Sema stores directly.
///
/// Sema tracks a few important decls, such as namespace std, directly.
SmallVector<serialization::DeclID, 4> SemaDeclRefs;
SmallVector<serialization::GlobalDeclID, 4> SemaDeclRefs;

/// The IDs of the types ASTContext stores directly.
///
Expand All @@ -891,7 +905,7 @@ class ASTReader
///
/// The AST context tracks a few important decls, currently cudaConfigureCall,
/// directly.
SmallVector<serialization::DeclID, 2> CUDASpecialDeclRefs;
SmallVector<serialization::GlobalDeclID, 2> CUDASpecialDeclRefs;

/// The floating point pragma option settings.
SmallVector<uint64_t, 1> FPPragmaOptions;
Expand Down Expand Up @@ -940,11 +954,15 @@ class ASTReader
llvm::DenseMap<const Decl *, std::set<std::string>> OpenCLDeclExtMap;

/// A list of the namespaces we've seen.
SmallVector<serialization::DeclID, 4> KnownNamespaces;
SmallVector<serialization::GlobalDeclID, 4> KnownNamespaces;

/// A list of undefined decls with internal linkage followed by the
/// SourceLocation of a matching ODR-use.
SmallVector<serialization::DeclID, 8> UndefinedButUsed;
struct UndefinedButUsedDecl {
serialization::GlobalDeclID ID;
SourceLocation::UIntTy RawLoc;
};
SmallVector<UndefinedButUsedDecl, 8> UndefinedButUsed;

/// Delete expressions to analyze at the end of translation unit.
SmallVector<uint64_t, 8> DelayedDeleteExprs;
Expand All @@ -956,7 +974,8 @@ class ASTReader
/// The IDs of all decls to be checked for deferred diags.
///
/// Sema tracks these to emit deferred diags.
llvm::SmallSetVector<serialization::DeclID, 4> DeclsToCheckForDeferredDiags;
llvm::SmallSetVector<serialization::GlobalDeclID, 4>
DeclsToCheckForDeferredDiags;

private:
struct ImportedSubmodule {
Expand Down Expand Up @@ -1093,8 +1112,8 @@ class ASTReader
///
/// The declarations on the identifier chain for these identifiers will be
/// loaded once the recursive loading has completed.
llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4>>
PendingIdentifierInfos;
llvm::MapVector<IdentifierInfo *, SmallVector<serialization::GlobalDeclID, 4>>
PendingIdentifierInfos;

/// The set of lookup results that we have faked in order to support
/// merging of partially deserialized decls but that we have not yet removed.
Expand Down Expand Up @@ -1221,7 +1240,7 @@ class ASTReader
SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded;

using KeyDeclsMap =
llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2>>;
llvm::DenseMap<Decl *, SmallVector<serialization::GlobalDeclID, 2>>;

/// A mapping from canonical declarations to the set of global
/// declaration IDs for key declaration that have been merged with that
Expand Down Expand Up @@ -1430,15 +1449,15 @@ class ASTReader
QualType readTypeRecord(unsigned Index);
RecordLocation TypeCursorForIndex(unsigned Index);
void LoadedDecl(unsigned Index, Decl *D);
Decl *ReadDeclRecord(serialization::DeclID ID);
Decl *ReadDeclRecord(serialization::GlobalDeclID ID);
void markIncompleteDeclChain(Decl *D);

/// Returns the most recent declaration of a declaration (which must be
/// of a redeclarable kind) that is either local or has already been loaded
/// merged into its redecl chain.
Decl *getMostRecentExistingDecl(Decl *D);

RecordLocation DeclCursorForID(serialization::DeclID ID,
RecordLocation DeclCursorForID(serialization::GlobalDeclID ID,
SourceLocation &Location);
void loadDeclUpdateRecords(PendingUpdateRecord &Record);
void loadPendingDeclChain(Decl *D, uint64_t LocalOffset);
Expand Down Expand Up @@ -1897,8 +1916,8 @@ class ASTReader

/// Map from a local declaration ID within a given module to a
/// global declaration ID.
serialization::DeclID getGlobalDeclID(ModuleFile &F,
serialization::LocalDeclID LocalID) const;
serialization::GlobalDeclID
getGlobalDeclID(ModuleFile &F, serialization::LocalDeclID LocalID) const;

/// Returns true if global DeclID \p ID originated from module \p M.
bool isDeclIDFromModule(serialization::GlobalDeclID ID, ModuleFile &M) const;
Expand All @@ -1912,23 +1931,23 @@ class ASTReader

/// Resolve a declaration ID into a declaration, potentially
/// building a new declaration.
Decl *GetDecl(serialization::DeclID ID);
Decl *GetExternalDecl(uint32_t ID) override;
Decl *GetDecl(serialization::GlobalDeclID ID);
Decl *GetExternalDecl(Decl::DeclID ID) override;

/// Resolve a declaration ID into a declaration. Return 0 if it's not
/// been loaded yet.
Decl *GetExistingDecl(serialization::DeclID ID);
Decl *GetExistingDecl(serialization::GlobalDeclID ID);

/// Reads a declaration with the given local ID in the given module.
Decl *GetLocalDecl(ModuleFile &F, uint32_t LocalID) {
Decl *GetLocalDecl(ModuleFile &F, serialization::LocalDeclID LocalID) {
return GetDecl(getGlobalDeclID(F, LocalID));
}

/// Reads a declaration with the given local ID in the given module.
///
/// \returns The requested declaration, casted to the given return type.
template<typename T>
T *GetLocalDeclAs(ModuleFile &F, uint32_t LocalID) {
template <typename T>
T *GetLocalDeclAs(ModuleFile &F, serialization::LocalDeclID LocalID) {
return cast_or_null<T>(GetLocalDecl(F, LocalID));
}

Expand All @@ -1939,14 +1958,14 @@ class ASTReader
/// module file.
serialization::DeclID
mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
serialization::DeclID GlobalID);
serialization::GlobalDeclID GlobalID);

/// Reads a declaration ID from the given position in a record in the
/// given module.
///
/// \returns The declaration ID read from the record, adjusted to a global ID.
serialization::DeclID ReadDeclID(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
serialization::GlobalDeclID
ReadDeclID(ModuleFile &F, const RecordData &Record, unsigned &Idx);

/// Reads a declaration from the given position in a record in the
/// given module.
Expand Down Expand Up @@ -2120,9 +2139,10 @@ class ASTReader
void LoadSelector(Selector Sel);

void SetIdentifierInfo(unsigned ID, IdentifierInfo *II);
void SetGloballyVisibleDecls(IdentifierInfo *II,
const SmallVectorImpl<uint32_t> &DeclIDs,
SmallVectorImpl<Decl *> *Decls = nullptr);
void SetGloballyVisibleDecls(
IdentifierInfo *II,
const SmallVectorImpl<serialization::GlobalDeclID> &DeclIDs,
SmallVectorImpl<Decl *> *Decls = nullptr);

/// Report a diagnostic.
DiagnosticBuilder Diag(unsigned DiagID) const;
Expand Down Expand Up @@ -2363,7 +2383,7 @@ class ASTReader

// Contains the IDs for declarations that were requested before we have
// access to a Sema object.
SmallVector<uint64_t, 16> PreloadedDeclIDs;
SmallVector<serialization::GlobalDeclID, 16> PreloadedDeclIDs;

/// Retrieve the semantic analysis object used to analyze the
/// translation unit in which the precompiled header is being
Expand Down
12 changes: 2 additions & 10 deletions clang/include/clang/Serialization/ASTRecordReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,6 @@ class ASTRecordReader
DC);
}

/// Read the record that describes the visible contents of a DC.
bool readVisibleDeclContextStorage(uint64_t Offset,
serialization::DeclID ID) {
return Reader->ReadVisibleDeclContextStorage(*F, F->DeclsCursor, Offset,
ID);
}

ExplicitSpecifier readExplicitSpec() {
uint64_t Kind = readInt();
bool HasExpr = Kind & 0x1;
Expand Down Expand Up @@ -143,8 +136,7 @@ class ASTRecordReader
/// Reads a declaration with the given local ID in the given module.
///
/// \returns The requested declaration, casted to the given return type.
template<typename T>
T *GetLocalDeclAs(uint32_t LocalID) {
template <typename T> T *GetLocalDeclAs(serialization::LocalDeclID LocalID) {
return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID));
}

Expand Down Expand Up @@ -190,7 +182,7 @@ class ASTRecordReader
/// Reads a declaration ID from the given position in this record.
///
/// \returns The declaration ID read from the record, adjusted to a global ID.
serialization::DeclID readDeclID() {
serialization::GlobalDeclID readDeclID() {
return Reader->ReadDeclID(*F, Record, Idx);
}

Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ class ModuleFile {
serialization::DeclID BaseDeclID = 0;

/// Remapping table for declaration IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> DeclRemap;
ContinuousRangeMap<serialization::DeclID, int, 2> DeclRemap;

/// Mapping from the module files that this module file depends on
/// to the base declaration ID for that module as it is understood within this
Expand All @@ -474,7 +474,7 @@ class ModuleFile {
llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs;

/// Array of file-level DeclIDs sorted by file.
const serialization::DeclID *FileSortedDecls = nullptr;
const serialization::LocalDeclID *FileSortedDecls = nullptr;
unsigned NumFileSortedDecls = 0;

/// Array of category list location information within this
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Support/RISCVVIntrinsicUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,8 @@ enum RVVRequire : uint32_t {
RVV_REQ_Zvksed = 1 << 14,
RVV_REQ_Zvksh = 1 << 15,
RVV_REQ_Zvfbfwma = 1 << 16,
RVV_REQ_Experimental = 1 << 17,
RVV_REQ_Zvfbfmin = 1 << 17,
RVV_REQ_Experimental = 1 << 18,

LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_Experimental)
};
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,8 @@ void ASTContext::addModuleInitializer(Module *M, Decl *D) {
Inits->Initializers.push_back(D);
}

void ASTContext::addLazyModuleInitializers(Module *M, ArrayRef<uint32_t> IDs) {
void ASTContext::addLazyModuleInitializers(Module *M,
ArrayRef<Decl::DeclID> IDs) {
auto *&Inits = ModuleInitializers[M];
if (!Inits)
Inits = new (*this) PerModuleInitializers;
Expand Down Expand Up @@ -7241,6 +7242,14 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
// We perform that promotion here to match GCC and C++.
// FIXME: C does not permit promotion of an enum bit-field whose rank is
// greater than that of 'int'. We perform that promotion to match GCC.
//
// C23 6.3.1.1p2:
// The value from a bit-field of a bit-precise integer type is converted to
// the corresponding bit-precise integer type. (The rest is the same as in
// C11.)
if (QualType QT = Field->getType(); QT->isBitIntType())
return QT;

if (BitWidth < IntSize)
return IntTy;

Expand Down
27 changes: 20 additions & 7 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ namespace clang {
// Returns true if the given function has a placeholder return type and
// that type is declared inside the body of the function.
// E.g. auto f() { struct X{}; return X(); }
bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D);
bool hasReturnTypeDeclaredInside(FunctionDecl *D);
};

template <typename InContainerTy>
Expand Down Expand Up @@ -3647,15 +3647,28 @@ class IsTypeDeclaredInsideVisitor
};
} // namespace

/// This function checks if the function has 'auto' return type that contains
/// This function checks if the given function has a return type that contains
/// a reference (in any way) to a declaration inside the same function.
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
bool ASTNodeImporter::hasReturnTypeDeclaredInside(FunctionDecl *D) {
QualType FromTy = D->getType();
const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
assert(FromFPT && "Must be called on FunctionProtoType");

auto IsCXX11LambdaWithouTrailingReturn = [&]() {
if (Importer.FromContext.getLangOpts().CPlusPlus14) // C++14 or later
return false;

if (FromFPT->hasTrailingReturn())
return false;

if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
return cast<CXXRecordDecl>(MD->getDeclContext())->isLambda();

return false;
};

QualType RetT = FromFPT->getReturnType();
if (isa<AutoType>(RetT.getTypePtr())) {
if (isa<AutoType>(RetT.getTypePtr()) || IsCXX11LambdaWithouTrailingReturn()) {
FunctionDecl *Def = D->getDefinition();
IsTypeDeclaredInsideVisitor Visitor(Def ? Def : D);
return Visitor.CheckType(RetT);
Expand Down Expand Up @@ -3811,7 +3824,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// E.g.: auto foo() { struct X{}; return X(); }
// To avoid an infinite recursion when importing, create the FunctionDecl
// with a simplified return type.
if (hasAutoReturnTypeDeclaredInside(D)) {
if (hasReturnTypeDeclaredInside(D)) {
FromReturnTy = Importer.getFromContext().VoidTy;
UsedDifferentProtoType = true;
}
Expand Down Expand Up @@ -8561,8 +8574,8 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {

return UnresolvedLookupExpr::Create(
Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr,
ToNameInfo, E->requiresADL(), E->isOverloaded(), ToDecls.begin(),
ToDecls.end());
ToNameInfo, E->requiresADL(), ToDecls.begin(), ToDecls.end(),
/*KnownDependent=*/E->isTypeDependent());
}

ExpectedStmt
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
if (CommonBasePtr->LazySpecializations) {
ASTContext &Context = getASTContext();
uint32_t *Specs = CommonBasePtr->LazySpecializations;
Decl::DeclID *Specs = CommonBasePtr->LazySpecializations;
CommonBasePtr->LazySpecializations = nullptr;
for (uint32_t I = 0, N = *Specs++; I != N; ++I)
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
Expand Down
28 changes: 14 additions & 14 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,15 +353,14 @@ SourceLocation CXXPseudoDestructorExpr::getEndLoc() const {
UnresolvedLookupExpr::UnresolvedLookupExpr(
const ASTContext &Context, CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded,
const DeclarationNameInfo &NameInfo, bool RequiresADL,
const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin,
UnresolvedSetIterator End, bool KnownDependent)
: OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc,
TemplateKWLoc, NameInfo, TemplateArgs, Begin, End,
KnownDependent, false, false),
NamingClass(NamingClass) {
UnresolvedLookupExprBits.RequiresADL = RequiresADL;
UnresolvedLookupExprBits.Overloaded = Overloaded;
}

UnresolvedLookupExpr::UnresolvedLookupExpr(EmptyShell Empty,
Expand All @@ -373,15 +372,16 @@ UnresolvedLookupExpr::UnresolvedLookupExpr(EmptyShell Empty,
UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
const ASTContext &Context, CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
bool RequiresADL, bool Overloaded, UnresolvedSetIterator Begin,
UnresolvedSetIterator End) {
bool RequiresADL, UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent) {
unsigned NumResults = End - Begin;
unsigned Size = totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc>(NumResults, 0, 0);
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
SourceLocation(), NameInfo, RequiresADL,
Overloaded, nullptr, Begin, End, false);
return new (Mem) UnresolvedLookupExpr(
Context, NamingClass, QualifierLoc,
/*TemplateKWLoc=*/SourceLocation(), NameInfo, RequiresADL,
/*TemplateArgs=*/nullptr, Begin, End, KnownDependent);
}

UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
Expand All @@ -390,16 +390,16 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
const DeclarationNameInfo &NameInfo, bool RequiresADL,
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
UnresolvedSetIterator End, bool KnownDependent) {
assert(Args || TemplateKWLoc.isValid());
unsigned NumResults = End - Begin;
bool HasTemplateKWAndArgsInfo = Args || TemplateKWLoc.isValid();
unsigned NumTemplateArgs = Args ? Args->size() : 0;
unsigned Size =
totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc>(NumResults, 1, NumTemplateArgs);
unsigned Size = totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc>(
NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs);
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
return new (Mem) UnresolvedLookupExpr(
Context, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, RequiresADL,
/*Overloaded=*/true, Args, Begin, End, KnownDependent);
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
TemplateKWLoc, NameInfo, RequiresADL,
Args, Begin, End, KnownDependent);
}

UnresolvedLookupExpr *UnresolvedLookupExpr::CreateEmpty(
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16853,13 +16853,13 @@ bool Expr::EvaluateCharRangeAsString(std::string &Result,
if (!::EvaluateInteger(SizeExpression, SizeValue, Info))
return false;

int64_t Size = SizeValue.getExtValue();
uint64_t Size = SizeValue.getZExtValue();

if (!::EvaluatePointer(PtrExpression, String, Info))
return false;

QualType CharTy = PtrExpression->getType()->getPointeeType();
for (int64_t I = 0; I < Size; ++I) {
for (uint64_t I = 0; I < Size; ++I) {
APValue Char;
if (!handleLValueToRValueConversion(Info, PtrExpression, CharTy, String,
Char))
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/AST/ExternalASTSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ bool ExternalASTSource::layoutRecordType(
return false;
}

Decl *ExternalASTSource::GetExternalDecl(uint32_t ID) {
return nullptr;
}
Decl *ExternalASTSource::GetExternalDecl(Decl::DeclID ID) { return nullptr; }

Selector ExternalASTSource::GetExternalSelector(uint32_t ID) {
return Selector();
Expand Down
30 changes: 26 additions & 4 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return false;

PrimType T = classifyPrim(CE->getType());
if (T == PT_IntAP)
return this->emitCastPointerIntegralAP(Ctx.getBitWidth(CE->getType()),
CE);
if (T == PT_IntAPS)
return this->emitCastPointerIntegralAPS(Ctx.getBitWidth(CE->getType()),
CE);
return this->emitCastPointerIntegral(T, CE);
}

Expand Down Expand Up @@ -922,9 +928,9 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
return true;
}

if (QT->isAnyComplexType()) {
if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
assert(Initializing);
QualType ElemQT = QT->getAs<ComplexType>()->getElementType();
QualType ElemQT = ComplexTy->getElementType();
PrimType ElemT = classifyPrim(ElemQT);
for (unsigned I = 0; I < 2; ++I) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
Expand All @@ -935,6 +941,20 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
return true;
}

if (const auto *VecT = E->getType()->getAs<VectorType>()) {
unsigned NumVecElements = VecT->getNumElements();
QualType ElemQT = VecT->getElementType();
PrimType ElemT = classifyPrim(ElemQT);

for (unsigned I = 0; I < NumVecElements; ++I) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}
return true;
}

return false;
}

Expand Down Expand Up @@ -1098,13 +1118,13 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
return true;
}

if (T->isAnyComplexType()) {
if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
unsigned NumInits = E->getNumInits();

if (NumInits == 1)
return this->delegate(E->inits()[0]);

QualType ElemQT = E->getType()->getAs<ComplexType>()->getElementType();
QualType ElemQT = ComplexTy->getElementType();
PrimType ElemT = classifyPrim(ElemQT);
if (NumInits == 0) {
// Zero-initialize both elements.
Expand Down Expand Up @@ -1337,6 +1357,8 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
if (const auto *FD = dyn_cast<FieldDecl>(Member)) {
const RecordDecl *RD = FD->getParent();
const Record *R = getRecord(RD);
if (!R)
return false;
const Record::Field *F = R->getField(FD);
// Leave a pointer to the field on the stack.
if (F->Decl->getType()->isReferenceType())
Expand Down
25 changes: 24 additions & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,30 @@ bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) {

template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
// Ignore all attributes.

for (const Attr *A : S->getAttrs()) {
auto *AA = dyn_cast<CXXAssumeAttr>(A);
if (!AA)
continue;

assert(isa<NullStmt>(S->getSubStmt()));

const Expr *Assumption = AA->getAssumption();
if (Assumption->isValueDependent())
return false;

if (Assumption->HasSideEffects(this->Ctx.getASTContext()))
continue;

// Evaluate assumption.
if (!this->visitBool(Assumption))
return false;

if (!this->emitAssume(Assumption))
return false;
}

// Ignore other attributes.
return this->visitStmt(S->getSubStmt());
}

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/Interp/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ template <bool Signed> class IntegralAP final {
}

IntegralAP truncate(unsigned BitWidth) const {
return IntegralAP(V.trunc(BitWidth));
if constexpr (Signed)
return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth()));
else
return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth()));
}

IntegralAP<false> toUnsigned() const {
Expand Down
63 changes: 51 additions & 12 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1548,17 +1548,16 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
if (!CheckArray(S, OpPC, Ptr))
return false;

// Get a version of the index comparable to the type.
T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
// Compute the largest index into the array.
T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
uint64_t Index = Ptr.getIndex();
uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());

bool Invalid = false;
// Helper to report an invalid offset, computed as APSInt.
auto DiagInvalidOffset = [&]() -> void {
const unsigned Bits = Offset.bitWidth();
APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
/*IsUnsigned=*/false);
APSInt NewIndex =
(Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
Expand All @@ -1569,22 +1568,24 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
};

if (Ptr.isBlockPointer()) {
T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
uint64_t IOffset = static_cast<uint64_t>(Offset);
uint64_t MaxOffset = MaxIndex - Index;

if constexpr (Op == ArithOp::Add) {
// If the new offset would be negative, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isPositive() && Offset > MaxOffset)
if (Offset.isPositive() && IOffset > MaxOffset)
DiagInvalidOffset();
} else {
// If the new offset would be negative, bail out.
if (Offset.isPositive() && Index < Offset)
if (Offset.isPositive() && Index < IOffset)
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
DiagInvalidOffset();
}
}
Expand All @@ -1601,7 +1602,7 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
else
Result = WideIndex - WideOffset;

S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
return true;
}

Expand Down Expand Up @@ -1832,6 +1833,32 @@ bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
return true;
}

static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
uint32_t BitWidth) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);

S.Stk.push<IntegralAP<false>>(
IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth));
return true;
}

static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
uint32_t BitWidth) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);

S.Stk.push<IntegralAP<true>>(
IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth));
return true;
}

//===----------------------------------------------------------------------===//
// Zero, Nullptr
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2300,6 +2327,18 @@ inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
return CheckDeclRef(S, OpPC, DR);
}

inline bool Assume(InterpState &S, CodePtr OpPC) {
const auto Val = S.Stk.pop<Boolean>();

if (Val)
return true;

// Else, diagnose.
const SourceLocation &Loc = S.Current->getLocation(OpPC);
S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
return false;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
llvm::SmallVector<int64_t> ArrayIndices;
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Boolean.h"
#include "Interp.h"
#include "PrimType.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
Expand Down Expand Up @@ -1088,6 +1089,17 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
return false;
}

static bool interp__builtin_os_log_format_buffer_size(InterpState &S,
CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
analyze_os_log::OSLogBufferLayout Layout;
analyze_os_log::computeOSLogBufferLayout(S.getCtx(), Call, Layout);
pushInteger(S, Layout.size().getQuantity(), Call->getType());
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
const InterpFrame *Frame = S.Current;
Expand Down Expand Up @@ -1409,6 +1421,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_os_log_format_buffer_size:
if (!interp__builtin_os_log_format_buffer_size(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand Down
15 changes: 13 additions & 2 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -664,10 +664,19 @@ def CastFloatingIntegralAPS : Opcode {
}

def CastPointerIntegral : Opcode {
let Types = [AluTypeClass];
let Args = [];
let Types = [FixedSizeIntegralTypeClass];
let HasGroup = 1;
}
def CastPointerIntegralAP : Opcode {
let Types = [];
let HasGroup = 0;
let Args = [ArgUint32];
}
def CastPointerIntegralAPS : Opcode {
let Types = [];
let HasGroup = 0;
let Args = [ArgUint32];
}

def DecayPtr : Opcode {
let Types = [PtrTypeClass, PtrTypeClass];
Expand Down Expand Up @@ -727,6 +736,8 @@ def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef];
}

def Assume : Opcode;

def ArrayDecay : Opcode;

def CheckNonNullArg : Opcode {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Pointer::Pointer(Block *Pointee)
: Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
Pointee->getDescriptor()->getMetadataSize()) {}

Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}

Pointer::Pointer(const Pointer &P)
Expand All @@ -34,7 +34,7 @@ Pointer::Pointer(const Pointer &P)
PointeeStorage.BS.Pointee->addPointer(this);
}

Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
: Offset(Offset), StorageKind(Storage::Block) {
assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");

Expand Down
12 changes: 6 additions & 6 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ class Pointer {
PointeeStorage.Int.Desc = nullptr;
}
Pointer(Block *B);
Pointer(Block *B, unsigned BaseAndOffset);
Pointer(Block *B, uint64_t BaseAndOffset);
Pointer(const Pointer &P);
Pointer(Pointer &&P);
Pointer(uint64_t Address, const Descriptor *Desc, unsigned Offset = 0)
Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Int) {
PointeeStorage.Int.Value = Address;
PointeeStorage.Int.Desc = Desc;
Expand Down Expand Up @@ -134,14 +134,14 @@ class Pointer {
std::optional<APValue> toRValue(const Context &Ctx) const;

/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(unsigned Idx) const {
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
if (isIntegralPointer())
return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);

if (asBlockPointer().Base == RootPtrMark)
return Pointer(asBlockPointer().Pointee, RootPtrMark,
getDeclDesc()->getSize());
unsigned Off = Idx * elemSize();
uint64_t Off = Idx * elemSize();
if (getFieldDesc()->ElemDesc)
Off += sizeof(InlineDescriptor);
else
Expand Down Expand Up @@ -630,7 +630,7 @@ class Pointer {
friend class DeadBlock;
friend struct InitMap;

Pointer(Block *Pointee, unsigned Base, unsigned Offset);
Pointer(Block *Pointee, unsigned Base, uint64_t Offset);

/// Returns the embedded descriptor preceding a field.
InlineDescriptor *getInlineDesc() const {
Expand All @@ -656,7 +656,7 @@ class Pointer {
}

/// Offset into the storage.
unsigned Offset = 0;
uint64_t Offset = 0;

/// Previous link in the pointer chain.
Pointer *Prev = nullptr;
Expand Down
15 changes: 5 additions & 10 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,23 @@ Pointer Program::getPtrGlobal(unsigned Idx) const {
}

std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
auto It = GlobalIndices.find(VD);
if (It != GlobalIndices.end())
if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
return It->second;

// Find any previous declarations which were already evaluated.
std::optional<unsigned> Index;
for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
auto It = GlobalIndices.find(P);
if (It != GlobalIndices.end()) {
for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) {
if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) {
Index = It->second;
break;
}
}

// Map the decl to the existing index.
if (Index) {
if (Index)
GlobalIndices[VD] = *Index;
return std::nullopt;
}

return Index;
return std::nullopt;
}

std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
Expand Down Expand Up @@ -173,7 +169,6 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {

std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
const Expr *Init) {
assert(!getGlobal(VD));
bool IsStatic, IsExtern;
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = Context::shouldBeGloballyIndexed(VD);
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,33 +1062,35 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
// ::= <local-name>
//
const DeclContext *DC = Context.getEffectiveDeclContext(ND);
bool IsLambda = isLambda(ND);

// If this is an extern variable declared locally, the relevant DeclContext
// is that of the containing namespace, or the translation unit.
// FIXME: This is a hack; extern variables declared locally should have
// a proper semantic declaration context!
if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND))
if (isLocalContainerContext(DC) && ND->hasLinkage() && !IsLambda)
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = Context.getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
else if (GetLocalClassDecl(ND) &&
(!IsLambda || isCompatibleWith(LangOptions::ClangABI::Ver18))) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

assert(!isa<LinkageSpecDecl>(DC) && "context cannot be LinkageSpecDecl");

if (isLocalContainerContext(DC)) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

// Closures can require a nested-name mangling even if they're semantically
// in the global namespace.
if (const NamedDecl *PrefixND = getClosurePrefix(ND)) {
mangleNestedNameWithClosurePrefix(GD, PrefixND, AdditionalAbiTags);
return;
}

if (isLocalContainerContext(DC)) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
Expand Down Expand Up @@ -2201,8 +2203,6 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (NoFunction && isLocalContainerContext(DC))
return;

assert(!isLocalContainerContext(DC));

const NamedDecl *ND = cast<NamedDecl>(DC);
if (mangleSubstitution(ND))
return;
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/AST/OpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ OpenACCVectorLengthClause::Create(const ASTContext &C, SourceLocation BeginLoc,
OpenACCVectorLengthClause(BeginLoc, LParenLoc, IntExpr, EndLoc);
}

OpenACCNumGangsClause *OpenACCNumGangsClause::Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
ArrayRef<Expr *> IntExprs,
SourceLocation EndLoc) {
void *Mem = C.Allocate(
OpenACCNumGangsClause::totalSizeToAlloc<Expr *>(IntExprs.size()));
return new (Mem) OpenACCNumGangsClause(BeginLoc, LParenLoc, IntExprs, EndLoc);
}

//===----------------------------------------------------------------------===//
// OpenACC clauses printing methods
//===----------------------------------------------------------------------===//
Expand All @@ -141,6 +151,12 @@ void OpenACCClausePrinter::VisitSelfClause(const OpenACCSelfClause &C) {
OS << "(" << CondExpr << ")";
}

void OpenACCClausePrinter::VisitNumGangsClause(const OpenACCNumGangsClause &C) {
OS << "num_gangs(";
llvm::interleaveComma(C.getIntExprs(), OS);
OS << ")";
}

void OpenACCClausePrinter::VisitNumWorkersClause(
const OpenACCNumWorkersClause &C) {
OS << "num_workers(" << C.getIntExpr() << ")";
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2497,6 +2497,12 @@ void OpenACCClauseProfiler::VisitSelfClause(const OpenACCSelfClause &Clause) {
Profiler.VisitStmt(Clause.getConditionExpr());
}

void OpenACCClauseProfiler::VisitNumGangsClause(
const OpenACCNumGangsClause &Clause) {
for (auto *E : Clause.getIntExprs())
Profiler.VisitStmt(E);
}

void OpenACCClauseProfiler::VisitNumWorkersClause(
const OpenACCNumWorkersClause &Clause) {
assert(Clause.hasIntExpr() && "num_workers clause requires a valid int expr");
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
break;
case OpenACCClauseKind::If:
case OpenACCClauseKind::Self:
case OpenACCClauseKind::NumGangs:
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::VectorLength:
// The condition expression will be printed as a part of the 'children',
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/ASTMatchers/Dynamic/Marshallers.h
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ class MapAnyOfMatcherDescriptor : public MatcherDescriptor {
public:
MapAnyOfMatcherDescriptor(ASTNodeKind CladeNodeKind,
std::vector<ASTNodeKind> NodeKinds)
: CladeNodeKind(CladeNodeKind), NodeKinds(NodeKinds) {}
: CladeNodeKind(CladeNodeKind), NodeKinds(std::move(NodeKinds)) {}

VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args,
Diagnostics *Error) const override {
Expand Down Expand Up @@ -1026,7 +1026,7 @@ class MapAnyOfBuilderDescriptor : public MatcherDescriptor {
}

return std::make_unique<MapAnyOfMatcherDescriptor>(CladeNodeKind,
NodeKinds);
std::move(NodeKinds));
}

bool isVariadic() const override { return true; }
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Analysis/FlowSensitive/ASTOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,10 @@ ReferencedDecls getReferencedDecls(const FunctionDecl &FD) {
return Result;
}

ReferencedDecls getReferencedDecls(const Stmt &S) {
ReferencedDecls Result;
getReferencedDecls(S, Result);
return Result;
}

} // namespace clang::dataflow
46 changes: 24 additions & 22 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,8 @@ joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
continue;
assert(It->second != nullptr);

if (areEquivalentValues(*Val, *It->second)) {
Result.insert({Loc, Val});
continue;
}

if (Value *JoinedVal = joinDistinctValues(
Loc->getType(), *Val, Env1, *It->second, Env2, JoinedEnv, Model)) {
if (Value *JoinedVal = Environment::joinValues(
Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
Result.insert({Loc, JoinedVal});
}
}
Expand Down Expand Up @@ -775,27 +770,16 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;

if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) {
// `ReturnVal` might not always get set -- for example if we have a return
// statement of the form `return some_other_func()` and we decide not to
// analyze `some_other_func()`.
// In this case, we can't say anything about the joined return value -- we
// don't simply want to propagate the return value that we do have, because
// it might not be the correct one.
// This occurs for example in the test `ContextSensitiveMutualRecursion`.
if (EnvA.CallStack.empty()) {
JoinedEnv.ReturnVal = nullptr;
} else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) {
JoinedEnv.ReturnVal = EnvA.ReturnVal;
} else {
assert(!EnvA.CallStack.empty());
// FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
// cast.
auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
assert(Func != nullptr);
if (Value *JoinedVal =
joinDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
*EnvB.ReturnVal, EnvB, JoinedEnv, Model))
JoinedEnv.ReturnVal = JoinedVal;
JoinedEnv.ReturnVal =
joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
EnvB, JoinedEnv, Model);
}

if (EnvA.ReturnLoc == EnvB.ReturnLoc)
Expand All @@ -821,6 +805,24 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
return JoinedEnv;
}

Value *Environment::joinValues(QualType Ty, Value *Val1,
const Environment &Env1, Value *Val2,
const Environment &Env2, Environment &JoinedEnv,
Environment::ValueModel &Model) {
if (Val1 == nullptr || Val2 == nullptr)
// We can't say anything about the joined value -- even if one of the values
// is non-null, we don't want to simply propagate it, because it would be
// too specific: Because the other value is null, that means we have no
// information at all about the value (i.e. the value is unconstrained).
return nullptr;

if (areEquivalentValues(*Val1, *Val2))
// Arbitrarily return one of the two values.
return Val1;

return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);
}

StorageLocation &Environment::createStorageLocation(QualType Type) {
return DACtx->createStorageLocation(Type);
}
Expand Down
58 changes: 43 additions & 15 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ namespace {

class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
public:
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
: StmtToEnv(StmtToEnv), Env(Env) {}
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
Environment::ValueModel &Model)
: StmtToEnv(StmtToEnv), Env(Env), Model(Model) {}

void VisitBinaryOperator(const BinaryOperator *S) {
const Expr *LHS = S->getLHS();
Expand Down Expand Up @@ -641,17 +642,42 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
}

void VisitConditionalOperator(const ConditionalOperator *S) {
// FIXME: Revisit this once flow conditions are added to the framework. For
// `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
// condition.
// When we do this, we will need to retrieve the values of the operands from
// the environments for the basic blocks they are computed in, in a similar
// way to how this is done for short-circuited logical operators in
// `getLogicOperatorSubExprValue()`.
if (S->isGLValue())
Env.setStorageLocation(*S, Env.createObject(S->getType()));
else if (!S->getType()->isRecordType()) {
if (Value *Val = Env.createValue(S->getType()))
const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());

if (TrueEnv == nullptr || FalseEnv == nullptr) {
// If the true or false branch is dead, we may not have an environment for
// it. We could handle this specifically by forwarding the value or
// location of the live branch, but this case is rare enough that this
// probably isn't worth the additional complexity.
return;
}

if (S->isGLValue()) {
StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr());
StorageLocation *FalseLoc =
FalseEnv->getStorageLocation(*S->getFalseExpr());
if (TrueLoc == FalseLoc && TrueLoc != nullptr)
Env.setStorageLocation(*S, *TrueLoc);
} else if (!S->getType()->isRecordType()) {
// The conditional operator can evaluate to either of the values of the
// two branches. To model this, join these two values together to yield
// the result of the conditional operator.
// Note: Most joins happen in `computeBlockInputState()`, but this case is
// different:
// - `computeBlockInputState()` (which in turn calls `Environment::join()`
// joins values associated with the _same_ expression or storage
// location, then associates the joined value with that expression or
// storage location. This join has nothing to do with transfer --
// instead, it joins together the results of performing transfer on two
// different blocks.
// - Here, we join values associated with _different_ expressions (the
// true and false branch), then associate the joined value with a third
// expression (the conditional operator itself). This join is what it
// means to perform transfer on the conditional operator.
if (Value *Val = Environment::joinValues(
S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv,
FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model))
Env.setValue(*S, *Val);
}
}
Expand Down Expand Up @@ -810,12 +836,14 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {

const StmtToEnvMap &StmtToEnv;
Environment &Env;
Environment::ValueModel &Model;
};

} // namespace

void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
TransferVisitor(StmtToEnv, Env).Visit(&S);
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
Environment::ValueModel &Model) {
TransferVisitor(StmtToEnv, Env, Model).Visit(&S);
}

} // namespace dataflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ builtinTransferStatement(unsigned CurBlockID, const CFGStmt &Elt,
const Stmt *S = Elt.getStmt();
assert(S != nullptr);
transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, CurBlockID, InputState), *S,
InputState.Env);
InputState.Env, AC.Analysis);
}

/// Built-in transfer function for `CFGInitializer`.
Expand Down Expand Up @@ -452,7 +452,7 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC,
// terminator condition, but not as a `CFGElement`. The condition of an if
// statement is one such example.
transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, Block.getBlockID(), State),
*TerminatorCond, State.Env);
*TerminatorCond, State.Env, AC.Analysis);

// If the transfer function didn't produce a value, create an atom so that
// we have *some* value for the condition expression. This ensures that
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasPrivileged = true;
} else if (Feature == "+aix-small-local-exec-tls") {
HasAIXSmallLocalExecTLS = true;
} else if (Feature == "+aix-small-local-dynamic-tls") {
HasAIXSmallLocalDynamicTLS = true;
} else if (Feature == "+isa-v206-instructions") {
IsISA2_06 = true;
} else if (Feature == "+isa-v207-instructions") {
Expand Down Expand Up @@ -573,9 +575,10 @@ bool PPCTargetInfo::initFeatureMap(
// Privileged instructions are off by default.
Features["privileged"] = false;

// The code generated by the -maix-small-local-exec-tls option is turned
// off by default.
// The code generated by the -maix-small-local-[exec|dynamic]-tls option is
// turned off by default.
Features["aix-small-local-exec-tls"] = false;
Features["aix-small-local-dynamic-tls"] = false;

Features["spe"] = llvm::StringSwitch<bool>(CPU)
.Case("8548", true)
Expand Down Expand Up @@ -713,6 +716,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
.Case("rop-protect", HasROPProtect)
.Case("privileged", HasPrivileged)
.Case("aix-small-local-exec-tls", HasAIXSmallLocalExecTLS)
.Case("aix-small-local-dynamic-tls", HasAIXSmallLocalDynamicTLS)
.Case("isa-v206-instructions", IsISA2_06)
.Case("isa-v207-instructions", IsISA2_07)
.Case("isa-v30-instructions", IsISA3_0)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
bool HasROPProtect = false;
bool HasPrivileged = false;
bool HasAIXSmallLocalExecTLS = false;
bool HasAIXSmallLocalDynamicTLS = false;
bool HasVSX = false;
bool UseCRBits = false;
bool HasP8Vector = false;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>

Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Basic/Targets/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,18 @@ bool WebAssemblyTargetInfo::initFeatureMap(
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
const std::vector<std::string> &FeaturesVec) const {
if (CPU == "bleeding-edge") {
Features["nontrapping-fptoint"] = true;
Features["sign-ext"] = true;
Features["bulk-memory"] = true;
Features["atomics"] = true;
Features["bulk-memory"] = true;
Features["multimemory"] = true;
Features["mutable-globals"] = true;
Features["tail-call"] = true;
Features["nontrapping-fptoint"] = true;
Features["reference-types"] = true;
Features["multimemory"] = true;
Features["sign-ext"] = true;
Features["tail-call"] = true;
setSIMDLevel(Features, SIMD128, true);
} else if (CPU == "generic") {
Features["sign-ext"] = true;
Features["mutable-globals"] = true;
Features["sign-ext"] = true;
}

return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
Expand Down
57 changes: 35 additions & 22 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
"sanitizer-early-opt-ep", cl::Optional,
cl::desc("Insert sanitizers on OptimizerEarlyEP."));

// Experiment to mark cold functions as optsize/minsize/optnone.
// TODO: remove once this is exposed as a proper driver flag.
static cl::opt<PGOOptions::ColdFuncOpt> ClPGOColdFuncAttr(
"pgo-cold-func-opt", cl::init(PGOOptions::ColdFuncOpt::Default), cl::Hidden,
cl::desc(
"Function attribute to apply to cold functions as determined by PGO"),
cl::values(clEnumValN(PGOOptions::ColdFuncOpt::Default, "default",
"Default (no attribute)"),
clEnumValN(PGOOptions::ColdFuncOpt::OptSize, "optsize",
"Mark cold functions with optsize."),
clEnumValN(PGOOptions::ColdFuncOpt::MinSize, "minsize",
"Mark cold functions with minsize."),
clEnumValN(PGOOptions::ColdFuncOpt::OptNone, "optnone",
"Mark cold functions with optnone.")));

extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;

// Re-link builtin bitcodes after optimization
Expand Down Expand Up @@ -769,42 +784,41 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
CodeGenOpts.InstrProfileOutput.empty() ? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", "", CodeGenOpts.MemoryProfileUsePath, nullptr, PGOOptions::IRInstr,
PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default,
PGOOptions::NoCSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling,
/*PseudoProbeForProfiling=*/false, CodeGenOpts.AtomicProfileUpdate);
else if (CodeGenOpts.hasProfileIRUse()) {
// -fprofile-use.
auto CSAction = CodeGenOpts.hasProfileCSIRUse() ? PGOOptions::CSIRUse
: PGOOptions::NoCSAction;
PGOOpt = PGOOptions(
CodeGenOpts.ProfileInstrumentUsePath, "",
CodeGenOpts.ProfileRemappingFile, CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::IRUse, CSAction, PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
PGOOpt = PGOOptions(CodeGenOpts.ProfileInstrumentUsePath, "",
CodeGenOpts.ProfileRemappingFile,
CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::IRUse, CSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling);
} else if (!CodeGenOpts.SampleProfileFile.empty())
// -fprofile-sample-use
PGOOpt = PGOOptions(
CodeGenOpts.SampleProfileFile, "", CodeGenOpts.ProfileRemappingFile,
CodeGenOpts.MemoryProfileUsePath, VFS, PGOOptions::SampleUse,
PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default,
PGOOptions::NoCSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling, CodeGenOpts.PseudoProbeForProfiling);
else if (!CodeGenOpts.MemoryProfileUsePath.empty())
// -fmemory-profile-use (without any of the above options)
PGOOpt = PGOOptions("", "", "", CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
else if (CodeGenOpts.PseudoProbeForProfiling)
// -fpseudo-probe-for-profiling
PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling, true);
PGOOpt =
PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling, true);
else if (CodeGenOpts.DebugInfoForProfiling)
// -fdebug-info-for-profiling
PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default, true);
ClPGOColdFuncAttr, true);

// Check to see if we want to generate a CS profile.
if (CodeGenOpts.hasProfileCSIRInstr()) {
Expand All @@ -821,14 +835,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
: CodeGenOpts.InstrProfileOutput;
PGOOpt->CSAction = PGOOptions::CSIRInstr;
} else
PGOOpt =
PGOOptions("",
CodeGenOpts.InstrProfileOutput.empty()
? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", /*MemoryProfile=*/"", nullptr, PGOOptions::NoAction,
PGOOptions::CSIRInstr, PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
PGOOpt = PGOOptions("",
CodeGenOpts.InstrProfileOutput.empty()
? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::CSIRInstr,
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
}
if (TM)
TM->setPGOOption(PGOOpt);
Expand Down
66 changes: 38 additions & 28 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,29 +826,32 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
ASTContext &Ctx, const RecordDecl *RD, StringRef Name, uint64_t &Offset) {
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
unsigned FieldNo = 0;
bool IsUnion = RD->isUnion();
uint32_t FieldNo = 0;

for (const Decl *D : RD->decls()) {
if (const auto *Field = dyn_cast<FieldDecl>(D);
Field && (Name.empty() || Field->getNameAsString() == Name) &&
if (RD->isImplicit())
return nullptr;

for (const FieldDecl *FD : RD->fields()) {
if ((Name.empty() || FD->getNameAsString() == Name) &&
Decl::isFlexibleArrayMemberLike(
Ctx, Field, Field->getType(), StrictFlexArraysLevel,
Ctx, FD, FD->getType(), StrictFlexArraysLevel,
/*IgnoreTemplateOrMacroSubstitution=*/true)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
return FD;
}

if (const auto *Record = dyn_cast<RecordDecl>(D))
if (const FieldDecl *Field =
FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
QualType Ty = FD->getType();
if (Ty->isRecordType()) {
if (const FieldDecl *Field = FindFlexibleArrayMemberField(
Ctx, Ty->getAsRecordDecl(), Name, Offset)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
}
}

if (!IsUnion && isa<FieldDecl>(D))
if (!RD->isUnion())
++FieldNo;
}

Expand All @@ -858,14 +861,13 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
static unsigned CountCountedByAttrs(const RecordDecl *RD) {
unsigned Num = 0;

for (const Decl *D : RD->decls()) {
if (const auto *FD = dyn_cast<FieldDecl>(D);
FD && FD->getType()->isCountAttributedType()) {
for (const FieldDecl *FD : RD->fields()) {
if (FD->getType()->isCountAttributedType())
return ++Num;
}

if (const auto *Rec = dyn_cast<RecordDecl>(D))
Num += CountCountedByAttrs(Rec);
QualType Ty = FD->getType();
if (Ty->isRecordType())
Num += CountCountedByAttrs(Ty->getAsRecordDecl());
}

return Num;
Expand Down Expand Up @@ -18265,8 +18267,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("lerp operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/X->getType(), Intrinsic::dx_lerp,
ArrayRef<Value *>{X, Y, S}, nullptr, "dx.lerp");
/*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getLerpIntrinsic(),
ArrayRef<Value *>{X, Y, S}, nullptr, "hlsl.lerp");
}
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Expand Down Expand Up @@ -18294,20 +18296,28 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *M = EmitScalarExpr(E->getArg(0));
Value *A = EmitScalarExpr(E->getArg(1));
Value *B = EmitScalarExpr(E->getArg(2));
if (E->getArg(0)->getType()->hasFloatingRepresentation()) {
if (E->getArg(0)->getType()->hasFloatingRepresentation())
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::fmuladd,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.fmad");
}
ArrayRef<Value *>{M, A, B}, nullptr, "hlsl.fmad");

if (E->getArg(0)->getType()->hasSignedIntegerRepresentation()) {
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");

Value *Mul = Builder.CreateNSWMul(M, A);
return Builder.CreateNSWAdd(Mul, B);
}
assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation());
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");

Value *Mul = Builder.CreateNUWMul(M, A);
return Builder.CreateNUWAdd(Mul, B);
}
case Builtin::BI__builtin_hlsl_elementwise_rcp: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
Expand Down Expand Up @@ -5707,6 +5708,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::MetadataAsValue::get(getLLVMContext(), TypeIdMD);
BundleList.emplace_back("type", TypeIdMDVal);
}

// Set type identifier metadata of indirect calls for call graph section.
if (callOrInvoke && *callOrInvoke && (*callOrInvoke)->isIndirectCall()) {
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
// Type id metadata is set only for C/C++ contexts.
if (dyn_cast<CXXConstructorDecl>(FD) || dyn_cast<CXXMethodDecl>(FD) ||
dyn_cast<CXXDestructorDecl>(FD)) {
CGM.CreateFunctionTypeMetadataForIcall(FD->getType(), *callOrInvoke);
}
}
}
}

// Emit the actual call/invoke instruction.
Expand Down
9 changes: 1 addition & 8 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2247,14 +2247,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs);
CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(D, Type));
llvm::CallBase *CallOrInvoke = nullptr;
EmitCall(Info, Callee, ReturnValueSlot(), Args, &CallOrInvoke, false, Loc);

// Set type identifier metadata of indirect calls for call graph section.
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
CallOrInvoke->isIndirectCall())
CGM.CreateFunctionTypeMetadataForIcall(D->getType(), CallOrInvoke);

EmitCall(Info, Callee, ReturnValueSlot(), Args, nullptr, false, Loc);

// Generate vtable assumptions if we're constructing a complete object
// with a vtable. We don't do this for base subobjects for two reasons:
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/CodeGen/CGCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,8 @@ llvm::Function *
CodeGenFunction::generateAwaitSuspendWrapper(Twine const &CoroName,
Twine const &SuspendPointName,
CoroutineSuspendExpr const &S) {
std::string FuncName = "__await_suspend_wrapper_";
FuncName += CoroName.str();
FuncName += '_';
FuncName += SuspendPointName.str();
std::string FuncName =
(CoroName + ".__await_suspend_wrapper__" + SuspendPointName).str();

ASTContext &C = getContext();

Expand Down
34 changes: 5 additions & 29 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,9 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
*this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs);
auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(
Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize);
llvm::CallBase *CallOrInvoke = nullptr;
auto Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke,
return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr,
CE && CE == MustTailCall,
CE ? CE->getExprLoc() : SourceLocation());

// Set type identifier metadata of indirect calls for call graph section.
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
CallOrInvoke->isIndirectCall())
CGM.CreateFunctionTypeMetadataForIcall(MD->getType(), CallOrInvoke);

return Call;
}

RValue CodeGenFunction::EmitCXXDestructorCall(
Expand All @@ -127,17 +119,9 @@ RValue CodeGenFunction::EmitCXXDestructorCall(
CallArgList Args;
commonEmitCXXMemberOrOperatorCall(*this, Dtor, This, ImplicitParam,
ImplicitParamTy, CE, Args, nullptr);
llvm::CallBase *CallOrInvoke = nullptr;
auto Call = EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee,
ReturnValueSlot(), Args, &CallOrInvoke, CE && CE == MustTailCall,
return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee,
ReturnValueSlot(), Args, nullptr, CE && CE == MustTailCall,
CE ? CE->getExprLoc() : SourceLocation{});

// Set type identifier metadata of indirect calls for call graph section.
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
CallOrInvoke->isIndirectCall())
CGM.CreateFunctionTypeMetadataForIcall(DtorDecl->getType(), CallOrInvoke);

return Call;
}

RValue CodeGenFunction::EmitCXXPseudoDestructorExpr(
Expand Down Expand Up @@ -498,18 +482,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,

// And the rest of the call args
EmitCallArgs(Args, FPT, E->arguments());
llvm::CallBase *CallOrInvoke = nullptr;
auto Call = EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
/*PrefixSize=*/0),
Callee, ReturnValue, Args, &CallOrInvoke, E == MustTailCall,
Callee, ReturnValue, Args, nullptr, E == MustTailCall,
E->getExprLoc());

// Set type identifier metadata of indirect calls for call graph section.
if (CGM.getCodeGenOpts().CallGraphSection && CallOrInvoke &&
CallOrInvoke->isIndirectCall())
CGM.CreateFunctionTypeMetadataForIcall(QualType(FPT, 0), CallOrInvoke);

return Call;
}

RValue
Expand Down
108 changes: 56 additions & 52 deletions clang/lib/CodeGen/CGExprConstant.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (auto DstPT = dyn_cast<llvm::PointerType>(DstTy)) {
// The source value may be an integer, or a pointer.
if (isa<llvm::PointerType>(SrcTy))
return Builder.CreateBitCast(Src, DstTy, "conv");
return Src;

assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?");
// First, convert to the correct width so that we control the kind of
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class CGHLSLRuntime {

GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)
GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)
GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)

//===----------------------------------------------------------------------===//
Expand Down
8 changes: 0 additions & 8 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2220,14 +2220,6 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs,
&CallSite);

// Set type identifier metadata of indirect calls for call graph section.
if (CGM.getCodeGenOpts().CallGraphSection && Method && CallSite &&
CallSite->isIndirectCall()) {
if (const auto *FnType = Method->getFunctionType()) {
CGM.CreateFunctionTypeMetadataForIcall(QualType(FnType, 0), CallSite);
}
}

// Mark the call as noreturn if the method is marked noreturn and the
// receiver cannot be null.
if (Method && Method->hasAttr<NoReturnAttr>() && !ReceiverCanBeNull) {
Expand Down
13 changes: 7 additions & 6 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/TargetParser/X86TargetParser.h"
#include <optional>
Expand Down Expand Up @@ -2495,7 +2495,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// In the cross-dso CFI mode with canonical jump tables, we want !type
// attributes on definitions only.
if ((CodeGenOpts.SanitizeCfiCrossDso &&
CodeGenOpts.SanitizeCfiCanonicalJumpTables) || CodeGenOpts.CallGraphSection) {
CodeGenOpts.SanitizeCfiCanonicalJumpTables) ||
CodeGenOpts.CallGraphSection) {
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
// Skip available_externally functions. They won't be codegen'ed in the
// current module anyway.
Expand Down Expand Up @@ -2688,9 +2689,9 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
bool EmittedMDIdGeneralized = false;
if (CodeGenOpts.CallGraphSection &&
(!F->hasLocalLinkage() ||
F->getFunction().hasAddressTaken(nullptr, /* IgnoreCallbackUses */ true,
/* IgnoreAssumeLikeCalls */ true,
/* IgnoreLLVMUsed */ false))) {
F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
/*IgnoreAssumeLikeCalls=*/true,
/*IgnoreLLVMUsed=*/false))) {
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
EmittedMDIdGeneralized = true;
}
Expand Down Expand Up @@ -2719,7 +2720,7 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
void CodeGenModule::CreateFunctionTypeMetadataForIcall(const QualType &QT,
llvm::CallBase *CB) {
// Only if needed for call graph section and only for indirect calls.
if (!(CodeGenOpts.CallGraphSection && CB && CB->isIndirectCall()))
if (!CodeGenOpts.CallGraphSection || !CB || !CB->isIndirectCall())
return;

auto *MD = CreateMetadataIdentifierGeneralized(QT);
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,12 @@ struct CounterCoverageMappingBuilder
/// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
SourceLocation BeforeLoc) {
// Some statements (like AttributedStmt and ImplicitValueInitExpr) don't
// have valid source locations. Do not emit a gap region if this is the case
// in either AfterLoc end or BeforeLoc end.
if (AfterLoc.isInvalid() || BeforeLoc.isInvalid())
return std::nullopt;

// If AfterLoc is in function-like macro, use the right parenthesis
// location.
if (AfterLoc.isMacroID()) {
Expand Down Expand Up @@ -1368,9 +1374,8 @@ struct CounterCoverageMappingBuilder
for (const Stmt *Child : S->children())
if (Child) {
// If last statement contains terminate statements, add a gap area
// between the two statements. Skipping attributed statements, because
// they don't have valid start location.
if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
// between the two statements.
if (LastStmt && HasTerminateStmt) {
auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include <cstdlib> // ::getenv
#include <map>
#include <memory>
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
BinaryMetadataIgnorelistFiles);
}

if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
if (TC.getTriple().isOSWindows() && needsUbsanRt() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
// Instruct the code generator to embed linker directives in the object file
// that cause the required runtime libraries to be linked.
CmdArgs.push_back(
Expand All @@ -1203,7 +1205,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
"--dependent-lib=" +
TC.getCompilerRTBasename(Args, "ubsan_standalone_cxx")));
}
if (TC.getTriple().isOSWindows() && needsStatsRt()) {
if (TC.getTriple().isOSWindows() && needsStatsRt() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "stats_client")));

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Driver/ToolChains/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,8 +617,7 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {

std::string Linker = getToolChain().GetProgramPath(getShortName());
std::string Linker = getToolChain().GetLinkerPath();
ArgStringList CmdArgs;
CmdArgs.push_back("--no-undefined");
CmdArgs.push_back("-shared");
Expand Down
17 changes: 9 additions & 8 deletions clang/lib/Driver/ToolChains/Arch/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,21 +125,22 @@ void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,

bool UseSeparateSections = isUseSeparateSections(Triple);
bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF();
if (Args.hasArg(options::OPT_maix_small_local_exec_tls)) {
if (Args.hasArg(options::OPT_maix_small_local_exec_tls) ||
Args.hasArg(options::OPT_maix_small_local_dynamic_tls)) {
if (!Triple.isOSAIX() || !Triple.isArch64Bit())
D.Diag(diag::err_opt_not_valid_on_target) << "-maix-small-local-exec-tls";
D.Diag(diag::err_opt_not_valid_on_target)
<< "-maix-small-local-[exec|dynamic]-tls";

// The -maix-small-local-exec-tls option should only be used with
// The -maix-small-local-[exec|dynamic]-tls option should only be used with
// -fdata-sections, as having data sections turned off with this option
// is not ideal for performance. Moreover, the small-local-exec-tls region
// is a limited resource, and should not be used for variables that may
// be replaced.
// is not ideal for performance. Moreover, the
// small-local-[exec|dynamic]-tls region is a limited resource, and should
// not be used for variables that may be replaced.
if (!Args.hasFlag(options::OPT_fdata_sections,
options::OPT_fno_data_sections,
UseSeparateSections || HasDefaultDataSections))
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-maix-small-local-exec-tls"
<< "-fdata-sections";
<< "-maix-small-local-[exec|dynamic]-tls" << "-fdata-sections";
}
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVTargetParser.h"

using namespace clang::driver;
Expand Down
34 changes: 27 additions & 7 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/TargetParser/ARMTargetParserCommon.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/LoongArchTargetParser.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVTargetParser.h"
#include <cctype>

Expand Down Expand Up @@ -637,7 +637,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
ProfileGenerateArg->getValue()));
// The default is to use Clang Instrumentation.
CmdArgs.push_back("-fprofile-instrument=clang");
if (TC.getTriple().isWindowsMSVCEnvironment()) {
if (TC.getTriple().isWindowsMSVCEnvironment() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
// Add dependent lib for clang_rt.profile
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile")));
Expand All @@ -656,7 +658,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
CmdArgs.push_back("-fprofile-instrument=csllvm");
}
if (PGOGenArg) {
if (TC.getTriple().isWindowsMSVCEnvironment()) {
if (TC.getTriple().isWindowsMSVCEnvironment() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
// Add dependent lib for clang_rt.profile
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile")));
Expand Down Expand Up @@ -847,6 +851,16 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_O_Group))
RelaxDefault = A->getOption().matches(options::OPT_O0);

// RISC-V requires an indirect jump for offsets larger than 1MiB. This cannot
// be done by assembler branch relaxation as it needs a free temporary
// register. Because of this, branch relaxation is handled by a MachineIR
// pass before the assembler. Forcing assembler branch relaxation for -O0
// makes the MachineIR branch relaxation inaccurate and it will miss cases
// where an indirect branch is necessary. To avoid this issue we are
// sacrificing the compile time improvement of using -mrelax-all for -O0.
if (C.getDefaultToolChain().getTriple().isRISCV())
RelaxDefault = false;

if (RelaxDefault) {
RelaxDefault = false;
for (const auto &Act : C.getActions()) {
Expand Down Expand Up @@ -4634,7 +4648,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,

// Emit DW_TAG_template_alias for template aliases? True by default for SCE.
bool UseDebugTemplateAlias =
DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 5;
DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 4;
if (const auto *DebugTemplateAlias = Args.getLastArg(
options::OPT_gtemplate_alias, options::OPT_gno_template_alias)) {
// DW_TAG_template_alias is only supported from DWARFv5 but if a user
Expand Down Expand Up @@ -4733,7 +4747,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
Output.getFilename());
}

static void ProcessVSRuntimeLibrary(const ArgList &Args,
static void ProcessVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
unsigned RTOptionID = options::OPT__SLASH_MT;

Expand Down Expand Up @@ -4796,6 +4810,12 @@ static void ProcessVSRuntimeLibrary(const ArgList &Args,
// implemented in clang.
CmdArgs.push_back("--dependent-lib=oldnames");
}

// All Arm64EC object files implicitly add softintrin.lib. This is necessary
// even if the file doesn't actually refer to any of the routines because
// the CRT itself has incomplete dependency markings.
if (TC.getTriple().isWindowsArm64EC())
CmdArgs.push_back("--dependent-lib=softintrin");
}

void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Expand Down Expand Up @@ -7055,7 +7075,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,

if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() &&
Args.hasArg(options::OPT_fms_runtime_lib_EQ))
ProcessVSRuntimeLibrary(Args, CmdArgs);
ProcessVSRuntimeLibrary(getToolChain(), Args, CmdArgs);

// Handle -fgcc-version, if present.
VersionTuple GNUCVer;
Expand Down Expand Up @@ -8182,7 +8202,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
ArgStringList &CmdArgs) const {
bool isNVPTX = getToolChain().getTriple().isNVPTX();

ProcessVSRuntimeLibrary(Args, CmdArgs);
ProcessVSRuntimeLibrary(getToolChain(), Args, CmdArgs);

if (Arg *ShowIncludes =
Args.getLastArg(options::OPT__SLASH_showIncludes,
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVTargetParser.h"

#include <cassert>
Expand Down Expand Up @@ -118,7 +118,7 @@ void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
Arg *gNArg = Args.getLastArg(options::OPT_gN_Group);
DebugInfoKind = debugLevelToInfoKind(*gNArg);
} else if (Args.hasArg(options::OPT_g_Flag)) {
DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly;
DebugInfoKind = llvm::codegenoptions::FullDebugInfo;
} else {
DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/TargetParser.h"
#include <system_error>

Expand Down
22 changes: 22 additions & 0 deletions clang/lib/ExtractAPI/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,28 @@ RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) {
}
}

bool RecordContext::IsWellFormed() const {
// Check that First and Last are both null or both non-null.
return (First == nullptr) == (Last == nullptr);
}

void RecordContext::stealRecordChain(RecordContext &Other) {
assert(IsWellFormed());
// If we don't have an empty chain append Other's chain into ours.
if (First)
Last->NextInContext = Other.First;
else
First = Other.First;

Last = Other.Last;

// Delete Other's chain to ensure we don't accidentally traverse it.
Other.First = nullptr;
Other.Last = nullptr;
}

void RecordContext::addToRecordChain(APIRecord *Record) const {
assert(IsWellFormed());
if (!First) {
First = Record;
Last = Record;
Expand Down Expand Up @@ -95,6 +116,7 @@ SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR,
}

APIRecord::~APIRecord() {}
TagRecord::~TagRecord() {}
RecordRecord::~RecordRecord() {}
RecordFieldRecord::~RecordFieldRecord() {}
ObjCContainerRecord::~ObjCContainerRecord() {}
Expand Down
17 changes: 13 additions & 4 deletions clang/lib/ExtractAPI/DeclarationFragments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
const TagDecl *Decl = TagTy->getDecl();
// Anonymous decl, skip this fragment.
if (Decl->getName().empty())
return Fragments;
return Fragments.append("{ ... }",
DeclarationFragments::FragmentKind::Text);
SmallString<128> TagUSR;
clang::index::generateUSRForDecl(Decl, TagUSR);
return Fragments.append(Decl->getName(),
Expand Down Expand Up @@ -743,11 +744,16 @@ DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) {

QualType IntegerType = EnumDecl->getIntegerType();
if (!IntegerType.isNull())
Fragments.append(": ", DeclarationFragments::FragmentKind::Text)
Fragments.appendSpace()
.append(": ", DeclarationFragments::FragmentKind::Text)
.append(
getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After))
.append(std::move(After));

if (EnumDecl->getName().empty())
Fragments.appendSpace().append("{ ... }",
DeclarationFragments::FragmentKind::Text);

return Fragments.appendSemicolon();
}

Expand Down Expand Up @@ -778,9 +784,12 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl(
else
Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);

Fragments.appendSpace();
if (!Record->getName().empty())
Fragments.appendSpace().append(
Record->getName(), DeclarationFragments::FragmentKind::Identifier);
Fragments.append(Record->getName(),
DeclarationFragments::FragmentKind::Identifier);
else
Fragments.append("{ ... }", DeclarationFragments::FragmentKind::Text);

return Fragments.appendSemicolon();
}
Expand Down
36 changes: 23 additions & 13 deletions clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,27 +164,29 @@ std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
if (Avail.isDefault())
return std::nullopt;

Object Availability;
Array AvailabilityArray;
Availability["domain"] = Avail.Domain;
serializeObject(Availability, "introduced",
serializeSemanticVersion(Avail.Introduced));
serializeObject(Availability, "deprecated",
serializeSemanticVersion(Avail.Deprecated));
serializeObject(Availability, "obsoleted",
serializeSemanticVersion(Avail.Obsoleted));

if (Avail.isUnconditionallyDeprecated()) {
Object UnconditionallyDeprecated;
UnconditionallyDeprecated["domain"] = "*";
UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
}
if (Avail.isUnconditionallyUnavailable()) {
Object UnconditionallyUnavailable;
UnconditionallyUnavailable["domain"] = "*";
UnconditionallyUnavailable["isUnconditionallyUnavailable"] = true;
AvailabilityArray.emplace_back(std::move(UnconditionallyUnavailable));
Object Availability;

Availability["domain"] = Avail.Domain;

if (Avail.isUnavailable()) {
Availability["isUnconditionallyUnavailable"] = true;
} else {
serializeObject(Availability, "introduced",
serializeSemanticVersion(Avail.Introduced));
serializeObject(Availability, "deprecated",
serializeSemanticVersion(Avail.Deprecated));
serializeObject(Availability, "obsoleted",
serializeSemanticVersion(Avail.Obsoleted));
}

AvailabilityArray.emplace_back(std::move(Availability));
return AvailabilityArray;
}
Expand Down Expand Up @@ -665,6 +667,14 @@ bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
if (Record->Availability.isUnconditionallyUnavailable())
return true;

// Filter out symbols without a name as we can generate correct symbol graphs
// for them. In practice these are anonymous record types that aren't attached
// to a declaration.
if (auto *Tag = dyn_cast<TagRecord>(Record)) {
if (Tag->IsEmbeddedInVarDeclarator)
return true;
}

// Filter out symbols prefixed with an underscored as they are understood to
// be symbols clients should not use.
if (Record->Name.starts_with("_"))
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,7 @@ class AnnotatingParser {
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
!Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) &&
!Line.startsWith(tok::l_paren) &&
!Tok->isOneOf(TT_TypeDeclarationParen, TT_RequiresExpressionLParen)) {
if (const auto *Previous = Tok->Previous;
!Previous ||
Expand Down Expand Up @@ -2726,8 +2727,10 @@ class AnnotatingParser {
}
}

if (Tok.Next->isOneOf(tok::question, tok::ampamp))
if (Tok.Next->is(tok::question) ||
(Tok.Next->is(tok::ampamp) && !Tok.Previous->isTypeName(IsCpp))) {
return false;
}

// `foreach((A a, B b) in someList)` should not be seen as a cast.
if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
Expand Down
41 changes: 35 additions & 6 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,8 +819,11 @@ FormatToken *UnwrappedLineParser::parseBlock(bool MustBeDeclaration,
return IfLBrace;
}

if (FormatTok->is(tok::r_brace) && Tok->is(TT_NamespaceLBrace))
FormatTok->setFinalizedType(TT_NamespaceRBrace);
if (FormatTok->is(tok::r_brace)) {
FormatTok->setBlockKind(BK_Block);
if (Tok->is(TT_NamespaceLBrace))
FormatTok->setFinalizedType(TT_NamespaceRBrace);
}

const bool IsFunctionRBrace =
FormatTok->is(tok::r_brace) && Tok->is(TT_FunctionLBrace);
Expand Down Expand Up @@ -3910,6 +3913,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
const FormatToken &InitialToken = *FormatTok;
nextToken();

const FormatToken *ClassName = nullptr;
bool IsDerived = false;
auto IsNonMacroIdentifier = [](const FormatToken *Tok) {
return Tok->is(tok::identifier) && Tok->TokenText != Tok->TokenText.upper();
};
Expand All @@ -3934,15 +3939,35 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
}
if (FormatTok->is(tok::l_square) && handleCppAttributes())
continue;
const auto *Previous = FormatTok;
nextToken();
// We can have macros in between 'class' and the class name.
if (!IsNonMacroIdentifier(FormatTok->Previous) &&
FormatTok->is(tok::l_paren)) {
parseParens();
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
// We can have macros in between 'class' and the class name.
if (!IsNonMacroIdentifier(Previous))
parseParens();
break;
case tok::coloncolon:
break;
default:
if (!ClassName && Previous->is(tok::identifier))
ClassName = Previous;
}
}

auto IsListInitialization = [&] {
if (!ClassName || IsDerived)
return false;
assert(FormatTok->is(tok::l_brace));
const auto *Prev = FormatTok->getPreviousNonComment();
assert(Prev);
return Prev != ClassName && Prev->is(tok::identifier) &&
Prev->isNot(Keywords.kw_final) && tryToParseBracedList();
};

if (FormatTok->isOneOf(tok::colon, tok::less)) {
if (FormatTok->is(tok::colon))
IsDerived = true;
int AngleNestingLevel = 0;
do {
if (FormatTok->is(tok::less))
Expand All @@ -3955,6 +3980,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
break;
}
if (FormatTok->is(tok::l_brace)) {
if (AngleNestingLevel == 0 && IsListInitialization())
return;
calculateBraceTypes(/*ExpectClassBody=*/true);
if (!tryToParseBracedList())
break;
Expand Down Expand Up @@ -3999,6 +4026,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
}
};
if (FormatTok->is(tok::l_brace)) {
if (IsListInitialization())
return;
auto [OpenBraceType, ClosingBraceType] = GetBraceTypes(InitialToken);
FormatTok->setFinalizedType(OpenBraceType);
if (ParseAsExpr) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3660,6 +3660,9 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
case LangOptions::ClangABI::Ver17:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "17.0");
break;
case LangOptions::ClangABI::Ver18:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "18.0");
break;
case LangOptions::ClangABI::Latest:
break;
}
Expand Down Expand Up @@ -4167,6 +4170,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
else if (Major <= 17)
Opts.setClangABICompat(LangOptions::ClangABI::Ver17);
else if (Major <= 18)
Opts.setClangABICompat(LangOptions::ClangABI::Ver18);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
Expand Down
Loading