227 changes: 89 additions & 138 deletions bolt/docs/CommandLineArgumentReference.md

Large diffs are not rendered by default.

149 changes: 149 additions & 0 deletions bolt/docs/generate_doc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#!/usr/bin/env python3
# A tool to parse the output of `llvm-bolt --help-hidden` and update the
# documentation in CommandLineArgumentReference.md automatically.
# Run from the directory in which this file is located to update the docs.

import subprocess
from textwrap import wrap

LINE_LIMIT = 80


def wrap_text(text, indent, limit=LINE_LIMIT):
wrapped_lines = wrap(text, width=limit - len(indent))
wrapped_text = ("\n" + indent).join(wrapped_lines)
return wrapped_text


def add_info(sections, section, option, description):
indent = " "
wrapped_description = "\n".join(
[
wrap_text(line, indent) if len(line) > LINE_LIMIT else line
for line in description
]
)
sections[section].append((option, indent + wrapped_description))


def parse_bolt_options(output):
section_headers = [
"Generic options:",
"Output options:",
"BOLT generic options:",
"BOLT optimization options:",
"BOLT options in relocation mode:",
"BOLT instrumentation options:",
"BOLT printing options:",
]

sections = {key: [] for key in section_headers}
current_section, prev_section = None, None
option, description = None, []

for line in output.split("\n"):
cleaned_line = line.strip()

if cleaned_line.casefold() in map(str.casefold, section_headers):
if prev_section != None: # Save last option from prev section
add_info(sections, current_section, option, description)
option, description = None, []

cleaned_line = cleaned_line.split()
# Apply lowercase to all words except the first one
cleaned_line = [cleaned_line[0]] + [
word.lower() for word in cleaned_line[1:]
]
# Join the words back together into a string
cleaned_line = " ".join(cleaned_line)

current_section = cleaned_line
prev_section = current_section
continue

if cleaned_line.startswith("-"):
if option and description:
# Join description lines, adding an extra newline for
# sub-options that start with '='
add_info(sections, current_section, option, description)
option, description = None, []

parts = cleaned_line.split(" ", 1)
if len(parts) > 1:
option = parts[0].strip()
descr = parts[1].strip()
descr = descr[2].upper() + descr[3:]
description = [descr]
if option.startswith("--print") or option.startswith("--time"):
current_section = "BOLT printing options:"
elif prev_section != None:
current_section = prev_section
continue

if cleaned_line.startswith("="):
parts = cleaned_line.split(maxsplit=1)
# Split into two parts: sub-option and description
if len(parts) == 2:
# Rejoin with a single space
cleaned_line = parts[0] + " " + parts[1].rstrip()
description.append(cleaned_line)
elif cleaned_line: # Multiline description continuation
description.append(cleaned_line)

add_info(sections, current_section, option, description)
return sections


def generate_markdown(sections):
markdown_lines = [
"# BOLT - a post-link optimizer developed to speed up large applications\n",
"## SYNOPSIS\n",
"`llvm-bolt <executable> [-o outputfile] <executable>.bolt "
"[-data=perf.fdata] [options]`\n",
"## OPTIONS",
]

for section, options in sections.items():
markdown_lines.append(f"\n### {section}")
if section == "BOLT instrumentation options:":
markdown_lines.append(
f"\n`llvm-bolt <executable> -instrument"
" [-o outputfile] <instrumented-executable>`"
)
for option, desc in options:
markdown_lines.append(f"\n- `{option}`\n")
# Split description into lines to handle sub-options
desc_lines = desc.split("\n")
for line in desc_lines:
if line.startswith("="):
# Sub-option: correct formatting with bullet
sub_option, sub_desc = line[1:].split(" ", 1)
markdown_lines.append(f" - `{sub_option}`: {sub_desc[4:]}")
else:
# Regular line of description
if line[2:].startswith("<"):
line = line.replace("<", "").replace(">", "")
markdown_lines.append(f"{line}")

return "\n".join(markdown_lines)


def main():
try:
help_output = subprocess.run(
["llvm-bolt", "--help-hidden"], capture_output=True, text=True, check=True
).stdout
except subprocess.CalledProcessError as e:
print("Failed to execute llvm-bolt --help:")
print(e)
return

sections = parse_bolt_options(help_output)
markdown = generate_markdown(sections)

with open("CommandLineArgumentReference.md", "w") as md_file:
md_file.write(markdown)


