6 changes: 2 additions & 4 deletions bolt/lib/Target/X86/X86MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2794,14 +2794,13 @@ class X86MCPlusBuilder : public MCPlusBuilder {
Inst.addOperand(MCOperand::createImm(CC));
}

bool reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
unsigned InvCC = getInvertedCondCode(getCondCode(Inst));
assert(InvCC != X86::COND_INVALID && "invalid branch instruction");
Inst.getOperand(Info->get(Inst.getOpcode()).NumOperands - 1).setImm(InvCC);
Inst.getOperand(0) = MCOperand::createExpr(
MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
return true;
}

bool replaceBranchCondition(MCInst &Inst, const MCSymbol *TBB, MCContext *Ctx,
Expand Down Expand Up @@ -2844,13 +2843,12 @@ class X86MCPlusBuilder : public MCPlusBuilder {
}
}

bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
"Invalid instruction");
Inst.getOperand(0) = MCOperand::createExpr(
MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
return true;
}

MCPhysReg getX86R11() const override { return X86::R11; }
Expand Down
1 change: 0 additions & 1 deletion clang-tools-extra/clang-tidy/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ add_clang_library(clangTidyMiscModule
UseAnonymousNamespaceCheck.cpp

LINK_LIBS
clangAnalysis
clangTidy
clangTidyUtils

Expand Down
11 changes: 4 additions & 7 deletions clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,15 @@ class CyclicDependencyCallbacks : public PPCallbacks {
<< FileName;

const bool IsIncludePathValid =
std::all_of(Files.rbegin(), It, [](const Include &Elem) {
std::all_of(Files.rbegin(), It + 1, [](const Include &Elem) {
return !Elem.Name.empty() && Elem.Loc.isValid();
});

if (!IsIncludePathValid)
return;

auto CurrentIt = Files.rbegin();
do {
Check.diag(CurrentIt->Loc, "'%0' included from here", DiagnosticIDs::Note)
<< CurrentIt->Name;
} while (CurrentIt++ != It);
for (const Include &I : llvm::make_range(Files.rbegin(), It + 1))
Check.diag(I.Loc, "'%0' included from here", DiagnosticIDs::Note)
<< I.Name;
}

bool isFileIgnored(StringRef FileName) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,14 @@ AST_MATCHER(QualType, isIntegralType) {

AST_MATCHER_P(UserDefinedLiteral, hasLiteral,
clang::ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
if (const Expr *CookedLiteral = Node.getCookedLiteral()) {
const UserDefinedLiteral::LiteralOperatorKind LOK =
Node.getLiteralOperatorKind();
if (LOK == UserDefinedLiteral::LOK_Template ||
LOK == UserDefinedLiteral::LOK_Raw)
return false;

if (const Expr *CookedLiteral = Node.getCookedLiteral())
return InnerMatcher.matches(*CookedLiteral, Finder, Builder);
}
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/FindSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ class DocumentOutline {
if (!MacroName.isValid() || !MacroName.isFileID())
continue;
// All conditions satisfied, add the macro.
if (auto *Tok = AST.getTokens().spelledTokenAt(MacroName))
if (auto *Tok = AST.getTokens().spelledTokenContaining(MacroName))
CurParent = &CurParent->inMacro(
*Tok, SM, AST.getTokens().expansionStartingAt(Tok));
}
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ collectMacroReferences(ParsedAST &AST) {
for (const auto &[_, Refs] : AST.getMacros().MacroRefs) {
for (const auto &Ref : Refs) {
auto Loc = SM.getComposedLoc(SM.getMainFileID(), Ref.StartOffset);
const auto *Tok = AST.getTokens().spelledTokenAt(Loc);
const auto *Tok = AST.getTokens().spelledTokenContaining(Loc);
if (!Tok)
continue;
auto Macro = locateMacroAt(*Tok, PP);
Expand Down
11 changes: 5 additions & 6 deletions clang-tools-extra/clangd/SemanticHighlighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,11 +447,10 @@ class HighlightingsBuilder {
if (!RLoc.isValid())
return;

const auto *RTok = TB.spelledTokenAt(RLoc);
// Handle `>>`. RLoc is always pointing at the right location, just change
// the end to be offset by 1.
// We'll either point at the beginning of `>>`, hence get a proper spelled
// or point in the middle of `>>` hence get no spelled tok.
const auto *RTok = TB.spelledTokenContaining(RLoc);
// Handle `>>`. RLoc is either part of `>>` or a spelled token on its own
// `>`. If it's the former, slice to have length of 1, if latter use the
// token as-is.
if (!RTok || RTok->kind() == tok::greatergreater) {
Position Begin = sourceLocToPosition(SourceMgr, RLoc);
Position End = sourceLocToPosition(SourceMgr, RLoc.getLocWithOffset(1));
Expand Down Expand Up @@ -577,7 +576,7 @@ class HighlightingsBuilder {
return std::nullopt;
// We might have offsets in the main file that don't correspond to any
// spelled tokens.
const auto *Tok = TB.spelledTokenAt(Loc);
const auto *Tok = TB.spelledTokenContaining(Loc);
if (!Tok)
return std::nullopt;
return halfOpenToRange(SourceMgr,
Expand Down
9 changes: 5 additions & 4 deletions clang-tools-extra/clangd/XRefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
if (Inc.Resolved.empty())
continue;
auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
const auto *HashTok = AST.getTokens().spelledTokenAt(HashLoc);
const auto *HashTok = AST.getTokens().spelledTokenContaining(HashLoc);
assert(HashTok && "got inclusion at wrong offset");
const auto *IncludeTok = std::next(HashTok);
const auto *FileTok = std::next(IncludeTok);
Expand Down Expand Up @@ -938,7 +938,7 @@ class ReferenceFinder : public index::IndexDataConsumer {
CollectorOpts.CollectMainFileSymbols = true;
for (SourceLocation L : Locs) {
L = SM.getFileLoc(L);
if (const auto *Tok = TB.spelledTokenAt(L))
if (const auto *Tok = TB.spelledTokenContaining(L))
References.push_back(
{*Tok, Roles,
SymbolCollector::getRefContainer(ASTNode.Parent, CollectorOpts)});
Expand Down Expand Up @@ -1216,7 +1216,7 @@ DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
const syntax::TokenBuffer &TB) {
Loc = TB.sourceManager().getFileLoc(Loc);
if (const auto *Tok = TB.spelledTokenAt(Loc)) {
if (const auto *Tok = TB.spelledTokenContaining(Loc)) {
DocumentHighlight Result;
Result.range = halfOpenToRange(
TB.sourceManager(),
Expand Down Expand Up @@ -1353,7 +1353,8 @@ maybeFindIncludeReferences(ParsedAST &AST, Position Pos,
Loc = SM.getIncludeLoc(SM.getFileID(Loc));

ReferencesResult::Reference Result;
const auto *Token = AST.getTokens().spelledTokenAt(Loc);
const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
assert(Token && "references expected token here");
Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
sourceLocToPosition(SM, Token->endLocation())};
Result.Loc.uri = URIMainFile;
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/refactor/Rename.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ std::vector<SymbolRange> collectRenameIdentifierRanges(
clangd::Range tokenRangeForLoc(ParsedAST &AST, SourceLocation TokLoc,
const SourceManager &SM,
const LangOptions &LangOpts) {
const auto *Token = AST.getTokens().spelledTokenAt(TokLoc);
const auto *Token = AST.getTokens().spelledTokenContaining(TokLoc);
assert(Token && "rename expects spelled tokens");
clangd::Range Result;
Result.start = sourceLocToPosition(SM, Token->location());
Expand Down
11 changes: 6 additions & 5 deletions clang-tools-extra/clangd/unittests/PreambleTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ TEST(PreamblePatchTest, LocateMacroAtWorks) {
ASSERT_TRUE(AST);

const auto &SM = AST->getSourceManager();
auto *MacroTok = AST->getTokens().spelledTokenAt(
auto *MacroTok = AST->getTokens().spelledTokenContaining(
SM.getComposedLoc(SM.getMainFileID(), Modified.point("use")));
ASSERT_TRUE(MacroTok);

Expand All @@ -441,7 +441,7 @@ TEST(PreamblePatchTest, LocateMacroAtDeletion) {
ASSERT_TRUE(AST);

const auto &SM = AST->getSourceManager();
auto *MacroTok = AST->getTokens().spelledTokenAt(
auto *MacroTok = AST->getTokens().spelledTokenContaining(
SM.getComposedLoc(SM.getMainFileID(), Modified.point()));
ASSERT_TRUE(MacroTok);

Expand Down Expand Up @@ -512,9 +512,10 @@ TEST(PreamblePatchTest, RefsToMacros) {
ExpectedLocations.push_back(referenceRangeIs(R));

for (const auto &P : Modified.points()) {
auto *MacroTok = AST->getTokens().spelledTokenAt(SM.getComposedLoc(
SM.getMainFileID(),
llvm::cantFail(positionToOffset(Modified.code(), P))));
auto *MacroTok =
AST->getTokens().spelledTokenContaining(SM.getComposedLoc(
SM.getMainFileID(),
llvm::cantFail(positionToOffset(Modified.code(), P))));
ASSERT_TRUE(MacroTok);
EXPECT_THAT(findReferences(*AST, P, 0).References,
testing::ElementsAreArray(ExpectedLocations));
Expand Down
16 changes: 15 additions & 1 deletion clang-tools-extra/clangd/unittests/XRefsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,11 @@ TEST(FindReferences, WithinAST) {
using $def[[MyTypeD^ef]] = int;
enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
)cpp",
// UDL
R"cpp(
bool $decl[[operator]]"" _u^dl(unsigned long long value);
bool x = $(x)[[1_udl]];
)cpp",
};
for (const char *Test : Tests)
checkFindRefs(Test);
Expand Down Expand Up @@ -2358,7 +2363,13 @@ TEST(FindReferences, UsedSymbolsFromInclude) {

R"cpp([[#in^clude <vector>]]
std::[[vector]]<int> vec;
)cpp"};
)cpp",

R"cpp(
[[#include ^"udl_header.h"]]
auto x = [[1_b]];
)cpp",
};
for (const char *Test : Tests) {
Annotations T(Test);
auto TU = TestTU::withCode(T.code());
Expand All @@ -2375,6 +2386,9 @@ TEST(FindReferences, UsedSymbolsFromInclude) {
class vector{};
}
)cpp");
TU.AdditionalFiles["udl_header.h"] = guard(R"cpp(
bool operator"" _b(unsigned long long value);
)cpp");
TU.ExtraArgs.push_back("-isystem" + testPath("system"));

auto AST = TU.build();
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ Changes in existing checks
Additionally, the option `UseHeaderFileExtensions` is removed, so that the
check uses the `HeaderFileExtensions` option unconditionally.

- Improved :doc:`misc-header-include-cycle
<clang-tidy/checks/misc/header-include-cycle>` check by avoiding crash for self
include cycles.

- Improved :doc:`misc-unused-using-decls
<clang-tidy/checks/misc/unused-using-decls>` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.
Expand Down Expand Up @@ -376,6 +380,7 @@ Changes in existing checks
- Improved :doc:`readability-container-size-empty
<clang-tidy/checks/readability/container-size-empty>` check to prevent false
positives when utilizing ``size`` or ``length`` methods that accept parameter.
Fixed crash when facing template user defined literals.

- Improved :doc:`readability-duplicate-include
<clang-tidy/checks/readability/duplicate-include>` check by excluding include
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// RUN: not clang-tidy %s -checks='-*,misc-header-include-cycle'

#include "header-include-cycle.self.cpp"
Original file line number Diff line number Diff line change
Expand Up @@ -889,3 +889,9 @@ namespace PR88203 {
// CHECK-FIXES: {{^ }}if (s.empty()) {}{{$}}
}
}

namespace PR94454 {
template <char...>
int operator""_ci() { return 0; }
auto eq = 0_ci == 0;
}
2 changes: 2 additions & 0 deletions clang/cmake/caches/Release.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ endif()
# Final Stage Config (stage2)
set_final_stage_var(LLVM_ENABLE_RUNTIMES "${LLVM_RELEASE_ENABLE_RUNTIMES}" STRING)
set_final_stage_var(LLVM_ENABLE_PROJECTS "${LLVM_RELEASE_ENABLE_PROJECTS}" STRING)
set_final_stage_var(CPACK_GENERATOR "TXZ" STRING)
set_final_stage_var(CPACK_ARCHIVE_THREADS "0" STRING)

24 changes: 24 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4016,6 +4016,30 @@ Note that the `size` argument must be a compile time constant.
Note that this intrinsic cannot yet be called in a ``constexpr`` context.
``__is_bitwise_cloneable``
--------------------------
A type trait is used to check whether a type can be safely copied by memcpy.
**Syntax**:
.. code-block:: c++
bool __is_bitwise_cloneable(Type)
**Description**:
Objects of bitwise cloneable types can be bitwise copied by memcpy/memmove. The
Clang compiler warrants that this behavior is well defined, and won't be
broken by compiler optimizations and sanitizers.
For implicit-lifetime types, the lifetime of the new object is implicitly
started after the copy. For other types (e.g., classes with virtual methods),
the lifetime isn't started, and using the object results in undefined behavior
according to the C++ Standard.
This builtin can be used in constant expressions.
Atomic Min/Max builtins with memory ordering
--------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ Non-comprehensive list of changes in this release
``-Winvalid-constexpr`` is not enabled for the function definition, which
should result in mild compile-time performance improvements.

- Added ``__is_bitwise_cloneable`` which is used to check whether a type
can be safely copied by memcpy/memmove.

New Compiler Flags
------------------
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
Expand Down Expand Up @@ -904,6 +907,7 @@ Arm and AArch64 Support
* Arm Cortex-A520AE (cortex-a520ae).
* Arm Cortex-A720AE (cortex-a720ae).
* Arm Cortex-R82AE (cortex-r82ae).
* Arm Cortex-R52+ (cortex-r52plus).
* Arm Neoverse-N3 (neoverse-n3).
* Arm Neoverse-V3 (neoverse-v3).
* Arm Neoverse-V3AE (neoverse-v3ae).
Expand Down
9 changes: 7 additions & 2 deletions clang/include/clang/AST/ASTUnresolvedSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "clang/AST/ASTVector.h"
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclID.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/Specifiers.h"
#include <cassert>
Expand Down Expand Up @@ -56,6 +57,10 @@ class ASTUnresolvedSet {
Decls.push_back(DeclAccessPair::make(D, AS), C);
}

void addLazyDecl(ASTContext &C, GlobalDeclID ID, AccessSpecifier AS) {
Decls.push_back(DeclAccessPair::makeLazy(ID.get(), AS), C);
}

/// Replaces the given declaration with the new one, once.
///
/// \return true if the set changed
Expand Down Expand Up @@ -109,10 +114,10 @@ class LazyASTUnresolvedSet {

void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }

void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
void addLazyDecl(ASTContext &C, GlobalDeclID ID, AccessSpecifier AS) {
assert(Impl.empty() || Impl.Decls.isLazy());
Impl.Decls.setLazy(true);
Impl.addDecl(C, reinterpret_cast<NamedDecl *>(ID << 2), AS);
Impl.addLazyDecl(C, ID, AS);
}
};

Expand Down
37 changes: 31 additions & 6 deletions clang/include/clang/AST/DeclAccessPair.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "clang/Basic/Specifiers.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Endian.h"

namespace clang {

Expand All @@ -27,9 +28,17 @@ class NamedDecl;
/// A POD class for pairing a NamedDecl* with an access specifier.
/// Can be put into unions.
class DeclAccessPair {
uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
/// Use the lower 2 bit to store AccessSpecifier. Use the higher
/// 61 bit to store the pointer to a NamedDecl or the DeclID to
/// a NamedDecl. If the 3rd bit is set, storing the DeclID, otherwise
/// storing the pointer.
llvm::support::detail::packed_endian_specific_integral<
uint64_t, llvm::endianness::native, alignof(void *)>
Ptr;

enum { Mask = 0x3 };
enum { ASMask = 0x3, Mask = 0x7 };

bool isDeclID() const { return (Ptr >> 2) & 0x1; }

public:
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
Expand All @@ -38,12 +47,22 @@ class DeclAccessPair {
return p;
}

static DeclAccessPair makeLazy(uint64_t ID, AccessSpecifier AS) {
DeclAccessPair p;
p.Ptr = (ID << 3) | (0x1 << 2) | uint64_t(AS);
return p;
}

uint64_t getDeclID() const {
assert(isDeclID());
return (~Mask & Ptr) >> 3;
}

NamedDecl *getDecl() const {
assert(!isDeclID());
return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
}
AccessSpecifier getAccess() const {
return AccessSpecifier(Mask & Ptr);
}
AccessSpecifier getAccess() const { return AccessSpecifier(ASMask & Ptr); }

void setDecl(NamedDecl *D) {
set(D, getAccess());
Expand All @@ -52,12 +71,18 @@ class DeclAccessPair {
set(getDecl(), AS);
}
void set(NamedDecl *D, AccessSpecifier AS) {
Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D);
Ptr = uint64_t(AS) | reinterpret_cast<uint64_t>(D);
}

operator NamedDecl*() const { return getDecl(); }
NamedDecl *operator->() const { return getDecl(); }
};

// Make sure DeclAccessPair is pointer-aligned types.
static_assert(alignof(DeclAccessPair) == alignof(void *));
// Make sure DeclAccessPair is still POD.
static_assert(std::is_standard_layout_v<DeclAccessPair> &&
std::is_trivial_v<DeclAccessPair>);
}

#endif
17 changes: 3 additions & 14 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -708,10 +708,7 @@ class alignas(8) Decl {

/// Set the owning module ID. This may only be called for
/// deserialized Decls.
void setOwningModuleID(unsigned ID) {
assert(isFromASTFile() && "Only works on a deserialized declaration");
*((unsigned*)this - 2) = ID;
}
void setOwningModuleID(unsigned ID);

public:
/// Determine the availability of the given declaration.
Expand Down Expand Up @@ -784,19 +781,11 @@ class alignas(8) Decl {

/// Retrieve the global declaration ID associated with this
/// declaration, which specifies where this Decl was loaded from.
GlobalDeclID getGlobalID() const {
if (isFromASTFile())
return (*((const GlobalDeclID *)this - 1));
return GlobalDeclID();
}
GlobalDeclID getGlobalID() const;

/// Retrieve the global ID of the module that owns this particular
/// declaration.
unsigned getOwningModuleID() const {
if (isFromASTFile())
return *((const unsigned*)this - 2);
return 0;
}
unsigned getOwningModuleID() const;

private:
Module *getOwningModuleSlow() const;
Expand Down
18 changes: 17 additions & 1 deletion clang/include/clang/AST/DeclID.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/iterator.h"

#include <climits>

namespace clang {

/// Predefined declaration IDs.
Expand Down Expand Up @@ -107,12 +109,16 @@ class DeclIDBase {
///
/// DeclID should only be used directly in serialization. All other users
/// should use LocalDeclID or GlobalDeclID.
using DeclID = uint32_t;
using DeclID = uint64_t;

protected:
DeclIDBase() : ID(PREDEF_DECL_NULL_ID) {}
explicit DeclIDBase(DeclID ID) : ID(ID) {}

explicit DeclIDBase(unsigned LocalID, unsigned ModuleFileIndex) {
ID = (DeclID)LocalID | ((DeclID)ModuleFileIndex << 32);
}

public:
DeclID get() const { return ID; }

Expand All @@ -124,6 +130,10 @@ class DeclIDBase {

bool isInvalid() const { return ID == PREDEF_DECL_NULL_ID; }

unsigned getModuleFileIndex() const { return ID >> 32; }

unsigned getLocalDeclIndex() const;

friend bool operator==(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID == RHS.ID;
}
Expand Down Expand Up @@ -156,6 +166,9 @@ class LocalDeclID : public DeclIDBase {
LocalDeclID(PredefinedDeclIDs ID) : Base(ID) {}
explicit LocalDeclID(DeclID ID) : Base(ID) {}

explicit LocalDeclID(unsigned LocalID, unsigned ModuleFileIndex)
: Base(LocalID, ModuleFileIndex) {}

LocalDeclID &operator++() {
++ID;
return *this;
Expand All @@ -175,6 +188,9 @@ class GlobalDeclID : public DeclIDBase {
GlobalDeclID() : Base() {}
explicit GlobalDeclID(DeclID ID) : Base(ID) {}

explicit GlobalDeclID(unsigned LocalID, unsigned ModuleFileIndex)
: Base(LocalID, ModuleFileIndex) {}

// For DeclIDIterator<GlobalDeclID> to be able to convert a GlobalDeclID
// to a LocalDeclID.
explicit operator LocalDeclID() const { return LocalDeclID(this->ID); }
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/OpenACCClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ template <class Impl> class OpenACCClauseVisitor {
case OpenACCClauseKind::CLAUSE_NAME: \
Visit##CLAUSE_NAME##Clause(*cast<OpenACC##CLAUSE_NAME##Clause>(C)); \
return;
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME) \
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, DEPRECATED) \
case OpenACCClauseKind::ALIAS_NAME: \
Visit##CLAUSE_NAME##Clause(*cast<OpenACC##CLAUSE_NAME##Clause>(C)); \
return;
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,20 @@ class QualType {
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
bool isTriviallyCopyableType(const ASTContext &Context) const;

/// Return true if the type is safe to bitwise copy using memcpy/memmove.
///
/// This is an extension in clang: bitwise cloneable types act as trivially
/// copyable types, meaning their underlying bytes can be safely copied by
/// memcpy or memmove. After the copy, the destination object has the same
/// object representation.
///
/// However, there are cases where it is not safe to copy:
/// - When sanitizers, such as AddressSanitizer, add padding with poison,
/// which can cause issues if those poisoned padding bits are accessed.
/// - Types with Objective-C lifetimes, where specific runtime
/// semantics may not be preserved during a bitwise copy.
bool isBitwiseCloneableType(const ASTContext &Context) const;

/// Return true if this is a trivially copyable type
bool isTriviallyCopyConstructibleType(const ASTContext &Context) const;

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/UnresolvedSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class UnresolvedSetIterator : public llvm::iterator_adaptor_base<
// temporaries with defaulted ctors are not zero initialized.
UnresolvedSetIterator() : iterator_adaptor_base(nullptr) {}

uint64_t getDeclID() const { return I->getDeclID(); }
NamedDecl *getDecl() const { return I->getDecl(); }
void setDecl(NamedDecl *ND) const { return I->setDecl(ND); }
AccessSpecifier getAccess() const { return I->getAccess(); }
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_v2bf16, "V2sV2s*0V2s", "t", "at
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_v2bf16, "V2sV2s*1V2s", "t", "atomic-global-pk-add-bf16-inst")
TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_v2bf16, "V2sV2s*3V2s", "t", "atomic-ds-pk-add-16-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_v2f16, "V2hV2h*3V2h", "t", "atomic-ds-pk-add-16-insts")
TARGET_BUILTIN(__builtin_amdgcn_global_load_lds, "vv*1v*3UiiUi", "t", "gfx940-insts")
TARGET_BUILTIN(__builtin_amdgcn_global_load_lds, "vv*1v*3IUiIiIUi", "t", "gfx940-insts")

//===----------------------------------------------------------------------===//
// Deep learning builtins.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ CODEGENOPT(SeparateNamedSections, 1, 0) ///< Set for -fseparate-named-sections.
CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX.
CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr.
CODEGENOPT(AllTocData, 1, 0) ///< AIX -mtocdata
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,reserved,none

CODEGENOPT(ClearASTBeforeBackend , 1, 0) ///< Free the AST before running backend code generation. Only works with -disable-free.
CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory.
Expand Down
9 changes: 6 additions & 3 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,18 @@ class CodeGenOptions : public CodeGenOptionsBase {
std::string BinutilsVersion;

enum class FramePointerKind {
None, // Omit all frame pointers.
NonLeaf, // Keep non-leaf frame pointers.
All, // Keep all frame pointers.
None, // Omit all frame pointers.
Reserved, // Maintain valid frame pointer chain.
NonLeaf, // Keep non-leaf frame pointers.
All, // Keep all frame pointers.
};

static StringRef getFramePointerKindName(FramePointerKind Kind) {
switch (Kind) {
case FramePointerKind::None:
return "none";
case FramePointerKind::Reserved:
return "reserved";
case FramePointerKind::NonLeaf:
return "non-leaf";
case FramePointerKind::All:
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ enum class CudaArch {
GFX1103,
GFX1150,
GFX1151,
GFX1152,
GFX12_GENERIC,
GFX1200,
GFX1201,
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{
/// default).
std::vector<std::string> VerifyPrefixes;

/// The list of -Wsystem-header-in-module=... options used to override
/// The list of -Wsystem-headers-in-module=... options used to override
/// whether -Wsystem-headers is enabled on a per-module basis.
std::vector<std::string> SystemHeaderWarningsModules;

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10082,6 +10082,12 @@ def warn_new_dangling_initializer_list : Warning<
"the allocated initializer list}0 "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingInitializerList>;
def warn_unsupported_lifetime_extension : Warning<
"lifetime extension of "
"%select{temporary|backing array of initializer list}0 created "
"by aggregate initialization using a default member initializer "
"is not yet supported; lifetime of %select{temporary|backing array}0 "
"will end at the end of the full-expression">, InGroup<Dangling>;

// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
Expand Down
22 changes: 11 additions & 11 deletions clang/include/clang/Basic/OpenACCClauses.def
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,31 @@
//
// VISIT_CLAUSE(CLAUSE_NAME)
//
// CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)
// CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, DEPRECATED)

#ifndef CLAUSE_ALIAS
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, false)
#endif

VISIT_CLAUSE(Auto)
VISIT_CLAUSE(Async)
VISIT_CLAUSE(Attach)
VISIT_CLAUSE(Copy)
CLAUSE_ALIAS(PCopy, Copy)
CLAUSE_ALIAS(PresentOrCopy, Copy)
CLAUSE_ALIAS(PCopy, Copy, true)
CLAUSE_ALIAS(PresentOrCopy, Copy, true)
VISIT_CLAUSE(CopyIn)
CLAUSE_ALIAS(PCopyIn, CopyIn)
CLAUSE_ALIAS(PresentOrCopyIn, CopyIn)
CLAUSE_ALIAS(PCopyIn, CopyIn, true)
CLAUSE_ALIAS(PresentOrCopyIn, CopyIn, true)
VISIT_CLAUSE(CopyOut)
CLAUSE_ALIAS(PCopyOut, CopyOut)
CLAUSE_ALIAS(PresentOrCopyOut, CopyOut)
CLAUSE_ALIAS(PCopyOut, CopyOut, true)
CLAUSE_ALIAS(PresentOrCopyOut, CopyOut, true)
VISIT_CLAUSE(Create)
CLAUSE_ALIAS(PCreate, Create)
CLAUSE_ALIAS(PresentOrCreate, Create)
CLAUSE_ALIAS(PCreate, Create, true)
CLAUSE_ALIAS(PresentOrCreate, Create, true)
VISIT_CLAUSE(Default)
VISIT_CLAUSE(DevicePtr)
VISIT_CLAUSE(DeviceType)
CLAUSE_ALIAS(DType, DeviceType)
CLAUSE_ALIAS(DType, DeviceType, false)
VISIT_CLAUSE(FirstPrivate)
VISIT_CLAUSE(If)
VISIT_CLAUSE(Independent)
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ TYPE_TRAIT_2(__reference_converts_from_temporary, ReferenceConvertsFromTemporary
// is not exposed to users.
TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX)

TYPE_TRAIT_1(__is_bitwise_cloneable, IsBitwiseCloneable, KEYALL)

// Embarcadero Expression Traits
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)
EXPRESSION_TRAIT(__is_rvalue_expr, IsRValueExpr, KEYCXX)
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/riscv_vector.td
Original file line number Diff line number Diff line change
Expand Up @@ -2637,7 +2637,8 @@ let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vbrev : RVVOutBuiltinSetZvbb;
defm vclz : RVVOutBuiltinSetZvbb;
defm vctz : RVVOutBuiltinSetZvbb;
defm vcpopv : RVVOutBuiltinSetZvbb;
let IRName = "vcpopv", MaskedIRName = "vcpopv_mask" in
defm vcpop : RVVOutBuiltinSetZvbb;
let OverloadedName = "vwsll" in
defm vwsll : RVVSignedWidenBinBuiltinSetVwsll;
}
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -7724,8 +7724,8 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">,
MarshallingInfoFlag<LangOpts<"PIE">>;

def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">,
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">,
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>,
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,reserved,none">,
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "Reserved", "None"]>,
MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">;


Expand Down
3 changes: 1 addition & 2 deletions clang/include/clang/Lex/DependencyDirectivesScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#ifndef LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H
#define LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H

#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"

Expand Down Expand Up @@ -118,7 +117,7 @@ struct Directive {
bool scanSourceForDependencyDirectives(
StringRef Input, SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
SmallVectorImpl<dependency_directives_scan::Directive> &Directives,
const LangOptions &LangOpts, DiagnosticsEngine *Diags = nullptr,
DiagnosticsEngine *Diags = nullptr,
SourceLocation InputSourceLoc = SourceLocation());

/// Print the previously scanned dependency directives as minimized source text.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class alignas(8) InitializedEntity {
struct C Capture;
};

InitializedEntity() {};
InitializedEntity() {}

/// Create the initialization entity for a variable.
InitializedEntity(VarDecl *Var, EntityKind EK = EK_Variable)
Expand Down
29 changes: 23 additions & 6 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ class DeclOffset {
}
};

// The unaligned decl ID used in the Blobs of bistreams.
using unaligned_decl_id_t =
llvm::support::detail::packed_endian_specific_integral<
serialization::DeclID, llvm::endianness::native,
llvm::support::unaligned>;

/// The number of predefined preprocessed entity IDs.
const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1;

Expand Down Expand Up @@ -1980,33 +1986,44 @@ enum CleanupObjectKind { COK_Block, COK_CompoundLiteral };

/// Describes the categories of an Objective-C class.
struct ObjCCategoriesInfo {
// The ID of the definition
LocalDeclID DefinitionID;
// The ID of the definition. Use unaligned_decl_id_t to keep
// ObjCCategoriesInfo 32-bit aligned.
unaligned_decl_id_t DefinitionID;

// Offset into the array of category lists.
unsigned Offset;

ObjCCategoriesInfo() = default;
ObjCCategoriesInfo(LocalDeclID ID, unsigned Offset)
: DefinitionID(ID.get()), Offset(Offset) {}

LocalDeclID getDefinitionID() const { return LocalDeclID(DefinitionID); }

friend bool operator<(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID < Y.DefinitionID;
return X.getDefinitionID() < Y.getDefinitionID();
}

friend bool operator>(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID > Y.DefinitionID;
return X.getDefinitionID() > Y.getDefinitionID();
}

friend bool operator<=(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID <= Y.DefinitionID;
return X.getDefinitionID() <= Y.getDefinitionID();
}

friend bool operator>=(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID >= Y.DefinitionID;
return X.getDefinitionID() >= Y.getDefinitionID();
}
};

static_assert(alignof(ObjCCategoriesInfo) <= 4);
static_assert(std::is_standard_layout_v<ObjCCategoriesInfo> &&
std::is_trivial_v<ObjCCategoriesInfo>);

/// A key used when looking up entities by \ref DeclarationName.
///
/// Different \ref DeclarationNames are mapped to different keys, but the
Expand Down
36 changes: 16 additions & 20 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,12 +504,6 @@ class ASTReader
/// = I + 1 has already been loaded.
llvm::PagedVector<Decl *> DeclsLoaded;

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

/// Mapping from global declaration IDs to the module in which the
/// declaration resides.
GlobalDeclMapType GlobalDeclMap;

using FileOffset = std::pair<ModuleFile *, uint64_t>;
using FileOffsetsTy = SmallVector<FileOffset, 2>;
using DeclUpdateOffsetsMap = llvm::DenseMap<GlobalDeclID, FileOffsetsTy>;
Expand Down Expand Up @@ -592,10 +586,11 @@ class ASTReader

struct FileDeclsInfo {
ModuleFile *Mod = nullptr;
ArrayRef<LocalDeclID> Decls;
ArrayRef<serialization::unaligned_decl_id_t> Decls;

FileDeclsInfo() = default;
FileDeclsInfo(ModuleFile *Mod, ArrayRef<LocalDeclID> Decls)
FileDeclsInfo(ModuleFile *Mod,
ArrayRef<serialization::unaligned_decl_id_t> Decls)
: Mod(Mod), Decls(Decls) {}
};

Expand All @@ -604,11 +599,7 @@ class ASTReader

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

/// Map from a DeclContext to its lexical contents.
llvm::DenseMap<const DeclContext*, std::pair<ModuleFile*, LexicalContents>>
Expand Down Expand Up @@ -1489,22 +1480,23 @@ class ASTReader
unsigned ClientLoadCapabilities);

public:
class ModuleDeclIterator : public llvm::iterator_adaptor_base<
ModuleDeclIterator, const LocalDeclID *,
std::random_access_iterator_tag, const Decl *,
ptrdiff_t, const Decl *, const Decl *> {
class ModuleDeclIterator
: public llvm::iterator_adaptor_base<
ModuleDeclIterator, const serialization::unaligned_decl_id_t *,
std::random_access_iterator_tag, const Decl *, ptrdiff_t,
const Decl *, const Decl *> {
ASTReader *Reader = nullptr;
ModuleFile *Mod = nullptr;

public:
ModuleDeclIterator() : iterator_adaptor_base(nullptr) {}

ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod,
const LocalDeclID *Pos)
const serialization::unaligned_decl_id_t *Pos)
: iterator_adaptor_base(Pos), Reader(Reader), Mod(Mod) {}

value_type operator*() const {
return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, *I));
return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, (LocalDeclID)*I));
}

value_type operator->() const { return **this; }
Expand Down Expand Up @@ -1544,6 +1536,9 @@ class ASTReader
StringRef Arg2 = StringRef(), StringRef Arg3 = StringRef()) const;
void Error(llvm::Error &&Err) const;

/// Translate a \param GlobalDeclID to the index of DeclsLoaded array.
unsigned translateGlobalDeclIDToIndex(GlobalDeclID ID) const;

public:
/// Load the AST file and validate its contents against the given
/// Preprocessor.
Expand Down Expand Up @@ -1915,7 +1910,8 @@ class ASTReader

/// Retrieve the module file that owns the given declaration, or NULL
/// if the declaration is not from a module file.
ModuleFile *getOwningModuleFile(const Decl *D);
ModuleFile *getOwningModuleFile(const Decl *D) const;
ModuleFile *getOwningModuleFile(GlobalDeclID ID) const;

/// Returns the source location for the decl \p ID.
SourceLocation getSourceLocationForDeclID(GlobalDeclID ID);
Expand Down
18 changes: 3 additions & 15 deletions clang/include/clang/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,23 +454,11 @@ class ModuleFile {
/// by the declaration ID (-1).
const DeclOffset *DeclOffsets = nullptr;

/// Base declaration ID for declarations local to this module.
serialization::DeclID BaseDeclID = 0;

/// Remapping table for declaration IDs in this module.
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
/// module.
///
/// This is effectively a reverse global-to-local mapping for declaration
/// IDs, so that we can interpret a true global ID (for this translation unit)
/// as a local ID (for this module file).
llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs;
/// Base declaration index in ASTReader for declarations local to this module.
unsigned BaseDeclIndex = 0;

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

/// Array of category list location information within this
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Serialization/ModuleManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace serialization {
/// Manages the set of modules loaded by an AST reader.
class ModuleManager {
/// The chain of AST files, in the order in which we started to load
/// them (this order isn't really useful for anything).
/// them.
SmallVector<std::unique_ptr<ModuleFile>, 2> Chain;

/// The chain of non-module PCH files. The first entry is the one named
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,7 @@ class DependencyScanningWorkerFilesystem
///
/// Returns true if the directive tokens are populated for this file entry,
/// false if not (i.e. this entry is not a file or its scan fails).
bool ensureDirectiveTokensArePopulated(EntryRef Entry,
const LangOptions &LangOpts);
bool ensureDirectiveTokensArePopulated(EntryRef Entry);

/// Check whether \p Path exists. By default checks cached result of \c
/// status(), and falls back on FS if unable to do so.
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Tooling/Syntax/Tokens.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,9 @@ class TokenBuffer {
/// "DECL", "(", "a", ")", ";"}
llvm::ArrayRef<syntax::Token> spelledTokens(FileID FID) const;

/// Returns the spelled Token starting at Loc, if there are no such tokens
/// Returns the spelled Token containing the Loc, if there are no such tokens
/// returns nullptr.
const syntax::Token *spelledTokenAt(SourceLocation Loc) const;
const syntax::Token *spelledTokenContaining(SourceLocation Loc) const;

/// Get all tokens that expand a macro in \p FID. For the following input
/// #define FOO B
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ add_clang_library(clangAST
Interp/Record.cpp
Interp/Source.cpp
Interp/State.cpp
Interp/MemberPointer.cpp
Interp/InterpShared.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
Expand Down
40 changes: 33 additions & 7 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,17 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Context,
GlobalDeclID ID, std::size_t Extra) {
// Allocate an extra 8 bytes worth of storage, which ensures that the
// resulting pointer will still be 8-byte aligned.
static_assert(sizeof(unsigned) * 2 >= alignof(Decl),
"Decl won't be misaligned");
static_assert(sizeof(uint64_t) >= alignof(Decl), "Decl won't be misaligned");
void *Start = Context.Allocate(Size + Extra + 8);
void *Result = (char*)Start + 8;

unsigned *PrefixPtr = (unsigned *)Result - 2;
uint64_t *PrefixPtr = (uint64_t *)Result - 1;

// Zero out the first 4 bytes; this is used to store the owning module ID.
PrefixPtr[0] = 0;
*PrefixPtr = ID.get();

// Store the global declaration ID in the second 4 bytes.
PrefixPtr[1] = ID.get();
// We leave the upper 16 bits to store the module IDs. 48 bits should be
// sufficient to store a declaration ID.
assert(*PrefixPtr < llvm::maskTrailingOnes<uint64_t>(48));

return Result;
}
Expand All @@ -111,6 +110,29 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
return ::operator new(Size + Extra, Ctx);
}

GlobalDeclID Decl::getGlobalID() const {
if (!isFromASTFile())
return GlobalDeclID();
// See the comments in `Decl::operator new` for details.
uint64_t ID = *((const uint64_t *)this - 1);
return GlobalDeclID(ID & llvm::maskTrailingOnes<uint64_t>(48));
}

unsigned Decl::getOwningModuleID() const {
if (!isFromASTFile())
return 0;

uint64_t ID = *((const uint64_t *)this - 1);
return ID >> 48;
}

void Decl::setOwningModuleID(unsigned ID) {
assert(isFromASTFile() && "Only works on a deserialized declaration");
uint64_t *IDAddress = (uint64_t *)this - 1;
*IDAddress &= llvm::maskTrailingOnes<uint64_t>(48);
*IDAddress |= (uint64_t)ID << 48;
}

Module *Decl::getOwningModuleSlow() const {
assert(isFromASTFile() && "Not from AST file?");
return getASTContext().getExternalSource()->getModule(getOwningModuleID());
Expand Down Expand Up @@ -2163,3 +2185,7 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,

return DD;
}

unsigned DeclIDBase::getLocalDeclIndex() const {
return ID & llvm::maskTrailingOnes<DeclID>(32);
}
4 changes: 2 additions & 2 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
assert(Source && "getFromExternalSource with no external source");

for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I)
I.setDecl(cast<NamedDecl>(Source->GetExternalDecl(
GlobalDeclID(reinterpret_cast<uintptr_t>(I.getDecl()) >> 2))));
I.setDecl(
cast<NamedDecl>(Source->GetExternalDecl(GlobalDeclID(I.getDeclID()))));
Impl.Decls.setLazy(false);
}

Expand Down
186 changes: 144 additions & 42 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,35 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitMemcpy(CE);
}

case CK_DerivedToBaseMemberPointer: {
assert(classifyPrim(CE->getType()) == PT_MemberPtr);
assert(classifyPrim(SubExpr->getType()) == PT_MemberPtr);
const auto *FromMP = SubExpr->getType()->getAs<MemberPointerType>();
const auto *ToMP = CE->getType()->getAs<MemberPointerType>();

unsigned DerivedOffset = collectBaseOffset(QualType(ToMP->getClass(), 0),
QualType(FromMP->getClass(), 0));

if (!this->visit(SubExpr))
return false;

return this->emitGetMemberPtrBasePop(DerivedOffset, CE);
}

case CK_BaseToDerivedMemberPointer: {
assert(classifyPrim(CE) == PT_MemberPtr);
assert(classifyPrim(SubExpr) == PT_MemberPtr);
const auto *FromMP = SubExpr->getType()->getAs<MemberPointerType>();
const auto *ToMP = CE->getType()->getAs<MemberPointerType>();

unsigned DerivedOffset = collectBaseOffset(QualType(FromMP->getClass(), 0),
QualType(ToMP->getClass(), 0));

if (!this->visit(SubExpr))
return false;
return this->emitGetMemberPtrBasePop(-DerivedOffset, CE);
}

case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
if (!this->visit(SubExpr))
Expand Down Expand Up @@ -187,7 +216,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitCastFloatingIntegral(*ToT, CE);
}

case CK_NullToPointer: {
case CK_NullToPointer:
case CK_NullToMemberPointer: {
if (DiscardResult)
return true;

Expand Down Expand Up @@ -326,7 +356,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitCast(*FromT, *ToT, CE);
}

case CK_PointerToBoolean: {
case CK_PointerToBoolean:
case CK_MemberPointerToBoolean: {
PrimType PtrT = classifyPrim(SubExpr->getType());

// Just emit p != nullptr for this.
Expand Down Expand Up @@ -534,8 +565,23 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
BO->isComparisonOp())
return this->emitComplexComparison(LHS, RHS, BO);

if (BO->isPtrMemOp())
return this->visit(RHS);
if (BO->isPtrMemOp()) {
if (!this->visit(LHS))
return false;

if (!this->visit(RHS))
return false;

if (!this->emitToMemberPtr(BO))
return false;

if (classifyPrim(BO) == PT_MemberPtr)
return true;

if (!this->emitCastMemberPtrPtr(BO))
return false;
return DiscardResult ? this->emitPopPtr(BO) : true;
}

// Typecheck the args.
std::optional<PrimType> LT = classify(LHS->getType());
Expand Down Expand Up @@ -1058,14 +1104,9 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
if (!this->visit(Init))
return false;

if (FieldToInit->isBitField()) {
if (!this->emitInitBitField(T, FieldToInit, E))
return false;
} else {
if (!this->emitInitField(T, FieldToInit->Offset, E))
return false;
}
return this->emitPopPtr(E);
if (FieldToInit->isBitField())
return this->emitInitBitField(T, FieldToInit, E);
return this->emitInitField(T, FieldToInit->Offset, E);
};

auto initCompositeField = [=](const Record::Field *FieldToInit,
Expand Down Expand Up @@ -1101,9 +1142,6 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
else
FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion();

if (!this->emitDupPtr(E))
return false;

const Record::Field *FieldToInit = R->getField(FToInit);
if (std::optional<PrimType> T = classify(Init)) {
if (!initPrimitiveField(FieldToInit, Init, *T))
Expand All @@ -1123,8 +1161,6 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
while (InitIndex < R->getNumFields() &&
R->getField(InitIndex)->Decl->isUnnamedBitField())
++InitIndex;
if (!this->emitDupPtr(E))
return false;

if (std::optional<PrimType> T = classify(Init)) {
const Record::Field *FieldToInit = R->getField(InitIndex);
Expand All @@ -1134,7 +1170,7 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
} else {
// Initializer for a direct base class.
if (const Record::Base *B = R->getBase(Init->getType())) {
if (!this->emitGetPtrBasePop(B->Offset, Init))
if (!this->emitGetPtrBase(B->Offset, Init))
return false;

if (!this->visitInitializer(Init))
Expand Down Expand Up @@ -1467,7 +1503,7 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
// Leave a pointer to the field on the stack.
if (F->Decl->getType()->isReferenceType())
return this->emitGetFieldPop(PT_Ptr, F->Offset, E) && maybeLoadValue();
return this->emitGetPtrField(F->Offset, E) && maybeLoadValue();
return this->emitGetPtrFieldPop(F->Offset, E) && maybeLoadValue();
}

return false;
Expand Down Expand Up @@ -2101,9 +2137,6 @@ bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
if (!this->emitInitField(*T, F.Offset, E))
return false;
} else {
if (!this->emitDupPtr(E))
return false;

if (!this->emitGetPtrField(F.Offset, E))
return false;

Expand Down Expand Up @@ -2773,6 +2806,8 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
return this->emitNullPtr(nullptr, E);
case PT_FnPtr:
return this->emitNullFnPtr(nullptr, E);
case PT_MemberPtr:
return this->emitNullMemberPtr(nullptr, E);
case PT_Float: {
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
}
Expand All @@ -2798,9 +2833,6 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
continue;
}

// TODO: Add GetPtrFieldPop and get rid of this dup.
if (!this->emitDupPtr(E))
return false;
if (!this->emitGetPtrField(Field.Offset, E))
return false;

Expand Down Expand Up @@ -2875,6 +2907,7 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
return this->emitConstBool(Value, E);
case PT_Ptr:
case PT_FnPtr:
case PT_MemberPtr:
case PT_Float:
case PT_IntAP:
case PT_IntAPS:
Expand Down Expand Up @@ -3169,9 +3202,18 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
return this->emitConst(Val.getInt(), ValType, E);

if (Val.isLValue()) {
if (Val.isNullPointer())
return this->emitNull(ValType, nullptr, E);
APValue::LValueBase Base = Val.getLValueBase();
if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>())
return this->visit(BaseExpr);
else if (const auto *VD = Base.dyn_cast<const ValueDecl *>()) {
return this->visitDeclRef(VD, E);
}
} else if (Val.isMemberPointer()) {
if (const ValueDecl *MemberDecl = Val.getMemberPointerDecl())
return this->emitGetMemberPtr(MemberDecl, E);
return this->emitNullMemberPtr(nullptr, E);
}

return false;
Expand All @@ -3180,15 +3222,15 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
const Expr *E) {

if (Val.isStruct()) {
const Record *R = this->getRecord(E->getType());
assert(R);

for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) {
const APValue &F = Val.getStructField(I);
const Record::Field *RF = R->getField(I);

if (F.isInt()) {
if (F.isInt() || F.isLValue() || F.isMemberPointer()) {
PrimType T = classifyPrim(RF->Decl->getType());
if (!this->visitAPValue(F, T, E))
return false;
Expand All @@ -3200,8 +3242,6 @@ bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
PrimType ElemT = classifyPrim(ArrType->getElementType());
assert(ArrType);

if (!this->emitDupPtr(E))
return false;
if (!this->emitGetPtrField(RF->Offset, E))
return false;

Expand All @@ -3214,11 +3254,28 @@ bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,

if (!this->emitPopPtr(E))
return false;
} else if (F.isStruct() || F.isUnion()) {
if (!this->emitGetPtrField(RF->Offset, E))
return false;
if (!this->visitAPValueInitializer(F, E))
return false;
if (!this->emitPopPtr(E))
return false;
} else {
assert(false && "I don't think this should be possible");
}
}
return true;
} else if (Val.isUnion()) {
const FieldDecl *UnionField = Val.getUnionField();
const Record *R = this->getRecord(UnionField->getParent());
assert(R);
const APValue &F = Val.getUnionValue();
const Record::Field *RF = R->getField(UnionField);
PrimType T = classifyPrim(RF->Decl->getType());
if (!this->visitAPValue(F, T, E))
return false;
return this->emitInitElem(T, 0, E);
}
// TODO: Other types.

Expand Down Expand Up @@ -3308,10 +3365,27 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
}
}

std::optional<unsigned> CalleeOffset;
// Add the (optional, implicit) This pointer.
if (const auto *MC = dyn_cast<CXXMemberCallExpr>(E)) {
if (!this->visit(MC->getImplicitObjectArgument()))
if (!FuncDecl && classifyPrim(E->getCallee()) == PT_MemberPtr) {
// If we end up creating a CallPtr op for this, we need the base of the
// member pointer as the instance pointer, and later extract the function
// decl as the function pointer.
const Expr *Callee = E->getCallee();
CalleeOffset =
this->allocateLocalPrimitive(Callee, PT_MemberPtr, true, false);
if (!this->visit(Callee))
return false;
if (!this->emitSetLocal(PT_MemberPtr, *CalleeOffset, E))
return false;
if (!this->emitGetLocal(PT_MemberPtr, *CalleeOffset, E))
return false;
if (!this->emitGetMemberPtrBase(E))
return false;
} else if (!this->visit(MC->getImplicitObjectArgument())) {
return false;
}
}

llvm::BitVector NonNullArgs = collectNonNullArgs(FuncDecl, Args);
Expand Down Expand Up @@ -3380,11 +3454,22 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
ArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr)));

if (!this->visit(E->getCallee()))
return false;
// Get the callee, either from a member pointer saved in CalleeOffset,
// or by just visiting the Callee expr.
if (CalleeOffset) {
if (!this->emitGetLocal(PT_MemberPtr, *CalleeOffset, E))
return false;
if (!this->emitGetMemberPtrDecl(E))
return false;
if (!this->emitCallPtr(ArgSize, E, E))
return false;
} else {
if (!this->visit(E->getCallee()))
return false;

if (!this->emitCallPtr(ArgSize, E, E))
return false;
if (!this->emitCallPtr(ArgSize, E, E))
return false;
}
}

// Cleanup for discarded return values.
Expand Down Expand Up @@ -3623,6 +3708,11 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return false;
return DiscardResult ? this->emitPop(*T, E) : true;
case UO_AddrOf: // &x
if (E->getType()->isMemberPointerType()) {
// C++11 [expr.unary.op]p3 has very strict rules on how the address of a
// member can be formed.
return this->emitGetMemberPtr(cast<DeclRefExpr>(SubExpr)->getDecl(), E);
}
// We should already have a pointer when we get here.
return this->delegate(SubExpr);
case UO_Deref: // *x
Expand Down Expand Up @@ -3745,12 +3835,10 @@ bool ByteCodeExprGen<Emitter>::VisitComplexUnaryOperator(
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
bool ByteCodeExprGen<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
if (DiscardResult)
return true;

const auto *D = E->getDecl();

if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
return this->emitConst(ECD->getInitVal(), E);
} else if (const auto *BD = dyn_cast<BindingDecl>(D)) {
Expand Down Expand Up @@ -3806,6 +3894,14 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
if (IsPtr)
return this->emitGetThisFieldPtr(Offset, E);
return this->emitGetPtrThisField(Offset, E);
} else if (const auto *DRE = dyn_cast<DeclRefExpr>(E);
DRE && DRE->refersToEnclosingVariableOrCapture()) {
if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture()) {
if (!this->visitVarDecl(cast<VarDecl>(D)))
return false;
// Retry.
return this->visitDeclRef(D, E);
}
}

// Try to lazily visit (or emit dummy pointers for) declarations
Expand All @@ -3818,7 +3914,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
if (!this->visitVarDecl(VD))
return false;
// Retry.
return this->VisitDeclRefExpr(E);
return this->visitDeclRef(VD, E);
}
}
} else {
Expand All @@ -3828,7 +3924,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
if (!this->visitVarDecl(VD))
return false;
// Retry.
return this->VisitDeclRefExpr(E);
return this->visitDeclRef(VD, E);
}
}

Expand All @@ -3845,7 +3941,15 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
return true;
}

return this->emitInvalidDeclRef(E, E);
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
return this->emitInvalidDeclRef(DRE, E);
return false;
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
const auto *D = E->getDecl();
return this->visitDeclRef(D, E);
}

template <class Emitter>
Expand Down Expand Up @@ -4085,8 +4189,6 @@ bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Record *R) {
for (const Record::Field &Field : llvm::reverse(R->fields())) {
const Descriptor *D = Field.Desc;
if (!D->isPrimitive() && !D->isPrimitiveArray()) {
if (!this->emitDupPtr(SourceInfo{}))
return false;
if (!this->emitGetPtrField(Field.Offset, SourceInfo{}))
return false;
if (!this->emitDestruction(D))
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
/// Visit an APValue.
bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
bool visitAPValueInitializer(const APValue &Val, const Expr *E);
/// Visit the given decl as if we have a reference to it.
bool visitDeclRef(const ValueDecl *D, const Expr *E);

/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
Expand Down
15 changes: 9 additions & 6 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,12 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (T->isFloatingType())
return PT_Float;

if (T->isSpecificBuiltinType(BuiltinType::BoundMember) ||
T->isMemberPointerType())
return PT_MemberPtr;

if (T->isFunctionPointerType() || T->isFunctionReferenceType() ||
T->isFunctionType() || T->isSpecificBuiltinType(BuiltinType::BoundMember))
T->isFunctionType())
return PT_FnPtr;

if (T->isReferenceType() || T->isPointerType() ||
Expand All @@ -177,9 +181,6 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (const auto *DT = dyn_cast<DecltypeType>(T))
return classify(DT->getUnderlyingType());

if (const auto *DT = dyn_cast<MemberPointerType>(T))
return classify(DT->getPointeeType());

return std::nullopt;
}

Expand Down Expand Up @@ -292,10 +293,12 @@ unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,
}
if (CurDecl == FinalDecl)
break;

// break;
}

assert(OffsetSum > 0);
return OffsetSum;
}

const Record *Context::getRecord(const RecordDecl *D) const {
return P->getOrCreateRecord(D);
}
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ class Context final {
unsigned collectBaseOffset(const RecordDecl *BaseDecl,
const RecordDecl *DerivedDecl) const;

const Record *getRecord(const RecordDecl *D) const;

private:
/// Runs a function.
bool Run(State &Parent, const Function *Func, APValue &Result);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Floating.h"
#include "FunctionPointer.h"
#include "IntegralAP.h"
#include "MemberPointer.h"
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Integral.h"
#include "IntegralAP.h"
#include "InterpFrame.h"
#include "MemberPointer.h"
#include "Opcode.h"
#include "PrimType.h"
#include "Program.h"
Expand Down Expand Up @@ -122,6 +123,8 @@ static const char *primTypeToString(PrimType T) {
return "Ptr";
case PT_FnPtr:
return "FnPtr";
case PT_MemberPtr:
return "MemberPtr";
}
llvm_unreachable("Unhandled PrimType");
}
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
bool ConvertResultToRValue) {
S.setEvalLocation(E->getExprLoc());
this->ConvertResultToRValue = ConvertResultToRValue;
this->CheckFullyInitialized = isa<ConstantExpr>(E);
EvalResult.setSource(E);

if (!this->visitExpr(E)) {
Expand Down Expand Up @@ -175,6 +176,10 @@ bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {

bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
const auto &Ptr = S.Stk.pop<Pointer>();

if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;

if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) {
EvalResult.setValue(*APV);
return true;
Expand Down
14 changes: 6 additions & 8 deletions clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,14 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S,
const Pointer &Ptr) const {
assert(Source);
assert(empty());

// Our Source must be a VarDecl.
const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
assert(SourceDecl);
const auto *VD = cast<VarDecl>(SourceDecl);
assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();

assert(!Ptr.isZero());

SourceLocation InitLoc;
if (const auto *D = Source.dyn_cast<const Decl *>())
InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
else if (const auto *E = Source.dyn_cast<const Expr *>())
InitLoc = E->getExprLoc();

if (const Record *R = Ptr.getRecord())
return CheckFieldsInitialized(S, InitLoc, Ptr, R);
const auto *CAT =
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ SourceInfo Function::getSource(CodePtr PC) const {
unsigned Offset = PC - getCodeBegin();
using Elem = std::pair<unsigned, SourceInfo>;
auto It = llvm::lower_bound(SrcMap, Elem{Offset, {}}, llvm::less_first());
assert(It != SrcMap.end());
if (It == SrcMap.end())
return SrcMap.back().second;
return It->second;
}

Expand Down
39 changes: 31 additions & 8 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,26 @@ bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}

bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
uint32_t Offset) {
uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();
uint32_t PtrOffset = Ptr.getByteOffset();

// We subtract Offset from PtrOffset. The result must be at least
// MinOffset.
if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
return true;

const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
QualType TargetQT = E->getType()->getPointeeType();
QualType MostDerivedQT = Ptr.getDeclPtr().getType();

S.CCEDiag(E, diag::note_constexpr_invalid_downcast)
<< MostDerivedQT << TargetQT;

return false;
}

bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
assert(Ptr.isLive() && "Pointer is not live");
if (!Ptr.isConst())
Expand Down Expand Up @@ -493,10 +513,12 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
return false;
if (!CheckExtern(S, OpPC, Ptr))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
return false;
if (!Ptr.isDummy()) {
if (!CheckExtern(S, OpPC, Ptr))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
return false;
}
return true;
}

Expand All @@ -516,7 +538,7 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
return false;
}

if (!F->isConstexpr()) {
if (!F->isConstexpr() || !F->hasBody()) {
const SourceLocation &Loc = S.Current->getLocation(OpPC);
if (S.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = F->getDecl();
Expand Down Expand Up @@ -550,9 +572,10 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
S.checkingPotentialConstantExpression())
return false;

// If the declaration is defined _and_ declared 'constexpr', the below
// diagnostic doesn't add anything useful.
if (DiagDecl->isDefined() && DiagDecl->isConstexpr())
// If the declaration is defined, declared 'constexpr' _and_ has a body,
// the below diagnostic doesn't add anything useful.
if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
DiagDecl->hasBody())
return false;

S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
Expand Down
132 changes: 128 additions & 4 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "InterpFrame.h"
#include "InterpStack.h"
#include "InterpState.h"
#include "MemberPointer.h"
#include "Opcode.h"
#include "PrimType.h"
#include "Program.h"
Expand Down Expand Up @@ -75,6 +76,11 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
CheckSubobjectKind CSK);

/// Checks if the dowcast using the given offset is possible with the given
/// pointer.
bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
uint32_t Offset);

/// Checks if a pointer points to const storage.
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);

Expand Down Expand Up @@ -725,6 +731,9 @@ using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;

template <typename T>
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
assert((!std::is_same_v<T, MemberPointer>) &&
"Non-equality comparisons on member pointer types should already be "
"rejected in Sema.");
using BoolT = PrimConv<PT_Bool>::T;
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
Expand Down Expand Up @@ -834,6 +843,47 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
}
}

template <>
inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
CompareFn Fn) {
const auto &RHS = S.Stk.pop<MemberPointer>();
const auto &LHS = S.Stk.pop<MemberPointer>();

// If either operand is a pointer to a weak function, the comparison is not
// constant.
for (const auto &MP : {LHS, RHS}) {
if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
return false;
}
}

