114 changes: 61 additions & 53 deletions clang-tools-extra/clang-doc/HTMLGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class HTMLTag {
operator TagType() const { return Value; }
operator bool() = delete;

bool IsSelfClosing() const;
bool isSelfClosing() const;
llvm::SmallString<16> ToString() const;

private:
Expand All @@ -71,7 +71,7 @@ struct HTMLNode {
HTMLNode(NodeType Type) : Type(Type) {}
virtual ~HTMLNode() = default;

virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
virtual void render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
NodeType Type; // Type of node
};

Expand All @@ -80,7 +80,7 @@ struct TextNode : public HTMLNode {
: HTMLNode(NodeType::NODE_TEXT), Text(Text.str()) {}

std::string Text; // Content of node
void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
void render(llvm::raw_ostream &OS, int IndentationLevel) override;
};

struct TagNode : public HTMLNode {
Expand All @@ -94,25 +94,25 @@ struct TagNode : public HTMLNode {
std::vector<std::pair<std::string, std::string>>
Attributes; // List of key-value attributes for tag

void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
void render(llvm::raw_ostream &OS, int IndentationLevel) override;
};

constexpr const char *kDoctypeDecl = "<!DOCTYPE html>";

struct HTMLFile {
std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
void Render(llvm::raw_ostream &OS) {
void render(llvm::raw_ostream &OS) {
OS << kDoctypeDecl << "\n";
for (const auto &C : Children) {
C->Render(OS, 0);
C->render(OS, 0);
OS << "\n";
}
}
};

} // namespace

bool HTMLTag::IsSelfClosing() const {
bool HTMLTag::isSelfClosing() const {
switch (Value) {
case HTMLTag::TAG_META:
case HTMLTag::TAG_LINK:
Expand Down Expand Up @@ -177,12 +177,12 @@ llvm::SmallString<16> HTMLTag::ToString() const {
llvm_unreachable("Unhandled HTMLTag::TagType");
}

void TextNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
void TextNode::render(llvm::raw_ostream &OS, int IndentationLevel) {
OS.indent(IndentationLevel * 2);
printHTMLEscaped(Text, OS);
}

void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
void TagNode::render(llvm::raw_ostream &OS, int IndentationLevel) {
// Children nodes are rendered in the same line if all of them are text nodes
bool InlineChildren = true;
for (const auto &C : Children)
Expand All @@ -194,7 +194,7 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
OS << "<" << Tag.ToString();
for (const auto &A : Attributes)
OS << " " << A.first << "=\"" << A.second << "\"";
if (Tag.IsSelfClosing()) {
if (Tag.isSelfClosing()) {
OS << "/>";
return;
}
Expand All @@ -205,7 +205,7 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
for (const auto &C : Children) {
int ChildrenIndentation =
InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
C->Render(OS, ChildrenIndentation);
C->render(OS, ChildrenIndentation);
if (!InlineChildren && (C == Children.back() ||
(C->Type != NodeType::NODE_TEXT ||
(&C + 1)->get()->Type != NodeType::NODE_TEXT))) {
Expand All @@ -221,7 +221,7 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {

template <typename Derived, typename Base,
typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
static void AppendVector(std::vector<Derived> &&New,
static void appendVector(std::vector<Derived> &&New,
std::vector<Base> &Original) {
std::move(New.begin(), New.end(), std::back_inserter(Original));
}
Expand Down Expand Up @@ -289,9 +289,18 @@ genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
static std::vector<std::unique_ptr<TagNode>>
genJsScriptsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
std::vector<std::unique_ptr<TagNode>> Out;

// index_json.js is part of every generated HTML file
SmallString<128> IndexJSONPath = computeRelativePath("", InfoPath);
auto IndexJSONNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
llvm::sys::path::append(IndexJSONPath, "index_json.js");
llvm::sys::path::native(IndexJSONPath, llvm::sys::path::Style::posix);
IndexJSONNode->Attributes.emplace_back("src", std::string(IndexJSONPath));
Out.emplace_back(std::move(IndexJSONNode));

for (const auto &FilePath : CDCtx.JsScripts) {
auto ScriptNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
SmallString<128> ScriptPath = computeRelativePath("", InfoPath);
auto ScriptNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath));
// Paths in HTML must be in posix-style
llvm::sys::path::native(ScriptPath, llvm::sys::path::Style::posix);
Expand All @@ -313,8 +322,7 @@ genReference(const Reference &Type, StringRef CurrentDirectory,
if (Type.Path.empty()) {
if (!JumpToSection)
return std::make_unique<TextNode>(Type.Name);
else
return genLink(Type.Name, "#" + *JumpToSection);
return genLink(Type.Name, "#" + *JumpToSection);
}
llvm::SmallString<64> Path = Type.getRelativeFilePath(CurrentDirectory);
llvm::sys::path::append(Path, Type.getFileBaseName() + ".html");
Expand Down Expand Up @@ -357,7 +365,7 @@ genEnumsBlock(const std::vector<EnumInfo> &Enums,
auto &DivBody = Out.back();
for (const auto &E : Enums) {
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E, CDCtx);
AppendVector(std::move(Nodes), DivBody->Children);
appendVector(std::move(Nodes), DivBody->Children);
}
return Out;
}
Expand Down Expand Up @@ -388,7 +396,7 @@ genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
for (const auto &F : Functions) {
std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(F, CDCtx, ParentInfoDir);
AppendVector(std::move(Nodes), DivBody->Children);
appendVector(std::move(Nodes), DivBody->Children);
}
return Out;
}
Expand Down Expand Up @@ -478,10 +486,10 @@ genFileHeadNodes(StringRef Title, StringRef InfoPath,
Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title));
std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
genStylesheetsHTML(InfoPath, CDCtx);
AppendVector(std::move(StylesheetsNodes), Out);
appendVector(std::move(StylesheetsNodes), Out);
std::vector<std::unique_ptr<TagNode>> JsNodes =
genJsScriptsHTML(InfoPath, CDCtx);
AppendVector(std::move(JsNodes), Out);
appendVector(std::move(JsNodes), Out);
return Out;
}

Expand Down Expand Up @@ -513,15 +521,15 @@ static std::unique_ptr<TagNode> genInfoFileMainNode(
MainContentNode->Attributes.emplace_back("id", "main-content");
MainContentNode->Attributes.emplace_back(
"class", "col-xs-12 col-sm-9 col-md-8 main-content");
AppendVector(std::move(MainContentInnerNodes), MainContentNode->Children);
appendVector(std::move(MainContentInnerNodes), MainContentNode->Children);

auto RightSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
RightSidebarNode->Attributes.emplace_back("id", "sidebar-right");
RightSidebarNode->Attributes.emplace_back(
"class", "col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right");
std::vector<std::unique_ptr<TagNode>> InfoIndexHTML =
genHTML(InfoIndex, InfoPath, true);
AppendVector(std::move(InfoIndexHTML), RightSidebarNode->Children);
appendVector(std::move(InfoIndexHTML), RightSidebarNode->Children);

MainNode->Children.emplace_back(std::move(LeftSidebarNode));
MainNode->Children.emplace_back(std::move(MainContentNode));
Expand Down Expand Up @@ -555,7 +563,7 @@ genInfoFile(StringRef Title, StringRef InfoPath,
genInfoFileMainNode(InfoPath, MainContentNodes, InfoIndex);
std::unique_ptr<TagNode> FooterNode = genFileFooterNode();

AppendVector(std::move(HeadNodes), F.Children);
appendVector(std::move(HeadNodes), F.Children);
F.Children.emplace_back(std::move(HeaderNode));
F.Children.emplace_back(std::move(MainNode));
F.Children.emplace_back(std::move(FooterNode));
Expand Down Expand Up @@ -594,7 +602,7 @@ genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList) {
for (const auto &C : Index.Children) {
auto LiBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(C, InfoPath, false);
AppendVector(std::move(Nodes), LiBody->Children);
appendVector(std::move(Nodes), LiBody->Children);
UlBody->Children.emplace_back(std::move(LiBody));
}
return Out;
Expand All @@ -609,7 +617,9 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
FullComment->Children.emplace_back(std::move(Node));
}
return std::move(FullComment);
} else if (I.Kind == "ParagraphComment") {
}

if (I.Kind == "ParagraphComment") {
auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
for (const auto &Child : I.Children) {
std::unique_ptr<HTMLNode> Node = genHTML(*Child);
Expand All @@ -619,7 +629,9 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
if (ParagraphComment->Children.empty())
return nullptr;
return std::move(ParagraphComment);
} else if (I.Kind == "TextComment") {
}

if (I.Kind == "TextComment") {
if (I.Text == "")
return nullptr;
return std::make_unique<TextNode>(I.Text);
Expand All @@ -639,11 +651,7 @@ static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {
static std::vector<std::unique_ptr<TagNode>>
genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
std::vector<std::unique_ptr<TagNode>> Out;
std::string EnumType;
if (I.Scoped)
EnumType = "enum class ";
else
EnumType = "enum ";
std::string EnumType = I.Scoped ? "enum class " : "enum ";

Out.emplace_back(
std::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
Expand Down Expand Up @@ -737,17 +745,17 @@ genHTML(const NamespaceInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,

std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
genReferencesBlock(I.Children.Namespaces, "Namespaces", BasePath);
AppendVector(std::move(ChildNamespaces), Out);
appendVector(std::move(ChildNamespaces), Out);
std::vector<std::unique_ptr<TagNode>> ChildRecords =
genReferencesBlock(I.Children.Records, "Records", BasePath);
AppendVector(std::move(ChildRecords), Out);
appendVector(std::move(ChildRecords), Out);

std::vector<std::unique_ptr<TagNode>> ChildFunctions =
genFunctionsBlock(I.Children.Functions, CDCtx, BasePath);
AppendVector(std::move(ChildFunctions), Out);
appendVector(std::move(ChildFunctions), Out);
std::vector<std::unique_ptr<TagNode>> ChildEnums =
genEnumsBlock(I.Children.Enums, CDCtx);
AppendVector(std::move(ChildEnums), Out);
appendVector(std::move(ChildEnums), Out);

if (!I.Children.Namespaces.empty())
InfoIndex.Children.emplace_back("Namespaces", "Namespaces");
Expand Down Expand Up @@ -791,29 +799,29 @@ genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
auto &PBody = Out.back();
PBody->Children.emplace_back(std::make_unique<TextNode>("Inherits from "));
if (Parents.empty())
AppendVector(std::move(VParents), PBody->Children);
appendVector(std::move(VParents), PBody->Children);
else if (VParents.empty())
AppendVector(std::move(Parents), PBody->Children);
appendVector(std::move(Parents), PBody->Children);
else {
AppendVector(std::move(Parents), PBody->Children);
appendVector(std::move(Parents), PBody->Children);
PBody->Children.emplace_back(std::make_unique<TextNode>(", "));
AppendVector(std::move(VParents), PBody->Children);
appendVector(std::move(VParents), PBody->Children);
}
}

std::vector<std::unique_ptr<TagNode>> Members =
genRecordMembersBlock(I.Members, I.Path);
AppendVector(std::move(Members), Out);
appendVector(std::move(Members), Out);
std::vector<std::unique_ptr<TagNode>> ChildRecords =
genReferencesBlock(I.Children.Records, "Records", I.Path);
AppendVector(std::move(ChildRecords), Out);
appendVector(std::move(ChildRecords), Out);

std::vector<std::unique_ptr<TagNode>> ChildFunctions =
genFunctionsBlock(I.Children.Functions, CDCtx, I.Path);
AppendVector(std::move(ChildFunctions), Out);
appendVector(std::move(ChildFunctions), Out);
std::vector<std::unique_ptr<TagNode>> ChildEnums =
genEnumsBlock(I.Children.Enums, CDCtx);
AppendVector(std::move(ChildEnums), Out);
appendVector(std::move(ChildEnums), Out);

if (!I.Members.empty())
InfoIndex.Children.emplace_back("Members", "Members");
Expand Down Expand Up @@ -936,7 +944,7 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,

HTMLFile F = genInfoFile(InfoTitle, I->getRelativeFilePath(""),
MainContentNodes, InfoIndex, CDCtx);
F.Render(OS);
F.render(OS);

return llvm::Error::success();
}
Expand All @@ -959,7 +967,7 @@ static std::string getRefType(InfoType IT) {
llvm_unreachable("Unknown InfoType");
}

static llvm::Error SerializeIndex(ClangDocContext &CDCtx) {
static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
std::error_code OK;
std::error_code FileErr;
llvm::SmallString<128> FilePath;
Expand Down Expand Up @@ -1009,7 +1017,7 @@ static std::unique_ptr<TagNode> genIndexFileMainNode() {
return MainNode;
}

static llvm::Error GenIndex(const ClangDocContext &CDCtx) {
static llvm::Error genIndex(const ClangDocContext &CDCtx) {
std::error_code FileErr, OK;
llvm::SmallString<128> IndexPath;
llvm::sys::path::native(CDCtx.OutDirectory, IndexPath);
Expand All @@ -1029,17 +1037,17 @@ static llvm::Error GenIndex(const ClangDocContext &CDCtx) {
std::unique_ptr<TagNode> MainNode = genIndexFileMainNode();
std::unique_ptr<TagNode> FooterNode = genFileFooterNode();

AppendVector(std::move(HeadNodes), F.Children);
appendVector(std::move(HeadNodes), F.Children);
F.Children.emplace_back(std::move(HeaderNode));
F.Children.emplace_back(std::move(MainNode));
F.Children.emplace_back(std::move(FooterNode));

F.Render(IndexOS);
F.render(IndexOS);

return llvm::Error::success();
}

static llvm::Error CopyFile(StringRef FilePath, StringRef OutDirectory) {
static llvm::Error copyFile(StringRef FilePath, StringRef OutDirectory) {
llvm::SmallString<128> PathWrite;
llvm::sys::path::native(OutDirectory, PathWrite);
llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
Expand All @@ -1057,20 +1065,20 @@ static llvm::Error CopyFile(StringRef FilePath, StringRef OutDirectory) {
}

llvm::Error HTMLGenerator::createResources(ClangDocContext &CDCtx) {
auto Err = SerializeIndex(CDCtx);
auto Err = serializeIndex(CDCtx);
if (Err)
return Err;
Err = GenIndex(CDCtx);
Err = genIndex(CDCtx);
if (Err)
return Err;

for (const auto &FilePath : CDCtx.UserStylesheets) {
Err = CopyFile(FilePath, CDCtx.OutDirectory);
Err = copyFile(FilePath, CDCtx.OutDirectory);
if (Err)
return Err;
}
for (const auto &FilePath : CDCtx.FilesToCopy) {
Err = CopyFile(FilePath, CDCtx.OutDirectory);
for (const auto &FilePath : CDCtx.JsScripts) {
Err = copyFile(FilePath, CDCtx.OutDirectory);
if (Err)
return Err;
}
Expand Down
6 changes: 2 additions & 4 deletions clang-tools-extra/clang-doc/Representation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,9 @@ ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
StringRef ProjectName, bool PublicOnly,
StringRef OutDirectory, StringRef SourceRoot,
StringRef RepositoryUrl,
std::vector<std::string> UserStylesheets,
std::vector<std::string> JsScripts)
std::vector<std::string> UserStylesheets)
: ECtx(ECtx), ProjectName(ProjectName), PublicOnly(PublicOnly),
OutDirectory(OutDirectory), UserStylesheets(UserStylesheets),
JsScripts(JsScripts) {
OutDirectory(OutDirectory), UserStylesheets(UserStylesheets) {
llvm::SmallString<128> SourceRootDir(SourceRoot);
if (SourceRoot.empty())
// If no SourceRoot was provided the current path is used as the default
Expand Down
5 changes: 1 addition & 4 deletions clang-tools-extra/clang-doc/Representation.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,7 @@ struct ClangDocContext {
ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName,
bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot,
StringRef RepositoryUrl,
std::vector<std::string> UserStylesheets,
std::vector<std::string> JsScripts);
std::vector<std::string> UserStylesheets);
tooling::ExecutionContext *ECtx;
std::string ProjectName; // Name of project clang-doc is documenting.
bool PublicOnly; // Indicates if only public declarations are documented.
Expand All @@ -498,8 +497,6 @@ struct ClangDocContext {
std::vector<std::string> UserStylesheets;
// JavaScript files that will be imported in allHTML file.
std::vector<std::string> JsScripts;
// Other files that should be copied to OutDirectory, besides UserStylesheets.
std::vector<std::string> FilesToCopy;
Index Idx;
};

Expand Down
103 changes: 82 additions & 21 deletions clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ static llvm::cl::list<std::string> UserStylesheets(
llvm::cl::desc("CSS stylesheets to extend the default styles."),
llvm::cl::cat(ClangDocCategory));

static llvm::cl::opt<std::string> UserAssetPath(
"asset",
llvm::cl::desc("User supplied asset path to "
"override the default css and js files for html output"),
llvm::cl::cat(ClangDocCategory));

static llvm::cl::opt<std::string> SourceRoot("source-root", llvm::cl::desc(R"(
Directory where processed files are stored.
Links to definition locations will only be
Expand Down Expand Up @@ -127,16 +133,84 @@ std::string getFormatString() {
// GetMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement GetMainExecutable
// without being given the address of a function in the main executable).
std::string GetExecutablePath(const char *Argv0, void *MainAddr) {
std::string getExecutablePath(const char *Argv0, void *MainAddr) {
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}

llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) {
using DirIt = llvm::sys::fs::directory_iterator;
std::error_code FileErr;
llvm::SmallString<128> FilePath(UserAssetPath);
for (DirIt DirStart = DirIt(UserAssetPath, FileErr),
DirEnd;
!FileErr && DirStart != DirEnd; DirStart.increment(FileErr)) {
FilePath = DirStart->path();
if (llvm::sys::fs::is_regular_file(FilePath)) {
if (llvm::sys::path::extension(FilePath) == ".css")
CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
std::string(FilePath));
else if (llvm::sys::path::extension(FilePath) == ".js")
CDCtx.JsScripts.emplace_back(FilePath.str());
}
}
if (FileErr)
return llvm::createFileError(FilePath, FileErr);
return llvm::Error::success();
}

llvm::Error getDefaultAssetFiles(const char *Argv0,
clang::doc::ClangDocContext &CDCtx) {
void *MainAddr = (void *)(intptr_t)getExecutablePath;
std::string ClangDocPath = getExecutablePath(Argv0, MainAddr);
llvm::SmallString<128> NativeClangDocPath;
llvm::sys::path::native(ClangDocPath, NativeClangDocPath);

llvm::SmallString<128> AssetsPath;
AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
llvm::SmallString<128> DefaultStylesheet;
llvm::sys::path::native(AssetsPath, DefaultStylesheet);
llvm::sys::path::append(DefaultStylesheet,
"clang-doc-default-stylesheet.css");
llvm::SmallString<128> IndexJS;
llvm::sys::path::native(AssetsPath, IndexJS);
llvm::sys::path::append(IndexJS, "index.js");

if (!llvm::sys::fs::is_regular_file(IndexJS))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"default index.js file missing at " +
IndexJS + "\n");

if (!llvm::sys::fs::is_regular_file(DefaultStylesheet))
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"default clang-doc-default-stylesheet.css file missing at " +
DefaultStylesheet + "\n");

CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
std::string(DefaultStylesheet));
CDCtx.JsScripts.emplace_back(IndexJS.str());

return llvm::Error::success();
}

llvm::Error getHtmlAssetFiles(const char *Argv0,
clang::doc::ClangDocContext &CDCtx) {
if (!UserAssetPath.empty() &&
!llvm::sys::fs::is_directory(std::string(UserAssetPath)))
llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath
<< " falling back to default\n";
if (llvm::sys::fs::is_directory(std::string(UserAssetPath)))
return getAssetFiles(CDCtx);
return getDefaultAssetFiles(Argv0, CDCtx);
}

int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
std::error_code OK;

const char *Overview =
R"(Generates documentation from source code and comments.
R"(Generates documentation from source code and comments.
Example usage for files without flags (default):
Expand Down Expand Up @@ -178,27 +252,14 @@ Example usage for a project using a compile commands database:
OutDirectory,
SourceRoot,
RepositoryUrl,
{UserStylesheets.begin(), UserStylesheets.end()},
{"index.js", "index_json.js"}};
{UserStylesheets.begin(), UserStylesheets.end()}
};

if (Format == "html") {
void *MainAddr = (void *)(intptr_t)GetExecutablePath;
std::string ClangDocPath = GetExecutablePath(argv[0], MainAddr);
llvm::SmallString<128> NativeClangDocPath;
llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
llvm::SmallString<128> AssetsPath;
AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
llvm::SmallString<128> DefaultStylesheet;
llvm::sys::path::native(AssetsPath, DefaultStylesheet);
llvm::sys::path::append(DefaultStylesheet,
"clang-doc-default-stylesheet.css");
llvm::SmallString<128> IndexJS;
llvm::sys::path::native(AssetsPath, IndexJS);
llvm::sys::path::append(IndexJS, "index.js");
CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
std::string(DefaultStylesheet));
CDCtx.FilesToCopy.emplace_back(IndexJS.str());
if (auto Err = getHtmlAssetFiles(argv[0], CDCtx)) {
llvm::errs() << toString(std::move(Err)) << "\n";
return 1;
}
}

// Mapping phase
Expand Down
14 changes: 13 additions & 1 deletion clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,14 @@ option is recognized.
)"),
cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<bool> AllowNoChecks("allow-no-checks", desc(R"(
Allow empty enabled checks. This suppresses
the "no checks enabled" error when disabling
all of the checks.
)"),
cl::init(false),
cl::cat(ClangTidyCategory));

namespace clang::tidy {

static void printStats(const ClangTidyStats &Stats) {
Expand Down Expand Up @@ -598,7 +606,7 @@ int clangTidyMain(int argc, const char **argv) {
}

if (ListChecks) {
if (EnabledChecks.empty()) {
if (EnabledChecks.empty() && !AllowNoChecks) {
llvm::errs() << "No checks enabled.\n";
return 1;
}
Expand Down Expand Up @@ -652,6 +660,10 @@ int clangTidyMain(int argc, const char **argv) {
}

if (EnabledChecks.empty()) {
if (AllowNoChecks) {
llvm::outs() << "No checks enabled.\n";
return 0;
}
llvm::errs() << "Error: no checks enabled.\n";
llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
return 1;
Expand Down
7 changes: 7 additions & 0 deletions clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ def main():
default=[],
help="Load the specified plugin in clang-tidy.",
)
parser.add_argument(
"-allow-no-checks",
action="store_true",
help="Allow empty enabled checks.",
)

clang_tidy_args = []
argv = sys.argv[1:]
Expand Down Expand Up @@ -327,6 +332,8 @@ def main():
common_clang_tidy_args.append("-p=%s" % args.build_path)
if args.use_color:
common_clang_tidy_args.append("--use-color")
if args.allow_no_checks:
common_clang_tidy_args.append("--allow-no-checks")
for arg in args.extra_arg:
common_clang_tidy_args.append("-extra-arg=%s" % arg)
for arg in args.extra_arg_before:
Expand Down
10 changes: 10 additions & 0 deletions clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def get_tidy_invocation(
plugins,
warnings_as_errors,
exclude_header_filter,
allow_no_checks,
):
"""Gets a command line for clang-tidy."""
start = [clang_tidy_binary]
Expand Down Expand Up @@ -147,6 +148,8 @@ def get_tidy_invocation(
start.append("-load=" + plugin)
if warnings_as_errors:
start.append("--warnings-as-errors=" + warnings_as_errors)
if allow_no_checks:
start.append("--allow-no-checks")
start.append(f)
return start

Expand Down Expand Up @@ -232,6 +235,7 @@ def run_tidy(args, clang_tidy_binary, tmpdir, build_path, queue, lock, failed_fi
args.plugins,
args.warnings_as_errors,
args.exclude_header_filter,
args.allow_no_checks,
)

proc = subprocess.Popen(
Expand Down Expand Up @@ -405,6 +409,11 @@ def main():
default=None,
help="Upgrades warnings to errors. Same format as '-checks'.",
)
parser.add_argument(
"-allow-no-checks",
action="store_true",
help="Allow empty enabled checks.",
)
args = parser.parse_args()

db_path = "compile_commands.json"
Expand Down Expand Up @@ -466,6 +475,7 @@ def main():
args.plugins,
args.warnings_as_errors,
args.exclude_header_filter,
args.allow_no_checks,
)
invocation.append("-list-checks")
invocation.append("-")
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ Improvements to clang-tidy
- Added argument `--exclude-header-filter` and config option `ExcludeHeaderFilterRegex`
to exclude headers from analysis via a RegEx.

- Added argument `--allow-no-checks` to suppress "no checks enabled" error
when disabling all of the checks by `--checks='-*'`.

New checks
^^^^^^^^^^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Options

.. option:: FixMode

Selects what kind of a fix the check should provide.
Selects what kind of a fix the check should provide. The default is `UseStatic`.

``None``
Don't fix automatically.
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/docs/clang-tidy/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ An overview of all the command-line options:
This option's value is appended to the value of
the 'WarningsAsErrors' option in .clang-tidy
file, if any.
--allow-no-checks - Allow empty enabled checks. This suppresses
the "no checks enabled" error when disabling
all of the checks.
-p <build-path> is used to read a compile command database.
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/test/clang-doc/Inputs/test-assets/test.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
padding: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("Hello, world!");
22 changes: 22 additions & 0 deletions clang-tools-extra/test/clang-doc/assets.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: rm -rf %t && mkdir %t
// RUN: clang-doc --format=html --output=%t --asset=%S/Inputs/test-assets --executor=standalone %s
// RUN: FileCheck %s -input-file=%t/index.html -check-prefix=INDEX
// RUN: FileCheck %s -input-file=%t/test.css -check-prefix=CSS
// RUN: FileCheck %s -input-file=%t/test.js -check-prefix=JS

// INDEX: <!DOCTYPE html>
// INDEX-NEXT: <meta charset="utf-8"/>
// INDEX-NEXT: <title>Index</title>
// INDEX-NEXT: <link rel="stylesheet" href="test.css"/>
// INDEX-NEXT: <script src="index_json.js"></script>
// INDEX-NEXT: <script src="test.js"></script>
// INDEX-NEXT: <header id="project-title"></header>
// INDEX-NEXT: <main>
// INDEX-NEXT: <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left" style="flex: 0 100%;"></div>
// INDEX-NEXT: </main>

// CSS: body {
// CSS-NEXT: padding: 0;
// CSS-NEXT: }

// JS: console.log("Hello, world!");
10 changes: 5 additions & 5 deletions clang-tools-extra/test/clang-doc/basic-project.test
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
// HTML-SHAPE-NEXT: <meta charset="utf-8"/>
// HTML-SHAPE-NEXT: <title>class Shape</title>
// HTML-SHAPE-NEXT: <link rel="stylesheet" href="../clang-doc-default-stylesheet.css"/>
// HTML-SHAPE-NEXT: <script src="../index.js"></script>
// HTML-SHAPE-NEXT: <script src="../index_json.js"></script>
// HTML-SHAPE-NEXT: <script src="{{.*}}index_json.js"></script>
// HTML-SHAPE-NEXT: <script src="{{.*}}index.js"></script>
// HTML-SHAPE-NEXT: <header id="project-title"></header>
// HTML-SHAPE-NEXT: <main>
// HTML-SHAPE-NEXT: <div id="sidebar-left" path="GlobalNamespace" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
Expand Down Expand Up @@ -122,8 +122,8 @@
// HTML-CALC-NEXT: <meta charset="utf-8"/>
// HTML-CALC-NEXT: <title>class Calculator</title>
// HTML-CALC-NEXT: <link rel="stylesheet" href="{{.*}}clang-doc-default-stylesheet.css"/>
// HTML-CALC-NEXT: <script src="{{.*}}index.js"></script>
// HTML-CALC-NEXT: <script src="{{.*}}index_json.js"></script>
// HTML-CALC-NEXT: <script src="{{.*}}index.js"></script>
// HTML-CALC-NEXT: <header id="project-title"></header>
// HTML-CALC-NEXT: <main>
// HTML-CALC-NEXT: <div id="sidebar-left" path="GlobalNamespace" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
Expand Down Expand Up @@ -200,8 +200,8 @@
// HTML-RECTANGLE-NEXT: <meta charset="utf-8"/>
// HTML-RECTANGLE-NEXT: <title>class Rectangle</title>
// HTML-RECTANGLE-NEXT: <link rel="stylesheet" href="{{.*}}clang-doc-default-stylesheet.css"/>
// HTML-RECTANGLE-NEXT: <script src="{{.*}}index.js"></script>
// HTML-RECTANGLE-NEXT: <script src="{{.*}}index_json.js"></script>
// HTML-RECTANGLE-NEXT: <script src="{{.*}}index.js"></script>
// HTML-RECTANGLE-NEXT: <header id="project-title"></header>
// HTML-RECTANGLE-NEXT: <main>
// HTML-RECTANGLE-NEXT: <div id="sidebar-left" path="GlobalNamespace" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
Expand Down Expand Up @@ -281,8 +281,8 @@
// HTML-CIRCLE-NEXT: <meta charset="utf-8"/>
// HTML-CIRCLE-NEXT: <title>class Circle</title>
// HTML-CIRCLE-NEXT: <link rel="stylesheet" href="{{.*}}clang-doc-default-stylesheet.css"/>
// HTML-CIRCLE-NEXT: <script src="{{.*}}index.js"></script>
// HTML-CIRCLE-NEXT: <script src="{{.*}}index_json.js"></script>
// HTML-CIRCLE-NEXT: <script src="{{.*}}index.js"></script>
// HTML-CIRCLE-NEXT: <header id="project-title"></header>
// HTML-CIRCLE-NEXT: <main>
// HTML-CIRCLE-NEXT: <div id="sidebar-left" path="GlobalNamespace" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// RUN: not clang-tidy %s -checks='-*'
// RUN: clang-tidy %s -checks='-*' --allow-no-checks | FileCheck --match-full-lines %s

// CHECK: No checks enabled.
7 changes: 6 additions & 1 deletion clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ClangDocContext
getClangDocContext(std::vector<std::string> UserStylesheets = {},
StringRef RepositoryUrl = "") {
ClangDocContext CDCtx{
{}, "test-project", {}, {}, {}, RepositoryUrl, UserStylesheets, {}};
{}, "test-project", {}, {}, {}, RepositoryUrl, UserStylesheets};
CDCtx.UserStylesheets.insert(
CDCtx.UserStylesheets.begin(),
"../share/clang/clang-doc-default-stylesheet.css");
Expand Down Expand Up @@ -66,6 +66,7 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) {
<title>namespace Namespace</title>
<link rel="stylesheet" href="../clang-doc-default-stylesheet.css"/>
<link rel="stylesheet" href="../user-provided-stylesheet.css"/>
<script src="../index_json.js"></script>
<script src="../index.js"></script>
<header id="project-title">test-project</header>
<main>
Expand Down Expand Up @@ -176,6 +177,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
<meta charset="utf-8"/>
<title>class r</title>
<link rel="stylesheet" href="../../../clang-doc-default-stylesheet.css"/>
<script src="../../../index_json.js"></script>
<script src="../../../index.js"></script>
<header id="project-title">test-project</header>
<main>
Expand Down Expand Up @@ -290,6 +292,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
<meta charset="utf-8"/>
<title></title>
<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
<script src="index_json.js"></script>
<script src="index.js"></script>
<header id="project-title">test-project</header>
<main>
Expand Down Expand Up @@ -337,6 +340,7 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
<meta charset="utf-8"/>
<title></title>
<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
<script src="index_json.js"></script>
<script src="index.js"></script>
<header id="project-title">test-project</header>
<main>
Expand Down Expand Up @@ -422,6 +426,7 @@ TEST(HTMLGeneratorTest, emitCommentHTML) {
<meta charset="utf-8"/>
<title></title>
<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
<script src="index_json.js"></script>
<script src="index.js"></script>
<header id="project-title">test-project</header>
<main>
Expand Down
2 changes: 1 addition & 1 deletion clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m-unknown-eabi)
set(RUNTIMES_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
foreach(lang C;CXX;ASM)
set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb" CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb -Wno-atomic-alignment" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
Expand Down
6 changes: 5 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ ABI Changes in This Version
ifuncs. Its purpose was to preserve backwards compatibility when the ".ifunc"
suffix got removed from the name mangling. The alias interacts badly with
GlobalOpt (see the issue #96197).

- Fixed Microsoft name mangling for auto non-type template arguments of pointer
type for MSVC 1920+. This change resolves incompatibilities with code compiled
by MSVC 1920+ but will introduce incompatibilities with code compiled by
Expand All @@ -115,6 +115,7 @@ AST Dumping Potentially Breaking Changes
----------------------------------------

- The text ast-dumper has improved printing of TemplateArguments.
- The text decl-dumper prints template parameters' trailing requires expressions now.

Clang Frontend Potentially Breaking Changes
-------------------------------------------
Expand Down Expand Up @@ -739,6 +740,9 @@ Bug Fixes in This Version
negatives where the analysis failed to detect unchecked access to guarded
data.

- ``__is_trivially_equality_comparable`` no longer returns true for types which
have a constrained defaulted comparison operator (#GH89293).

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

Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/TypeSize.h"
#include <optional>
Expand Down Expand Up @@ -1277,6 +1278,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// space.
QualType removeAddrSpaceQualType(QualType T) const;

/// Return the "other" discriminator used for the pointer auth schema used for
/// vtable pointers in instances of the requested type.
uint16_t
getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD);

/// Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol
/// qualifiers on ObjCObjectPointerType. It can be set to true when
Expand Down Expand Up @@ -3438,12 +3444,21 @@ OPT_LIST(V)
/// Whether a C++ static variable or CUDA/HIP kernel should be externalized.
bool shouldExternalize(const Decl *D) const;

/// Resolve the root record to be used to derive the vtable pointer
/// authentication policy for the specified record.
const CXXRecordDecl *
baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName);

StringRef getCUIDHash() const;

private:
/// All OMPTraitInfo objects live in this collection, one per
/// `pragma omp [begin] declare variant` directive.
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;

llvm::DenseMap<GlobalDecl, llvm::StringSet<>> ThunksToBeAbbreviated;
};

/// Insertion operator for diagnostics.
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/GlobalDecl.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ class GlobalDecl {
LHS.MultiVersionIndex == RHS.MultiVersionIndex;
}

bool operator!=(const GlobalDecl &Other) const {
return !(*this == Other);
}

void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }

explicit operator bool() const { return getAsOpaquePtr(); }
Expand Down
11 changes: 5 additions & 6 deletions clang/include/clang/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,15 @@ class MangleContext {
// FIXME: consider replacing raw_ostream & with something like SmallString &.
void mangleName(GlobalDecl GD, raw_ostream &);
virtual void mangleCXXName(GlobalDecl GD, raw_ostream &) = 0;
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &) = 0;
virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
bool ElideOverrideInfo, raw_ostream &) = 0;
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
raw_ostream &) = 0;
const ThunkInfo &Thunk,
bool ElideOverrideInfo, raw_ostream &) = 0;
virtual void mangleReferenceTemporary(const VarDecl *D,
unsigned ManglingNumber,
raw_ostream &) = 0;
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &,
bool NormalizeIntegers = false) = 0;
Expand Down Expand Up @@ -192,7 +192,6 @@ class ItaniumMangleContext : public MangleContext {
bool IsAux = false)
: MangleContext(C, D, MK_Itanium, IsAux) {}

virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1142,9 +1142,6 @@ class QualType {
/// Return true if this is a trivially relocatable type.
bool isTriviallyRelocatableType(const ASTContext &Context) const;

/// Return true if this is a trivially equality comparable type.
bool isTriviallyEqualityComparableType(const ASTContext &Context) const;

/// Returns true if it is a class and it might be dynamic.
bool mayBeDynamicClass() const;

Expand Down
29 changes: 29 additions & 0 deletions clang/include/clang/AST/VTableBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ class VTableContextBase {
};

class ItaniumVTableContext : public VTableContextBase {
public:
typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl *>
OriginalMethodMapTy;

private:

/// Contains the index (relative to the vtable address point)
Expand All @@ -384,6 +388,10 @@ class ItaniumVTableContext : public VTableContextBase {
VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;

/// Map from a virtual method to the nearest method in the primary base class
/// chain that it overrides.
OriginalMethodMapTy OriginalMethodMap;

void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;

public:
Expand Down Expand Up @@ -425,6 +433,27 @@ class ItaniumVTableContext : public VTableContextBase {
CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase);

/// Return the method that added the v-table slot that will be used to call
/// the given method.
///
/// In the Itanium ABI, where overrides always cause methods to be added to
/// the primary v-table if they're not already there, this will be the first
/// declaration in the primary base class chain for which the return type
/// adjustment is trivial.
GlobalDecl findOriginalMethod(GlobalDecl GD);

const CXXMethodDecl *findOriginalMethodInMap(const CXXMethodDecl *MD) const;

void setOriginalMethod(const CXXMethodDecl *Key, const CXXMethodDecl *Val) {
OriginalMethodMap[Key] = Val;
}

/// This method is reserved for the implementation and shouldn't be used
/// directly.
const OriginalMethodMapTy &getOriginalMethodMap() {
return OriginalMethodMap;
}

static bool classof(const VTableContextBase *VT) {
return !VT->isMicrosoft();
}
Expand Down
29 changes: 29 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,10 @@ class Attr {
bit PragmaAttributeSupport;
// Set to true if this attribute accepts parameter pack expansion expressions.
bit AcceptsExprPack = 0;
// To support multiple enum parameters to an attribute without breaking
// our existing general parsing we need to have a separate flag that
// opts an attribute into strict parsing of attribute parameters
bit StrictEnumParameters = 0;
// Lists language options, one of which is required to be true for the
// attribute to be applicable. If empty, no language options are required.
list<LangOpt> LangOpts = [];
Expand Down Expand Up @@ -4576,6 +4580,31 @@ def NoRandomizeLayout : InheritableAttr {
}
def : MutualExclusions<[RandomizeLayout, NoRandomizeLayout]>;

def VTablePointerAuthentication : InheritableAttr {
let Spellings = [Clang<"ptrauth_vtable_pointer">];
let Subjects = SubjectList<[CXXRecord]>;
let Documentation = [Undocumented];
let StrictEnumParameters = 1;
let Args = [EnumArgument<"Key", "VPtrAuthKeyType", /*is_string=*/ true,
["default_key", "no_authentication", "process_dependent",
"process_independent"],
["DefaultKey", "NoKey", "ProcessDependent",
"ProcessIndependent"]>,
EnumArgument<"AddressDiscrimination", "AddressDiscriminationMode",
/*is_string=*/ true,
["default_address_discrimination", "no_address_discrimination",
"address_discrimination"],
["DefaultAddressDiscrimination", "NoAddressDiscrimination",
"AddressDiscrimination"]>,
EnumArgument<"ExtraDiscrimination", "ExtraDiscrimination",
/*is_string=*/ true,
["default_extra_discrimination", "no_extra_discrimination",
"type_discrimination", "custom_discrimination"],
["DefaultExtraDiscrimination", "NoExtraDiscrimination",
"TypeDiscrimination", "CustomDiscrimination"]>,
IntArgument<"CustomDiscriminationValue", 1>];
}

def FunctionReturnThunks : InheritableAttr,
TargetSpecificAttr<TargetAnyX86> {
let Spellings = [GCC<"function_return">];
Expand Down
11 changes: 4 additions & 7 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -6585,7 +6585,8 @@ like pointers to an object of type ``T``:
private:
int *valuePointer;
public:
int *getInt() { return &valuePointer; }
IntPointer(const IntOwner&);
int *getInt() { return valuePointer; }
};

The argument ``T`` is optional and is ignored.
Expand All @@ -6601,12 +6602,8 @@ When the Owner's lifetime ends, it will consider the Pointer to be dangling.
.. code-block:: c++

int f() {
IntPointer P;
if (true) {
IntOwner O(7);
P = IntPointer(O); // P "points into" O
} // P is dangling
return P.get(); // error: Using a dangling Pointer.
IntPointer P(IntOwner{}); // P "points into" a temporary IntOwner object
P.getInt(); // P is dangling
}

}];
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1539,3 +1539,7 @@ def BitIntExtension : DiagGroup<"bit-int-extension">;

// Warnings about misuse of ExtractAPI options.
def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">;

// Warnings about using the non-standard extension having an explicit specialization
// with a storage class specifier.
def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-storage-class">;
41 changes: 34 additions & 7 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,13 @@ def warn_ptrauth_auth_null_pointer :
def err_ptrauth_string_not_literal : Error<
"argument must be a string literal%select{| of char type}0">;

def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
Note<"cannot take an address of a virtual member function if its return or "
"argument types are incomplete">;
def note_ptrauth_virtual_function_incomplete_arg_ret_type :
Note<"%0 is incomplete">;


/// main()
// static main() is not an error in C, just in C++.
def warn_static_main : Warning<"'main' should not be declared static">,
Expand Down Expand Up @@ -5382,7 +5389,7 @@ def err_not_class_template_specialization : Error<
"cannot specialize a %select{dependent template|template template "
"parameter}0">;
def ext_explicit_specialization_storage_class : ExtWarn<
"explicit specialization cannot have a storage class">;
"explicit specialization cannot have a storage class">, InGroup<ExplicitSpecializationStorageClass>;
def err_dependent_function_template_spec_no_match : Error<
"no candidate function template was found for dependent"
" %select{member|friend}0 function template specialization">;
Expand Down Expand Up @@ -11173,16 +11180,12 @@ def err_omp_several_directives_in_region : Error<
def note_omp_previous_directive : Note<
"previous '%0' directive used here">;
def err_omp_sections_not_compound_stmt : Error<
"the statement for '#pragma omp sections' must be a compound statement">;
def err_omp_parallel_sections_not_compound_stmt : Error<
"the statement for '#pragma omp parallel sections' must be a compound statement">;
"the statement for '#pragma omp %0' must be a compound statement">;
def err_omp_orphaned_section_directive : Error<
"%select{orphaned 'omp section' directives are prohibited, it|'omp section' directive}0"
" must be closely nested to a sections region%select{|, not a %1 region}0">;
def err_omp_sections_substmt_not_section : Error<
"statement in 'omp sections' directive must be enclosed into a section region">;
def err_omp_parallel_sections_substmt_not_section : Error<
"statement in 'omp parallel sections' directive must be enclosed into a section region">;
"statement in 'omp %0' directive must be enclosed into a section region">;
def err_omp_parallel_reduction_in_task_firstprivate : Error<
"argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">;
def err_omp_atomic_read_not_expression_statement : Error<
Expand Down Expand Up @@ -12220,6 +12223,30 @@ def warn_cuda_maxclusterrank_sm_90 : Warning<
"maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring "
"%1 attribute">, InGroup<IgnoredAttributes>;

// VTable pointer authentication errors
def err_non_polymorphic_vtable_pointer_auth : Error<
"cannot set vtable pointer authentication on monomorphic type %0">;
def err_incomplete_type_vtable_pointer_auth : Error<
"cannot set vtable pointer authentication on an incomplete type %0">;
def err_non_top_level_vtable_pointer_auth : Error<
"cannot set vtable pointer authentication on %0 which is a subclass of polymorphic type %1">;
def err_duplicated_vtable_pointer_auth : Error<
"multiple vtable pointer authentication policies on %0">;
def err_invalid_authentication_key : Error<
"invalid authentication key %0">;
def err_invalid_address_discrimination : Error<
"invalid address discrimination mode %0">;
def err_invalid_extra_discrimination : Error<
"invalid extra discrimination selection %0">;
def err_invalid_custom_discrimination : Error<
"invalid custom discrimination">;
def err_missing_custom_discrimination : Error<
"missing custom discrimination">;
def err_no_default_vtable_pointer_auth : Error<
"cannot specify a default vtable pointer authentication "
"%select{key|address discrimination mode|discriminator}0 with no default set"
>;

def err_bit_int_bad_size : Error<"%select{signed|unsigned}0 _BitInt must "
"have a bit size of at least %select{2|1}0">;
def err_bit_int_max_size : Error<"%select{signed|unsigned}0 _BitInt of bit "
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ class PointerAuthSchema {
/// No additional discrimination.
None,

/// Include a hash of the entity's type.
Type,

/// Include a hash of the entity's identity.
Decl,

/// Discriminate using a constant value.
Constant,
};
Expand Down Expand Up @@ -150,6 +156,25 @@ class PointerAuthSchema {
struct PointerAuthOptions {
/// The ABI for C function pointers.
PointerAuthSchema FunctionPointers;

/// The ABI for C++ virtual table pointers (the pointer to the table
/// itself) as installed in an actual class instance.
PointerAuthSchema CXXVTablePointers;

/// TypeInfo has external ABI requirements and is emitted without
/// actually having parsed the libcxx definition, so we can't simply
/// perform a look up. The settings for this should match the exact
/// specification in type_info.h
PointerAuthSchema CXXTypeInfoVTablePointer;

/// The ABI for C++ virtual table pointers as installed in a VTT.
PointerAuthSchema CXXVTTVTablePointers;

/// The ABI for most C++ virtual function pointers, i.e. v-table entries.
PointerAuthSchema CXXVirtualFunctionPointers;

/// The ABI for variadic C++ virtual function pointers.
PointerAuthSchema CXXVirtualVariadicFunctionPointers;
};

} // end namespace clang
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/TargetCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class TargetCXXABI {
return T.isKnownWindowsMSVCEnvironment();
}
llvm_unreachable("invalid CXXABI kind");
};
}

/// Does this ABI generally fall into the Itanium family of ABIs?
bool isItaniumFamily() const {
Expand Down
15 changes: 10 additions & 5 deletions clang/include/clang/Basic/Thunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
namespace clang {

class CXXMethodDecl;
class Type;

/// A return adjustment.
struct ReturnAdjustment {
Expand Down Expand Up @@ -162,20 +163,24 @@ struct ThunkInfo {

/// Holds a pointer to the overridden method this thunk is for,
/// if needed by the ABI to distinguish different thunks with equal
/// adjustments. Otherwise, null.
/// adjustments.
/// In the Itanium ABI, this field can hold the method that created the
/// vtable entry for this thunk.
/// Otherwise, null.
/// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using
/// an ABI-specific comparator.
const CXXMethodDecl *Method;
const Type *ThisType;

ThunkInfo() : Method(nullptr) {}
ThunkInfo() : Method(nullptr), ThisType(nullptr) {}

ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return,
const CXXMethodDecl *Method = nullptr)
: This(This), Return(Return), Method(Method) {}
const Type *ThisT, const CXXMethodDecl *Method = nullptr)
: This(This), Return(Return), Method(Method), ThisType(ThisT) {}

friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
return LHS.This == RHS.This && LHS.Return == RHS.Return &&
LHS.Method == RHS.Method;
LHS.Method == RHS.Method && LHS.ThisType == RHS.ThisType;
}

bool isEmpty() const {
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/CodeGen/CodeGenABITypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class CXXConstructorDecl;
class CXXDestructorDecl;
class CXXRecordDecl;
class CXXMethodDecl;
class GlobalDecl;
class ObjCMethodDecl;
class ObjCProtocolDecl;

Expand Down Expand Up @@ -104,6 +105,9 @@ llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T);
unsigned getLLVMFieldNumber(CodeGenModule &CGM,
const RecordDecl *RD, const FieldDecl *FD);

/// Return a declaration discriminator for the given global decl.
uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD);

/// Given the language and code-generation options that Clang was configured
/// with, set the default LLVM IR attributes for a function definition.
/// The attributes set here are mostly global target-configuration and
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/CodeGen/ConstantInitBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
#include <vector>

namespace clang {
namespace CodeGen {
class GlobalDecl;
class PointerAuthSchema;
class QualType;

namespace CodeGen {
class CodeGenModule;

/// A convenience builder class for complex constant initializers,
Expand Down Expand Up @@ -199,6 +202,11 @@ class ConstantAggregateBuilderBase {
add(llvm::ConstantInt::get(intTy, value, isSigned));
}

/// Add a signed pointer using the given pointer authentication schema.
void addSignedPointer(llvm::Constant *Pointer,
const PointerAuthSchema &Schema, GlobalDecl CalleeDecl,
QualType CalleeType);

/// Add a null pointer of a specific type.
void addNullPointer(llvm::PointerType *ptrTy) {
add(llvm::ConstantPointerNull::get(ptrTy));
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/InstallAPI/Visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ class InstallAPIVisitor final : public ASTConsumer,
std::string getMangledName(const NamedDecl *D) const;
std::string getBackendMangledName(llvm::Twine Name) const;
std::string getMangledCXXVTableName(const CXXRecordDecl *D) const;
std::string getMangledCXXThunk(const GlobalDecl &D,
const ThunkInfo &Thunk) const;
std::string getMangledCXXThunk(const GlobalDecl &D, const ThunkInfo &Thunk,
bool ElideOverrideInfo) const;
std::string getMangledCXXRTTI(const CXXRecordDecl *D) const;
std::string getMangledCXXRTTIName(const CXXRecordDecl *D) const;
std::string getMangledCtorDtor(const CXXMethodDecl *D, int Type) const;
Expand Down
19 changes: 12 additions & 7 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2114,8 +2114,6 @@ class Sema final : public SemaBase {

bool FormatStringHasSArg(const StringLiteral *FExpr);

static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx);

void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
BinaryOperatorKind Opcode);

Expand Down Expand Up @@ -2228,8 +2226,6 @@ class Sema final : public SemaBase {
bool BuiltinVectorMath(CallExpr *TheCall, QualType &Res);
bool BuiltinVectorToScalarMath(CallExpr *TheCall);

bool CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
const Expr *ThisArg, ArrayRef<const Expr *> Args,
bool IsMemberFunction, SourceLocation Loc, SourceRange Range,
Expand Down Expand Up @@ -2259,6 +2255,14 @@ class Sema final : public SemaBase {

bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum);

void CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
bool *ICContext = nullptr,
bool IsListInit = false);

bool BuiltinElementwiseTernaryMath(CallExpr *TheCall,
bool CheckForFloatArgs = true);
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall);

private:
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ArraySubscriptExpr *ASE = nullptr,
Expand Down Expand Up @@ -2306,9 +2310,6 @@ class Sema final : public SemaBase {
AtomicExpr::AtomicOp Op);

bool BuiltinElementwiseMath(CallExpr *TheCall);
bool BuiltinElementwiseTernaryMath(CallExpr *TheCall,
bool CheckForFloatArgs = true);
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall);
bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall);

bool BuiltinNonDeterministicValue(CallExpr *TheCall);
Expand Down Expand Up @@ -4566,6 +4567,10 @@ class Sema final : public SemaBase {
/// conditions that are needed for the attribute to have an effect.
void checkIllFormedTrivialABIStruct(CXXRecordDecl &RD);

/// Check that VTable Pointer authentication is only being set on the first
/// first instantiation of the vtable
void checkIncorrectVTablePointerAuthenticationAttribute(CXXRecordDecl &RD);

void ActOnFinishCXXMemberSpecification(Scope *S, SourceLocation RLoc,
Decl *TagDecl, SourceLocation LBrac,
SourceLocation RBrac,
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class SemaHLSL : public SemaBase {
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);

bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
};

} // namespace clang
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/Sema/SemaObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,27 @@ class SemaObjC : public SemaBase {

IdentifierInfo *getNSErrorIdent();

bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx);

/// Diagnose use of %s directive in an NSString which is being passed
/// as formatting string to formatting method.
void DiagnoseCStringFormatDirectiveInCFAPI(const NamedDecl *FDecl,
Expr **Args, unsigned NumArgs);

bool isSignedCharBool(QualType Ty);

void adornBoolConversionDiagWithTernaryFixit(
Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder);

/// Check an Objective-C dictionary literal being converted to the given
/// target type.
void checkDictionaryLiteral(QualType TargetType,
ObjCDictionaryLiteral *DictionaryLiteral);

/// Check an Objective-C array literal being converted to the given
/// target type.
void checkArrayLiteral(QualType TargetType, ObjCArrayLiteral *ArrayLiteral);

private:
IdentifierInfo *Ident_NSError = nullptr;

Expand Down
72 changes: 72 additions & 0 deletions clang/include/clang/Sema/SemaOpenCL.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,78 @@ class SemaOpenCL : public SemaBase {

// Handles intel_reqd_sub_group_size.
void handleSubGroupSize(Decl *D, const ParsedAttr &AL);

// Performs semantic analysis for the read/write_pipe call.
// \param S Reference to the semantic analyzer.
// \param Call A pointer to the builtin call.
// \return True if a semantic error has been found, false otherwise.
bool checkBuiltinRWPipe(CallExpr *Call);

// Performs a semantic analysis on the {work_group_/sub_group_
// /_}reserve_{read/write}_pipe
// \param S Reference to the semantic analyzer.
// \param Call The call to the builtin function to be analyzed.
// \return True if a semantic error was found, false otherwise.
bool checkBuiltinReserveRWPipe(CallExpr *Call);

bool checkSubgroupExt(CallExpr *Call);

// Performs a semantic analysis on {work_group_/sub_group_
// /_}commit_{read/write}_pipe
// \param S Reference to the semantic analyzer.
// \param Call The call to the builtin function to be analyzed.
// \return True if a semantic error was found, false otherwise.
bool checkBuiltinCommitRWPipe(CallExpr *Call);

// Performs a semantic analysis on the call to built-in Pipe
// Query Functions.
// \param S Reference to the semantic analyzer.
// \param Call The call to the builtin function to be analyzed.
// \return True if a semantic error was found, false otherwise.
bool checkBuiltinPipePackets(CallExpr *Call);

// OpenCL v2.0 s6.13.9 - Address space qualifier functions.
// Performs semantic analysis for the to_global/local/private call.
// \param S Reference to the semantic analyzer.
// \param BuiltinID ID of the builtin function.
// \param Call A pointer to the builtin call.
// \return True if a semantic error has been found, false otherwise.
bool checkBuiltinToAddr(unsigned BuiltinID, CallExpr *Call);

/// OpenCL C v2.0, s6.13.17 - Enqueue kernel function contains four different
/// overload formats specified in Table 6.13.17.1.
/// int enqueue_kernel(queue_t queue,
/// kernel_enqueue_flags_t flags,
/// const ndrange_t ndrange,
/// void (^block)(void))
/// int enqueue_kernel(queue_t queue,
/// kernel_enqueue_flags_t flags,
/// const ndrange_t ndrange,
/// uint num_events_in_wait_list,
/// clk_event_t *event_wait_list,
/// clk_event_t *event_ret,
/// void (^block)(void))
/// int enqueue_kernel(queue_t queue,
/// kernel_enqueue_flags_t flags,
/// const ndrange_t ndrange,
/// void (^block)(local void*, ...),
/// uint size0, ...)
/// int enqueue_kernel(queue_t queue,
/// kernel_enqueue_flags_t flags,
/// const ndrange_t ndrange,
/// uint num_events_in_wait_list,
/// clk_event_t *event_wait_list,
/// clk_event_t *event_ret,
/// void (^block)(local void*, ...),
/// uint size0, ...)
bool checkBuiltinEnqueueKernel(CallExpr *TheCall);

/// OpenCL C v2.0, s6.13.17.6 - Check the argument to the
/// get_kernel_work_group_size
/// and get_kernel_preferred_work_group_size_multiple builtin functions.
bool checkBuiltinKernelWorkGroupSize(CallExpr *TheCall);

bool checkBuiltinNDRangeAndBlock(CallExpr *TheCall);
};

} // namespace clang
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Tooling/Transformer/RangeSelector.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ RangeSelector name(std::string ID);
// source between the call's parentheses).
RangeSelector callArgs(std::string ID);

// Given a \c CXXConstructExpr (bound to \p ID), selects the
// arguments' source text. Depending on the syntactic form of the construct,
// this is the range between parentheses or braces.
RangeSelector constructExprArgs(std::string ID);

// Given a \c CompoundStmt (bound to \p ID), selects the source of the
// statements (all source between the braces).
RangeSelector statements(std::string ID);
Expand Down
16 changes: 9 additions & 7 deletions clang/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,20 @@ module Clang_Basic {
umbrella "clang/Basic"

textual header "clang/Basic/AArch64SVEACLETypes.def"
textual header "clang/Basic/AMDGPUTypes.def"
textual header "clang/Basic/BuiltinHeaders.def"
textual header "clang/Basic/BuiltinsAArch64.def"
textual header "clang/Basic/BuiltinsAMDGPU.def"
textual header "clang/Basic/BuiltinsAArch64NeonSVEBridge.def"
textual header "clang/Basic/BuiltinsAArch64NeonSVEBridge_cg.def"
textual header "clang/Basic/BuiltinsAMDGPU.def"
textual header "clang/Basic/BuiltinsARM.def"
textual header "clang/Basic/BuiltinHeaders.def"
textual header "clang/Basic/BuiltinsHexagon.def"
textual header "clang/Basic/BuiltinsHexagonDep.def"
textual header "clang/Basic/BuiltinsHexagonMapCustomDep.def"
textual header "clang/Basic/BuiltinsLoongArch.def"
textual header "clang/Basic/BuiltinsLoongArchBase.def"
textual header "clang/Basic/BuiltinsLoongArchLSX.def"
textual header "clang/Basic/BuiltinsLoongArchLASX.def"
textual header "clang/Basic/BuiltinsLoongArchLSX.def"
textual header "clang/Basic/BuiltinsMips.def"
textual header "clang/Basic/BuiltinsNEON.def"
textual header "clang/Basic/BuiltinsNVPTX.def"
Expand All @@ -67,22 +68,23 @@ module Clang_Basic {
textual header "clang/Basic/CodeGenOptions.def"
textual header "clang/Basic/DebugOptions.def"
textual header "clang/Basic/DiagnosticOptions.def"
textual header "clang/Basic/Features.def"
textual header "clang/Basic/FPOptions.def"
textual header "clang/Basic/MSP430Target.def"
textual header "clang/Basic/Features.def"
textual header "clang/Basic/LangOptions.def"
textual header "clang/Basic/MSP430Target.def"
textual header "clang/Basic/OpenACCClauses.def"
textual header "clang/Basic/OpenCLExtensionTypes.def"
textual header "clang/Basic/OpenCLExtensions.def"
textual header "clang/Basic/OpenCLImageTypes.def"
textual header "clang/Basic/OpenCLExtensionTypes.def"
textual header "clang/Basic/OpenMPKinds.def"
textual header "clang/Basic/OperatorKinds.def"
textual header "clang/Basic/PPCTypes.def"
textual header "clang/Basic/RISCVVTypes.def"
textual header "clang/Basic/Sanitizers.def"
textual header "clang/Basic/TargetCXXABI.def"
textual header "clang/Basic/TargetOSMacros.def"
textual header "clang/Basic/TransformTypeTraits.def"
textual header "clang/Basic/TokenKinds.def"
textual header "clang/Basic/TransformTypeTraits.def"
textual header "clang/Basic/WebAssemblyReferenceTypes.def"

module * { export * }
Expand Down
83 changes: 83 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SipHash.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/AArch64TargetParser.h"
#include "llvm/TargetParser/Triple.h"
Expand Down Expand Up @@ -3128,6 +3129,17 @@ QualType ASTContext::removeAddrSpaceQualType(QualType T) const {
return QualType(TypeNode, Quals.getFastQualifiers());
}

uint16_t
ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD) {
assert(RD->isPolymorphic() &&
"Attempted to get vtable pointer discriminator on a monomorphic type");
std::unique_ptr<MangleContext> MC(createMangleContext());
SmallString<256> Str;
llvm::raw_svector_ostream Out(Str);
MC->mangleCXXVTable(RD, Out);
return llvm::getPointerAuthStableSipHash(Str);
}

QualType ASTContext::getObjCGCQualType(QualType T,
Qualifiers::GC GCAttr) const {
QualType CanT = getCanonicalType(T);
Expand Down Expand Up @@ -13894,3 +13906,74 @@ StringRef ASTContext::getCUIDHash() const {
CUIDHash = llvm::utohexstr(llvm::MD5Hash(LangOpts.CUID), /*LowerCase=*/true);
return CUIDHash;
}

const CXXRecordDecl *
ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
assert(ThisClass);
assert(ThisClass->isPolymorphic());
const CXXRecordDecl *PrimaryBase = ThisClass;
while (1) {
assert(PrimaryBase);
assert(PrimaryBase->isPolymorphic());
auto &Layout = getASTRecordLayout(PrimaryBase);
auto Base = Layout.getPrimaryBase();
if (!Base || Base == PrimaryBase || !Base->isPolymorphic())
break;
PrimaryBase = Base;
}
return PrimaryBase;
}

bool ASTContext::useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName) {
auto *Method = cast<CXXMethodDecl>(VirtualMethodDecl.getDecl());
assert(Method->isVirtual());
bool DefaultIncludesPointerAuth =
LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics;

if (!DefaultIncludesPointerAuth)
return true;

auto Existing = ThunksToBeAbbreviated.find(VirtualMethodDecl);
if (Existing != ThunksToBeAbbreviated.end())
return Existing->second.contains(MangledName.str());

std::unique_ptr<MangleContext> Mangler(createMangleContext());
llvm::StringMap<llvm::SmallVector<std::string, 2>> Thunks;
auto VtableContext = getVTableContext();
if (const auto *ThunkInfos = VtableContext->getThunkInfo(VirtualMethodDecl)) {
auto *Destructor = dyn_cast<CXXDestructorDecl>(Method);
for (const auto &Thunk : *ThunkInfos) {
SmallString<256> ElidedName;
llvm::raw_svector_ostream ElidedNameStream(ElidedName);
if (Destructor)
Mangler->mangleCXXDtorThunk(Destructor, VirtualMethodDecl.getDtorType(),
Thunk, /* elideOverrideInfo */ true,
ElidedNameStream);
else
Mangler->mangleThunk(Method, Thunk, /* elideOverrideInfo */ true,
ElidedNameStream);
SmallString<256> MangledName;
llvm::raw_svector_ostream mangledNameStream(MangledName);
if (Destructor)
Mangler->mangleCXXDtorThunk(Destructor, VirtualMethodDecl.getDtorType(),
Thunk, /* elideOverrideInfo */ false,
mangledNameStream);
else
Mangler->mangleThunk(Method, Thunk, /* elideOverrideInfo */ false,
mangledNameStream);

if (Thunks.find(ElidedName) == Thunks.end())
Thunks[ElidedName] = {};
Thunks[ElidedName].push_back(std::string(MangledName));
}
}
llvm::StringSet<> SimplifiedThunkNames;
for (auto &ThunkList : Thunks) {
llvm::sort(ThunkList.second);
SimplifiedThunkNames.insert(ThunkList.second[0]);
}
bool Result = SimplifiedThunkNames.contains(MangledName);
ThunksToBeAbbreviated[VirtualMethodDecl] = std::move(SimplifiedThunkNames);
return Result;
}
3 changes: 1 addition & 2 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ add_clang_library(clangAST
FormatString.cpp
InheritViz.cpp
Interp/ByteCodeEmitter.cpp
Interp/ByteCodeExprGen.cpp
Interp/ByteCodeStmtGen.cpp
Interp/Compiler.cpp
Interp/Context.cpp
Interp/Descriptor.cpp
Interp/Disasm.cpp
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,13 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
}

Out << '>';

if (const Expr *RequiresClause = Params->getRequiresClause()) {
Out << " requires ";
RequiresClause->printPretty(Out, nullptr, Policy, Indentation, "\n",
&Context);
}

if (!OmitTemplateKW)
Out << ' ';
}
Expand Down
734 changes: 0 additions & 734 deletions clang/lib/AST/Interp/ByteCodeStmtGen.cpp

This file was deleted.

91 changes: 0 additions & 91 deletions clang/lib/AST/Interp/ByteCodeStmtGen.h

This file was deleted.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===//
//===--- Compiler.h - Code generator for expressions -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down Expand Up @@ -36,8 +36,11 @@ template <class Emitter> class InitLinkScope;
template <class Emitter> class OptionScope;
template <class Emitter> class ArrayIndexScope;
template <class Emitter> class SourceLocScope;
template <class Emitter> class LoopScope;
template <class Emitter> class LabelScope;
template <class Emitter> class SwitchScope;

template <class Emitter> class ByteCodeExprGen;
template <class Emitter> class Compiler;
struct InitLink {
public:
enum {
Expand All @@ -60,7 +63,7 @@ struct InitLink {

InitLink(uint8_t Kind) : Kind(Kind) {}
template <class Emitter>
bool emit(ByteCodeExprGen<Emitter> *Ctx, const Expr *E) const;
bool emit(Compiler<Emitter> *Ctx, const Expr *E) const;

private:
uint32_t Kind;
Expand All @@ -84,12 +87,14 @@ struct VarCreationState {

/// Compilation context for expressions.
template <class Emitter>
class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
public Emitter {
class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
public Emitter {
protected:
// Aliases for types defined in the emitter.
using LabelTy = typename Emitter::LabelTy;
using AddrTy = typename Emitter::AddrTy;
using OptLabelTy = std::optional<LabelTy>;
using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;

/// Current compilation context.
Context &Ctx;
Expand All @@ -99,10 +104,10 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
public:
/// Initializes the compiler and the backend emitter.
template <typename... Tys>
ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
Compiler(Context &Ctx, Program &P, Tys &&...Args)
: Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}

// Expression visitors - result returned on interp stack.
// Expressions.
bool VisitCastExpr(const CastExpr *E);
bool VisitIntegerLiteral(const IntegerLiteral *E);
bool VisitFloatingLiteral(const FloatingLiteral *E);
Expand Down Expand Up @@ -179,9 +184,29 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);

// Statements.
bool visitCompoundStmt(const CompoundStmt *S);
bool visitLoopBody(const Stmt *S);
bool visitDeclStmt(const DeclStmt *DS);
bool visitReturnStmt(const ReturnStmt *RS);
bool visitIfStmt(const IfStmt *IS);
bool visitWhileStmt(const WhileStmt *S);
bool visitDoStmt(const DoStmt *S);
bool visitForStmt(const ForStmt *S);
bool visitCXXForRangeStmt(const CXXForRangeStmt *S);
bool visitBreakStmt(const BreakStmt *S);
bool visitContinueStmt(const ContinueStmt *S);
bool visitSwitchStmt(const SwitchStmt *S);
bool visitCaseStmt(const CaseStmt *S);
bool visitDefaultStmt(const DefaultStmt *S);
bool visitAttributedStmt(const AttributedStmt *S);
bool visitCXXTryStmt(const CXXTryStmt *S);

protected:
bool visitStmt(const Stmt *S);
bool visitExpr(const Expr *E) override;
bool visitDecl(const VarDecl *VD, bool ConstantContext) override;
bool visitFunc(const FunctionDecl *F) override;

protected:
/// Emits scope cleanup instructions.
Expand All @@ -194,8 +219,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
Record *getRecord(QualType Ty);
Record *getRecord(const RecordDecl *RD);

// Returns a function for the given FunctionDecl.
// If the function does not exist yet, it is compiled.
/// Returns a function for the given FunctionDecl.
/// If the function does not exist yet, it is compiled.
const Function *getFunction(const FunctionDecl *FD);

std::optional<PrimType> classify(const Expr *E) const {
Expand Down Expand Up @@ -305,6 +330,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
friend class ArrayIndexScope<Emitter>;
friend class SourceLocScope<Emitter>;
friend struct InitLink;
friend class LoopScope<Emitter>;
friend class LabelScope<Emitter>;
friend class SwitchScope<Emitter>;

/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
Expand Down Expand Up @@ -348,6 +376,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool emitDestruction(const Descriptor *Desc);
unsigned collectBaseOffset(const QualType BaseType,
const QualType DerivedType);
bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);

protected:
/// Variable to storage mapping.
Expand Down Expand Up @@ -378,15 +407,28 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,

/// Flag indicating if we're initializing a global variable.
bool GlobalDecl = false;

/// Type of the expression returned by the function.
std::optional<PrimType> ReturnType;

/// Switch case mapping.
CaseMap CaseLabels;

/// Point to break to.
OptLabelTy BreakLabel;
/// Point to continue to.
OptLabelTy ContinueLabel;
/// Default case label.
OptLabelTy DefaultLabel;
};

extern template class ByteCodeExprGen<ByteCodeEmitter>;
extern template class ByteCodeExprGen<EvalEmitter>;
extern template class Compiler<ByteCodeEmitter>;
extern template class Compiler<EvalEmitter>;

/// Scope chain managing the variable lifetimes.
template <class Emitter> class VariableScope {
public:
VariableScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
: Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD) {
Ctx->VarScope = this;
}
Expand Down Expand Up @@ -433,8 +475,8 @@ template <class Emitter> class VariableScope {
VariableScope *getParent() const { return Parent; }

protected:
/// ByteCodeExprGen instance.
ByteCodeExprGen<Emitter> *Ctx;
/// Compiler instance.
Compiler<Emitter> *Ctx;
/// Link to the parent scope.
VariableScope *Parent;
const ValueDecl *ValDecl = nullptr;
Expand All @@ -443,8 +485,7 @@ template <class Emitter> class VariableScope {
/// Generic scope for local variables.
template <class Emitter> class LocalScope : public VariableScope<Emitter> {
public:
LocalScope(ByteCodeExprGen<Emitter> *Ctx)
: VariableScope<Emitter>(Ctx, nullptr) {}
LocalScope(Compiler<Emitter> *Ctx) : VariableScope<Emitter>(Ctx, nullptr) {}

/// Emit a Destroy op for this scope.
~LocalScope() override {
Expand Down Expand Up @@ -538,8 +579,7 @@ template <class Emitter> class DestructorScope final {
/// variables are automatically emitted when the AutoScope is destroyed.
template <class Emitter> class AutoScope : public LocalScope<Emitter> {
public:
AutoScope(ByteCodeExprGen<Emitter> *Ctx)
: LocalScope<Emitter>(Ctx), DS(*this) {}
AutoScope(Compiler<Emitter> *Ctx) : LocalScope<Emitter>(Ctx), DS(*this) {}

private:
DestructorScope<Emitter> DS;
Expand All @@ -548,7 +588,7 @@ template <class Emitter> class AutoScope : public LocalScope<Emitter> {
/// Scope for storage declared in a compound statement.
template <class Emitter> class BlockScope final : public AutoScope<Emitter> {
public:
BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
BlockScope(Compiler<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}

void addExtended(const Scope::Local &Local) override {
// If we to this point, just add the variable as a normal local
Expand All @@ -560,27 +600,26 @@ template <class Emitter> class BlockScope final : public AutoScope<Emitter> {

template <class Emitter> class ExprScope final : public AutoScope<Emitter> {
public:
ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
ExprScope(Compiler<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
};

template <class Emitter> class ArrayIndexScope final {
public:
ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
OldArrayIndex = Ctx->ArrayIndex;
Ctx->ArrayIndex = Index;
}

~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }

private:
ByteCodeExprGen<Emitter> *Ctx;
Compiler<Emitter> *Ctx;
std::optional<uint64_t> OldArrayIndex;
};

template <class Emitter> class SourceLocScope final {
public:
SourceLocScope(ByteCodeExprGen<Emitter> *Ctx, const Expr *DefaultExpr)
: Ctx(Ctx) {
SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) {
assert(DefaultExpr);
// We only switch if the current SourceLocDefaultExpr is null.
if (!Ctx->SourceLocDefaultExpr) {
Expand All @@ -595,20 +634,20 @@ template <class Emitter> class SourceLocScope final {
}

private:
ByteCodeExprGen<Emitter> *Ctx;
Compiler<Emitter> *Ctx;
bool Enabled = false;
};

template <class Emitter> class InitLinkScope final {
public:
InitLinkScope(ByteCodeExprGen<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {
InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {
Ctx->InitStack.push_back(std::move(Link));
}

~InitLinkScope() { this->Ctx->InitStack.pop_back(); }

private:
ByteCodeExprGen<Emitter> *Ctx;
Compiler<Emitter> *Ctx;
};

} // namespace interp
Expand Down
13 changes: 6 additions & 7 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

#include "Context.h"
#include "ByteCodeEmitter.h"
#include "ByteCodeExprGen.h"
#include "ByteCodeStmtGen.h"
#include "Compiler.h"
#include "EvalEmitter.h"
#include "Interp.h"
#include "InterpFrame.h"
Expand All @@ -30,7 +29,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
assert(Stk.empty());
Function *Func = P->getFunction(FD);
if (!Func || !Func->hasBody())
Func = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD);
Func = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD);

APValue DummyResult;
if (!Run(Parent, Func, DummyResult))
Expand All @@ -41,7 +40,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {

bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
bool Recursing = !Stk.empty();
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk);
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);

auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());

Expand All @@ -67,7 +66,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {

bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) {
bool Recursing = !Stk.empty();
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk);
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);

auto Res = C.interpretExpr(E);
if (Res.isInvalid()) {
Expand All @@ -92,7 +91,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) {
bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
APValue &Result) {
bool Recursing = !Stk.empty();
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk);
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);

bool CheckGlobalInitialized =
shouldBeGloballyIndexed(VD) &&
Expand Down Expand Up @@ -261,7 +260,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {
return Func;

if (!Func || WasNotDefined) {
if (auto F = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD))
if (auto F = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD))
Func = F;
}

Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Program.h"
#include "clang/AST/ASTDumperUtils.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"

Expand Down Expand Up @@ -154,6 +155,19 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
}
Desc->dump(OS);

if (Desc->IsTemporary) {
if (const auto *MTE =
dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->asExpr());
MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
const APValue *V = MTE->getLifetimeExtendedTemporaryDecl()->getValue();
if (V->isInt())
OS << " (global temporary value: " << V->getInt() << ")";
else
OS << " (huh?)";
}
}

OS << "\n";
if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {
OS << " ";
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
bool CheckFullyInitialized) {
this->CheckFullyInitialized = CheckFullyInitialized;
S.EvaluatingDecl = VD;

if (const Expr *Init = VD->getAnyInitializer()) {
QualType T = VD->getType();
Expand All @@ -69,6 +70,7 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
if (!this->visitDecl(VD, S.inConstantContext()) && EvalResult.empty())
EvalResult.setInvalid();

S.EvaluatingDecl = nullptr;
return std::move(this->EvalResult);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/EvalEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class EvalEmitter : public SourceMapper {
/// Methods implemented by the compiler.
virtual bool visitExpr(const Expr *E) = 0;
virtual bool visitDecl(const VarDecl *VD, bool ConstantContext) = 0;
virtual bool visitFunc(const FunctionDecl *F) = 0;

/// Emits jumps.
bool jumpTrue(const LabelTy &Label);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
};

if (const auto *D = Desc->asVarDecl();
D && D->hasGlobalStorage() && !IsConstType(D)) {
D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) {
diagnoseNonConstVariable(S, OpPC, D);
return S.inConstantContext();
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/InterpState.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class InterpState final : public State, public SourceMapper {
InterpFrame *Current = nullptr;
/// Source location of the evaluating expression
SourceLocation EvalLocation;
/// Declaration we're initializing/evaluting, if any.
const VarDecl *EvaluatingDecl = nullptr;
};

} // namespace interp
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//

#include "Program.h"
#include "ByteCodeStmtGen.h"
#include "Context.h"
#include "Function.h"
#include "Integral.h"
Expand Down
90 changes: 83 additions & 7 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
}

void mangleCXXName(GlobalDecl GD, raw_ostream &) override;
void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, bool,
raw_ostream &) override;
void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
raw_ostream &) override;
const ThunkInfo &Thunk, bool, raw_ostream &) override;
void mangleReferenceTemporary(const VarDecl *D, unsigned ManglingNumber,
raw_ostream &) override;
void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) override;
Expand Down Expand Up @@ -468,6 +467,7 @@ class CXXNameMangler {
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
void mangleLambdaSig(const CXXRecordDecl *Lambda);
void mangleModuleNamePrefix(StringRef Name, bool IsPartition = false);
void mangleVendorQualifier(StringRef Name);

private:

Expand Down Expand Up @@ -559,7 +559,6 @@ class CXXNameMangler {
StringRef Prefix = "");
void mangleOperatorName(DeclarationName Name, unsigned Arity);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleVendorQualifier(StringRef qualifier);
void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr);
void mangleRefQualifier(RefQualifierKind RefQualifier);

Expand Down Expand Up @@ -7044,8 +7043,78 @@ void ItaniumMangleContextImpl::mangleCXXDtorComdat(const CXXDestructorDecl *D,
Mangler.mangle(GlobalDecl(D, Dtor_Comdat));
}

/// Mangles the pointer authentication override attribute for classes
/// that have explicit overrides for the vtable authentication schema.
///
/// The override is mangled as a parameterized vendor extension as follows
///
/// <type> ::= U "__vtptrauth" I
/// <key>
/// <addressDiscriminated>
/// <extraDiscriminator>
/// E
///
/// The extra discriminator encodes the explicit value derived from the
/// override schema, e.g. if the override has specified type based
/// discrimination the encoded value will be the discriminator derived from the
/// type name.
static void mangleOverrideDiscrimination(CXXNameMangler &Mangler,
ASTContext &Context,
const ThunkInfo &Thunk) {
auto &LangOpts = Context.getLangOpts();
const CXXRecordDecl *ThisRD = Thunk.ThisType->getPointeeCXXRecordDecl();
const CXXRecordDecl *PtrauthClassRD =
Context.baseForVTableAuthentication(ThisRD);
unsigned TypedDiscriminator =
Context.getPointerAuthVTablePointerDiscriminator(ThisRD);
Mangler.mangleVendorQualifier("__vtptrauth");
auto &ManglerStream = Mangler.getStream();
ManglerStream << "I";
if (const auto *ExplicitAuth =
PtrauthClassRD->getAttr<VTablePointerAuthenticationAttr>()) {
ManglerStream << "Lj" << ExplicitAuth->getKey();

if (ExplicitAuth->getAddressDiscrimination() ==
VTablePointerAuthenticationAttr::DefaultAddressDiscrimination)
ManglerStream << "Lb" << LangOpts.PointerAuthVTPtrAddressDiscrimination;
else
ManglerStream << "Lb"
<< (ExplicitAuth->getAddressDiscrimination() ==
VTablePointerAuthenticationAttr::AddressDiscrimination);

switch (ExplicitAuth->getExtraDiscrimination()) {
case VTablePointerAuthenticationAttr::DefaultExtraDiscrimination: {
if (LangOpts.PointerAuthVTPtrTypeDiscrimination)
ManglerStream << "Lj" << TypedDiscriminator;
else
ManglerStream << "Lj" << 0;
break;
}
case VTablePointerAuthenticationAttr::TypeDiscrimination:
ManglerStream << "Lj" << TypedDiscriminator;
break;
case VTablePointerAuthenticationAttr::CustomDiscrimination:
ManglerStream << "Lj" << ExplicitAuth->getCustomDiscriminationValue();
break;
case VTablePointerAuthenticationAttr::NoExtraDiscrimination:
ManglerStream << "Lj" << 0;
break;
}
} else {
ManglerStream << "Lj"
<< (unsigned)VTablePointerAuthenticationAttr::DefaultKey;
ManglerStream << "Lb" << LangOpts.PointerAuthVTPtrAddressDiscrimination;
if (LangOpts.PointerAuthVTPtrTypeDiscrimination)
ManglerStream << "Lj" << TypedDiscriminator;
else
ManglerStream << "Lj" << 0;
}
ManglerStream << "E";
}

void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
bool ElideOverrideInfo,
raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
Expand All @@ -7071,21 +7140,28 @@ void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
Thunk.Return.Virtual.Itanium.VBaseOffsetOffset);

Mangler.mangleFunctionEncoding(MD);
if (!ElideOverrideInfo)
mangleOverrideDiscrimination(Mangler, getASTContext(), Thunk);
}

void ItaniumMangleContextImpl::mangleCXXDtorThunk(
const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment, raw_ostream &Out) {
void ItaniumMangleContextImpl::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
CXXDtorType Type,
const ThunkInfo &Thunk,
bool ElideOverrideInfo,
raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
CXXNameMangler Mangler(*this, Out, DD, Type);
Mangler.getStream() << "_ZT";

auto &ThisAdjustment = Thunk.This;
// Mangle the 'this' pointer adjustment.
Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
ThisAdjustment.Virtual.Itanium.VCallOffsetOffset);

Mangler.mangleFunctionEncoding(GlobalDecl(DD, Type));
if (!ElideOverrideInfo)
mangleOverrideDiscrimination(Mangler, getASTContext(), Thunk);
}

/// Returns the mangled name for a guard variable for the passed in VarDecl.
Expand Down
23 changes: 17 additions & 6 deletions clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,20 @@ class ASTNameGenerator::Implementation {
}
} else if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(ND)) {
Manglings.emplace_back(getName(ND));
if (MD->isVirtual())
if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD))
for (const auto &T : *TIV)
Manglings.emplace_back(getMangledThunk(MD, T));
if (MD->isVirtual()) {
if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD)) {
for (const auto &T : *TIV) {
std::string ThunkName;
std::string ContextualizedName =
getMangledThunk(MD, T, /* ElideOverrideInfo */ false);
if (Ctx.useAbbreviatedThunkName(MD, ContextualizedName))
ThunkName = getMangledThunk(MD, T, /* ElideOverrideInfo */ true);
else
ThunkName = ContextualizedName;
Manglings.emplace_back(ThunkName);
}
}
}
}

return Manglings;
Expand Down Expand Up @@ -569,11 +579,12 @@ class ASTNameGenerator::Implementation {
return BOS.str();
}

std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T) {
std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T,
bool ElideOverrideInfo) {
std::string FrontendBuf;
llvm::raw_string_ostream FOS(FrontendBuf);

MC->mangleThunk(MD, T, FOS);
MC->mangleThunk(MD, T, ElideOverrideInfo, FOS);

std::string BackendBuf;
llvm::raw_string_ostream BOS(BackendBuf);
Expand Down
Loading