if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions bolt/include/bolt/Core/BinaryBasicBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class BinaryBasicBlock {
unsigned Index{InvalidIndex};

/// Index in the current layout.
mutable unsigned LayoutIndex{InvalidIndex};
unsigned LayoutIndex{InvalidIndex};

/// Number of pseudo instructions in this block.
uint32_t NumPseudos{0};
Expand Down Expand Up @@ -891,7 +891,7 @@ class BinaryBasicBlock {
}

/// Set layout index. To be used by BinaryFunction.
void setLayoutIndex(unsigned Index) const { LayoutIndex = Index; }
void setLayoutIndex(unsigned Index) { LayoutIndex = Index; }

/// Needed by graph traits.
BinaryFunction *getParent() const { return getFunction(); }
Expand Down
3 changes: 2 additions & 1 deletion bolt/include/bolt/Core/FunctionLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ class FunctionLayout {
void eraseBasicBlocks(const DenseSet<const BinaryBasicBlock *> ToErase);

/// Make sure fragments' and basic blocks' indices match the current layout.
void updateLayoutIndices();
void updateLayoutIndices() const;
void updateLayoutIndices(ArrayRef<BinaryBasicBlock *> Order) const;

/// Replace the current layout with NewLayout. Uses the block's
/// self-identifying fragment number to assign blocks to infer function
Expand Down
4 changes: 4 additions & 0 deletions bolt/include/bolt/Rewrite/RewriteInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Regex.h"
#include <map>
#include <set>
#include <unordered_map>
Expand Down Expand Up @@ -596,6 +597,9 @@ class RewriteInstance {

NameResolver NR;

// Regex object matching split function names.
const Regex FunctionFragmentTemplate{"(.*)\\.(cold|warm)(\\.[0-9]+)?"};

friend class RewriteInstanceDiff;
};

Expand Down
10 changes: 3 additions & 7 deletions bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3641,8 +3641,8 @@ bool BinaryFunction::forEachEntryPoint(EntryPointCallbackTy Callback) const {

BinaryFunction::BasicBlockListType BinaryFunction::dfs() const {
BasicBlockListType DFS;
unsigned Index = 0;
std::stack<BinaryBasicBlock *> Stack;
std::set<BinaryBasicBlock *> Visited;

// Push entry points to the stack in reverse order.
//
Expand All @@ -3659,17 +3659,13 @@ BinaryFunction::BasicBlockListType BinaryFunction::dfs() const {
for (BinaryBasicBlock *const BB : reverse(EntryPoints))
Stack.push(BB);

for (BinaryBasicBlock &BB : blocks())
BB.setLayoutIndex(BinaryBasicBlock::InvalidIndex);

while (!Stack.empty()) {
BinaryBasicBlock *BB = Stack.top();
Stack.pop();

if (BB->getLayoutIndex() != BinaryBasicBlock::InvalidIndex)
if (Visited.find(BB) != Visited.end())
continue;

BB->setLayoutIndex(Index++);
Visited.insert(BB);
DFS.push_back(BB);

for (BinaryBasicBlock *SuccBB : BB->landing_pads()) {
Expand Down
9 changes: 7 additions & 2 deletions bolt/lib/Core/FunctionLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,20 @@ void FunctionLayout::eraseBasicBlocks(
updateLayoutIndices();
}

void FunctionLayout::updateLayoutIndices() {
void FunctionLayout::updateLayoutIndices() const {
unsigned BlockIndex = 0;
for (FunctionFragment &FF : fragments()) {
for (const FunctionFragment &FF : fragments()) {
for (BinaryBasicBlock *const BB : FF) {
BB->setLayoutIndex(BlockIndex++);
BB->setFragmentNum(FF.getFragmentNum());
}
}
}
void FunctionLayout::updateLayoutIndices(
ArrayRef<BinaryBasicBlock *> Order) const {
for (auto [Index, BB] : llvm::enumerate(Order))
BB->setLayoutIndex(Index);
}

bool FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
const bool EqualBlockOrder = llvm::equal(Blocks, NewLayout);
Expand Down
5 changes: 4 additions & 1 deletion bolt/lib/Passes/IdenticalCodeFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,10 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
"ICF breakdown", opts::TimeICF);
ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
// Make sure indices are in-order.
BF.getLayout().updateLayoutIndices();
if (opts::ICFUseDFS)
BF.getLayout().updateLayoutIndices(BF.dfs());
else
BF.getLayout().updateLayoutIndices();

// Pre-compute hash before pushing into hashtable.
// Hash instruction operands to minimize hash collisions.
Expand Down
3 changes: 3 additions & 0 deletions bolt/lib/Profile/YAMLProfileWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS,
llvm::copy(UseDFS ? BF.dfs() : BF.getLayout().blocks(),
std::back_inserter(Order));

const FunctionLayout Layout = BF.getLayout();
Layout.updateLayoutIndices(Order);

for (const BinaryBasicBlock *BB : Order) {
yaml::bolt::BinaryBasicBlockProfile YamlBB;
YamlBB.Index = BB->getLayoutIndex();
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Rewrite/DWARFRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ static cl::opt<bool> CreateDebugNames(

static cl::opt<bool>
DebugSkeletonCu("debug-skeleton-cu",
cl::desc("prints out offsetrs for abbrev and debu_info of "
cl::desc("prints out offsets for abbrev and debug_info of "
"Skeleton CUs that get patched."),
cl::ZeroOrMore, cl::Hidden, cl::init(false),
cl::cat(BoltCategory));
Expand Down
12 changes: 4 additions & 8 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -945,9 +944,6 @@ void RewriteInstance::discoverFileObjects() {
BinaryFunction *PreviousFunction = nullptr;
unsigned AnonymousId = 0;

// Regex object for matching cold fragments.
const Regex ColdFragment(".*\\.cold(\\.[0-9]+)?");

const auto SortedSymbolsEnd =
LastSymbol == SortedSymbols.end() ? LastSymbol : std::next(LastSymbol);
for (auto Iter = SortedSymbols.begin(); Iter != SortedSymbolsEnd; ++Iter) {
Expand Down Expand Up @@ -1229,7 +1225,7 @@ void RewriteInstance::discoverFileObjects() {
}

// Check if it's a cold function fragment.
if (ColdFragment.match(SymName)) {
if (FunctionFragmentTemplate.match(SymName)) {
static bool PrintedWarning = false;
if (!PrintedWarning) {
PrintedWarning = true;
Expand Down Expand Up @@ -1460,10 +1456,10 @@ void RewriteInstance::registerFragments() {
for (StringRef Name : Function.getNames()) {
StringRef BaseName = NR.restore(Name);
const bool IsGlobal = BaseName == Name;
const size_t ColdSuffixPos = BaseName.find(".cold");
if (ColdSuffixPos == StringRef::npos)
SmallVector<StringRef> Matches;
if (!FunctionFragmentTemplate.match(BaseName, &Matches))
continue;
StringRef ParentName = BaseName.substr(0, ColdSuffixPos);
StringRef ParentName = Matches[1];
const BinaryData *BD = BC->getBinaryDataByName(ParentName);
const uint64_t NumPossibleLocalParents =
NR.getUniquifiedNameCount(ParentName);
Expand Down
3 changes: 3 additions & 0 deletions bolt/test/AArch64/Inputs/array_end.lld_script
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
SECTIONS {
.interp : { *(.interp) }

. = ALIGN(CONSTANT(MAXPAGESIZE));
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
Expand Down
3 changes: 3 additions & 0 deletions bolt/test/Inputs/lsda.ldscript
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
SECTIONS {
.interp : { *(.interp) }
. = ALIGN(CONSTANT(MAXPAGESIZE));
.text : { *(.text*) }
. = ALIGN(CONSTANT(MAXPAGESIZE));
.gcc_except_table.main : { *(.gcc_except_table*) }
. = 0x20000;
.eh_frame : { *(.eh_frame) }
Expand Down
14 changes: 13 additions & 1 deletion bolt/test/X86/register-fragments-bolt-symbols.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@
# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %S/cdsplit-symbol-names.s -o %t.main.o
# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.chain.o
# RUN: link_fdata %S/cdsplit-symbol-names.s %t.main.o %t.fdata
# RUN: sed -i 's|chain|chain/2|g' %t.fdata
# RUN: llvm-strip --strip-unneeded %t.main.o

## Check warm fragment name matching (produced by cdsplit)
# RUN: %clang %cflags %t.main.o -o %t.warm.exe -Wl,-q
# RUN: llvm-bolt %t.warm.exe -o %t.warm.bolt --split-functions --split-strategy=cdsplit \
# RUN: --call-scale=2 --data=%t.fdata --reorder-blocks=ext-tsp --enable-bat
# RUN: link_fdata %s %t.warm.bolt %t.preagg.warm PREAGGWARM
# PREAGGWARM: B X:0 #chain.warm# 1 0
# RUN: perf2bolt %t.warm.bolt -p %t.preagg.warm --pa -o %t.warm.fdata -w %t.warm.yaml \
# RUN: -v=1 | FileCheck %s --check-prefix=CHECK-BOLT-WARM

# CHECK-BOLT-WARM: marking chain.warm/1(*2) as a fragment of chain

# RUN: sed -i 's|chain|chain/2|g' %t.fdata
# RUN: llvm-objcopy --localize-symbol=chain %t.main.o
# RUN: %clang %cflags %t.chain.o %t.main.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=randomN \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {

Finder->addMatcher(
cxxMemberCallExpr(
argumentCountIs(0),
on(expr(anyOf(hasType(ValidContainer),
hasType(pointsTo(ValidContainer)),
hasType(references(ValidContainer))))
Expand All @@ -163,7 +164,8 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
this);

Finder->addMatcher(
callExpr(has(cxxDependentScopeMemberExpr(
callExpr(argumentCountIs(0),
has(cxxDependentScopeMemberExpr(
hasObjectExpression(
expr(anyOf(hasType(ValidContainer),
hasType(pointsTo(ValidContainer)),
Expand Down
5 changes: 3 additions & 2 deletions clang-tools-extra/clangd/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@ struct Config {
IncludesPolicy UnusedIncludes = IncludesPolicy::Strict;
IncludesPolicy MissingIncludes = IncludesPolicy::None;

/// IncludeCleaner will not diagnose usages of these headers matched by
/// these regexes.
struct {
/// IncludeCleaner will not diagnose usages of these headers matched by
/// these regexes.
std::vector<std::function<bool(llvm::StringRef)>> IgnoreHeader;
bool AnalyzeAngledIncludes = false;
} Includes;
} Diagnostics;

Expand Down
60 changes: 37 additions & 23 deletions clang-tools-extra/clangd/ConfigCompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,32 +572,46 @@ struct FragmentCompiler {
#else
static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags;
#endif
auto Filters = std::make_shared<std::vector<llvm::Regex>>();
for (auto &HeaderPattern : F.IgnoreHeader) {
// Anchor on the right.
std::string AnchoredPattern = "(" + *HeaderPattern + ")$";
llvm::Regex CompiledRegex(AnchoredPattern, Flags);
std::string RegexError;
if (!CompiledRegex.isValid(RegexError)) {
diag(Warning,
llvm::formatv("Invalid regular expression '{0}': {1}",
*HeaderPattern, RegexError)
.str(),
HeaderPattern.Range);
continue;
std::shared_ptr<std::vector<llvm::Regex>> Filters;
if (!F.IgnoreHeader.empty()) {
Filters = std::make_shared<std::vector<llvm::Regex>>();
for (auto &HeaderPattern : F.IgnoreHeader) {
// Anchor on the right.
std::string AnchoredPattern = "(" + *HeaderPattern + ")$";
llvm::Regex CompiledRegex(AnchoredPattern, Flags);
std::string RegexError;
if (!CompiledRegex.isValid(RegexError)) {
diag(Warning,
llvm::formatv("Invalid regular expression '{0}': {1}",
*HeaderPattern, RegexError)
.str(),
HeaderPattern.Range);
continue;
}
Filters->push_back(std::move(CompiledRegex));
}
Filters->push_back(std::move(CompiledRegex));
}
if (Filters->empty())
// Optional to override the resulting AnalyzeAngledIncludes
// only if it's explicitly set in the current fragment.
// Otherwise it's inherited from parent fragment.
std::optional<bool> AnalyzeAngledIncludes;
if (F.AnalyzeAngledIncludes.has_value())
AnalyzeAngledIncludes = **F.AnalyzeAngledIncludes;
if (!Filters && !AnalyzeAngledIncludes.has_value())
return;
auto Filter = [Filters](llvm::StringRef Path) {
for (auto &Regex : *Filters)
if (Regex.match(Path))
return true;
return false;
};
Out.Apply.push_back([Filter](const Params &, Config &C) {
C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter);
Out.Apply.push_back([Filters = std::move(Filters),
AnalyzeAngledIncludes](const Params &, Config &C) {
if (Filters) {
auto Filter = [Filters](llvm::StringRef Path) {
for (auto &Regex : *Filters)
if (Regex.match(Path))
return true;
return false;
};
C.Diagnostics.Includes.IgnoreHeader.emplace_back(std::move(Filter));
}
if (AnalyzeAngledIncludes.has_value())
C.Diagnostics.Includes.AnalyzeAngledIncludes = *AnalyzeAngledIncludes;
});
}

Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/ConfigFragment.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ struct Fragment {
/// unused or missing. These can match any suffix of the header file in
/// question.
std::vector<Located<std::string>> IgnoreHeader;

/// If false (default), unused system headers will be ignored.
/// Standard library headers are analyzed regardless of this option.
std::optional<Located<bool>> AnalyzeAngledIncludes;
};
IncludesBlock Includes;

Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/ConfigYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ class Parser {
if (auto Values = scalarValues(N))
F.IgnoreHeader = std::move(*Values);
});
Dict.handle("AnalyzeAngledIncludes", [&](Node &N) {
if (auto Value = boolValue(N, "AnalyzeAngledIncludes"))
F.AnalyzeAngledIncludes = *Value;
});
Dict.parse(N);
}

Expand Down
32 changes: 21 additions & 11 deletions clang-tools-extra/clangd/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,24 +68,30 @@ bool isIgnored(llvm::StringRef HeaderPath, HeaderFilter IgnoreHeaders) {
}

bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST,
const include_cleaner::PragmaIncludes *PI) {
const include_cleaner::PragmaIncludes *PI,
bool AnalyzeAngledIncludes) {
assert(Inc.HeaderID);
auto HID = static_cast<IncludeStructure::HeaderID>(*Inc.HeaderID);
auto FE = AST.getSourceManager().getFileManager().getFileRef(
AST.getIncludeStructure().getRealPath(HID));
assert(FE);
if (FE->getDir() == AST.getPreprocessor()
.getHeaderSearchInfo()
.getModuleMap()
.getBuiltinDir())
.getHeaderSearchInfo()
.getModuleMap()
.getBuiltinDir())
return false;
if (PI && PI->shouldKeep(*FE))
return false;
// FIXME(kirillbobyrev): We currently do not support the umbrella headers.
// System headers are likely to be standard library headers.
// Until we have good support for umbrella headers, don't warn about them.
if (Inc.Written.front() == '<')
return tooling::stdlib::Header::named(Inc.Written).has_value();
// Until we have good support for umbrella headers, don't warn about them
// (unless analysis is explicitly enabled).
if (Inc.Written.front() == '<') {
if (tooling::stdlib::Header::named(Inc.Written))
return true;
if (!AnalyzeAngledIncludes)
return false;
}
if (PI) {
// Check if main file is the public interface for a private header. If so we
// shouldn't diagnose it as unused.
Expand Down Expand Up @@ -266,7 +272,8 @@ Fix fixAll(const Fix &RemoveAllUnused, const Fix &AddAllMissing) {

std::vector<const Inclusion *>
getUnused(ParsedAST &AST,
const llvm::DenseSet<IncludeStructure::HeaderID> &ReferencedFiles) {
const llvm::DenseSet<IncludeStructure::HeaderID> &ReferencedFiles,
bool AnalyzeAngledIncludes) {
trace::Span Tracer("IncludeCleaner::getUnused");
std::vector<const Inclusion *> Unused;
for (const Inclusion &MFI : AST.getIncludeStructure().MainFileIncludes) {
Expand All @@ -275,7 +282,8 @@ getUnused(ParsedAST &AST,
auto IncludeID = static_cast<IncludeStructure::HeaderID>(*MFI.HeaderID);
if (ReferencedFiles.contains(IncludeID))
continue;
if (!mayConsiderUnused(MFI, AST, &AST.getPragmaIncludes())) {
if (!mayConsiderUnused(MFI, AST, &AST.getPragmaIncludes(),
AnalyzeAngledIncludes)) {
dlog("{0} was not used, but is not eligible to be diagnosed as unused",
MFI.Written);
continue;
Expand Down Expand Up @@ -347,7 +355,8 @@ include_cleaner::Includes convertIncludes(const ParsedAST &AST) {
return ConvertedIncludes;
}

IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) {
IncludeCleanerFindings
computeIncludeCleanerFindings(ParsedAST &AST, bool AnalyzeAngledIncludes) {
// Interaction is only polished for C/CPP.
if (AST.getLangOpts().ObjC)
return {};
Expand Down Expand Up @@ -432,7 +441,8 @@ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) {
MapInfo::getHashValue(RHS.Symbol);
});
MissingIncludes.erase(llvm::unique(MissingIncludes), MissingIncludes.end());
std::vector<const Inclusion *> UnusedIncludes = getUnused(AST, Used);
std::vector<const Inclusion *> UnusedIncludes =
getUnused(AST, Used, AnalyzeAngledIncludes);
return {std::move(UnusedIncludes), std::move(MissingIncludes)};
}

Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/clangd/IncludeCleaner.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ struct IncludeCleanerFindings {
std::vector<MissingIncludeDiagInfo> MissingIncludes;
};

IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST);
IncludeCleanerFindings
computeIncludeCleanerFindings(ParsedAST &AST,
bool AnalyzeAngledIncludes = false);

using HeaderFilter = llvm::ArrayRef<std::function<bool(llvm::StringRef)>>;
std::vector<Diag>
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/ParsedAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,8 @@ std::vector<Diag> getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code,
Cfg.Diagnostics.UnusedIncludes == Config::IncludesPolicy::None;
if (SuppressMissing && SuppressUnused)
return {};
auto Findings = computeIncludeCleanerFindings(AST);
auto Findings = computeIncludeCleanerFindings(
AST, Cfg.Diagnostics.Includes.AnalyzeAngledIncludes);
if (SuppressMissing)
Findings.MissingIncludes.clear();
if (SuppressUnused)
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ TEST_F(ConfigCompileTests, DiagnosticsIncludeCleaner) {
};
EXPECT_TRUE(HeaderFilter("foo.h"));
EXPECT_FALSE(HeaderFilter("bar.h"));

Frag = {};
EXPECT_FALSE(Conf.Diagnostics.Includes.AnalyzeAngledIncludes);
Frag.Diagnostics.Includes.AnalyzeAngledIncludes = true;
EXPECT_TRUE(compileAndApply());
EXPECT_TRUE(Conf.Diagnostics.Includes.AnalyzeAngledIncludes);
}

TEST_F(ConfigCompileTests, DiagnosticSuppression) {
Expand Down
15 changes: 15 additions & 0 deletions clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,21 @@ TEST(ParseYAML, IncludesIgnoreHeader) {
ElementsAre(val("foo"), val("bar")));
}

TEST(ParseYAML, IncludesAnalyzeAngledIncludes) {
CapturedDiags Diags;
Annotations YAML(R"yaml(
Diagnostics:
Includes:
AnalyzeAngledIncludes: true
)yaml");
auto Results =
Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
ASSERT_THAT(Diags.Diagnostics, IsEmpty());
ASSERT_EQ(Results.size(), 1u);
EXPECT_THAT(Results[0].Diagnostics.Includes.AnalyzeAngledIncludes,
llvm::ValueIs(val(true)));
}

TEST(ParseYAML, Style) {
CapturedDiags Diags;
Annotations YAML(R"yaml(
Expand Down
44 changes: 44 additions & 0 deletions clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ TEST(IncludeCleaner, GetUnusedHeaders) {
#include "unguarded.h"
#include "unused.h"
#include <system_header.h>
#include <non_system_angled_header.h>
void foo() {
a();
b();
Expand All @@ -122,6 +123,7 @@ TEST(IncludeCleaner, GetUnusedHeaders) {
TU.AdditionalFiles["dir/c.h"] = guard("void c();");
TU.AdditionalFiles["unused.h"] = guard("void unused();");
TU.AdditionalFiles["dir/unused.h"] = guard("void dirUnused();");
TU.AdditionalFiles["dir/non_system_angled_header.h"] = guard("");
TU.AdditionalFiles["system/system_header.h"] = guard("");
TU.AdditionalFiles["unguarded.h"] = "";
TU.ExtraArgs.push_back("-I" + testPath("dir"));
Expand All @@ -135,6 +137,48 @@ TEST(IncludeCleaner, GetUnusedHeaders) {
Pointee(writtenInclusion("\"dir/unused.h\""))));
}

TEST(IncludeCleaner, IgnoredAngledHeaders) {
// Currently the default behavior is to ignore unused angled includes
auto TU = TestTU::withCode(R"cpp(
#include <system_header.h>
#include <system_unused.h>
#include <non_system_angled_unused.h>
SystemClass x;
)cpp");
TU.AdditionalFiles["system/system_header.h"] = guard("class SystemClass {};");
TU.AdditionalFiles["system/system_unused.h"] = guard("");
TU.AdditionalFiles["dir/non_system_angled_unused.h"] = guard("");
TU.ExtraArgs = {
"-isystem" + testPath("system"),
"-I" + testPath("dir"),
};
auto AST = TU.build();
IncludeCleanerFindings Findings = computeIncludeCleanerFindings(AST);
EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
}

TEST(IncludeCleaner, UnusedAngledHeaders) {
auto TU = TestTU::withCode(R"cpp(
#include <system_header.h>
#include <system_unused.h>
#include <non_system_angled_unused.h>
SystemClass x;
)cpp");
TU.AdditionalFiles["system/system_header.h"] = guard("class SystemClass {};");
TU.AdditionalFiles["system/system_unused.h"] = guard("");
TU.AdditionalFiles["dir/non_system_angled_unused.h"] = guard("");
TU.ExtraArgs = {
"-isystem" + testPath("system"),
"-I" + testPath("dir"),
};
auto AST = TU.build();
IncludeCleanerFindings Findings = computeIncludeCleanerFindings(AST, true);
EXPECT_THAT(Findings.UnusedIncludes,
UnorderedElementsAre(
Pointee(writtenInclusion("<system_unused.h>")),
Pointee(writtenInclusion("<non_system_angled_unused.h>"))));
}

TEST(IncludeCleaner, ComputeMissingHeaders) {
Annotations MainFile(R"cpp(
#include "a.h"
Expand Down
9 changes: 9 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ Objective-C
Miscellaneous
^^^^^^^^^^^^^

- Added a boolean option `AnalyzeAngledIncludes` to `Includes` config section,
which allows to enable unused includes detection for all angled ("system") headers.
At this moment umbrella headers are not supported, so enabling this option
may result in false-positives.

Improvements to clang-doc
-------------------------

Expand Down Expand Up @@ -363,6 +368,10 @@ Changes in existing checks
<clang-tidy/checks/readability/const-return-type>` check to eliminate false
positives when returning types with const not at the top level.

- 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.

- Improved :doc:`readability-duplicate-include
<clang-tidy/checks/readability/duplicate-include>` check by excluding include
directives that form the filename using macro.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -861,3 +861,31 @@ namespace PR72619 {
if (0 >= s.size()) {}
}
}

namespace PR88203 {
struct SS {
bool empty() const;
int size() const;
int length(int) const;
};

struct SU {
bool empty() const;
int size(int) const;
int length() const;
};

void f(const SS& s) {
if (0 == s.length(1)) {}
if (0 == s.size()) {}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
// CHECK-FIXES: {{^ }}if (s.empty()) {}{{$}}
}

void f(const SU& s) {
if (0 == s.size(1)) {}
if (0 == s.length()) {}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: the 'empty' method should be used to check for emptiness instead of 'length' [readability-container-size-empty]
// CHECK-FIXES: {{^ }}if (s.empty()) {}{{$}}
}
}
2 changes: 1 addition & 1 deletion clang/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ on the Clang forums:
https://discourse.llvm.org/c/clang/

If you find a bug in Clang, please file it in the LLVM bug tracker:
http://llvm.org/bugs/
https://github.com/llvm/llvm-project/issues
13 changes: 13 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ ABI Changes in This Version
AST Dumping Potentially Breaking Changes
----------------------------------------

- The text ast-dumper has improved printing of TemplateArguments.

Clang Frontend Potentially Breaking Changes
-------------------------------------------
- Removed support for constructing on-stack ``TemplateArgumentList``\ s; interfaces should instead
Expand Down Expand Up @@ -249,6 +251,9 @@ Resolutions to C++ Defect Reports
- P0522 implementation is enabled by default in all language versions, and
provisional wording for CWG2398 is implemented.

- Clang now requires a template argument list after a template keyword.
(`CWG96: Syntactic disambiguation using the template keyword <https://cplusplus.github.io/CWG/issues/96.html>`_).

C Language Changes
------------------

Expand Down Expand Up @@ -811,12 +816,20 @@ Bug Fixes to C++ Support
- Clang now allows ``@$``` in raw string literals. Fixes (#GH93130).
- Fix an assertion failure when checking invalid ``this`` usage in the wrong context. (Fixes #GH91536).
- Clang no longer models dependent NTTP arguments as ``TemplateParamObjectDecl`` s. Fixes (#GH84052).
- Fix incorrect merging of modules which contain using declarations which shadow
other declarations. This could manifest as ODR checker false positives.
Fixes (`#80252 <https://github.com/llvm/llvm-project/issues/80252>`_)
- Fix a regression introduced in Clang 18 causing incorrect overload resolution in the presence of functions only
differering by their constraints when only one of these function was variadic.
- Fix a crash when a variable is captured by a block nested inside a lambda. (Fixes #GH93625).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628)
- The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``.
- Fixed malformed AST generated for anonymous union access in templates. (#GH90842)
- Improved preservation of qualifiers and sugar in `TemplateNames`, including
template keyword.

Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
6 changes: 3 additions & 3 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4430,9 +4430,9 @@ To generate SPIR-V binaries, Clang uses the external ``llvm-spirv`` tool from th
Prior to the generation of SPIR-V binary with Clang, ``llvm-spirv``
should be built or installed. Please refer to `the following instructions
<https://github.com/KhronosGroup/SPIRV-LLVM-Translator#build-instructions>`_
for more details. Clang will expect the ``llvm-spirv`` executable to
be present in the ``PATH`` environment variable. Clang uses ``llvm-spirv``
with `the widely adopted assembly syntax package
for more details. Clang will look for ``llvm-spirv-<LLVM-major-version>`` and
``llvm-spirv`` executables, in this order, in the ``PATH`` environment variable.
Clang uses ``llvm-spirv`` with `the widely adopted assembly syntax package
<https://github.com/KhronosGroup/SPIRV-LLVM-Translator/#build-with-spirv-tools>`_.

`The versioning
Expand Down
41 changes: 33 additions & 8 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3135,17 +3135,42 @@ alpha.unix
alpha.unix.BlockInCriticalSection (C)
"""""""""""""""""""""""""""""""""""""
Check for calls to blocking functions inside a critical section.
Applies to: ``lock, unlock, sleep, getc, fgets, read, recv, pthread_mutex_lock,``
`` pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock``
Blocking functions detected by this checker: ``sleep, getc, fgets, read, recv``.
Critical section handling functions modelled by this checker: ``lock, unlock, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock``.
.. code-block:: c
void test() {
std::mutex m;
m.lock();
sleep(3); // warn: a blocking function sleep is called inside a critical
// section
m.unlock();
void pthread_lock_example(pthread_mutex_t *m) {
pthread_mutex_lock(m); // note: entering critical section here
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
pthread_mutex_unlock(m);
}
.. code-block:: cpp
void overlapping_critical_sections(mtx_t *m1, std::mutex &m2) {
std::lock_guard lg{m2}; // note: entering critical section here
mtx_lock(m1); // note: entering critical section here
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
mtx_unlock(m1);
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
// still inside of the critical section of the std::lock_guard
}
**Limitations**
* The ``trylock`` and ``timedlock`` versions of acquiring locks are currently assumed to always succeed.
This can lead to false positives.
.. code-block:: c
void trylock_example(pthread_mutex_t *m) {
if (pthread_mutex_trylock(m) == 0) { // assume trylock always succeeds
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
pthread_mutex_unlock(m);
} else {
sleep(10); // false positive: Incorrect warning about blocking function inside critical section.
}
}
.. _alpha-unix-Chroot:
Expand Down
10 changes: 7 additions & 3 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -855,10 +855,14 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) {
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier()));
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier()));
} else if (QualifiedTemplateName *QTN =
Template.getAsQualifiedTemplateName()) {
if (QTN->getQualifier()) {
TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier()));
}
}

return true;
}
Expand Down
23 changes: 14 additions & 9 deletions clang/include/clang/AST/TemplateName.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ class TemplateName {
/// unexpanded parameter pack (for C++0x variadic templates).
bool containsUnexpandedParameterPack() const;

enum class Qualified { None, AsWritten, Fully };
enum class Qualified { None, AsWritten };
/// Print the template name.
///
/// \param OS the output stream to which the template name will be
Expand Down Expand Up @@ -360,6 +360,10 @@ class TemplateName {
static TemplateName getFromVoidPointer(void *Ptr) {
return TemplateName(Ptr);
}

/// Structural equality.
bool operator==(TemplateName Other) const { return Storage == Other.Storage; }
bool operator!=(TemplateName Other) const { return !operator==(Other); }
};

/// Insertion operator for diagnostics. This allows sending TemplateName's
Expand Down Expand Up @@ -417,17 +421,18 @@ inline TemplateName TemplateName::getUnderlying() const {
return *this;
}

/// Represents a template name that was expressed as a
/// qualified name.
/// Represents a template name as written in source code.
///
/// This kind of template name refers to a template name that was
/// This kind of template name may refer to a template name that was
/// preceded by a nested name specifier, e.g., \c std::vector. Here,
/// the nested name specifier is "std::" and the template name is the
/// declaration for "vector". The QualifiedTemplateName class is only
/// used to provide "sugar" for template names that were expressed
/// with a qualified name, and has no semantic meaning. In this
/// manner, it is to TemplateName what ElaboratedType is to Type,
/// providing extra syntactic sugar for downstream clients.
/// declaration for "vector". It may also have been written with the
/// 'template' keyword. The QualifiedTemplateName class is only
/// used to provide "sugar" for template names, so that they can
/// be differentiated from canonical template names. and has no
/// semantic meaning. In this manner, it is to TemplateName what
/// ElaboratedType is to Type, providing extra syntactic sugar
/// for downstream clients.
class QualifiedTemplateName : public llvm::FoldingSetNode {
friend class ASTContext;

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ class TextNodeDumper
void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK);
void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS);
void dumpConceptReference(const ConceptReference *R);
void dumpTemplateArgument(const TemplateArgument &TA);
void dumpBareTemplateName(TemplateName TN);
void dumpTemplateName(TemplateName TN, StringRef Label = {});

void dumpDeclRef(const Decl *D, StringRef Label = {});

Expand Down
45 changes: 33 additions & 12 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1060,18 +1060,10 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
.Case("ShaderModel", "shadermodel")
.Default(Platform);
}
static llvm::StringRef getPrettyEnviromentName(llvm::StringRef Environment) {
return llvm::StringSwitch<llvm::StringRef>(Environment)
.Case("pixel", "pixel shader")
.Case("vertex", "vertex shader")
.Case("geometry", "geometry shader")
.Case("hull", "hull shader")
.Case("domain", "domain shader")
.Case("compute", "compute shader")
.Case("mesh", "mesh shader")
.Case("amplification", "amplification shader")
.Case("library", "shader library")
.Default(Environment);
static llvm::StringRef getPrettyEnviromentName(llvm::Triple::EnvironmentType EnvironmentType) {
if (EnvironmentType >= llvm::Triple::Pixel && EnvironmentType <= llvm::Triple::Amplification)
return llvm::Triple::getEnvironmentTypeName(EnvironmentType);
return "";
}
static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) {
return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment)
Expand All @@ -1081,6 +1073,12 @@ static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environm
.Case("hull", llvm::Triple::Hull)
.Case("domain", llvm::Triple::Domain)
.Case("compute", llvm::Triple::Compute)
.Case("raygeneration", llvm::Triple::RayGeneration)
.Case("intersection", llvm::Triple::Intersection)
.Case("anyhit", llvm::Triple::AnyHit)
.Case("closesthit", llvm::Triple::ClosestHit)
.Case("miss", llvm::Triple::Miss)
.Case("callable", llvm::Triple::Callable)
.Case("mesh", llvm::Triple::Mesh)
.Case("amplification", llvm::Triple::Amplification)
.Case("library", llvm::Triple::Library)
Expand Down Expand Up @@ -4480,6 +4478,29 @@ def HLSLShader : InheritableAttr {
"Miss", "Callable", "Mesh", "Amplification"]>
];
let Documentation = [HLSLSV_ShaderTypeAttrDocs];
let AdditionalMembers =
[{
static const unsigned ShaderTypeMaxValue = (unsigned)HLSLShaderAttr::Amplification;

static llvm::Triple::EnvironmentType getTypeAsEnvironment(HLSLShaderAttr::ShaderType ShaderType) {
switch (ShaderType) {
case HLSLShaderAttr::Pixel: return llvm::Triple::Pixel;
case HLSLShaderAttr::Vertex: return llvm::Triple::Vertex;
case HLSLShaderAttr::Geometry: return llvm::Triple::Geometry;
case HLSLShaderAttr::Hull: return llvm::Triple::Hull;
case HLSLShaderAttr::Domain: return llvm::Triple::Domain;
case HLSLShaderAttr::Compute: return llvm::Triple::Compute;
case HLSLShaderAttr::RayGeneration: return llvm::Triple::RayGeneration;
case HLSLShaderAttr::Intersection: return llvm::Triple::Intersection;
case HLSLShaderAttr::AnyHit: return llvm::Triple::AnyHit;
case HLSLShaderAttr::ClosestHit: return llvm::Triple::ClosestHit;
case HLSLShaderAttr::Miss: return llvm::Triple::Miss;
case HLSLShaderAttr::Callable: return llvm::Triple::Callable;
case HLSLShaderAttr::Mesh: return llvm::Triple::Mesh;
case HLSLShaderAttr::Amplification: return llvm::Triple::Amplification;
}
}
}];
}

def HLSLResource : InheritableAttr {
Expand Down
8 changes: 0 additions & 8 deletions clang/include/clang/Basic/CustomizableOptional.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,6 @@ template <typename T> class CustomizableOptional {
template <typename U> T value_or(U &&alt) && {
return has_value() ? std::move(operator*()) : std::forward<U>(alt);
}

// Allow conversion to std::optional<T>.
explicit operator std::optional<T> &() const & {
return *this ? **this : std::optional<T>();
}
explicit operator std::optional<T> &&() const && {
return *this ? std::move(**this) : std::optional<T>();
}
};

template <typename T>
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DebugOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ BENIGN_DEBUGOPT(NoInlineLineTables, 1, 0) ///< Whether debug info should contain
///< inline line tables.

DEBUGOPT(DebugStrictDwarf, 1, 1) ///< Whether or not to use strict DWARF info.
DEBUGOPT(DebugOmitUnreferencedMethods, 1, 0) ///< Omit unreferenced member
///< functions in type debug info.

/// Control the Assignment Tracking debug info feature.
BENIGN_ENUM_DEBUGOPT(AssignmentTrackingMode, AssignmentTrackingOpts, 2,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,9 @@ def HLSLMixPackOffset : DiagGroup<"mix-packoffset">;
// Warnings for DXIL validation
def DXILValidation : DiagGroup<"dxil-validation">;

// Warning for HLSL API availability
def HLSLAvailability : DiagGroup<"hlsl-availability">;

// Warnings and notes related to const_var_decl_type attribute checks
def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,10 @@ def err_requires_expr_in_simple_requirement : Error<
"requires expression in requirement body; did "
"you intend to place it in a nested requirement? (add another 'requires' "
"before the expression)">;
def missing_template_arg_list_after_template_kw : Extension<
"a template argument list is expected after a name prefixed by the template "
"keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>,
DefaultError;

def err_missing_dependent_template_keyword : Error<
"use 'template' keyword to treat '%0' as a dependent template name">;
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12239,6 +12239,13 @@ def err_hlsl_param_qualifier_mismatch :
def warn_hlsl_impcast_vector_truncation : Warning<
"implicit conversion truncates vector: %0 to %1">, InGroup<Conversion>;

def warn_hlsl_availability : Warning<
"%0 is only available %select{|in %4 environment }3on %1 %2 or newer">,
InGroup<HLSLAvailability>, DefaultError;
def warn_hlsl_availability_unavailable :
Warning<err_unavailable.Summary>,
InGroup<HLSLAvailability>, DefaultError;

// Layout randomization diagnostics.
def err_non_designated_init_used : Error<
"a randomized struct can only be initialized with a designated initializer">;
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Basic/arm_sme.td
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,25 @@ let TargetGuard = "sme" in {
[IsOverloadNone, IsStreamingCompatible, IsOutZA]>;
}

let TargetGuard = "sme2p1" in {
def SVZERO_ZA64_VG1x2 : SInst<"svzero_za64_vg1x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x2",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
def SVZERO_ZA64_VG1x4 : SInst<"svzero_za64_vg1x4", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x4",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
def SVZERO_ZA64_VG2x1 : SInst<"svzero_za64_vg2x1", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg2x1",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
def SVZERO_ZA64_VG2x2 : SInst<"svzero_za64_vg2x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg2x2",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
def SVZERO_ZA64_VG2x4 : SInst<"svzero_za64_vg2x4", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg2x4",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
def SVZERO_ZA64_VG4x1 : SInst<"svzero_za64_vg4x1", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg4x1",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
def SVZERO_ZA64_VG4x2 : SInst<"svzero_za64_vg4x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg4x2",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
def SVZERO_ZA64_VG4x4 : SInst<"svzero_za64_vg4x4", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg4x4",
[IsOverloadNone, IsStreaming, IsInOutZA]>;
}

////////////////////////////////////////////////////////////////////////////////
// SME - Counting elements in a streaming vector

Expand Down
16 changes: 16 additions & 0 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -2151,6 +2151,11 @@ let TargetGuard = "sme2" in {
def SVFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "hfd", MergeNone, "aarch64_sve_fclamp_single_x4", [IsStreaming], []>;
}

let TargetGuard = "sme2,b16b16"in {
def SVBFCLAMP_X2 : SInst<"svclamp[_single_{d}_x2]", "22dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x2", [IsStreaming], []>;
def SVBFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x4", [IsStreaming], []>;
}

let TargetGuard = "sme2" in {
// == ADD (vectors) ==
def SVADD_SINGLE_X2 : SInst<"svadd[_single_{d}_x2]", "22d", "cUcsUsiUilUl", MergeNone, "aarch64_sve_add_single_x2", [IsStreaming], []>;
Expand Down Expand Up @@ -2265,6 +2270,10 @@ let TargetGuard = "sme2" in {
def SVCVT_S32_F32_X4 : SInst<"svcvt_{d}[_f32_x4]", "4.d4.M", "i", MergeNone, "aarch64_sve_fcvtzs_x4", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>;
}

let TargetGuard = "sme-f16f16" in {
def SVCVT_F32_X2 : SInst<"svcvt_{d}[_f16_x2]", "2h", "f", MergeNone, "aarch64_sve_fcvt_widen_x2", [ IsStreaming],[]>;
}

//
// Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16
//
Expand All @@ -2273,6 +2282,13 @@ let TargetGuard = "sme2" in {
def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>;
}

//
//Multi-vector floating-point convert from half-precision to deinterleaved single-precision.
//
let TargetGuard = "sme-f16f16" in {
def SVCVTL_F32_X2 : SInst<"svcvtl_f32[_f16_x2]", "2h", "f", MergeNone, "aarch64_sve_fcvtl_widen_x2", [ IsStreaming],[]>;
}

//
// Multi-vector saturating extract narrow
//
Expand Down
14 changes: 9 additions & 5 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4345,6 +4345,10 @@ defm strict_dwarf : BoolOption<"g", "strict-dwarf",
"the specified version, avoiding features from later versions.">,
NegFlag<SetFalse>, BothFlags<[], [ClangOption, CLOption, DXCOption]>>,
Group<g_flags_Group>;
defm omit_unreferenced_methods : BoolGOption<"omit-unreferenced-methods",
CodeGenOpts<"DebugOmitUnreferencedMethods">, DefaultFalse,
NegFlag<SetFalse>,
PosFlag<SetTrue, [], [CC1Option]>, BothFlags<[], [ClangOption, CLOption, DXCOption]>>;
defm column_info : BoolOption<"g", "column-info",
CodeGenOpts<"DebugColumnInfo">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option]>,
Expand Down Expand Up @@ -6277,11 +6281,11 @@ def mapx_features_EQ : CommaJoined<["-"], "mapx-features=">, Group<m_x86_Feature
HelpText<"Enable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf">;
def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group<m_x86_Features_Group>,
HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf">;
// Features egpr, push2pop2, ppx and ndd are validated with llvm-test-suite && cpu2017 on Intel SDE.
// For stability, we turn on these features only for -mapxf. After a feature pass the validation,
// we will add it to -mapxf.
def mapxf : Flag<["-"], "mapxf">, Alias<mapx_features_EQ>, AliasArgs<["egpr","push2pop2","ppx", "ndd"]>;
def mno_apxf : Flag<["-"], "mno-apxf">, Alias<mno_apx_features_EQ>, AliasArgs<["egpr","push2pop2","ppx","ndd"]>;
// For stability, we only add a feature to -mapxf after it passes the validation of llvm-test-suite && cpu2017 on Intel SDE.
def mapxf : Flag<["-"], "mapxf">, Alias<mapx_features_EQ>, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>;
def mno_apxf : Flag<["-"], "mno-apxf">, Alias<mno_apx_features_EQ>, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>;
def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group<m_Group>,
HelpText<"Enable use of GPR32 in inline assembly for APX">;
} // let Flags = [TargetSpecific]

// VE feature flags
Expand Down
65 changes: 38 additions & 27 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
Expand Down Expand Up @@ -127,7 +128,7 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
protected:
/// Collect API information for the enum constants and associate with the
/// parent enum.
void recordEnumConstants(EnumRecord *EnumRecord,
void recordEnumConstants(SymbolReference Container,
const EnumDecl::enumerator_range Constants);

/// Collect API information for the Objective-C methods and associate with the
Expand Down Expand Up @@ -248,12 +249,8 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
clang::index::generateUSRForDecl(Tag, TagUSR);
if (auto *Record = llvm::dyn_cast_if_present<TagRecord>(
API.findRecordForUSR(TagUSR))) {
if (Record->IsEmbeddedInVarDeclarator) {
if (Record->IsEmbeddedInVarDeclarator)
NewRecordContext->stealRecordChain(*Record);
auto *NewRecord = cast<APIRecord>(NewRecordContext);
if (NewRecord->Comment.empty())
NewRecord->Comment = Record->Comment;
}
}
}
};
Expand Down Expand Up @@ -394,17 +391,6 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
return true;

SmallString<128> QualifiedNameBuffer;
// Collect symbol information.
StringRef Name = Decl->getName();
if (Name.empty())
Name = getTypedefName(Decl);
if (Name.empty()) {
llvm::raw_svector_ostream OS(QualifiedNameBuffer);
Decl->printQualifiedName(OS);
Name = QualifiedNameBuffer;
}

SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
PresumedLoc Loc =
Expand All @@ -420,13 +406,29 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
auto *ER = API.createRecord<EnumRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));

// Collect symbol information.
SymbolReference ParentContainer;

if (Decl->hasNameForLinkage()) {
StringRef Name = Decl->getName();
if (Name.empty())
Name = getTypedefName(Decl);

auto *ER = API.createRecord<EnumRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, isInSystemHeader(Decl), false);
ParentContainer = SymbolReference(ER);
} else {
// If this an anonymous enum then the parent scope of the constants is the
// top level namespace.
ParentContainer = {};
}

// Now collect information about the enumerators in this enum.
getDerivedExtractAPIVisitor().recordEnumConstants(ER, Decl->enumerators());
getDerivedExtractAPIVisitor().recordEnumConstants(ParentContainer,
Decl->enumerators());

return true;
}
Expand Down Expand Up @@ -1197,7 +1199,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl(
/// parent enum.
template <typename Derived>
void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
SymbolReference Container, const EnumDecl::enumerator_range Constants) {
for (const auto *Constant : Constants) {
// Collect symbol information.
StringRef Name = Constant->getName();
Expand All @@ -1218,9 +1220,8 @@ void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
DeclarationFragmentsBuilder::getSubHeading(Constant);

API.createRecord<EnumConstantRecord>(
USR, Name, createHierarchyInformationForDecl(*Constant), Loc,
AvailabilityInfo::createFromDecl(Constant), Comment, Declaration,
SubHeading, isInSystemHeader(Constant));
USR, Name, Container, Loc, AvailabilityInfo::createFromDecl(Constant),
Comment, Declaration, SubHeading, isInSystemHeader(Constant));
}
}

Expand Down Expand Up @@ -1469,7 +1470,17 @@ class ExtractAPIVisitor

bool shouldDeclBeIncluded(const Decl *D) const { return true; }
const RawComment *fetchRawCommentForDecl(const Decl *D) const {
return this->Context.getRawCommentForDeclNoCache(D);
if (const auto *Comment = this->Context.getRawCommentForDeclNoCache(D))
return Comment;

if (const auto *Declarator = dyn_cast<DeclaratorDecl>(D)) {
const auto *TagTypeDecl = Declarator->getType()->getAsTagDecl();
if (TagTypeDecl && TagTypeDecl->isEmbeddedInDeclarator() &&
TagTypeDecl->isCompleteDefinition())
return this->Context.getRawCommentForDeclNoCache(TagTypeDecl);
}

return nullptr;
}
};

Expand Down
36 changes: 36 additions & 0 deletions clang/include/clang/Sema/Attr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----- Attr.h --- Helper functions for attribute handling in Sema -----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides helpers for Sema functions that handle attributes.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_ATTR_H
#define LLVM_CLANG_SEMA_ATTR_H

#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Support/Casting.h"

namespace clang {

/// isFuncOrMethodForAttrSubject - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method.
inline bool isFuncOrMethodForAttrSubject(const Decl *D) {
return (D->getFunctionType() != nullptr) || llvm::isa<ObjCMethodDecl>(D);
}

/// Return true if the given decl has function type (function or
/// function-typed variable) or an Objective-C method or a block.
inline bool isFunctionOrMethodOrBlockForAttrSubject(const Decl *D) {
return isFuncOrMethodForAttrSubject(D) || llvm::isa<BlockDecl>(D);
}

} // namespace clang
#endif // LLVM_CLANG_SEMA_ATTR_H
221 changes: 123 additions & 98 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/TinyPtrVector.h"
#include <deque>
#include <memory>
Expand Down Expand Up @@ -168,15 +169,25 @@ class Preprocessor;
class PseudoDestructorTypeStorage;
class PseudoObjectExpr;
class QualType;
class SemaAMDGPU;
class SemaARM;
class SemaBPF;
class SemaCodeCompletion;
class SemaCUDA;
class SemaHLSL;
class SemaHexagon;
class SemaLoongArch;
class SemaMIPS;
class SemaNVPTX;
class SemaObjC;
class SemaOpenACC;
class SemaOpenMP;
class SemaPPC;
class SemaPseudoObject;
class SemaRISCV;
class SemaSYCL;
class SemaSystemZ;
class SemaWasm;
class SemaX86;
class StandardConversionSequence;
class Stmt;
Expand Down Expand Up @@ -884,9 +895,6 @@ class Sema final : public SemaBase {
void disable() { Active = false; }
};

/// Build a partial diagnostic.
PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h

sema::FunctionScopeInfo *getCurFunction() const {
return FunctionScopes.empty() ? nullptr : FunctionScopes.back();
}
Expand Down Expand Up @@ -993,6 +1001,21 @@ class Sema final : public SemaBase {
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;

SemaAMDGPU &AMDGPU() {
assert(AMDGPUPtr);
return *AMDGPUPtr;
}

SemaARM &ARM() {
assert(ARMPtr);
return *ARMPtr;
}

SemaBPF &BPF() {
assert(BPFPtr);
return *BPFPtr;
}

SemaCodeCompletion &CodeCompletion() {
assert(CodeCompletionPtr);
return *CodeCompletionPtr;
Expand All @@ -1008,6 +1031,26 @@ class Sema final : public SemaBase {
return *HLSLPtr;
}

SemaHexagon &Hexagon() {
assert(HexagonPtr);
return *HexagonPtr;
}

SemaLoongArch &LoongArch() {
assert(LoongArchPtr);
return *LoongArchPtr;
}

SemaMIPS &MIPS() {
assert(MIPSPtr);
return *MIPSPtr;
}

SemaNVPTX &NVPTX() {
assert(NVPTXPtr);
return *NVPTXPtr;
}

SemaObjC &ObjC() {
assert(ObjCPtr);
return *ObjCPtr;
Expand All @@ -1023,6 +1066,11 @@ class Sema final : public SemaBase {
return *OpenMPPtr;
}

SemaPPC &PPC() {
assert(PPCPtr);
return *PPCPtr;
}

SemaPseudoObject &PseudoObject() {
assert(PseudoObjectPtr);
return *PseudoObjectPtr;
Expand All @@ -1038,6 +1086,16 @@ class Sema final : public SemaBase {
return *SYCLPtr;
}

SemaSystemZ &SystemZ() {
assert(SystemZPtr);
return *SystemZPtr;
}

SemaWasm &Wasm() {
assert(WasmPtr);
return *WasmPtr;
}

SemaX86 &X86() {
assert(X86Ptr);
return *X86Ptr;
Expand Down Expand Up @@ -1073,15 +1131,25 @@ class Sema final : public SemaBase {

mutable IdentifierInfo *Ident_super;

std::unique_ptr<SemaAMDGPU> AMDGPUPtr;
std::unique_ptr<SemaARM> ARMPtr;
std::unique_ptr<SemaBPF> BPFPtr;
std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
std::unique_ptr<SemaCUDA> CUDAPtr;
std::unique_ptr<SemaHLSL> HLSLPtr;
std::unique_ptr<SemaHexagon> HexagonPtr;
std::unique_ptr<SemaLoongArch> LoongArchPtr;
std::unique_ptr<SemaMIPS> MIPSPtr;
std::unique_ptr<SemaNVPTX> NVPTXPtr;
std::unique_ptr<SemaObjC> ObjCPtr;
std::unique_ptr<SemaOpenACC> OpenACCPtr;
std::unique_ptr<SemaOpenMP> OpenMPPtr;
std::unique_ptr<SemaPPC> PPCPtr;
std::unique_ptr<SemaPseudoObject> PseudoObjectPtr;
std::unique_ptr<SemaRISCV> RISCVPtr;
std::unique_ptr<SemaSYCL> SYCLPtr;
std::unique_ptr<SemaSystemZ> SystemZPtr;
std::unique_ptr<SemaWasm> WasmPtr;
std::unique_ptr<SemaX86> X86Ptr;

///@}
Expand Down Expand Up @@ -2074,6 +2142,8 @@ class Sema final : public SemaBase {
unsigned MaxArgCount);
bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount);

bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum);

private:
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ArraySubscriptExpr *ASE = nullptr,
Expand All @@ -2087,8 +2157,6 @@ class Sema final : public SemaBase {
ArrayRef<const Expr *> Args,
const FunctionProtoType *Proto, SourceLocation Loc);

void checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg);

void CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
StringRef ParamName, QualType ArgTy, QualType ParamTy);

Expand All @@ -2102,54 +2170,13 @@ class Sema final : public SemaBase {

void checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall);

bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
unsigned MaxWidth);
bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool ParseSVEImmChecks(CallExpr *TheCall,
SmallVector<std::tuple<int, int, int>, 3> &ImmChecks);
bool CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg,
bool WantCDE);
bool CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);

bool CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall);
bool CheckMipsBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall);
bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID, CallExpr *TheCall);
bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID,
CallExpr *TheCall);
bool CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);

bool BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall);
bool BuiltinVAStartARMMicrosoft(CallExpr *Call);
bool BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID);
bool BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
unsigned BuiltinID);
bool BuiltinComplex(CallExpr *TheCall);
bool BuiltinVSX(CallExpr *TheCall);
bool BuiltinOSLogFormat(CallExpr *TheCall);
bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum);

bool BuiltinPrefetch(CallExpr *TheCall);
bool BuiltinAllocaWithAlign(CallExpr *TheCall);
Expand All @@ -2162,13 +2189,6 @@ class Sema final : public SemaBase {
ExprResult BuiltinNontemporalOverloaded(ExprResult TheCallResult);
ExprResult AtomicOpsOverloaded(ExprResult TheCallResult,
AtomicExpr::AtomicOp Op);
bool BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum,
unsigned ExpectedFieldNum, bool AllowName);
bool BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall);
bool BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID,
const char *TypeDesc);

bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc);

bool BuiltinElementwiseMath(CallExpr *TheCall);
bool BuiltinElementwiseTernaryMath(CallExpr *TheCall,
Expand All @@ -2185,16 +2205,6 @@ class Sema final : public SemaBase {
ExprResult BuiltinMatrixColumnMajorStore(CallExpr *TheCall,
ExprResult CallResult);

// WebAssembly builtin handling.
bool BuiltinWasmRefNullExtern(CallExpr *TheCall);
bool BuiltinWasmRefNullFunc(CallExpr *TheCall);
bool BuiltinWasmTableGet(CallExpr *TheCall);
bool BuiltinWasmTableSet(CallExpr *TheCall);
bool BuiltinWasmTableSize(CallExpr *TheCall);
bool BuiltinWasmTableGrow(CallExpr *TheCall);
bool BuiltinWasmTableFill(CallExpr *TheCall);
bool BuiltinWasmTableCopy(CallExpr *TheCall);

bool CheckFormatArguments(const FormatAttr *Format,
ArrayRef<const Expr *> Args, bool IsCXXMember,
VariadicCallType CallType, SourceLocation Loc,
Expand Down Expand Up @@ -3548,6 +3558,53 @@ class Sema final : public SemaBase {
BuiltinFunction
};

/// A helper function to provide Attribute Location for the Attr types
/// AND the ParsedAttr.
template <typename AttrInfo>
static std::enable_if_t<std::is_base_of_v<Attr, AttrInfo>, SourceLocation>
getAttrLoc(const AttrInfo &AL) {
return AL.getLocation();
}
SourceLocation getAttrLoc(const ParsedAttr &AL);

/// If Expr is a valid integer constant, get the value of the integer
/// expression and return success or failure. May output an error.
///
/// Negative argument is implicitly converted to unsigned, unless
/// \p StrictlyUnsigned is true.
template <typename AttrInfo>
bool checkUInt32Argument(const AttrInfo &AI, const Expr *Expr, uint32_t &Val,
unsigned Idx = UINT_MAX,
bool StrictlyUnsigned = false) {
std::optional<llvm::APSInt> I = llvm::APSInt(32);
if (Expr->isTypeDependent() ||
!(I = Expr->getIntegerConstantExpr(Context))) {
if (Idx != UINT_MAX)
Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
<< &AI << Idx << AANT_ArgumentIntegerConstant
<< Expr->getSourceRange();
else
Diag(getAttrLoc(AI), diag::err_attribute_argument_type)
<< &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
return false;
}

if (!I->isIntN(32)) {
Diag(Expr->getExprLoc(), diag::err_ice_too_large)
<< toString(*I, 10, false) << 32 << /* Unsigned */ 1;
return false;
}

if (StrictlyUnsigned && I->isSigned() && I->isNegative()) {
Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer)
<< &AI << /*non-negative*/ 1;
return false;
}

Val = (uint32_t)I->getZExtValue();
return true;
}

/// WeakTopLevelDecl - Translation-unit scoped declarations generated by
/// \#pragma weak during processing of other Decls.
/// I couldn't figure out a clean way to generate these in-line, so
Expand Down Expand Up @@ -3705,41 +3762,6 @@ class Sema final : public SemaBase {

BTFDeclTagAttr *mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL);

WebAssemblyImportNameAttr *
mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);
WebAssemblyImportModuleAttr *
mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL);

/// Create an AMDGPUWavesPerEUAttr attribute.
AMDGPUFlatWorkGroupSizeAttr *
CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, Expr *Min,
Expr *Max);

/// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size
/// attribute to a particular declaration.
void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *Min, Expr *Max);

/// Create an AMDGPUWavesPerEUAttr attribute.
AMDGPUWavesPerEUAttr *
CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, Expr *Min,
Expr *Max);

/// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a
/// particular declaration.
void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *Min, Expr *Max);

/// Create an AMDGPUMaxNumWorkGroupsAttr attribute.
AMDGPUMaxNumWorkGroupsAttr *
CreateAMDGPUMaxNumWorkGroupsAttr(const AttributeCommonInfo &CI, Expr *XExpr,
Expr *YExpr, Expr *ZExpr);

/// addAMDGPUMaxNumWorkGroupsAttr - Adds an amdgpu_max_num_work_groups
/// attribute to a particular declaration.
void addAMDGPUMaxNumWorkGroupsAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *XExpr, Expr *YExpr, Expr *ZExpr);

DLLImportAttr *mergeDLLImportAttr(Decl *D, const AttributeCommonInfo &CI);
DLLExportAttr *mergeDLLExportAttr(Decl *D, const AttributeCommonInfo &CI);
MSInheritanceAttr *mergeMSInheritanceAttr(Decl *D,
Expand Down Expand Up @@ -8988,6 +9010,9 @@ class Sema final : public SemaBase {
const TemplateArgumentListInfo *TemplateArgs);

void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
void diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
bool TemplateKeyword, TemplateDecl *TD,
SourceLocation Loc);

ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc, LookupResult &R,
Expand Down
68 changes: 68 additions & 0 deletions clang/include/clang/Sema/SemaAMDGPU.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===----- SemaAMDGPU.h --- AMDGPU target-specific routines ---*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to AMDGPU.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAAMDGPU_H
#define LLVM_CLANG_SEMA_SEMAAMDGPU_H

#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaAMDGPU : public SemaBase {
public:
SemaAMDGPU(Sema &S);

bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

/// Create an AMDGPUWavesPerEUAttr attribute.
AMDGPUFlatWorkGroupSizeAttr *
CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, Expr *Min,
Expr *Max);

/// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size
/// attribute to a particular declaration.
void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *Min, Expr *Max);

/// Create an AMDGPUWavesPerEUAttr attribute.
AMDGPUWavesPerEUAttr *
CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, Expr *Min,
Expr *Max);

/// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a
/// particular declaration.
void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *Min, Expr *Max);

/// Create an AMDGPUMaxNumWorkGroupsAttr attribute.
AMDGPUMaxNumWorkGroupsAttr *
CreateAMDGPUMaxNumWorkGroupsAttr(const AttributeCommonInfo &CI, Expr *XExpr,
Expr *YExpr, Expr *ZExpr);

/// addAMDGPUMaxNumWorkGroupsAttr - Adds an amdgpu_max_num_work_groups
/// attribute to a particular declaration.
void addAMDGPUMaxNumWorkGroupsAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *XExpr, Expr *YExpr, Expr *ZExpr);

void handleAMDGPUWavesPerEUAttr(Decl *D, const ParsedAttr &AL);
void handleAMDGPUNumSGPRAttr(Decl *D, const ParsedAttr &AL);
void handleAMDGPUNumVGPRAttr(Decl *D, const ParsedAttr &AL);
void handleAMDGPUMaxNumWorkGroupsAttr(Decl *D, const ParsedAttr &AL);
void handleAMDGPUFlatWorkGroupSizeAttr(Decl *D, const ParsedAttr &AL);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAAMDGPU_H
63 changes: 63 additions & 0 deletions clang/include/clang/Sema/SemaARM.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===----- SemaARM.h ------- ARM target-specific routines -----*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to ARM.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAARM_H
#define LLVM_CLANG_SEMA_SEMAARM_H

#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"
#include "llvm/ADT/SmallVector.h"
#include <tuple>

namespace clang {

class SemaARM : public SemaBase {
public:
SemaARM(Sema &S);

enum ArmStreamingType {
ArmNonStreaming,
ArmStreaming,
ArmStreamingCompatible,
ArmStreamingOrSVE2p1
};

bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
unsigned MaxWidth);
bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool
ParseSVEImmChecks(CallExpr *TheCall,
llvm::SmallVector<std::tuple<int, int, int>, 3> &ImmChecks);
bool CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg,
bool WantCDE);
bool CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);

bool CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum,
unsigned ExpectedFieldNum, bool AllowName);
bool BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall);
};

SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD);

} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAARM_H
28 changes: 28 additions & 0 deletions clang/include/clang/Sema/SemaBPF.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----- SemaBPF.h ------- BPF target-specific routines -----*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to BPF.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMABPF_H
#define LLVM_CLANG_SEMA_SEMABPF_H

#include "clang/AST/Expr.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaBPF : public SemaBase {
public:
SemaBPF(Sema &S);

bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMABPF_H
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/SemaBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ class SemaBase {
/// Emit a partial diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD,
bool DeferHint = false);

/// Build a partial diagnostic.
PartialDiagnostic PDiag(unsigned DiagID = 0);
};

} // namespace clang
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class SemaHLSL : public SemaBase {
void DiagnoseAttrStageMismatch(
const Attr *A, HLSLShaderAttr::ShaderType Stage,
std::initializer_list<HLSLShaderAttr::ShaderType> AllowedStages);
void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU);
};

} // namespace clang
Expand Down
29 changes: 29 additions & 0 deletions clang/include/clang/Sema/SemaHexagon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===----- SemaHexagon.h -- Hexagon target-specific routines --*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to Hexagon.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAHEXAGON_H
#define LLVM_CLANG_SEMA_SEMAHEXAGON_H

#include "clang/AST/Expr.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaHexagon : public SemaBase {
public:
SemaHexagon(Sema &S);

bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAHEXAGON_H
4 changes: 0 additions & 4 deletions clang/include/clang/Sema/SemaInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@

namespace clang {

inline PartialDiagnostic Sema::PDiag(unsigned DiagID) {
return PartialDiagnostic(DiagID, Context.getDiagAllocator());
}

inline bool
FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo &FTI) {
return FTI.NumParams == 1 && !FTI.isVariadic &&
Expand Down
30 changes: 30 additions & 0 deletions clang/include/clang/Sema/SemaLoongArch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===-- SemaLoongArch.h -- LoongArch target-specific routines --*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to LoongArch.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMALOONGARCH_H
#define LLVM_CLANG_SEMA_SEMALOONGARCH_H

#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaLoongArch : public SemaBase {
public:
SemaLoongArch(Sema &S);

bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID, CallExpr *TheCall);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMALOONGARCH_H
33 changes: 33 additions & 0 deletions clang/include/clang/Sema/SemaMIPS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===----- SemaMIPS.h ------ MIPS target-specific routines ----*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to MIPS.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAMIPS_H
#define LLVM_CLANG_SEMA_SEMAMIPS_H

#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaMIPS : public SemaBase {
public:
SemaMIPS(Sema &S);

bool CheckMipsBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAMIPS_H
30 changes: 30 additions & 0 deletions clang/include/clang/Sema/SemaNVPTX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===----- SemaNVPTX.h ----- NVPTX target-specific routines ---*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to NVPTX.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMANVPTX_H
#define LLVM_CLANG_SEMA_SEMANVPTX_H

#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaNVPTX : public SemaBase {
public:
SemaNVPTX(Sema &S);

bool CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMANVPTX_H
58 changes: 58 additions & 0 deletions clang/include/clang/Sema/SemaPPC.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===----- SemaPPC.h ------- PPC target-specific routines -----*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to PowerPC.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAPPC_H
#define LLVM_CLANG_SEMA_SEMAPPC_H

#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaPPC : public SemaBase {
public:
SemaPPC(Sema &S);

bool CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
// 16 byte ByVal alignment not due to a vector member is not honoured by XL
// on AIX. Emit a warning here that users are generating binary incompatible
// code to be safe.
// Here we try to get information about the alignment of the struct member
// from the struct passed to the caller function. We only warn when the struct
// is passed byval, hence the series of checks and early returns if we are a
// not passing a struct byval.
void checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg);

/// BuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity.
/// Emit an error and return true on failure; return false on success.
/// TypeStr is a string containing the type descriptor of the value returned
/// by the builtin and the descriptors of the expected type of the arguments.
bool BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID,
const char *TypeDesc);

bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc);

// Customized Sema Checking for VSX builtins that have the following
// signature: vector [...] builtinName(vector [...], vector [...], const int);
// Which takes the same type of vectors (any legal vector type) for the first
// two arguments and takes compile time constant for the third argument.
// Example builtins are :
// vector double vec_xxpermdi(vector double, vector double, int);
// vector short vec_xxsldwi(vector short, vector short, int);
bool BuiltinVSX(CallExpr *TheCall);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAPPC_H
28 changes: 28 additions & 0 deletions clang/include/clang/Sema/SemaSystemZ.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----- SemaSystemZ.h -- SystemZ target-specific routines --*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to SystemZ.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMASYSTEMZ_H
#define LLVM_CLANG_SEMA_SEMASYSTEMZ_H

#include "clang/AST/Expr.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaSystemZ : public SemaBase {
public:
SemaSystemZ(Sema &S);

bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMASYSTEMZ_H
52 changes: 52 additions & 0 deletions clang/include/clang/Sema/SemaWasm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===----- SemaWasm.h ------ Wasm target-specific routines ----*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis functions specific to Wasm.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAWASM_H
#define LLVM_CLANG_SEMA_SEMAWASM_H

#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/SemaBase.h"

namespace clang {
class SemaWasm : public SemaBase {
public:
SemaWasm(Sema &S);

bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID,
CallExpr *TheCall);

bool BuiltinWasmRefNullExtern(CallExpr *TheCall);
bool BuiltinWasmRefNullFunc(CallExpr *TheCall);
bool BuiltinWasmTableGet(CallExpr *TheCall);
bool BuiltinWasmTableSet(CallExpr *TheCall);
bool BuiltinWasmTableSize(CallExpr *TheCall);
bool BuiltinWasmTableGrow(CallExpr *TheCall);
bool BuiltinWasmTableFill(CallExpr *TheCall);
bool BuiltinWasmTableCopy(CallExpr *TheCall);

WebAssemblyImportNameAttr *
mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);
WebAssemblyImportModuleAttr *
mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL);

void handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL);
void handleWebAssemblyImportModuleAttr(Decl *D, const ParsedAttr &AL);
void handleWebAssemblyImportNameAttr(Decl *D, const ParsedAttr &AL);
};
} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAWASM_H
18 changes: 7 additions & 11 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5006,9 +5006,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = QTN->getUnderlyingTemplate();

const auto *TD = Template.getAsTemplateDecl();
bool IsTypeAlias = TD && TD->isTypeAlias();
Expand Down Expand Up @@ -5044,10 +5041,6 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");

// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getUnderlyingTemplate());

// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
bool AnyNonCanonArgs = false;
Expand Down Expand Up @@ -5262,10 +5255,12 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
Arg = TemplateArgument(E);
} else {
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
TemplateName Name = getQualifiedTemplateName(
nullptr, /*TemplateKeyword=*/false, TemplateName(TTP));
if (TTP->isParameterPack())
Arg = TemplateArgument(TemplateName(TTP), std::optional<unsigned>());
Arg = TemplateArgument(Name, std::optional<unsigned>());
else
Arg = TemplateArgument(TemplateName(TTP));
Arg = TemplateArgument(Name);
}

if (Param->isTemplateParameterPack())
Expand Down Expand Up @@ -6799,7 +6794,7 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
// Using shadow declarations with the same target match.
if (const auto *USX = dyn_cast<UsingShadowDecl>(X)) {
const auto *USY = cast<UsingShadowDecl>(Y);
return USX->getTargetDecl() == USY->getTargetDecl();
return declaresSameEntity(USX->getTargetDecl(), USY->getTargetDecl());
}

// Using declarations with the same qualifier match. (We already know that
Expand Down Expand Up @@ -9304,7 +9299,8 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const {
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateName Template) const {
assert(NNS && "Missing nested-name-specifier in qualified template name");
assert(Template.getKind() == TemplateName::Template ||
Template.getKind() == TemplateName::UsingTemplate);

// FIXME: Canonicalization?
llvm::FoldingSetNodeID ID;
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2408,9 +2408,11 @@ Expr *VarDecl::getInit() {
return cast<Expr>(S);

auto *Eval = getEvaluatedStmt();
return cast<Expr>(Eval->Value.isOffset()
? Eval->Value.get(getASTContext().getExternalSource())
: Eval->Value.get(nullptr));

return cast_if_present<Expr>(
Eval->Value.isOffset()
? Eval->Value.get(getASTContext().getExternalSource())
: Eval->Value.get(nullptr));
}

Stmt **VarDecl::getInitAddress() {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,8 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
IdentifierInfo *IIEnv = A->getEnvironment();
StringRef TargetEnv =
Context.getTargetInfo().getTriple().getEnvironmentName();
StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(TargetEnv);
StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(
Context.getTargetInfo().getTriple().getEnvironment());
// Matching environment or no environment on attribute
if (!IIEnv || (!TargetEnv.empty() && IIEnv->getName() == TargetEnv)) {
if (Message) {
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,9 +627,10 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
TemplateParameterList *Params = getTemplateParameters();
SmallVector<TemplateArgument, 16> TemplateArgs;
Context.getInjectedTemplateArgs(Params, TemplateArgs);
CommonPtr->InjectedClassNameType
= Context.getTemplateSpecializationType(TemplateName(this),
TemplateArgs);
TemplateName Name = Context.getQualifiedTemplateName(
/*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this));
CommonPtr->InjectedClassNameType =
Context.getTemplateSpecializationType(Name, TemplateArgs);
return CommonPtr->InjectedClassNameType;
}

Expand Down
9 changes: 8 additions & 1 deletion clang/lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,17 @@ void ODRHash::AddTemplateName(TemplateName Name) {
case TemplateName::Template:
AddDecl(Name.getAsTemplateDecl());
break;
case TemplateName::QualifiedTemplate: {
QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
if (NestedNameSpecifier *NNS = QTN->getQualifier())
AddNestedNameSpecifier(NNS);
AddBoolean(QTN->hasTemplateKeyword());
AddTemplateName(QTN->getUnderlyingTemplate());
break;
}
// TODO: Support these cases.
case TemplateName::OverloadedTemplate:
case TemplateName::AssumedTemplate:
case TemplateName::QualifiedTemplate:
case TemplateName::DependentTemplate:
case TemplateName::SubstTemplateTemplateParm:
case TemplateName::SubstTemplateTemplateParmPack:
Expand Down
11 changes: 1 addition & 10 deletions clang/lib/AST/TemplateBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,16 +544,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
break;

case Template: {
TemplateName TN = getAsTemplate();
if (const auto *TD = TN.getAsTemplateDecl();
TD && TD->getDeclName().isEmpty()) {
assert(isa<TemplateTemplateParmDecl>(TD) &&
"Unexpected anonymous template");
const auto *TTP = cast<TemplateTemplateParmDecl>(TD);
Out << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex();
} else {
TN.print(Out, Policy, TemplateName::Qualified::Fully);
}
getAsTemplate().print(Out, Policy);
break;
}

Expand Down
78 changes: 44 additions & 34 deletions clang/lib/AST/TemplateName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ TemplateNameDependence TemplateName::getDependence() const {
auto D = TemplateNameDependence::None;
switch (getKind()) {
case TemplateName::NameKind::QualifiedTemplate:
D |= toTemplateNameDependence(
getAsQualifiedTemplateName()->getQualifier()->getDependence());
if (NestedNameSpecifier *NNS = getAsQualifiedTemplateName()->getQualifier())
D |= toTemplateNameDependence(NNS->getDependence());
break;
case TemplateName::NameKind::DependentTemplate:
D |= toTemplateNameDependence(
Expand Down Expand Up @@ -292,9 +292,16 @@ void TemplateName::Profile(llvm::FoldingSetNodeID &ID) {

void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
Qualified Qual) const {
auto Kind = getKind();
TemplateDecl *Template = nullptr;
if (Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
auto handleAnonymousTTP = [](TemplateDecl *TD, raw_ostream &OS) {
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(TD);
TTP && TTP->getIdentifier() == nullptr) {
OS << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex();
return true;
}
return false;
};
if (NameKind Kind = getKind();
Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
// After `namespace ns { using std::vector }`, what is the fully-qualified
// name of the UsingTemplateName `vector` within ns?
//
Expand All @@ -304,46 +311,49 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
// Similar to the UsingType behavior, using declarations are used to import
// names more often than to export them, thus using the original name is
// most useful in this case.
Template = getAsTemplateDecl();
}

if (Template)
if (Policy.CleanUglifiedParameters &&
isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier())
OS << Template->getIdentifier()->deuglifiedName();
else if (Qual == Qualified::Fully &&
getDependence() !=
TemplateNameDependenceScope::DependentInstantiation)
Template->printQualifiedName(OS, Policy);
else
OS << *Template;
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (Qual == Qualified::Fully &&
getDependence() !=
TemplateNameDependenceScope::DependentInstantiation) {
QTN->getUnderlyingTemplate().getAsTemplateDecl()->printQualifiedName(
OS, Policy);
TemplateDecl *Template = getAsTemplateDecl();
if (handleAnonymousTTP(Template, OS))
return;
}
if (Qual == Qualified::AsWritten)
QTN->getQualifier()->print(OS, Policy);
if (Qual == Qualified::None)
OS << *Template;
else
Template->printQualifiedName(OS, Policy);
} else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (NestedNameSpecifier *NNS = QTN->getQualifier();
Qual != Qualified::None && NNS)
NNS->print(OS, Policy);
if (QTN->hasTemplateKeyword())
OS << "template ";
OS << *QTN->getUnderlyingTemplate().getAsTemplateDecl();

TemplateName Underlying = QTN->getUnderlyingTemplate();
assert(Underlying.getKind() == TemplateName::Template ||
Underlying.getKind() == TemplateName::UsingTemplate);

TemplateDecl *UTD = Underlying.getAsTemplateDecl();

if (handleAnonymousTTP(UTD, OS))
return;

if (IdentifierInfo *II = UTD->getIdentifier();
Policy.CleanUglifiedParameters && II &&
isa<TemplateTemplateParmDecl>(UTD))
OS << II->deuglifiedName();
else
OS << *UTD;
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
if (Qual == Qualified::AsWritten && DTN->getQualifier())
DTN->getQualifier()->print(OS, Policy);
if (NestedNameSpecifier *NNS = DTN->getQualifier())
NNS->print(OS, Policy);
OS << "template ";

if (DTN->isIdentifier())
OS << DTN->getIdentifier()->getName();
else
OS << "operator " << getOperatorSpelling(DTN->getOperator());
} else if (SubstTemplateTemplateParmStorage *subst
= getAsSubstTemplateTemplateParm()) {
} else if (SubstTemplateTemplateParmStorage *subst =
getAsSubstTemplateTemplateParm()) {
subst->getReplacement().print(OS, Policy, Qual);
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
= getAsSubstTemplateTemplateParmPack())
} else if (SubstTemplateTemplateParmPackStorage *SubstPack =
getAsSubstTemplateTemplateParmPack())
OS << *SubstPack->getParameterPack();
else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
Assumed->getDeclName().print(OS, Policy);
Expand Down
Loading