// C++11 [expr.eq]p2:
// If both operands are null, they compare equal. Otherwise if only one is
// null, they compare unequal.
if (LHS.isZero() && RHS.isZero()) {
S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));
return true;
}
if (LHS.isZero() || RHS.isZero()) {
S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));
return true;
}

// We cannot compare against virtual declarations at compile time.
for (const auto &MP : {LHS, RHS}) {
if (const CXXMethodDecl *MD = MP.getMemberFunction();
MD && MD->isVirtual()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
}
}

S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool EQ(InterpState &S, CodePtr OpPC) {
return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
Expand Down Expand Up @@ -1233,9 +1283,32 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}

/// 1) Pops a Pointer from the stack
/// 1) Peeks a Pointer
/// 2) Pushes Pointer.atField(Off) on the stack
inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
!CheckNull(S, OpPC, Ptr, CSK_Field))
return false;

if (!CheckExtern(S, OpPC, Ptr))
return false;
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false;
if (!CheckArray(S, OpPC, Ptr))
return false;
if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
return false;

if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
return false;

S.Stk.push<Pointer>(Ptr.atField(Off));
return true;
}

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

if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
Expand Down Expand Up @@ -1300,6 +1373,9 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false;
if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
return false;
if (!CheckDowncast(S, OpPC, Ptr, Off))
return false;

S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
return true;
}
Expand All @@ -1324,6 +1400,12 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
return true;
}

inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
const auto &Ptr = S.Stk.pop<MemberPointer>();
S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
return true;
}

inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
if (S.checkingPotentialConstantExpression())
return false;
Expand Down Expand Up @@ -1532,6 +1614,24 @@ inline bool Memcpy(InterpState &S, CodePtr OpPC) {
return DoMemcpy(S, OpPC, Src, Dest);
}

inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
const auto &Member = S.Stk.pop<MemberPointer>();
const auto &Base = S.Stk.pop<Pointer>();

S.Stk.push<MemberPointer>(Member.takeInstance(Base));
return true;
}

inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
const auto &MP = S.Stk.pop<MemberPointer>();

if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
S.Stk.push<Pointer>(*Ptr);
return true;
}
return false;
}

//===----------------------------------------------------------------------===//
// AddOffset, SubOffset
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1696,8 +1796,10 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
return true;
}

T A = T::from(LHS.getIndex());
T B = T::from(RHS.getIndex());
T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
: T::from(LHS.getIndex());
T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
: T::from(RHS.getIndex());
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
}

Expand Down Expand Up @@ -2115,7 +2217,7 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
return false;

if (!Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
S.Stk.push<Pointer>(Ptr.atIndex(0));
return true;
}
Expand Down Expand Up @@ -2329,6 +2431,28 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
return true;
}

inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
S.Stk.push<MemberPointer>(D);
return true;
}

inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
const auto &MP = S.Stk.pop<MemberPointer>();

S.Stk.push<Pointer>(MP.getBase());
return true;
}

inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
const auto &MP = S.Stk.pop<MemberPointer>();

const auto *FD = cast<FunctionDecl>(MP.getDecl());
const auto *Func = S.getContext().getOrCreateFunction(FD);

S.Stk.push<FunctionPointer>(Func);
return true;
}

/// Just emit a diagnostic. The expression that caused emission of this
/// op is not valid in a constant context.
inline bool Invalid(InterpState &S, CodePtr OpPC) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Function.h"
#include "InterpStack.h"
#include "InterpState.h"
#include "MemberPointer.h"
#include "Pointer.h"
#include "PrimType.h"
#include "Program.h"
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/InterpStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Boolean.h"
#include "Floating.h"
#include "Integral.h"
#include "MemberPointer.h"
#include "Pointer.h"
#include <cassert>
#include <cstdlib>
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/InterpStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "FunctionPointer.h"
#include "IntegralAP.h"
#include "MemberPointer.h"
#include "PrimType.h"
#include <memory>
#include <vector>
Expand Down Expand Up @@ -188,6 +189,8 @@ class InterpStack final {
return PT_IntAP;
else if constexpr (std::is_same_v<T, IntegralAP<false>>)
return PT_IntAP;
else if constexpr (std::is_same_v<T, MemberPointer>)
return PT_MemberPtr;

llvm_unreachable("unknown type push()'ed into InterpStack");
}
Expand Down
76 changes: 76 additions & 0 deletions clang/lib/AST/Interp/MemberPointer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===------------------------- MemberPointer.cpp ----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "MemberPointer.h"
#include "Context.h"
#include "FunctionPointer.h"
#include "Program.h"
#include "Record.h"

namespace clang {
namespace interp {

std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
if (!Dcl || isa<FunctionDecl>(Dcl))
return Base;
const FieldDecl *FD = cast<FieldDecl>(Dcl);
assert(FD);

if (!Base.isBlockPointer())
return std::nullopt;

Pointer CastedBase =
(PtrOffset < 0 ? Base.atField(-PtrOffset) : Base.atFieldSub(PtrOffset));

const Record *BaseRecord = CastedBase.getRecord();
if (!BaseRecord)
return std::nullopt;

assert(BaseRecord);
if (FD->getParent() == BaseRecord->getDecl())
return CastedBase.atField(BaseRecord->getField(FD)->Offset);

const RecordDecl *FieldParent = FD->getParent();
const Record *FieldRecord = Ctx.getRecord(FieldParent);

unsigned Offset = 0;
Offset += FieldRecord->getField(FD)->Offset;
Offset += CastedBase.block()->getDescriptor()->getMetadataSize();

if (Offset > CastedBase.block()->getSize())
return std::nullopt;

if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
BaseDecl != FieldParent)
Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);

if (Offset > CastedBase.block()->getSize())
return std::nullopt;

assert(Offset <= CastedBase.block()->getSize());
return Pointer(const_cast<Block *>(Base.block()), Offset, Offset);
}

FunctionPointer MemberPointer::toFunctionPointer(const Context &Ctx) const {
return FunctionPointer(Ctx.getProgram().getFunction(cast<FunctionDecl>(Dcl)));
}

APValue MemberPointer::toAPValue() const {
if (isZero())
return APValue(static_cast<ValueDecl *>(nullptr), /*IsDerivedMember=*/false,
/*Path=*/{});

if (hasBase())
return Base.toAPValue();

return APValue(cast<ValueDecl>(getDecl()), /*IsDerivedMember=*/false,
/*Path=*/{});
}

} // namespace interp
} // namespace clang
112 changes: 112 additions & 0 deletions clang/lib/AST/Interp/MemberPointer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//===------------------------- MemberPointer.h ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_INTERP_MEMBER_POINTER_H
#define LLVM_CLANG_AST_INTERP_MEMBER_POINTER_H

#include "Pointer.h"
#include <optional>

namespace clang {
class ASTContext;
namespace interp {

class Context;
class FunctionPointer;

class MemberPointer final {
private:
Pointer Base;
const Decl *Dcl = nullptr;
int32_t PtrOffset = 0;

MemberPointer(Pointer Base, const Decl *Dcl, int32_t PtrOffset)
: Base(Base), Dcl(Dcl), PtrOffset(PtrOffset) {}

public:
MemberPointer() = default;
MemberPointer(Pointer Base, const Decl *Dcl) : Base(Base), Dcl(Dcl) {}
MemberPointer(uint32_t Address, const Descriptor *D) {
// We only reach this for Address == 0, when creating a null member pointer.
assert(Address == 0);
}

MemberPointer(const Decl *D) : Dcl(D) {
assert((isa<FieldDecl, IndirectFieldDecl, CXXMethodDecl>(D)));
}

uint64_t getIntegerRepresentation() const {
assert(
false &&
"getIntegerRepresentation() shouldn't be reachable for MemberPointers");
return 17;
}

std::optional<Pointer> toPointer(const Context &Ctx) const;

FunctionPointer toFunctionPointer(const Context &Ctx) const;

Pointer getBase() const {
if (PtrOffset < 0)
return Base.atField(-PtrOffset);
return Base.atFieldSub(PtrOffset);
}
bool isMemberFunctionPointer() const {
return isa_and_nonnull<CXXMethodDecl>(Dcl);
}
const CXXMethodDecl *getMemberFunction() const {
return dyn_cast_if_present<CXXMethodDecl>(Dcl);
}
const FieldDecl *getField() const {
return dyn_cast_if_present<FieldDecl>(Dcl);
}

bool hasDecl() const { return Dcl; }
const Decl *getDecl() const { return Dcl; }

MemberPointer atInstanceBase(unsigned Offset) const {
if (Base.isZero())
return MemberPointer(Base, Dcl, Offset);
return MemberPointer(this->Base, Dcl, Offset + PtrOffset);
}

MemberPointer takeInstance(Pointer Instance) const {
assert(this->Base.isZero());
return MemberPointer(Instance, this->Dcl, this->PtrOffset);
}

APValue toAPValue() const;

bool isZero() const { return Base.isZero() && !Dcl; }
bool hasBase() const { return !Base.isZero(); }

void print(llvm::raw_ostream &OS) const {
OS << "MemberPtr(" << Base << " " << (const void *)Dcl << " + " << PtrOffset
<< ")";
}

std::string toDiagnosticString(const ASTContext &Ctx) const {
return "FIXME";
}

ComparisonCategoryResult compare(const MemberPointer &RHS) const {
if (this->Dcl == RHS.Dcl)
return ComparisonCategoryResult::Equal;
return ComparisonCategoryResult::Unordered;
}
};

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MemberPointer FP) {
FP.print(OS);
return OS;
}

} // namespace interp
} // namespace clang

#endif
62 changes: 27 additions & 35 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def IntAPS : Type;
def Float : Type;
def Ptr : Type;
def FnPtr : Type;
def MemberPtr : Type;

//===----------------------------------------------------------------------===//
// Types transferred to the interpreter.
Expand Down Expand Up @@ -61,6 +62,7 @@ def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; }
def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; }
def ArgDesc : ArgType { let Name = "const Descriptor *"; }
def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; }
def ArgDecl : ArgType { let Name = "const Decl*"; }

//===----------------------------------------------------------------------===//
// Classes of types instructions operate on.
Expand Down Expand Up @@ -93,7 +95,7 @@ def AluTypeClass : TypeClass {
}

def PtrTypeClass : TypeClass {
let Types = [Ptr, FnPtr];
let Types = [Ptr, FnPtr, MemberPtr];
}

def BoolTypeClass : TypeClass {
Expand Down Expand Up @@ -208,7 +210,6 @@ def CallBI : Opcode {

def CallPtr : Opcode {
let Args = [ArgUint32, ArgCallExpr];
let Types = [];
}

def CallVar : Opcode {
Expand Down Expand Up @@ -280,54 +281,37 @@ def Null : Opcode {
//===----------------------------------------------------------------------===//
// Pointer generation
//===----------------------------------------------------------------------===//
class OffsetOpcode : Opcode {
let Args = [ArgUint32];
}

// [] -> [Pointer]
def GetPtrLocal : Opcode {
// Offset of local.
let Args = [ArgUint32];
def GetPtrLocal : OffsetOpcode {
bit HasCustomEval = 1;
}
// [] -> [Pointer]
def GetPtrParam : Opcode {
// Offset of parameter.
let Args = [ArgUint32];
}
def GetPtrParam : OffsetOpcode;
// [] -> [Pointer]
def GetPtrGlobal : Opcode {
// Index of global.
let Args = [ArgUint32];
}
def GetPtrGlobal : OffsetOpcode;
// [Pointer] -> [Pointer]
def GetPtrField : Opcode {
// Offset of field.
let Args = [ArgUint32];
}
def GetPtrField : OffsetOpcode;
def GetPtrFieldPop : OffsetOpcode;
// [Pointer] -> [Pointer]
def GetPtrActiveField : Opcode {
// Offset of field.
let Args = [ArgUint32];
}
def GetPtrActiveField : OffsetOpcode;
// [] -> [Pointer]
def GetPtrActiveThisField : Opcode {
// Offset of field.
let Args = [ArgUint32];
}
def GetPtrActiveThisField : OffsetOpcode;
// [] -> [Pointer]
def GetPtrThisField : Opcode {
// Offset of field.
let Args = [ArgUint32];
}
def GetPtrThisField : OffsetOpcode;
// [Pointer] -> [Pointer]
def GetPtrBase : Opcode {
// Offset of field, which is a base.
let Args = [ArgUint32];
}
def GetPtrBase : OffsetOpcode;
// [Pointer] -> [Pointer]
def GetPtrBasePop : Opcode {
def GetPtrBasePop : OffsetOpcode;
def GetMemberPtrBasePop : Opcode {
// Offset of field, which is a base.
let Args = [ArgUint32];
let Args = [ArgSint32];
}


def FinishInitPop : Opcode;
def FinishInit : Opcode;

Expand Down Expand Up @@ -751,6 +735,14 @@ def CheckNonNullArg : Opcode {

def Memcpy : Opcode;

def ToMemberPtr : Opcode;
def CastMemberPtrPtr : Opcode;
def GetMemberPtr : Opcode {
let Args = [ArgDecl];
}
def GetMemberPtrBase : Opcode;
def GetMemberPtrDecl : Opcode;

//===----------------------------------------------------------------------===//
// Debugging.
//===----------------------------------------------------------------------===//
Expand Down
47 changes: 25 additions & 22 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "Function.h"
#include "Integral.h"
#include "InterpBlock.h"
#include "MemberPointer.h"
#include "PrimType.h"
#include "Record.h"

Expand Down Expand Up @@ -63,53 +64,55 @@ Pointer::~Pointer() {
}

void Pointer::operator=(const Pointer &P) {
if (!this->isIntegralPointer() || !P.isBlockPointer())
assert(P.StorageKind == StorageKind || (this->isZero() && P.isZero()));

// If the current storage type is Block, we need to remove
// this pointer from the block.
bool WasBlockPointer = isBlockPointer();
StorageKind = P.StorageKind;
if (StorageKind == Storage::Block) {
Block *Old = PointeeStorage.BS.Pointee;
if (WasBlockPointer && PointeeStorage.BS.Pointee)
if (WasBlockPointer && Old) {
PointeeStorage.BS.Pointee->removePointer(this);
Old->cleanup();
}
}

Offset = P.Offset;
StorageKind = P.StorageKind;
Offset = P.Offset;

if (P.isBlockPointer()) {
PointeeStorage.BS = P.PointeeStorage.BS;
PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;

if (PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);

if (WasBlockPointer && Old)
Old->cleanup();

} else if (StorageKind == Storage::Int) {
} else if (P.isIntegralPointer()) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else {
assert(false && "Unhandled storage kind");
}
}

void Pointer::operator=(Pointer &&P) {
if (!this->isIntegralPointer() || !P.isBlockPointer())
assert(P.StorageKind == StorageKind || (this->isZero() && P.isZero()));

// If the current storage type is Block, we need to remove
// this pointer from the block.
bool WasBlockPointer = isBlockPointer();
StorageKind = P.StorageKind;
if (StorageKind == Storage::Block) {
Block *Old = PointeeStorage.BS.Pointee;
if (WasBlockPointer && PointeeStorage.BS.Pointee)
if (WasBlockPointer && Old) {
PointeeStorage.BS.Pointee->removePointer(this);
Old->cleanup();
}
}

Offset = P.Offset;
StorageKind = P.StorageKind;
Offset = P.Offset;

if (P.isBlockPointer()) {
PointeeStorage.BS = P.PointeeStorage.BS;
PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;

if (PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);

if (WasBlockPointer && Old)
Old->cleanup();

} else if (StorageKind == Storage::Int) {
} else if (P.isIntegralPointer()) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else {
assert(false && "Unhandled storage kind");
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ class Pointer {
private:
friend class Block;
friend class DeadBlock;
friend class MemberPointer;
friend struct InitMap;

Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/PrimType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Floating.h"
#include "FunctionPointer.h"
#include "IntegralAP.h"
#include "MemberPointer.h"
#include "Pointer.h"

using namespace clang;
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/AST/Interp/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Pointer;
class Boolean;
class Floating;
class FunctionPointer;
class MemberPointer;
template <bool Signed> class IntegralAP;
template <unsigned Bits, bool Signed> class Integral;

Expand All @@ -44,10 +45,11 @@ enum PrimType : unsigned {
PT_Float = 11,
PT_Ptr = 12,
PT_FnPtr = 13,
PT_MemberPtr = 14,
};

inline constexpr bool isPtrType(PrimType T) {
return T == PT_Ptr || T == PT_FnPtr;
return T == PT_Ptr || T == PT_FnPtr || T == PT_MemberPtr;
}

enum class CastKind : uint8_t {
Expand Down Expand Up @@ -91,6 +93,9 @@ template <> struct PrimConv<PT_Ptr> { using T = Pointer; };
template <> struct PrimConv<PT_FnPtr> {
using T = FunctionPointer;
};
template <> struct PrimConv<PT_MemberPtr> {
using T = MemberPointer;
};

/// Returns the size of a primitive type in bytes.
size_t primSize(PrimType Type);
Expand Down Expand Up @@ -131,6 +136,7 @@ static inline bool aligned(const void *P) {
TYPE_SWITCH_CASE(PT_Bool, B) \
TYPE_SWITCH_CASE(PT_Ptr, B) \
TYPE_SWITCH_CASE(PT_FnPtr, B) \
TYPE_SWITCH_CASE(PT_MemberPtr, B) \
} \
} while (0)

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/OpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ OpenACCClause::child_range OpenACCClause::children() {
#define VISIT_CLAUSE(CLAUSE_NAME) \
case OpenACCClauseKind::CLAUSE_NAME: \
return cast<OpenACC##CLAUSE_NAME##Clause>(this)->children();
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME) \
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, DEPRECATED) \
case OpenACCClauseKind::ALIAS_NAME: \
return cast<OpenACC##CLAUSE_NAME##Clause>(this)->children();

Expand Down
16 changes: 0 additions & 16 deletions clang/lib/AST/ParentMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,22 +97,6 @@ static void BuildParentMap(MapTy& M, Stmt* S,
BuildParentMap(M, SubStmt, OVMode);
}
break;
case Stmt::CXXDefaultArgExprClass:
if (auto *Arg = dyn_cast<CXXDefaultArgExpr>(S)) {
if (Arg->hasRewrittenInit()) {
M[Arg->getExpr()] = S;
BuildParentMap(M, Arg->getExpr(), OVMode);
}
}
break;
case Stmt::CXXDefaultInitExprClass:
if (auto *Init = dyn_cast<CXXDefaultInitExpr>(S)) {
if (Init->hasRewrittenInit()) {
M[Init->getExpr()] = S;
BuildParentMap(M, Init->getExpr(), OVMode);
}
}
break;
default:
for (Stmt *SubStmt : S->children()) {
if (SubStmt) {
Expand Down
21 changes: 13 additions & 8 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,9 @@ void TextNodeDumper::dumpTemplateArgument(const TemplateArgument &TA) {
}
OS << " '" << Str << "'";

if (!Context)
return;

if (TemplateArgument CanonTA = Context->getCanonicalTemplateArgument(TA);
!CanonTA.structurallyEquals(TA)) {
llvm::SmallString<128> CanonStr;
Expand Down Expand Up @@ -1139,15 +1142,17 @@ void TextNodeDumper::dumpTemplateName(TemplateName TN, StringRef Label) {
}
OS << " '" << Str << "'";

if (TemplateName CanonTN = Context->getCanonicalTemplateName(TN);
CanonTN != TN) {
llvm::SmallString<128> CanonStr;
{
llvm::raw_svector_ostream SS(CanonStr);
CanonTN.print(SS, PrintPolicy);
if (Context) {
if (TemplateName CanonTN = Context->getCanonicalTemplateName(TN);
CanonTN != TN) {
llvm::SmallString<128> CanonStr;
{
llvm::raw_svector_ostream SS(CanonStr);
CanonTN.print(SS, PrintPolicy);
}
if (CanonStr != Str)
OS << ":'" << CanonStr << "'";
}
if (CanonStr != Str)
OS << ":'" << CanonStr << "'";
}
}
dumpBareTemplateName(TN);
Expand Down
38 changes: 37 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2749,6 +2749,43 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
/*IsCopyConstructible=*/false);
}

// FIXME: each call will trigger a full computation, cache the result.
bool QualType::isBitwiseCloneableType(const ASTContext &Context) const {
auto CanonicalType = getCanonicalType();
if (CanonicalType.hasNonTrivialObjCLifetime())
return false;
if (CanonicalType->isArrayType())
return Context.getBaseElementType(CanonicalType)
.isBitwiseCloneableType(Context);

if (CanonicalType->isIncompleteType())
return false;
const auto *RD = CanonicalType->getAsRecordDecl(); // struct/union/class
if (!RD)
return true;

// Never allow memcpy when we're adding poisoned padding bits to the struct.
// Accessing these posioned bits will trigger false alarms on
// SanitizeAddressFieldPadding etc.
if (RD->mayInsertExtraPadding())
return false;

for (auto *const Field : RD->fields()) {
if (!Field->getType().isBitwiseCloneableType(Context))
return false;
}

if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
for (auto Base : CXXRD->bases())
if (!Base.getType().isBitwiseCloneableType(Context))
return false;
for (auto VBase : CXXRD->vbases())
if (!VBase.getType().isBitwiseCloneableType(Context))
return false;
}
return true;
}

bool QualType::isTriviallyCopyConstructibleType(
const ASTContext &Context) const {
return isTriviallyCopyableTypeImpl(*this, Context,
Expand Down Expand Up @@ -4444,7 +4481,6 @@ static CachedProperties computeCachedProperties(const Type *T) {
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
#include "clang/AST/TypeNodes.inc"
// Treat instantiation-dependent types as external.
if (!T->isInstantiationDependentType()) T->dump();
assert(T->isInstantiationDependentType());
return CachedProperties(Linkage::External, false);

Expand Down
50 changes: 9 additions & 41 deletions clang/lib/Analysis/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,10 +556,6 @@ class CFGBuilder {

private:
// Visitors to walk an AST and construct the CFG.
CFGBlock *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Default,
AddStmtChoice asc);
CFGBlock *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Default,
AddStmtChoice asc);
CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc);
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc);
Expand Down Expand Up @@ -2258,10 +2254,16 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
asc, ExternallyDestructed);

case Stmt::CXXDefaultArgExprClass:
return VisitCXXDefaultArgExpr(cast<CXXDefaultArgExpr>(S), asc);

case Stmt::CXXDefaultInitExprClass:
return VisitCXXDefaultInitExpr(cast<CXXDefaultInitExpr>(S), asc);
// FIXME: The expression inside a CXXDefaultArgExpr is owned by the
// called function's declaration, not by the caller. If we simply add
// this expression to the CFG, we could end up with the same Expr
// appearing multiple times (PR13385).
//
// It's likewise possible for multiple CXXDefaultInitExprs for the same
// expression to be used in the same function (through aggregate
// initialization).
return VisitStmt(S, asc);

case Stmt::CXXBindTemporaryExprClass:
return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
Expand Down Expand Up @@ -2431,40 +2433,6 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
return B;
}

CFGBlock *CFGBuilder::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Arg,
AddStmtChoice asc) {
if (Arg->hasRewrittenInit()) {
if (asc.alwaysAdd(*this, Arg)) {
autoCreateBlock();
appendStmt(Block, Arg);
}
return VisitStmt(Arg->getExpr(), asc);
}

// We can't add the default argument if it's not rewritten because the
// expression inside a CXXDefaultArgExpr is owned by the called function's
// declaration, not by the caller, we could end up with the same expression
// appearing multiple times.
return VisitStmt(Arg, asc);
}

CFGBlock *CFGBuilder::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Init,
AddStmtChoice asc) {
if (Init->hasRewrittenInit()) {
if (asc.alwaysAdd(*this, Init)) {
autoCreateBlock();
appendStmt(Block, Init);
}
return VisitStmt(Init->getExpr(), asc);
}

// We can't add the default initializer if it's not rewritten because multiple
// CXXDefaultInitExprs for the same sub-expression to be used in the same
// function (through aggregate initialization). we could end up with the same
// expression appearing multiple times.
return VisitStmt(Init, asc);
}

CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
if (asc.alwaysAdd(*this, ILE)) {
autoCreateBlock();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ static const CudaArchToStringMap arch_names[] = {
GFX(1103), // gfx1103
GFX(1150), // gfx1150
GFX(1151), // gfx1151
GFX(1152), // gfx1152
{CudaArch::GFX12_GENERIC, "gfx12-generic", "compute_amdgcn"},
GFX(1200), // gfx1200
GFX(1201), // gfx1201
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Basic/Targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,8 +673,11 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
}
case llvm::Triple::spirv64: {
if (os != llvm::Triple::UnknownOS ||
Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) {
if (os == llvm::Triple::OSType::AMDHSA)
return std::make_unique<SPIRV64AMDGCNTargetInfo>(Triple, Opts);
return nullptr;
}
return std::make_unique<SPIRV64TargetInfo>(Triple, Opts);
}
case llvm::Triple::wasm32:
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/LoongArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArch64TargetInfo
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = Int64Type = SignedLong;
HasUnalignedAccess = true;
resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n64-S128");
resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128");
// TODO: select appropriate ABI.
setABI("lp64d");
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/NVPTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts,
case CudaArch::GFX1103:
case CudaArch::GFX1150:
case CudaArch::GFX1151:
case CudaArch::GFX1152:
case CudaArch::GFX12_GENERIC:
case CudaArch::GFX1200:
case CudaArch::GFX1201:
Expand Down
75 changes: 75 additions & 0 deletions clang/lib/Basic/Targets/SPIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//

#include "SPIR.h"
#include "AMDGPU.h"
#include "Targets.h"
#include "llvm/TargetParser/TargetParser.h"

using namespace clang;
using namespace clang::targets;
Expand Down Expand Up @@ -54,3 +56,76 @@ void SPIRV64TargetInfo::getTargetDefines(const LangOptions &Opts,
BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder);
DefineStd(Builder, "SPIRV64", Opts);
}

static const AMDGPUTargetInfo AMDGPUTI(llvm::Triple("amdgcn-amd-amdhsa"), {});

ArrayRef<const char *> SPIRV64AMDGCNTargetInfo::getGCCRegNames() const {
return AMDGPUTI.getGCCRegNames();
}

bool SPIRV64AMDGCNTargetInfo::initFeatureMap(
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef,
const std::vector<std::string> &FeatureVec) const {
llvm::AMDGPU::fillAMDGPUFeatureMap({}, getTriple(), Features);

return TargetInfo::initFeatureMap(Features, Diags, {}, FeatureVec);
}

bool SPIRV64AMDGCNTargetInfo::validateAsmConstraint(
const char *&Name, TargetInfo::ConstraintInfo &Info) const {
return AMDGPUTI.validateAsmConstraint(Name, Info);
}

std::string
SPIRV64AMDGCNTargetInfo::convertConstraint(const char *&Constraint) const {
return AMDGPUTI.convertConstraint(Constraint);
}

ArrayRef<Builtin::Info> SPIRV64AMDGCNTargetInfo::getTargetBuiltins() const {
return AMDGPUTI.getTargetBuiltins();
}

void SPIRV64AMDGCNTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder);
DefineStd(Builder, "SPIRV64", Opts);

Builder.defineMacro("__AMD__");
Builder.defineMacro("__AMDGPU__");
Builder.defineMacro("__AMDGCN__");
}

void SPIRV64AMDGCNTargetInfo::setAuxTarget(const TargetInfo *Aux) {
assert(Aux && "Cannot invoke setAuxTarget without a valid auxiliary target!");

// This is a 1:1 copy of AMDGPUTargetInfo::setAuxTarget()
assert(HalfFormat == Aux->HalfFormat);
assert(FloatFormat == Aux->FloatFormat);
assert(DoubleFormat == Aux->DoubleFormat);

// On x86_64 long double is 80-bit extended precision format, which is
// not supported by AMDGPU. 128-bit floating point format is also not
// supported by AMDGPU. Therefore keep its own format for these two types.
auto SaveLongDoubleFormat = LongDoubleFormat;
auto SaveFloat128Format = Float128Format;
auto SaveLongDoubleWidth = LongDoubleWidth;
auto SaveLongDoubleAlign = LongDoubleAlign;
copyAuxTarget(Aux);
LongDoubleFormat = SaveLongDoubleFormat;
Float128Format = SaveFloat128Format;
LongDoubleWidth = SaveLongDoubleWidth;
LongDoubleAlign = SaveLongDoubleAlign;
// For certain builtin types support on the host target, claim they are
// supported to pass the compilation of the host code during the device-side
// compilation.
// FIXME: As the side effect, we also accept `__float128` uses in the device
// code. To reject these builtin types supported in the host target but not in
// the device target, one approach would support `device_builtin` attribute
// so that we could tell the device builtin types from the host ones. This
// also solves the different representations of the same builtin type, such
// as `size_t` in the MSVC environment.
if (Aux->hasFloat128Type()) {
HasFloat128 = true;
Float128Format = DoubleFormat;
}
}
51 changes: 51 additions & 0 deletions clang/lib/Basic/Targets/SPIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,57 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
MacroBuilder &Builder) const override;
};

class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final
: public BaseSPIRVTargetInfo {
public:
SPIRV64AMDGCNTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: BaseSPIRVTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spirv64 &&
"Invalid architecture for 64-bit AMDGCN SPIR-V.");
assert(Triple.getVendor() == llvm::Triple::VendorType::AMD &&
"64-bit AMDGCN SPIR-V target must use AMD vendor");
assert(getTriple().getOS() == llvm::Triple::OSType::AMDHSA &&
"64-bit AMDGCN SPIR-V target must use AMDHSA OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
"64-bit SPIR-V target must use unknown environment type");
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;

resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1-P4-A0");

BFloat16Width = BFloat16Align = 16;
BFloat16Format = &llvm::APFloat::BFloat();

HasLegalHalfType = true;
HasFloat16 = true;
HalfArgsAndReturns = true;
}

bool hasBFloat16Type() const override { return true; }

ArrayRef<const char *> getGCCRegNames() const override;

bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
StringRef,
const std::vector<std::string> &) const override;

bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const override;

std::string convertConstraint(const char *&Constraint) const override;

ArrayRef<Builtin::Info> getTargetBuiltins() const override;

void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;

void setAuxTarget(const TargetInfo *Aux) override;

bool hasInt128Type() const override { return TargetInfo::hasInt128Type(); }
};

} // namespace targets
} // namespace clang
#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
7 changes: 7 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6012,6 +6012,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch());
if (!Prefix.empty()) {
IntrinsicID = Intrinsic::getIntrinsicForClangBuiltin(Prefix.data(), Name);
if (IntrinsicID == Intrinsic::not_intrinsic && Prefix == "spv" &&
getTarget().getTriple().getOS() == llvm::Triple::OSType::AMDHSA)
IntrinsicID = Intrinsic::getIntrinsicForClangBuiltin("amdgcn", Name);
// NOTE we don't need to perform a compatibility flag check here since the
// intrinsics are declared in Builtins*.def via LANGBUILTIN which filter the
// MS builtins via ALL_MS_LANGUAGES and are filtered earlier.
Expand Down Expand Up @@ -6182,6 +6185,10 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue);
case llvm::Triple::spirv64:
if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
return nullptr;
return CGF->EmitAMDGPUBuiltinExpr(BuiltinID, E);
default:
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1917,6 +1917,7 @@ static void getTrivialDefaultFunctionAttributes(
case CodeGenOptions::FramePointerKind::None:
// This is the default behavior.
break;
case CodeGenOptions::FramePointerKind::Reserved:
case CodeGenOptions::FramePointerKind::NonLeaf:
case CodeGenOptions::FramePointerKind::All:
FuncAttrs.addAttribute("frame-pointer",
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3537,6 +3537,7 @@ void CGOpenMPRuntimeGPU::processRequiresDirective(
case CudaArch::GFX1103:
case CudaArch::GFX1150:
case CudaArch::GFX1151:
case CudaArch::GFX1152:
case CudaArch::GFX12_GENERIC:
case CudaArch::GFX1200:
case CudaArch::GFX1201:
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,9 @@ void CodeGenModule::Release() {
case CodeGenOptions::FramePointerKind::None:
// 0 ("none") is the default.
break;
case CodeGenOptions::FramePointerKind::Reserved:
getModule().setFramePointer(llvm::FramePointerKind::Reserved);
break;
case CodeGenOptions::FramePointerKind::NonLeaf:
getModule().setFramePointer(llvm::FramePointerKind::NonLeaf);
break;
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/Targets/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const {

Address AMDGPUABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const {
llvm_unreachable("AMDGPU does not support varargs");
const bool IsIndirect = false;
const bool AllowHigherAlign = false;
return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
getContext().getTypeInfoInChars(Ty),
CharUnits::fromQuantity(4), AllowHigherAlign);
}

ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const {
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,8 +799,6 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
StringRef FrameChainOption = A->getValue();
if (FrameChainOption.starts_with("aapcs"))
Features.push_back("+aapcs-frame-chain");
if (FrameChainOption == "aapcs+leaf")
Features.push_back("+aapcs-frame-chain-leaf");
}

// CMSE: Check for target 8M (for -mcmse to be applicable) is performed later.
Expand Down
Loading