Compare commits
135 Commits
users/ming
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2a79ef66eb | ||
![]() |
b149fc7755 | ||
![]() |
7c1d2467f1 | ||
![]() |
15a192cde5 | ||
![]() |
2014890c09 | ||
![]() |
d8769bb5b7 | ||
![]() |
3292edb7b4 | ||
![]() |
d2b810e24f | ||
![]() |
a8aacb1b66 | ||
![]() |
d2dee948a4 | ||
![]() |
a6fcd1a663 | ||
![]() |
2975e674ec | ||
![]() |
ee5367bedb | ||
![]() |
d5af08a221 | ||
![]() |
d6fcaef281 | ||
![]() |
17dbb92612 | ||
![]() |
8439777131 | ||
![]() |
fda24dbc16 | ||
![]() |
7594b4b8d1 | ||
![]() |
bfc16510c7 | ||
![]() |
fd52f4d232 | ||
![]() |
8bc038daf2 | ||
![]() |
faca8c9ed4 | ||
![]() |
1b4fe26343 | ||
![]() |
00a405f666 | ||
![]() |
8bf105cb01 | ||
![]() |
2d3167f8d8 | ||
![]() |
4ff7ac2330 | ||
![]() |
8d7df8bba1 | ||
![]() |
4ab5efd48d | ||
![]() |
f1aee598e7 | ||
![]() |
2a59400003 | ||
![]() |
2b8e806942 | ||
![]() |
149d9a38e1 | ||
![]() |
6560adb584 | ||
![]() |
2b46f31ee3 | ||
![]() |
e0945dfa30 | ||
![]() |
cf5243619a | ||
![]() |
50f7c6a5b9 | ||
![]() |
945a186089 | ||
![]() |
06ab660911 | ||
![]() |
36dc6146b8 | ||
![]() |
5050da7ba1 | ||
![]() |
a2f542b7a5 | ||
![]() |
04a3dd5a19 | ||
![]() |
1def457228 | ||
![]() |
d3d5751a39 | ||
![]() |
595148ab76 | ||
![]() |
0fff460592 | ||
![]() |
b08b219650 | ||
![]() |
be179d0696 | ||
![]() |
dee25a8a8e | ||
![]() |
d6fae7f921 | ||
![]() |
630712f4c1 | ||
![]() |
b1b5102624 | ||
![]() |
c1625fad02 | ||
![]() |
c346f4079a | ||
![]() |
fc5fcc0c95 | ||
![]() |
01f785cac4 | ||
![]() |
6a7ade03d1 | ||
![]() |
586a7131d3 | ||
![]() |
49d4712129 | ||
![]() |
6df9a13e40 | ||
![]() |
d26ea02060 | ||
![]() |
f1f194bf10 | ||
![]() |
418fb50301 | ||
![]() |
273b6f2911 | ||
![]() |
4d323206ed | ||
![]() |
3ce25abd4a | ||
![]() |
783859b2a0 | ||
![]() |
9d2a66fb32 | ||
![]() |
0bc02096f6 | ||
![]() |
6167b1e6e9 | ||
![]() |
b3f04bf44c | ||
![]() |
4eeeb8a01e | ||
![]() |
c97c6869b6 | ||
![]() |
e6d095e89c | ||
![]() |
05b1ec3724 | ||
![]() |
ff85dbdf6b | ||
![]() |
f961b61f88 | ||
![]() |
c74afaac6c | ||
![]() |
a3ed96b899 | ||
![]() |
304373fb6d | ||
![]() |
36d07ad83b | ||
![]() |
33f6b10c17 | ||
![]() |
d4b9acad58 | ||
![]() |
7f0e70fd2d | ||
![]() |
22f8693248 | ||
![]() |
628280b597 | ||
![]() |
67e95c6f60 | ||
![]() |
4e98641451 | ||
![]() |
ec07d8e941 | ||
![]() |
f5f6613af6 | ||
![]() |
e45210afe2 | ||
![]() |
1d05d693a1 | ||
![]() |
fa67855c99 | ||
![]() |
2421929ca6 | ||
![]() |
d38a5afa5a | ||
![]() |
04a271adf8 | ||
![]() |
c704dabe88 | ||
![]() |
8fa55a023b | ||
![]() |
09612007f1 | ||
![]() |
300d2c6d20 | ||
![]() |
38f0b9e6d9 | ||
![]() |
9b24ccca73 | ||
![]() |
933d8723b0 | ||
![]() |
545cda649e | ||
![]() |
ba5d487ac4 | ||
![]() |
4a9d2187ee | ||
![]() |
76b8e19203 | ||
![]() |
a447fc63f9 | ||
![]() |
a64e6f4928 | ||
![]() |
de7bac6426 | ||
![]() |
344793e513 | ||
![]() |
b3baa4d063 | ||
![]() |
779bb04a9a | ||
![]() |
9b5282723b | ||
![]() |
4e7779c099 | ||
![]() |
8d69c83808 | ||
![]() |
7d1f15c985 | ||
![]() |
f66d7b50ff | ||
![]() |
0f33b90b61 | ||
![]() |
424521f599 | ||
![]() |
1b9e9e29e2 | ||
![]() |
c80b7822e3 | ||
![]() |
de64f85f5d | ||
![]() |
e42ef8083c | ||
![]() |
8b091961b1 | ||
![]() |
e41aaf5a64 | ||
![]() |
21cca5ea9d | ||
![]() |
11994e8da7 | ||
![]() |
c91f7dc7cd | ||
![]() |
1a09581aa1 | ||
![]() |
87a1d42bed | ||
![]() |
a9de1ab44d |
@ -138,6 +138,12 @@
|
|||||||
Dump function CFGs to graphviz format after each stage;enable '-print-loops'
|
Dump function CFGs to graphviz format after each stage;enable '-print-loops'
|
||||||
for color-coded blocks
|
for color-coded blocks
|
||||||
|
|
||||||
|
- `--dump-dot-func=<func1,func2,func3...>`
|
||||||
|
|
||||||
|
Dump function CFGs to graphviz format for specified functions only;
|
||||||
|
takes function name patterns (regex supported). Note: C++ function names
|
||||||
|
must be passed using their mangled names
|
||||||
|
|
||||||
- `--dump-linux-exceptions`
|
- `--dump-linux-exceptions`
|
||||||
|
|
||||||
Dump Linux kernel exception table
|
Dump Linux kernel exception table
|
||||||
|
@ -15,6 +15,12 @@
|
|||||||
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace bolt {
|
||||||
|
class BinaryFunction;
|
||||||
|
}
|
||||||
|
} // namespace llvm
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
|
|
||||||
enum HeatmapModeKind {
|
enum HeatmapModeKind {
|
||||||
@ -100,6 +106,9 @@ extern llvm::cl::opt<unsigned> Verbosity;
|
|||||||
/// Return true if we should process all functions in the binary.
|
/// Return true if we should process all functions in the binary.
|
||||||
bool processAllFunctions();
|
bool processAllFunctions();
|
||||||
|
|
||||||
|
/// Return true if we should dump dot graphs for the given function.
|
||||||
|
bool shouldDumpDot(const llvm::bolt::BinaryFunction &Function);
|
||||||
|
|
||||||
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
|
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
|
||||||
|
|
||||||
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
|
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
|
||||||
|
@ -52,6 +52,7 @@ namespace opts {
|
|||||||
extern cl::opt<bool> PrintAll;
|
extern cl::opt<bool> PrintAll;
|
||||||
extern cl::opt<bool> PrintDynoStats;
|
extern cl::opt<bool> PrintDynoStats;
|
||||||
extern cl::opt<bool> DumpDotAll;
|
extern cl::opt<bool> DumpDotAll;
|
||||||
|
extern bool shouldDumpDot(const bolt::BinaryFunction &Function);
|
||||||
extern cl::opt<std::string> AsmDump;
|
extern cl::opt<std::string> AsmDump;
|
||||||
extern cl::opt<bolt::PLTCall::OptType> PLT;
|
extern cl::opt<bolt::PLTCall::OptType> PLT;
|
||||||
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
|
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
|
||||||
@ -340,7 +341,7 @@ Error BinaryFunctionPassManager::runPasses() {
|
|||||||
|
|
||||||
Function.print(BC.outs(), Message);
|
Function.print(BC.outs(), Message);
|
||||||
|
|
||||||
if (opts::DumpDotAll)
|
if (opts::shouldDumpDot(Function))
|
||||||
Function.dumpGraphForPass(PassIdName);
|
Function.dumpGraphForPass(PassIdName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,35 @@ cl::opt<bool> DumpDotAll(
|
|||||||
"enable '-print-loops' for color-coded blocks"),
|
"enable '-print-loops' for color-coded blocks"),
|
||||||
cl::Hidden, cl::cat(BoltCategory));
|
cl::Hidden, cl::cat(BoltCategory));
|
||||||
|
|
||||||
|
cl::list<std::string> DumpDotFunc(
|
||||||
|
"dump-dot-func", cl::CommaSeparated,
|
||||||
|
cl::desc(
|
||||||
|
"dump function CFGs to graphviz format for specified functions only;"
|
||||||
|
"takes function name patterns (regex supported)"),
|
||||||
|
cl::value_desc("func1,func2,func3,..."), cl::Hidden, cl::cat(BoltCategory));
|
||||||
|
|
||||||
|
bool shouldDumpDot(const bolt::BinaryFunction &Function) {
|
||||||
|
// If dump-dot-all is enabled, dump all functions
|
||||||
|
if (DumpDotAll)
|
||||||
|
return !Function.isIgnored();
|
||||||
|
|
||||||
|
// If no specific functions specified in dump-dot-func, don't dump any
|
||||||
|
if (DumpDotFunc.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Function.isIgnored())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check if function matches any of the specified patterns
|
||||||
|
for (const std::string &Name : DumpDotFunc) {
|
||||||
|
if (Function.hasNameRegex(Name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static cl::list<std::string>
|
static cl::list<std::string>
|
||||||
ForceFunctionNames("funcs",
|
ForceFunctionNames("funcs",
|
||||||
cl::CommaSeparated,
|
cl::CommaSeparated,
|
||||||
@ -3569,7 +3598,7 @@ void RewriteInstance::postProcessFunctions() {
|
|||||||
if (opts::PrintAll || opts::PrintCFG)
|
if (opts::PrintAll || opts::PrintCFG)
|
||||||
Function.print(BC->outs(), "after building cfg");
|
Function.print(BC->outs(), "after building cfg");
|
||||||
|
|
||||||
if (opts::DumpDotAll)
|
if (opts::shouldDumpDot(Function))
|
||||||
Function.dumpGraphForPass("00_build-cfg");
|
Function.dumpGraphForPass("00_build-cfg");
|
||||||
|
|
||||||
if (opts::PrintLoopInfo) {
|
if (opts::PrintLoopInfo) {
|
||||||
|
24
bolt/test/Inputs/multi-func.cpp
Normal file
24
bolt/test/Inputs/multi-func.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// Multiple functions to test selective dumping
|
||||||
|
int add(int a, int b) { return a + b; }
|
||||||
|
|
||||||
|
int multiply(int a, int b) { return a * b; }
|
||||||
|
|
||||||
|
int main_helper() {
|
||||||
|
std::cout << "Helper function" << std::endl;
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main_secondary() { return add(5, 3); }
|
||||||
|
|
||||||
|
void other_function() { std::cout << "Other function" << std::endl; }
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int result = add(10, 20);
|
||||||
|
result = multiply(result, 2);
|
||||||
|
main_helper();
|
||||||
|
main_secondary();
|
||||||
|
other_function();
|
||||||
|
return result;
|
||||||
|
}
|
52
bolt/test/dump-dot-func.test
Normal file
52
bolt/test/dump-dot-func.test
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Test the --dump-dot-func option with multiple functions
|
||||||
|
# (includes tests for both mangled/unmangled names)
|
||||||
|
|
||||||
|
RUN: %clang++ %p/Inputs/multi-func.cpp -o %t.exe -Wl,-q
|
||||||
|
|
||||||
|
# Test 1: --dump-dot-func with specific function name (mangled)
|
||||||
|
RUN: llvm-bolt %t.exe -o %t.bolt1 --dump-dot-func=_Z3addii -v=1 2>&1 | FileCheck %s --check-prefix=ADD
|
||||||
|
|
||||||
|
# Test 2: --dump-dot-func with regex pattern (main.*)
|
||||||
|
RUN: llvm-bolt %t.exe -o %t.bolt2 --dump-dot-func="main.*" -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-REGEX
|
||||||
|
|
||||||
|
# Test 3: --dump-dot-func with multiple specific functions (mangled names)
|
||||||
|
RUN: llvm-bolt %t.exe -o %t.bolt3 --dump-dot-func=_Z3addii,_Z8multiplyii -v=1 2>&1 | FileCheck %s --check-prefix=MULTI
|
||||||
|
|
||||||
|
# Test 4: No option specified should create no dot files
|
||||||
|
RUN: llvm-bolt %t.exe -o %t.bolt4 2>&1 | FileCheck %s --check-prefix=NONE
|
||||||
|
|
||||||
|
# Test 5: --dump-dot-func with non-existent function
|
||||||
|
RUN: llvm-bolt %t.exe -o %t.bolt5 --dump-dot-func=nonexistent -v=1 2>&1 | FileCheck %s --check-prefix=NONEXISTENT
|
||||||
|
|
||||||
|
# Test 6: Backward compatibility - --dump-dot-all should still work
|
||||||
|
RUN: llvm-bolt %t.exe -o %t.bolt6 --dump-dot-all -v=1 2>&1 | FileCheck %s --check-prefix=ALL
|
||||||
|
|
||||||
|
# Test 7: Test with unmangled function name (main function)
|
||||||
|
RUN: llvm-bolt %t.exe -o %t.bolt7 --dump-dot-func=main -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-UNMANGLED
|
||||||
|
|
||||||
|
# Check that specific functions are dumped
|
||||||
|
ADD: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
||||||
|
ADD-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
||||||
|
ADD-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
||||||
|
ADD-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
|
||||||
|
|
||||||
|
MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
||||||
|
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
||||||
|
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
||||||
|
|
||||||
|
MULTI-DAG: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
||||||
|
MULTI-DAG: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
||||||
|
MULTI-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
||||||
|
MULTI-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
|
||||||
|
|
||||||
|
# Should be no dumping messages when no option is specified
|
||||||
|
NONE-NOT: BOLT-INFO: dumping CFG
|
||||||
|
|
||||||
|
# Should be no dumping messages for non-existent function
|
||||||
|
NONEXISTENT-NOT: BOLT-INFO: dumping CFG
|
||||||
|
|
||||||
|
ALL: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
||||||
|
|
||||||
|
MAIN-UNMANGLED: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
|
||||||
|
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
|
||||||
|
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
|
@ -1575,6 +1575,10 @@ template <typename T, std::size_t N = SmallDataStructureSize>
|
|||||||
using ParamToSmallSetMap =
|
using ParamToSmallSetMap =
|
||||||
llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
|
llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
|
||||||
|
|
||||||
|
template <typename T, std::size_t N = SmallDataStructureSize>
|
||||||
|
using ParamToSmallPtrSetMap =
|
||||||
|
llvm::DenseMap<const ParmVarDecl *, llvm::SmallPtrSet<T, N>>;
|
||||||
|
|
||||||
/// Returns whether the sets mapped to the two elements in the map have at
|
/// Returns whether the sets mapped to the two elements in the map have at
|
||||||
/// least one element in common.
|
/// least one element in common.
|
||||||
template <typename MapTy, typename ElemTy>
|
template <typename MapTy, typename ElemTy>
|
||||||
@ -1699,7 +1703,7 @@ public:
|
|||||||
/// Implements the heuristic that marks two parameters related if the same
|
/// Implements the heuristic that marks two parameters related if the same
|
||||||
/// member is accessed (referred to) inside the current function's body.
|
/// member is accessed (referred to) inside the current function's body.
|
||||||
class AccessedSameMemberOf {
|
class AccessedSameMemberOf {
|
||||||
ParamToSmallSetMap<const Decl *> AccessedMembers;
|
ParamToSmallPtrSetMap<const Decl *> AccessedMembers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setup(const FunctionDecl *FD) {
|
void setup(const FunctionDecl *FD) {
|
||||||
|
@ -15,14 +15,12 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::bugprone {
|
namespace clang::tidy::bugprone {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Determine if the result of an expression is "stored" in some way.
|
// Determine if the result of an expression is "stored" in some way.
|
||||||
// It is true if the value is stored into a variable or used as initialization
|
// It is true if the value is stored into a variable or used as initialization
|
||||||
// or passed to a function or constructor.
|
// or passed to a function or constructor.
|
||||||
// For this use case compound assignments are not counted as a "store" (the 'E'
|
// For this use case compound assignments are not counted as a "store" (the 'E'
|
||||||
// expression should have pointer type).
|
// expression should have pointer type).
|
||||||
bool isExprValueStored(const Expr *E, ASTContext &C) {
|
static bool isExprValueStored(const Expr *E, ASTContext &C) {
|
||||||
E = E->IgnoreParenCasts();
|
E = E->IgnoreParenCasts();
|
||||||
// Get first non-paren, non-cast parent.
|
// Get first non-paren, non-cast parent.
|
||||||
ParentMapContext &PMap = C.getParentMapContext();
|
ParentMapContext &PMap = C.getParentMapContext();
|
||||||
@ -49,6 +47,8 @@ bool isExprValueStored(const Expr *E, ASTContext &C) {
|
|||||||
return isa<CallExpr, CXXConstructExpr>(ParentE);
|
return isa<CallExpr, CXXConstructExpr>(ParentE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
AST_MATCHER_P(CXXTryStmt, hasHandlerFor,
|
AST_MATCHER_P(CXXTryStmt, hasHandlerFor,
|
||||||
ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
|
ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
|
||||||
for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) {
|
for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) {
|
||||||
|
@ -14,10 +14,8 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::bugprone {
|
namespace clang::tidy::bugprone {
|
||||||
|
|
||||||
namespace {
|
static bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
||||||
|
const StringLiteral *Lit) {
|
||||||
bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
|
||||||
const StringLiteral *Lit) {
|
|
||||||
// String literals surrounded by parentheses are assumed to be on purpose.
|
// String literals surrounded by parentheses are assumed to be on purpose.
|
||||||
// i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
|
// i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
|
||||||
|
|
||||||
@ -58,6 +56,8 @@ bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
|
AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
|
||||||
MaxConcatenatedTokens) {
|
MaxConcatenatedTokens) {
|
||||||
return Node.getNumConcatenated() > 1 &&
|
return Node.getNumConcatenated() > 1 &&
|
||||||
|
@ -46,7 +46,9 @@ enum class ConversionKind {
|
|||||||
ToLongDouble
|
ToLongDouble
|
||||||
};
|
};
|
||||||
|
|
||||||
ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
} // namespace
|
||||||
|
|
||||||
|
static ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
||||||
return llvm::StringSwitch<ConversionKind>(FD->getName())
|
return llvm::StringSwitch<ConversionKind>(FD->getName())
|
||||||
.Cases("atoi", "atol", ConversionKind::ToInt)
|
.Cases("atoi", "atol", ConversionKind::ToInt)
|
||||||
.Case("atoll", ConversionKind::ToLongInt)
|
.Case("atoll", ConversionKind::ToLongInt)
|
||||||
@ -54,8 +56,8 @@ ConversionKind classifyConversionFunc(const FunctionDecl *FD) {
|
|||||||
.Default(ConversionKind::None);
|
.Default(ConversionKind::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
static ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
||||||
const TargetInfo &TI) {
|
const TargetInfo &TI) {
|
||||||
// Scan the format string for the first problematic format specifier, then
|
// Scan the format string for the first problematic format specifier, then
|
||||||
// report that as the conversion type. This will miss additional conversion
|
// report that as the conversion type. This will miss additional conversion
|
||||||
// specifiers, but that is acceptable behavior.
|
// specifiers, but that is acceptable behavior.
|
||||||
@ -128,7 +130,7 @@ ConversionKind classifyFormatString(StringRef Fmt, const LangOptions &LO,
|
|||||||
return H.get();
|
return H.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef classifyConversionType(ConversionKind K) {
|
static StringRef classifyConversionType(ConversionKind K) {
|
||||||
switch (K) {
|
switch (K) {
|
||||||
case ConversionKind::None:
|
case ConversionKind::None:
|
||||||
llvm_unreachable("Unexpected conversion kind");
|
llvm_unreachable("Unexpected conversion kind");
|
||||||
@ -148,7 +150,7 @@ StringRef classifyConversionType(ConversionKind K) {
|
|||||||
llvm_unreachable("Unknown conversion kind");
|
llvm_unreachable("Unknown conversion kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef classifyReplacement(ConversionKind K) {
|
static StringRef classifyReplacement(ConversionKind K) {
|
||||||
switch (K) {
|
switch (K) {
|
||||||
case ConversionKind::None:
|
case ConversionKind::None:
|
||||||
llvm_unreachable("Unexpected conversion kind");
|
llvm_unreachable("Unexpected conversion kind");
|
||||||
@ -173,7 +175,6 @@ StringRef classifyReplacement(ConversionKind K) {
|
|||||||
}
|
}
|
||||||
llvm_unreachable("Unknown conversion kind");
|
llvm_unreachable("Unknown conversion kind");
|
||||||
}
|
}
|
||||||
} // unnamed namespace
|
|
||||||
|
|
||||||
void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
|
void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
|
||||||
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");
|
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");
|
||||||
|
@ -59,7 +59,9 @@ AST_MATCHER(FunctionDecl, isPlacementOverload) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
} // namespace
|
||||||
|
|
||||||
|
static OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
||||||
switch (FD->getOverloadedOperator()) {
|
switch (FD->getOverloadedOperator()) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -75,7 +77,7 @@ OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
|
|||||||
llvm_unreachable("Not an overloaded allocation operator");
|
llvm_unreachable("Not an overloaded allocation operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *getOperatorName(OverloadedOperatorKind K) {
|
static const char *getOperatorName(OverloadedOperatorKind K) {
|
||||||
switch (K) {
|
switch (K) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -91,13 +93,14 @@ const char *getOperatorName(OverloadedOperatorKind K) {
|
|||||||
llvm_unreachable("Not an overloaded allocation operator");
|
llvm_unreachable("Not an overloaded allocation operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool areCorrespondingOverloads(const FunctionDecl *LHS,
|
static bool areCorrespondingOverloads(const FunctionDecl *LHS,
|
||||||
const FunctionDecl *RHS) {
|
const FunctionDecl *RHS) {
|
||||||
return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
|
return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
static bool
|
||||||
const CXXRecordDecl *RD = nullptr) {
|
hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
||||||
|
const CXXRecordDecl *RD = nullptr) {
|
||||||
if (RD) {
|
if (RD) {
|
||||||
// Check the methods in the given class and accessible to derived classes.
|
// Check the methods in the given class and accessible to derived classes.
|
||||||
for (const auto *BMD : RD->methods())
|
for (const auto *BMD : RD->methods())
|
||||||
@ -124,8 +127,6 @@ bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
|
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
// Match all operator new and operator delete overloads (including the array
|
// Match all operator new and operator delete overloads (including the array
|
||||||
// forms). Do not match implicit operators, placement operators, or
|
// forms). Do not match implicit operators, placement operators, or
|
||||||
|
@ -395,16 +395,12 @@ void MacroToEnumCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) {
|
|||||||
--CurrentFile->ConditionScopes;
|
--CurrentFile->ConditionScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
bool textEquals(const char (&Needle)[N], const char *HayStack) {
|
static bool textEquals(const char (&Needle)[N], const char *HayStack) {
|
||||||
return StringRef{HayStack, N - 1} == Needle;
|
return StringRef{HayStack, N - 1} == Needle;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N> size_t len(const char (&)[N]) { return N - 1; }
|
template <size_t N> static size_t len(const char (&)[N]) { return N - 1; }
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc,
|
void MacroToEnumCallbacks::PragmaDirective(SourceLocation Loc,
|
||||||
PragmaIntroducerKind Introducer) {
|
PragmaIntroducerKind Introducer) {
|
||||||
|
@ -16,14 +16,13 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::modernize {
|
namespace clang::tidy::modernize {
|
||||||
|
|
||||||
namespace {
|
static constexpr char ConstructorCall[] = "constructorCall";
|
||||||
|
static constexpr char ResetCall[] = "resetCall";
|
||||||
|
static constexpr char NewExpression[] = "newExpression";
|
||||||
|
|
||||||
constexpr char ConstructorCall[] = "constructorCall";
|
static std::string getNewExprName(const CXXNewExpr *NewExpr,
|
||||||
constexpr char ResetCall[] = "resetCall";
|
const SourceManager &SM,
|
||||||
constexpr char NewExpression[] = "newExpression";
|
const LangOptions &Lang) {
|
||||||
|
|
||||||
std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
|
|
||||||
const LangOptions &Lang) {
|
|
||||||
StringRef WrittenName = Lexer::getSourceText(
|
StringRef WrittenName = Lexer::getSourceText(
|
||||||
CharSourceRange::getTokenRange(
|
CharSourceRange::getTokenRange(
|
||||||
NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
|
NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
|
||||||
@ -34,8 +33,6 @@ std::string getNewExprName(const CXXNewExpr *NewExpr, const SourceManager &SM,
|
|||||||
return WrittenName.str();
|
return WrittenName.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
const char MakeSmartPtrCheck::PointerType[] = "pointerType";
|
const char MakeSmartPtrCheck::PointerType[] = "pointerType";
|
||||||
|
|
||||||
MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
|
MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
|
||||||
|
@ -19,9 +19,7 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::modernize {
|
namespace clang::tidy::modernize {
|
||||||
|
|
||||||
namespace {
|
static bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
||||||
|
|
||||||
bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
|
||||||
size_t BackSlash = HayStack.find('\\');
|
size_t BackSlash = HayStack.find('\\');
|
||||||
if (BackSlash == StringRef::npos)
|
if (BackSlash == StringRef::npos)
|
||||||
return false;
|
return false;
|
||||||
@ -35,16 +33,16 @@ bool containsEscapes(StringRef HayStack, StringRef Escapes) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isRawStringLiteral(StringRef Text) {
|
static bool isRawStringLiteral(StringRef Text) {
|
||||||
// Already a raw string literal if R comes before ".
|
// Already a raw string literal if R comes before ".
|
||||||
const size_t QuotePos = Text.find('"');
|
const size_t QuotePos = Text.find('"');
|
||||||
assert(QuotePos != StringRef::npos);
|
assert(QuotePos != StringRef::npos);
|
||||||
return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
|
return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
static bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
||||||
const StringLiteral *Literal,
|
const StringLiteral *Literal,
|
||||||
const CharsBitSet &DisallowedChars) {
|
const CharsBitSet &DisallowedChars) {
|
||||||
// FIXME: Handle L"", u8"", u"" and U"" literals.
|
// FIXME: Handle L"", u8"", u"" and U"" literals.
|
||||||
if (!Literal->isOrdinary())
|
if (!Literal->isOrdinary())
|
||||||
return false;
|
return false;
|
||||||
@ -64,14 +62,12 @@ bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
|
|||||||
return containsEscapes(Text, R"('\"?x01)");
|
return containsEscapes(Text, R"('\"?x01)");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
|
static bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
|
||||||
return Bytes.find(Delimiter.empty()
|
return Bytes.find(Delimiter.empty()
|
||||||
? std::string(R"lit()")lit")
|
? std::string(R"lit()")lit")
|
||||||
: (")" + Delimiter + R"(")")) != StringRef::npos;
|
: (")" + Delimiter + R"(")")) != StringRef::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
|
RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
|
||||||
ClangTidyContext *Context)
|
ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -29,12 +29,13 @@
|
|||||||
using namespace clang::ast_matchers;
|
using namespace clang::ast_matchers;
|
||||||
|
|
||||||
namespace clang::tidy::objc {
|
namespace clang::tidy::objc {
|
||||||
namespace {
|
|
||||||
|
|
||||||
static constexpr StringRef WeakText = "__weak";
|
static constexpr StringRef WeakText = "__weak";
|
||||||
static constexpr StringRef StrongText = "__strong";
|
static constexpr StringRef StrongText = "__strong";
|
||||||
static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained";
|
static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained";
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
/// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference
|
/// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference
|
||||||
/// Objective-C object (or block) variables or fields whose object lifetimes
|
/// Objective-C object (or block) variables or fields whose object lifetimes
|
||||||
/// are not __unsafe_unretained.
|
/// are not __unsafe_unretained.
|
||||||
@ -49,6 +50,8 @@ AST_POLYMORPHIC_MATCHER(isObjCManagedLifetime,
|
|||||||
QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone;
|
QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
static std::optional<FixItHint>
|
static std::optional<FixItHint>
|
||||||
fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range,
|
fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range,
|
||||||
StringRef Ownership) {
|
StringRef Ownership) {
|
||||||
@ -93,8 +96,6 @@ fixItHintForVarDecl(const VarDecl *VD, const SourceManager &SM,
|
|||||||
return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained ");
|
return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained ");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) {
|
void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(
|
||||||
traverse(
|
traverse(
|
||||||
|
@ -27,11 +27,14 @@ enum NamingStyle {
|
|||||||
CategoryProperty = 2,
|
CategoryProperty = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
|
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
|
||||||
/// 'camelCase' or 'abc_camelCase'. For other cases the users need to
|
/// 'camelCase' or 'abc_camelCase'. For other cases the users need to
|
||||||
/// come up with a proper name by their own.
|
/// come up with a proper name by their own.
|
||||||
/// FIXME: provide fix for snake_case to snakeCase
|
/// FIXME: provide fix for snake_case to snakeCase
|
||||||
FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
|
static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl,
|
||||||
|
NamingStyle Style) {
|
||||||
auto Name = Decl->getName();
|
auto Name = Decl->getName();
|
||||||
auto NewName = Decl->getName().str();
|
auto NewName = Decl->getName().str();
|
||||||
size_t Index = 0;
|
size_t Index = 0;
|
||||||
@ -50,7 +53,7 @@ FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string validPropertyNameRegex(bool UsedInMatcher) {
|
static std::string validPropertyNameRegex(bool UsedInMatcher) {
|
||||||
// Allow any of these names:
|
// Allow any of these names:
|
||||||
// foo
|
// foo
|
||||||
// fooBar
|
// fooBar
|
||||||
@ -72,13 +75,13 @@ std::string validPropertyNameRegex(bool UsedInMatcher) {
|
|||||||
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
|
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
|
static bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
|
||||||
auto RegexExp =
|
auto RegexExp =
|
||||||
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
|
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
|
||||||
return RegexExp.match(PropertyName);
|
return RegexExp.match(PropertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
static bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
||||||
size_t Start = PropertyName.find_first_of('_');
|
size_t Start = PropertyName.find_first_of('_');
|
||||||
assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
|
assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
|
||||||
auto Prefix = PropertyName.substr(0, Start);
|
auto Prefix = PropertyName.substr(0, Start);
|
||||||
@ -88,7 +91,6 @@ bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
|
|||||||
auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
|
auto RegexExp = llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
|
||||||
return RegexExp.match(PropertyName.substr(Start + 1));
|
return RegexExp.match(PropertyName.substr(Start + 1));
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
|
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
Finder->addMatcher(objcPropertyDecl(
|
Finder->addMatcher(objcPropertyDecl(
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace clang::tidy::performance {
|
namespace clang::tidy::performance {
|
||||||
namespace {
|
|
||||||
|
|
||||||
using namespace ::clang::ast_matchers;
|
using namespace ::clang::ast_matchers;
|
||||||
using llvm::StringRef;
|
using llvm::StringRef;
|
||||||
@ -30,8 +29,8 @@ static constexpr StringRef MethodDeclId = "methodDecl";
|
|||||||
static constexpr StringRef FunctionDeclId = "functionDecl";
|
static constexpr StringRef FunctionDeclId = "functionDecl";
|
||||||
static constexpr StringRef OldVarDeclId = "oldVarDecl";
|
static constexpr StringRef OldVarDeclId = "oldVarDecl";
|
||||||
|
|
||||||
void recordFixes(const VarDecl &Var, ASTContext &Context,
|
static void recordFixes(const VarDecl &Var, ASTContext &Context,
|
||||||
DiagnosticBuilder &Diagnostic) {
|
DiagnosticBuilder &Diagnostic) {
|
||||||
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
|
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
|
||||||
if (!Var.getType().isLocalConstQualified()) {
|
if (!Var.getType().isLocalConstQualified()) {
|
||||||
if (std::optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
|
if (std::optional<FixItHint> Fix = utils::fixit::addQualifierToVarDecl(
|
||||||
@ -40,8 +39,8 @@ void recordFixes(const VarDecl &Var, ASTContext &Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
static std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
||||||
SourceManager &SM) {
|
SourceManager &SM) {
|
||||||
bool Invalid = false;
|
bool Invalid = false;
|
||||||
const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
|
const char *TextAfter = SM.getCharacterData(Loc, &Invalid);
|
||||||
if (Invalid) {
|
if (Invalid) {
|
||||||
@ -51,8 +50,8 @@ std::optional<SourceLocation> firstLocAfterNewLine(SourceLocation Loc,
|
|||||||
return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
|
return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
static void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
||||||
DiagnosticBuilder &Diagnostic) {
|
DiagnosticBuilder &Diagnostic) {
|
||||||
auto &SM = Context.getSourceManager();
|
auto &SM = Context.getSourceManager();
|
||||||
// Attempt to remove trailing comments as well.
|
// Attempt to remove trailing comments as well.
|
||||||
auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
|
auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM,
|
||||||
@ -74,6 +73,8 @@ void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
AST_MATCHER_FUNCTION_P(StatementMatcher,
|
AST_MATCHER_FUNCTION_P(StatementMatcher,
|
||||||
isRefReturningMethodCallWithConstOverloads,
|
isRefReturningMethodCallWithConstOverloads,
|
||||||
std::vector<StringRef>, ExcludedContainerTypes) {
|
std::vector<StringRef>, ExcludedContainerTypes) {
|
||||||
@ -130,6 +131,8 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst,
|
|||||||
hasUnaryOperand(OldVarDeclRef)))));
|
hasUnaryOperand(OldVarDeclRef)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// This checks that the variable itself is only used as const, and also makes
|
// This checks that the variable itself is only used as const, and also makes
|
||||||
// sure that it does not reference another variable that could be modified in
|
// sure that it does not reference another variable that could be modified in
|
||||||
// the BlockStmt. It does this by checking the following:
|
// the BlockStmt. It does this by checking the following:
|
||||||
@ -180,13 +183,13 @@ static bool isInitializingVariableImmutable(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
|
static bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
return allDeclRefExprs(Var, BlockStmt, Context).empty();
|
return allDeclRefExprs(Var, BlockStmt, Context).empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
|
static const SubstTemplateTypeParmType *
|
||||||
ASTContext &Context) {
|
getSubstitutedType(const QualType &Type, ASTContext &Context) {
|
||||||
auto Matches = match(
|
auto Matches = match(
|
||||||
qualType(anyOf(substTemplateTypeParmType().bind("subst"),
|
qualType(anyOf(substTemplateTypeParmType().bind("subst"),
|
||||||
hasDescendant(substTemplateTypeParmType().bind("subst")))),
|
hasDescendant(substTemplateTypeParmType().bind("subst")))),
|
||||||
@ -194,9 +197,9 @@ const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type,
|
|||||||
return selectFirst<SubstTemplateTypeParmType>("subst", Matches);
|
return selectFirst<SubstTemplateTypeParmType>("subst", Matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool differentReplacedTemplateParams(const QualType &VarType,
|
static bool differentReplacedTemplateParams(const QualType &VarType,
|
||||||
const QualType &InitializerType,
|
const QualType &InitializerType,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
if (const SubstTemplateTypeParmType *VarTmplType =
|
if (const SubstTemplateTypeParmType *VarTmplType =
|
||||||
getSubstitutedType(VarType, Context)) {
|
getSubstitutedType(VarType, Context)) {
|
||||||
if (const SubstTemplateTypeParmType *InitializerTmplType =
|
if (const SubstTemplateTypeParmType *InitializerTmplType =
|
||||||
@ -212,8 +215,8 @@ bool differentReplacedTemplateParams(const QualType &VarType,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType constructorArgumentType(const VarDecl *OldVar,
|
static QualType constructorArgumentType(const VarDecl *OldVar,
|
||||||
const BoundNodes &Nodes) {
|
const BoundNodes &Nodes) {
|
||||||
if (OldVar) {
|
if (OldVar) {
|
||||||
return OldVar->getType();
|
return OldVar->getType();
|
||||||
}
|
}
|
||||||
@ -224,8 +227,6 @@ QualType constructorArgumentType(const VarDecl *OldVar,
|
|||||||
return MethodDecl->getReturnType();
|
return MethodDecl->getReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
|
UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
|
||||||
StringRef Name, ClangTidyContext *Context)
|
StringRef Name, ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -21,16 +21,14 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::performance {
|
namespace clang::tidy::performance {
|
||||||
|
|
||||||
namespace {
|
static std::string paramNameOrIndex(StringRef Name, size_t Index) {
|
||||||
|
|
||||||
std::string paramNameOrIndex(StringRef Name, size_t Index) {
|
|
||||||
return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
|
return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
|
||||||
: llvm::Twine('\'') + Name + llvm::Twine('\''))
|
: llvm::Twine('\'') + Name + llvm::Twine('\''))
|
||||||
.str();
|
.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
static bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
auto Matches = match(
|
auto Matches = match(
|
||||||
traverse(TK_AsIs,
|
traverse(TK_AsIs,
|
||||||
decl(forEachDescendant(declRefExpr(
|
decl(forEachDescendant(declRefExpr(
|
||||||
@ -41,8 +39,6 @@ bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
|
|||||||
return Matches.empty();
|
return Matches.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
|
UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
|
||||||
StringRef Name, ClangTidyContext *Context)
|
StringRef Name, ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -122,15 +122,15 @@ AST_MATCHER(EnumDecl, hasSequentialInitialValues) {
|
|||||||
return !AllEnumeratorsArePowersOfTwo;
|
return !AllEnumeratorsArePowersOfTwo;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getName(const EnumDecl *Decl) {
|
} // namespace
|
||||||
|
|
||||||
|
static std::string getName(const EnumDecl *Decl) {
|
||||||
if (!Decl->getDeclName())
|
if (!Decl->getDeclName())
|
||||||
return "<unnamed>";
|
return "<unnamed>";
|
||||||
|
|
||||||
return Decl->getQualifiedNameAsString();
|
return Decl->getQualifiedNameAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
|
EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
|
||||||
ClangTidyContext *Context)
|
ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -144,6 +144,8 @@ struct CognitiveComplexity final {
|
|||||||
void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
|
void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// All the possible messages that can be output. The choice of the message
|
// All the possible messages that can be output. The choice of the message
|
||||||
// to use is based of the combination of the CognitiveComplexity::Criteria.
|
// to use is based of the combination of the CognitiveComplexity::Criteria.
|
||||||
// It would be nice to have it in CognitiveComplexity struct, but then it is
|
// It would be nice to have it in CognitiveComplexity struct, but then it is
|
||||||
@ -163,23 +165,27 @@ static const std::array<const StringRef, 4> Msgs = {{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
// Criteria is a bitset, thus a few helpers are needed.
|
// Criteria is a bitset, thus a few helpers are needed.
|
||||||
CognitiveComplexity::Criteria operator|(CognitiveComplexity::Criteria LHS,
|
static CognitiveComplexity::Criteria
|
||||||
CognitiveComplexity::Criteria RHS) {
|
operator|(CognitiveComplexity::Criteria LHS,
|
||||||
|
CognitiveComplexity::Criteria RHS) {
|
||||||
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) |
|
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) |
|
||||||
llvm::to_underlying(RHS));
|
llvm::to_underlying(RHS));
|
||||||
}
|
}
|
||||||
CognitiveComplexity::Criteria operator&(CognitiveComplexity::Criteria LHS,
|
static CognitiveComplexity::Criteria
|
||||||
CognitiveComplexity::Criteria RHS) {
|
operator&(CognitiveComplexity::Criteria LHS,
|
||||||
|
CognitiveComplexity::Criteria RHS) {
|
||||||
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) &
|
return static_cast<CognitiveComplexity::Criteria>(llvm::to_underlying(LHS) &
|
||||||
llvm::to_underlying(RHS));
|
llvm::to_underlying(RHS));
|
||||||
}
|
}
|
||||||
CognitiveComplexity::Criteria &operator|=(CognitiveComplexity::Criteria &LHS,
|
static CognitiveComplexity::Criteria &
|
||||||
CognitiveComplexity::Criteria RHS) {
|
operator|=(CognitiveComplexity::Criteria &LHS,
|
||||||
|
CognitiveComplexity::Criteria RHS) {
|
||||||
LHS = operator|(LHS, RHS);
|
LHS = operator|(LHS, RHS);
|
||||||
return LHS;
|
return LHS;
|
||||||
}
|
}
|
||||||
CognitiveComplexity::Criteria &operator&=(CognitiveComplexity::Criteria &LHS,
|
static CognitiveComplexity::Criteria &
|
||||||
CognitiveComplexity::Criteria RHS) {
|
operator&=(CognitiveComplexity::Criteria &LHS,
|
||||||
|
CognitiveComplexity::Criteria RHS) {
|
||||||
LHS = operator&(LHS, RHS);
|
LHS = operator&(LHS, RHS);
|
||||||
return LHS;
|
return LHS;
|
||||||
}
|
}
|
||||||
@ -199,6 +205,8 @@ void CognitiveComplexity::account(SourceLocation Loc, unsigned short Nesting,
|
|||||||
Total += Increase;
|
Total += Increase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
class FunctionASTVisitor final
|
class FunctionASTVisitor final
|
||||||
: public RecursiveASTVisitor<FunctionASTVisitor> {
|
: public RecursiveASTVisitor<FunctionASTVisitor> {
|
||||||
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
|
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
|
||||||
|
@ -41,9 +41,11 @@ AST_MATCHER(Stmt, isNULLMacroExpansion) {
|
|||||||
return isNULLMacroExpansion(&Node, Finder->getASTContext());
|
return isNULLMacroExpansion(&Node, Finder->getASTContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
} // namespace
|
||||||
QualType Type,
|
|
||||||
ASTContext &Context) {
|
static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
||||||
|
QualType Type,
|
||||||
|
ASTContext &Context) {
|
||||||
switch (CastExprKind) {
|
switch (CastExprKind) {
|
||||||
case CK_IntegralToBoolean:
|
case CK_IntegralToBoolean:
|
||||||
return Type->isUnsignedIntegerType() ? "0u" : "0";
|
return Type->isUnsignedIntegerType() ? "0u" : "0";
|
||||||
@ -62,15 +64,15 @@ StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUnaryLogicalNotOperator(const Stmt *Statement) {
|
static bool isUnaryLogicalNotOperator(const Stmt *Statement) {
|
||||||
const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
|
const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
|
||||||
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
|
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
static void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
||||||
const ImplicitCastExpr *Cast, const Stmt *Parent,
|
const ImplicitCastExpr *Cast,
|
||||||
ASTContext &Context,
|
const Stmt *Parent, ASTContext &Context,
|
||||||
bool UseUpperCaseLiteralSuffix) {
|
bool UseUpperCaseLiteralSuffix) {
|
||||||
// In case of expressions like (! integer), we should remove the redundant not
|
// In case of expressions like (! integer), we should remove the redundant not
|
||||||
// operator and use inverted comparison (integer == 0).
|
// operator and use inverted comparison (integer == 0).
|
||||||
bool InvertComparison =
|
bool InvertComparison =
|
||||||
@ -133,8 +135,8 @@ void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
|
|||||||
Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
|
Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
static StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
if (isNULLMacroExpansion(Expression, Context)) {
|
if (isNULLMacroExpansion(Expression, Context)) {
|
||||||
return "false";
|
return "false";
|
||||||
}
|
}
|
||||||
@ -161,7 +163,7 @@ StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
static bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
||||||
SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc);
|
SourceRange PrefixRange(Loc.getLocWithOffset(-1), Loc);
|
||||||
StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
|
StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
|
||||||
CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(),
|
CharSourceRange::getCharRange(PrefixRange), Context.getSourceManager(),
|
||||||
@ -173,9 +175,10 @@ bool needsSpacePrefix(SourceLocation Loc, ASTContext &Context) {
|
|||||||
return !AllowedCharacters.contains(SpaceBeforeStmtStr.back());
|
return !AllowedCharacters.contains(SpaceBeforeStmtStr.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
static void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
||||||
const ImplicitCastExpr *Cast,
|
const ImplicitCastExpr *Cast,
|
||||||
ASTContext &Context, StringRef OtherType) {
|
ASTContext &Context,
|
||||||
|
StringRef OtherType) {
|
||||||
if (!Context.getLangOpts().CPlusPlus) {
|
if (!Context.getLangOpts().CPlusPlus) {
|
||||||
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
|
Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(),
|
||||||
(Twine("(") + OtherType + ")").str());
|
(Twine("(") + OtherType + ")").str());
|
||||||
@ -200,8 +203,9 @@ void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
static StringRef
|
||||||
QualType DestType, ASTContext &Context) {
|
getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
||||||
|
QualType DestType, ASTContext &Context) {
|
||||||
// Prior to C++11, false literal could be implicitly converted to pointer.
|
// Prior to C++11, false literal could be implicitly converted to pointer.
|
||||||
if (!Context.getLangOpts().CPlusPlus11 &&
|
if (!Context.getLangOpts().CPlusPlus11 &&
|
||||||
(DestType->isPointerType() || DestType->isMemberPointerType()) &&
|
(DestType->isPointerType() || DestType->isMemberPointerType()) &&
|
||||||
@ -222,8 +226,8 @@ StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
|
|||||||
return BoolLiteral->getValue() ? "1" : "0";
|
return BoolLiteral->getValue() ? "1" : "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
static bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
||||||
ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
std::queue<const Stmt *> Q;
|
std::queue<const Stmt *> Q;
|
||||||
Q.push(Cast);
|
Q.push(Cast);
|
||||||
|
|
||||||
@ -251,8 +255,6 @@ bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
|
ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
|
||||||
StringRef Name, ClangTidyContext *Context)
|
StringRef Name, ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -28,8 +28,11 @@ AST_MATCHER_P(QualType, hasUnqualifiedType,
|
|||||||
|
|
||||||
enum class Qualifier { Const, Volatile, Restrict };
|
enum class Qualifier { Const, Volatile, Restrict };
|
||||||
|
|
||||||
std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
|
} // namespace
|
||||||
const MatchFinder::MatchResult &Result) {
|
|
||||||
|
static std::optional<Token>
|
||||||
|
findQualToken(const VarDecl *Decl, Qualifier Qual,
|
||||||
|
const MatchFinder::MatchResult &Result) {
|
||||||
// Since either of the locs can be in a macro, use `makeFileCharRange` to be
|
// Since either of the locs can be in a macro, use `makeFileCharRange` to be
|
||||||
// sure that we have a consistent `CharSourceRange`, located entirely in the
|
// sure that we have a consistent `CharSourceRange`, located entirely in the
|
||||||
// source file.
|
// source file.
|
||||||
@ -58,7 +61,7 @@ std::optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
|
|||||||
*Result.SourceManager);
|
*Result.SourceManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SourceRange>
|
static std::optional<SourceRange>
|
||||||
getTypeSpecifierLocation(const VarDecl *Var,
|
getTypeSpecifierLocation(const VarDecl *Var,
|
||||||
const MatchFinder::MatchResult &Result) {
|
const MatchFinder::MatchResult &Result) {
|
||||||
SourceRange TypeSpecifier(
|
SourceRange TypeSpecifier(
|
||||||
@ -73,8 +76,8 @@ getTypeSpecifierLocation(const VarDecl *Var,
|
|||||||
return TypeSpecifier;
|
return TypeSpecifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
|
static std::optional<SourceRange>
|
||||||
const Token &ConstToken) {
|
mergeReplacementRange(SourceRange &TypeSpecifier, const Token &ConstToken) {
|
||||||
if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
|
if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
|
||||||
TypeSpecifier.setBegin(ConstToken.getLocation());
|
TypeSpecifier.setBegin(ConstToken.getLocation());
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -86,21 +89,19 @@ std::optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
|
|||||||
return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
|
return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPointerConst(QualType QType) {
|
static bool isPointerConst(QualType QType) {
|
||||||
QualType Pointee = QType->getPointeeType();
|
QualType Pointee = QType->getPointeeType();
|
||||||
assert(!Pointee.isNull() && "can't have a null Pointee");
|
assert(!Pointee.isNull() && "can't have a null Pointee");
|
||||||
return Pointee.isConstQualified();
|
return Pointee.isConstQualified();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAutoPointerConst(QualType QType) {
|
static bool isAutoPointerConst(QualType QType) {
|
||||||
QualType Pointee =
|
QualType Pointee =
|
||||||
cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar();
|
cast<AutoType>(QType->getPointeeType().getTypePtr())->desugar();
|
||||||
assert(!Pointee.isNull() && "can't have a null Pointee");
|
assert(!Pointee.isNull() && "can't have a null Pointee");
|
||||||
return Pointee.isConstQualified();
|
return Pointee.isConstQualified();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
|
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
|
||||||
ClangTidyContext *Context)
|
ClangTidyContext *Context)
|
||||||
: ClangTidyCheck(Name, Context),
|
: ClangTidyCheck(Name, Context),
|
||||||
|
@ -14,19 +14,18 @@ using namespace clang::ast_matchers;
|
|||||||
|
|
||||||
namespace clang::tidy::readability {
|
namespace clang::tidy::readability {
|
||||||
|
|
||||||
namespace {
|
static const char *const RedundantReturnDiag =
|
||||||
|
"redundant return statement at the end "
|
||||||
|
"of a function with a void return type";
|
||||||
|
static const char *const RedundantContinueDiag =
|
||||||
|
"redundant continue statement at the "
|
||||||
|
"end of loop statement";
|
||||||
|
|
||||||
const char *const RedundantReturnDiag = "redundant return statement at the end "
|
static bool isLocationInMacroExpansion(const SourceManager &SM,
|
||||||
"of a function with a void return type";
|
SourceLocation Loc) {
|
||||||
const char *const RedundantContinueDiag = "redundant continue statement at the "
|
|
||||||
"end of loop statement";
|
|
||||||
|
|
||||||
bool isLocationInMacroExpansion(const SourceManager &SM, SourceLocation Loc) {
|
|
||||||
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
|
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
|
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(
|
||||||
functionDecl(isDefinition(), returns(voidType()),
|
functionDecl(isDefinition(), returns(voidType()),
|
||||||
|
@ -13,16 +13,14 @@
|
|||||||
|
|
||||||
namespace clang::tidy::utils::type_traits {
|
namespace clang::tidy::utils::type_traits {
|
||||||
|
|
||||||
namespace {
|
static bool classHasTrivialCopyAndDestroy(QualType Type) {
|
||||||
|
|
||||||
bool classHasTrivialCopyAndDestroy(QualType Type) {
|
|
||||||
auto *Record = Type->getAsCXXRecordDecl();
|
auto *Record = Type->getAsCXXRecordDecl();
|
||||||
return Record && Record->hasDefinition() &&
|
return Record && Record->hasDefinition() &&
|
||||||
!Record->hasNonTrivialCopyConstructor() &&
|
!Record->hasNonTrivialCopyConstructor() &&
|
||||||
!Record->hasNonTrivialDestructor();
|
!Record->hasNonTrivialDestructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasDeletedCopyConstructor(QualType Type) {
|
static bool hasDeletedCopyConstructor(QualType Type) {
|
||||||
auto *Record = Type->getAsCXXRecordDecl();
|
auto *Record = Type->getAsCXXRecordDecl();
|
||||||
if (!Record || !Record->hasDefinition())
|
if (!Record || !Record->hasDefinition())
|
||||||
return false;
|
return false;
|
||||||
@ -33,8 +31,6 @@ bool hasDeletedCopyConstructor(QualType Type) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
std::optional<bool> isExpensiveToCopy(QualType Type,
|
std::optional<bool> isExpensiveToCopy(QualType Type,
|
||||||
const ASTContext &Context) {
|
const ASTContext &Context) {
|
||||||
if (Type->isDependentType() || Type->isIncompleteType())
|
if (Type->isDependentType() || Type->isIncompleteType())
|
||||||
|
@ -215,7 +215,8 @@ Changes in existing checks
|
|||||||
|
|
||||||
- Improved :doc:`readability-identifier-naming
|
- Improved :doc:`readability-identifier-naming
|
||||||
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
|
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
|
||||||
declarations in system headers.
|
declarations in system headers. The documentation is also improved to
|
||||||
|
differentiate the general options from the specific ones.
|
||||||
|
|
||||||
- Improved :doc:`readability-qualified-auto
|
- Improved :doc:`readability-qualified-auto
|
||||||
<clang-tidy/checks/readability/qualified-auto>` check by adding the option
|
<clang-tidy/checks/readability/qualified-auto>` check by adding the option
|
||||||
|
@ -43,14 +43,21 @@ The options and their corresponding values are:
|
|||||||
- ``LowerCase`` - example: ``int i_Variable``
|
- ``LowerCase`` - example: ``int i_Variable``
|
||||||
- ``CamelCase`` - example: ``int IVariable``
|
- ``CamelCase`` - example: ``int IVariable``
|
||||||
|
|
||||||
Options
|
Options summary
|
||||||
-------
|
---------------
|
||||||
|
|
||||||
The following options are described below:
|
The available options are summarized below:
|
||||||
|
|
||||||
|
**General options**
|
||||||
|
|
||||||
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
|
|
||||||
- :option:`AggressiveDependentMemberLookup`
|
- :option:`AggressiveDependentMemberLookup`
|
||||||
- :option:`CheckAnonFieldInParent`
|
- :option:`CheckAnonFieldInParent`
|
||||||
|
- :option:`GetConfigPerFile`
|
||||||
|
- :option:`IgnoreMainLikeFunctions`
|
||||||
|
|
||||||
|
**Specific options**
|
||||||
|
|
||||||
|
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
|
||||||
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
|
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
|
||||||
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
|
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
|
||||||
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
|
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
|
||||||
@ -66,13 +73,11 @@ The following options are described below:
|
|||||||
- :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp`
|
- :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix`, :option:`EnumIgnoredRegexp`
|
||||||
- :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix`
|
- :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix`, :option:`EnumConstantIgnoredRegexp`, :option:`EnumConstantHungarianPrefix`
|
||||||
- :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp`
|
- :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix`, :option:`FunctionIgnoredRegexp`
|
||||||
- :option:`GetConfigPerFile`
|
|
||||||
- :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix`
|
- :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix`, :option:`GlobalConstantIgnoredRegexp`, :option:`GlobalConstantHungarianPrefix`
|
||||||
- :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix`
|
- :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix`, :option:`GlobalConstantPointerIgnoredRegexp`, :option:`GlobalConstantPointerHungarianPrefix`
|
||||||
- :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp`
|
- :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix`, :option:`GlobalFunctionIgnoredRegexp`
|
||||||
- :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix`
|
- :option:`GlobalPointerCase`, :option:`GlobalPointerPrefix`, :option:`GlobalPointerSuffix`, :option:`GlobalPointerIgnoredRegexp`, :option:`GlobalPointerHungarianPrefix`
|
||||||
- :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix`
|
- :option:`GlobalVariableCase`, :option:`GlobalVariablePrefix`, :option:`GlobalVariableSuffix`, :option:`GlobalVariableIgnoredRegexp`, :option:`GlobalVariableHungarianPrefix`
|
||||||
- :option:`IgnoreMainLikeFunctions`
|
|
||||||
- :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp`
|
- :option:`InlineNamespaceCase`, :option:`InlineNamespacePrefix`, :option:`InlineNamespaceSuffix`, :option:`InlineNamespaceIgnoredRegexp`
|
||||||
- :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix`
|
- :option:`LocalConstantCase`, :option:`LocalConstantPrefix`, :option:`LocalConstantSuffix`, :option:`LocalConstantIgnoredRegexp`, :option:`LocalConstantHungarianPrefix`
|
||||||
- :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix`
|
- :option:`LocalConstantPointerCase`, :option:`LocalConstantPointerPrefix`, :option:`LocalConstantPointerSuffix`, :option:`LocalConstantPointerIgnoredRegexp`, :option:`LocalConstantPointerHungarianPrefix`
|
||||||
@ -105,6 +110,12 @@ The following options are described below:
|
|||||||
- :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix`
|
- :option:`VariableCase`, :option:`VariablePrefix`, :option:`VariableSuffix`, :option:`VariableIgnoredRegexp`, :option:`VariableHungarianPrefix`
|
||||||
- :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp`
|
- :option:`VirtualMethodCase`, :option:`VirtualMethodPrefix`, :option:`VirtualMethodSuffix`, :option:`VirtualMethodIgnoredRegexp`
|
||||||
|
|
||||||
|
|
||||||
|
Options description
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
A detailed description of each option is presented below:
|
||||||
|
|
||||||
.. option:: AbstractClassCase
|
.. option:: AbstractClassCase
|
||||||
|
|
||||||
When defined, the check will ensure abstract class names conform to the
|
When defined, the check will ensure abstract class names conform to the
|
||||||
|
@ -9,14 +9,14 @@ Introduction
|
|||||||
============
|
============
|
||||||
|
|
||||||
Coroutines in C++ were introduced in C++20, and the user experience for
|
Coroutines in C++ were introduced in C++20, and the user experience for
|
||||||
debugging them can still be challenging. This document guides you how to most
|
debugging them can still be challenging. This document guides you on how to most
|
||||||
efficiently debug coroutines and how to navigate existing shortcomings in
|
efficiently debug coroutines and how to navigate existing shortcomings in
|
||||||
debuggers and compilers.
|
debuggers and compilers.
|
||||||
|
|
||||||
Coroutines are generally used either as generators or for asynchronous
|
Coroutines are generally used either as generators or for asynchronous
|
||||||
programming. In this document, we will discuss both use cases. Even if you are
|
programming. In this document, we will discuss both use cases. Even if you are
|
||||||
using coroutines for asynchronous programming, you should still read the
|
using coroutines for asynchronous programming, you should still read the
|
||||||
generators section, as it will introduce foundational debugging techniques also
|
generators section, as it introduces foundational debugging techniques also
|
||||||
applicable to the debugging of asynchronous programs.
|
applicable to the debugging of asynchronous programs.
|
||||||
|
|
||||||
Both compilers (clang, gcc, ...) and debuggers (lldb, gdb, ...) are
|
Both compilers (clang, gcc, ...) and debuggers (lldb, gdb, ...) are
|
||||||
@ -34,15 +34,15 @@ scripting. This guide comes with a basic GDB script for coroutine debugging.
|
|||||||
This guide will first showcase the more polished, bleeding-edge experience, but
|
This guide will first showcase the more polished, bleeding-edge experience, but
|
||||||
will also show you how to debug coroutines with older toolchains. In general,
|
will also show you how to debug coroutines with older toolchains. In general,
|
||||||
the older your toolchain, the deeper you will have to dive into the
|
the older your toolchain, the deeper you will have to dive into the
|
||||||
implementation details of coroutines (such as their ABI). The further down in
|
implementation details of coroutines (such as their ABI). The further down you go in
|
||||||
this document you go, the more low-level, technical the content will become. If
|
this document, the more low-level, technical the content will become. If
|
||||||
you are on an up-to-date toolchain, you will hopefully be able to stop reading
|
you are on an up-to-date toolchain, you will hopefully be able to stop reading
|
||||||
earlier.
|
earlier.
|
||||||
|
|
||||||
Debugging generators
|
Debugging generators
|
||||||
====================
|
====================
|
||||||
|
|
||||||
One of the two major use cases for coroutines in C++ are generators, i.e.,
|
One of the two major use cases for coroutines in C++ is generators, i.e.,
|
||||||
functions which can produce values via ``co_yield``. Values are produced
|
functions which can produce values via ``co_yield``. Values are produced
|
||||||
lazily, on-demand. For this purpose, every time a new value is requested, the
|
lazily, on-demand. For this purpose, every time a new value is requested, the
|
||||||
coroutine gets resumed. As soon as it reaches a ``co_yield`` and thereby
|
coroutine gets resumed. As soon as it reaches a ``co_yield`` and thereby
|
||||||
@ -141,7 +141,7 @@ a regular function.
|
|||||||
|
|
||||||
Note the two additional variables ``__promise`` and ``__coro_frame``. Those
|
Note the two additional variables ``__promise`` and ``__coro_frame``. Those
|
||||||
show the internal state of the coroutine. They are not relevant for our
|
show the internal state of the coroutine. They are not relevant for our
|
||||||
generator example, but will be relevant for asynchronous programming described
|
generator example but will be relevant for asynchronous programming described
|
||||||
in the next section.
|
in the next section.
|
||||||
|
|
||||||
Stepping out of a coroutine
|
Stepping out of a coroutine
|
||||||
@ -174,7 +174,7 @@ Inspecting a suspended coroutine
|
|||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
The ``print10Elements`` function receives an opaque ``generator`` type. Let's
|
The ``print10Elements`` function receives an opaque ``generator`` type. Let's
|
||||||
assume we are suspended at the ``++gen;`` line, and want to inspect the
|
assume we are suspended at the ``++gen;`` line and want to inspect the
|
||||||
generator and its internal state.
|
generator and its internal state.
|
||||||
|
|
||||||
To do so, we can simply look into the ``gen.hdl`` variable. LLDB comes with a
|
To do so, we can simply look into the ``gen.hdl`` variable. LLDB comes with a
|
||||||
@ -188,7 +188,7 @@ We can see two function pointers ``resume`` and ``destroy``. These pointers
|
|||||||
point to the resume / destroy functions. By inspecting those function pointers,
|
point to the resume / destroy functions. By inspecting those function pointers,
|
||||||
we can see that our ``generator`` is actually backed by our ``fibonacci``
|
we can see that our ``generator`` is actually backed by our ``fibonacci``
|
||||||
coroutine. When using VS Code + lldb-dap, you can Cmd+Click on the function
|
coroutine. When using VS Code + lldb-dap, you can Cmd+Click on the function
|
||||||
address (``0x555...`` in the screenshot) to directly jump to the function
|
address (``0x555...`` in the screenshot) to jump directly to the function
|
||||||
definition backing your coroutine handle.
|
definition backing your coroutine handle.
|
||||||
|
|
||||||
Next, we see the ``promise``. In our case, this reveals the current value of
|
Next, we see the ``promise``. In our case, this reveals the current value of
|
||||||
@ -247,12 +247,12 @@ the line number of the current suspension point in the promise:
|
|||||||
};
|
};
|
||||||
|
|
||||||
This stores the return address of ``await_suspend`` within the promise.
|
This stores the return address of ``await_suspend`` within the promise.
|
||||||
Thereby, we can read it back from the promise of a suspended coroutine, and map
|
Thereby, we can read it back from the promise of a suspended coroutine and map
|
||||||
it to an exact source code location. For a complete example, see the ``task``
|
it to an exact source code location. For a complete example, see the ``task``
|
||||||
type used below for asynchronous programming.
|
type used below for asynchronous programming.
|
||||||
|
|
||||||
Alternatively, we can modify the C++ code to store the line number in the
|
Alternatively, we can modify the C++ code to store the line number in the
|
||||||
promise type. We can use a ``std::source_location`` to get the line number of
|
promise type. We can use ``std::source_location`` to get the line number of
|
||||||
the await and store it inside the ``promise_type``. In the debugger, we can
|
the await and store it inside the ``promise_type``. In the debugger, we can
|
||||||
then read the line number from the promise of the suspended coroutine.
|
then read the line number from the promise of the suspended coroutine.
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ then read the line number from the promise of the suspended coroutine.
|
|||||||
};
|
};
|
||||||
|
|
||||||
The downside of both approaches is that they come at the price of additional
|
The downside of both approaches is that they come at the price of additional
|
||||||
runtime cost. In particular the second approach increases binary size, since it
|
runtime cost. In particular, the second approach increases binary size, since it
|
||||||
requires additional ``std::source_location`` objects, and those source
|
requires additional ``std::source_location`` objects, and those source
|
||||||
locations are not stripped by split-dwarf. Whether the first approach is worth
|
locations are not stripped by split-dwarf. Whether the first approach is worth
|
||||||
the additional runtime cost is a trade-off you need to make yourself.
|
the additional runtime cost is a trade-off you need to make yourself.
|
||||||
@ -285,7 +285,7 @@ provide custom debugging support, so in addition to this guide, you might want
|
|||||||
to check out their documentation.
|
to check out their documentation.
|
||||||
|
|
||||||
When using coroutines for asynchronous programming, your library usually
|
When using coroutines for asynchronous programming, your library usually
|
||||||
provides you some ``task`` type. This type usually looks similar to this:
|
provides you with some ``task`` type. This type usually looks similar to this:
|
||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ One such solution is to store the list of in-flight coroutines in a collection:
|
|||||||
};
|
};
|
||||||
|
|
||||||
With this in place, it is possible to inspect ``inflight_coroutines`` from the
|
With this in place, it is possible to inspect ``inflight_coroutines`` from the
|
||||||
debugger, and rely on LLDB's ``std::coroutine_handle`` pretty-printer to
|
debugger and rely on LLDB's ``std::coroutine_handle`` pretty-printer to
|
||||||
inspect the coroutines.
|
inspect the coroutines.
|
||||||
|
|
||||||
This technique will track *all* coroutines, also the ones which are currently
|
This technique will track *all* coroutines, also the ones which are currently
|
||||||
@ -498,8 +498,8 @@ LLDB before 21.0 did not yet show the ``__coro_frame`` inside
|
|||||||
``coroutine_handle``. To inspect the coroutine frame, you had to use the
|
``coroutine_handle``. To inspect the coroutine frame, you had to use the
|
||||||
approach described in the :ref:`devirtualization` section.
|
approach described in the :ref:`devirtualization` section.
|
||||||
|
|
||||||
LLDB before 18.0 was hiding the ``__promise`` and ``__coro_frame``
|
LLDB before 18.0 hid the ``__promise`` and ``__coro_frame``
|
||||||
variable by default. The variables are still present, but they need to be
|
variables by default. The variables are still present, but they need to be
|
||||||
explicitly added to the "watch" pane in VS Code or requested via
|
explicitly added to the "watch" pane in VS Code or requested via
|
||||||
``print __promise`` and ``print __coro_frame`` from the debugger console.
|
``print __promise`` and ``print __coro_frame`` from the debugger console.
|
||||||
|
|
||||||
@ -511,9 +511,9 @@ section.
|
|||||||
Toolchain Implementation Details
|
Toolchain Implementation Details
|
||||||
================================
|
================================
|
||||||
|
|
||||||
This section covers the ABI, as well as additional compiler-specific behavior.
|
This section covers the ABI as well as additional compiler-specific behavior.
|
||||||
The ABI is followed by all compilers, on all major systems, including Windows,
|
The ABI is followed by all compilers, on all major systems, including Windows,
|
||||||
Linux and macOS. Different compilers emit different debug information, though.
|
Linux, and macOS. Different compilers emit different debug information, though.
|
||||||
|
|
||||||
Ramp, resume and destroy functions
|
Ramp, resume and destroy functions
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@ -595,7 +595,7 @@ functions as their first two members. As such, we can read the function
|
|||||||
pointers from the coroutine frame and then obtain the function's name from its
|
pointers from the coroutine frame and then obtain the function's name from its
|
||||||
address.
|
address.
|
||||||
|
|
||||||
The promise is guaranteed to be at a 16 byte offset from the coroutine frame.
|
The promise is guaranteed to be at a 16-byte offset from the coroutine frame.
|
||||||
If we have a coroutine handle at address 0x416eb0, we can hence reinterpret-cast
|
If we have a coroutine handle at address 0x416eb0, we can hence reinterpret-cast
|
||||||
the promise as follows:
|
the promise as follows:
|
||||||
|
|
||||||
@ -607,8 +607,8 @@ Implementation in clang / LLVM
|
|||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
The C++ Coroutines feature in the Clang compiler is implemented in two parts of
|
The C++ Coroutines feature in the Clang compiler is implemented in two parts of
|
||||||
the compiler. Semantic analysis is performed in Clang, and Coroutine
|
the compiler. Semantic analysis is performed in Clang, and coroutine
|
||||||
construction and optimization takes place in the LLVM middle-end.
|
construction and optimization take place in the LLVM middle-end.
|
||||||
|
|
||||||
For each coroutine function, the frontend generates a single corresponding
|
For each coroutine function, the frontend generates a single corresponding
|
||||||
LLVM-IR function. This function uses special ``llvm.coro.suspend`` intrinsics
|
LLVM-IR function. This function uses special ``llvm.coro.suspend`` intrinsics
|
||||||
@ -622,7 +622,7 @@ points into the coroutine frame. Most of the heavy lifting to preserve debugging
|
|||||||
information is done in this pass. This pass needs to rewrite all variable
|
information is done in this pass. This pass needs to rewrite all variable
|
||||||
locations to point into the coroutine frame.
|
locations to point into the coroutine frame.
|
||||||
|
|
||||||
Afterwards, a couple of additional optimizations are applied, before code
|
Afterwards, a couple of additional optimizations are applied before code
|
||||||
gets emitted, but none of them are really interesting regarding debugging
|
gets emitted, but none of them are really interesting regarding debugging
|
||||||
information.
|
information.
|
||||||
|
|
||||||
@ -636,8 +636,8 @@ However, this is not possible for coroutine frames because the frames are
|
|||||||
constructed in the LLVM middle-end.
|
constructed in the LLVM middle-end.
|
||||||
|
|
||||||
To mitigate this problem, the LLVM middle end attempts to generate some debug
|
To mitigate this problem, the LLVM middle end attempts to generate some debug
|
||||||
information, which is unfortunately incomplete, since much of the language
|
information, which is unfortunately incomplete, since much of the
|
||||||
specific information is missing in the middle end.
|
language-specific information is missing in the middle end.
|
||||||
|
|
||||||
.. _devirtualization:
|
.. _devirtualization:
|
||||||
|
|
||||||
@ -655,7 +655,7 @@ There are two possible approaches to do so:
|
|||||||
We can lookup their types and thereby get the types of promise
|
We can lookup their types and thereby get the types of promise
|
||||||
and coroutine frame.
|
and coroutine frame.
|
||||||
|
|
||||||
In gdb, one can use the following approach to devirtualize coroutine type,
|
In gdb, one can use the following approach to devirtualize a coroutine type,
|
||||||
assuming we have a ``std::coroutine_handle`` is at address 0x418eb0:
|
assuming we have a ``std::coroutine_handle`` is at address 0x418eb0:
|
||||||
|
|
||||||
::
|
::
|
||||||
@ -679,7 +679,7 @@ LLDB comes with devirtualization support out of the box, as part of the
|
|||||||
pretty-printer for ``std::coroutine_handle``. Internally, this pretty-printer
|
pretty-printer for ``std::coroutine_handle``. Internally, this pretty-printer
|
||||||
uses the second approach. We look up the types in the destroy function and not
|
uses the second approach. We look up the types in the destroy function and not
|
||||||
the resume function because the resume function pointer will be set to a
|
the resume function because the resume function pointer will be set to a
|
||||||
nullptr as soon as a coroutine reaches its final suspension point. If we used
|
``nullptr`` as soon as a coroutine reaches its final suspension point. If we used
|
||||||
the resume function, devirtualization would hence fail for all coroutines that
|
the resume function, devirtualization would hence fail for all coroutines that
|
||||||
have reached their final suspension point.
|
have reached their final suspension point.
|
||||||
|
|
||||||
@ -687,10 +687,10 @@ Interpreting the coroutine frame in optimized builds
|
|||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
The ``__coro_frame`` variable usually refers to the coroutine frame of an
|
The ``__coro_frame`` variable usually refers to the coroutine frame of an
|
||||||
*in-flight* coroutine. This means, the coroutine is currently executing.
|
*in-flight* coroutine. This means the coroutine is currently executing.
|
||||||
However, the compiler only guarantees the coroutine frame to be in a consistent
|
However, the compiler only guarantees the coroutine frame to be in a consistent
|
||||||
state while the coroutine is suspended. As such, the variables inside the
|
state while the coroutine is suspended. As such, the variables inside the
|
||||||
``__coro_frame`` variable might be outdated, in particular when optimizations
|
``__coro_frame`` variable might be outdated, particularly when optimizations
|
||||||
are enabled.
|
are enabled.
|
||||||
|
|
||||||
Furthermore, when optimizations are enabled, the compiler will layout the
|
Furthermore, when optimizations are enabled, the compiler will layout the
|
||||||
@ -731,7 +731,7 @@ despite ``a`` being frequently incremented.
|
|||||||
|
|
||||||
While this might be surprising, this is a result of the optimizer recognizing
|
While this might be surprising, this is a result of the optimizer recognizing
|
||||||
that it can eliminate most of the load/store operations.
|
that it can eliminate most of the load/store operations.
|
||||||
The above code gets optimized to the equivalent of:
|
The above code is optimized to the equivalent of:
|
||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
@ -1180,5 +1180,5 @@ The authors of the Folly libraries wrote a blog post series on how they debug co
|
|||||||
* `Async stack traces in folly: Improving debugging in the developer lifecycle <https://developers.facebook.com/blog/post/2021/10/21/async-stack-traces-folly-improving-debugging-developer-lifecycle/>`_
|
* `Async stack traces in folly: Improving debugging in the developer lifecycle <https://developers.facebook.com/blog/post/2021/10/21/async-stack-traces-folly-improving-debugging-developer-lifecycle/>`_
|
||||||
|
|
||||||
Besides some topics also covered here (stack traces from the debugger), Folly's blog post series also covers
|
Besides some topics also covered here (stack traces from the debugger), Folly's blog post series also covers
|
||||||
more additional topics, such as capturing async stack traces in performance profiles via eBPF filters
|
additional topics, such as capturing async stack traces in performance profiles via eBPF filters
|
||||||
and printing async stack traces on crashes.
|
and printing async stack traces on crashes.
|
||||||
|
@ -37,6 +37,22 @@ latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the
|
|||||||
Potentially Breaking Changes
|
Potentially Breaking Changes
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
- Clang will now emit a warning if the auto-detected GCC installation
|
||||||
|
directory (i.e. the one with the largest version number) does not
|
||||||
|
contain libstdc++ include directories although a "complete" GCC
|
||||||
|
installation directory containing the include directories is
|
||||||
|
available. It is planned to change the auto-detection to prefer the
|
||||||
|
"complete" directory in the future. The warning will disappear if
|
||||||
|
the libstdc++ include directories are either installed or removed
|
||||||
|
for all GCC installation directories considered by the
|
||||||
|
auto-detection; see the output of ``clang -v`` for a list of those
|
||||||
|
directories. If the GCC installations cannot be modified and
|
||||||
|
maintaining the current choice of the auto-detection is desired, the
|
||||||
|
GCC installation directory can be selected explicitly using the
|
||||||
|
``--gcc-install-dir`` command line argument. This will silence the
|
||||||
|
warning. It can also be disabled using the
|
||||||
|
``-Wno-gcc-install-dir-libstdcxx`` command line flag.
|
||||||
|
|
||||||
C/C++ Language Potentially Breaking Changes
|
C/C++ Language Potentially Breaking Changes
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
@ -229,6 +245,7 @@ Bug Fixes in This Version
|
|||||||
cast chain. (#GH149967).
|
cast chain. (#GH149967).
|
||||||
- Fixed a crash with incompatible pointer to integer conversions in designated
|
- Fixed a crash with incompatible pointer to integer conversions in designated
|
||||||
initializers involving string literals. (#GH154046)
|
initializers involving string literals. (#GH154046)
|
||||||
|
- Fixed scope of typedefs present inside a template class. (#GH91451)
|
||||||
|
|
||||||
Bug Fixes to Compiler Builtins
|
Bug Fixes to Compiler Builtins
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -292,6 +309,13 @@ NVPTX Support
|
|||||||
|
|
||||||
X86 Support
|
X86 Support
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
|
- More SSE, AVX and AVX512 intrinsics, including initializers and general
|
||||||
|
arithmetic can now be used in C++ constant expressions.
|
||||||
|
- Some SSE, AVX and AVX512 intrinsics have been converted to wrap
|
||||||
|
generic __builtin intrinsics.
|
||||||
|
- NOTE: Please avoid use of the __builtin_ia32_* intrinsics - these are not
|
||||||
|
guaranteed to exist in future releases, or match behaviour with previous
|
||||||
|
releases of clang or other compilers.
|
||||||
|
|
||||||
Arm and AArch64 Support
|
Arm and AArch64 Support
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -23,20 +23,20 @@
|
|||||||
#include "clang/Basic/DiagnosticInstallAPI.h"
|
#include "clang/Basic/DiagnosticInstallAPI.h"
|
||||||
#include "clang/Basic/DiagnosticLex.h"
|
#include "clang/Basic/DiagnosticLex.h"
|
||||||
#include "clang/Basic/DiagnosticParse.h"
|
#include "clang/Basic/DiagnosticParse.h"
|
||||||
|
#include "clang/Basic/DiagnosticRefactoring.h"
|
||||||
#include "clang/Basic/DiagnosticSema.h"
|
#include "clang/Basic/DiagnosticSema.h"
|
||||||
#include "clang/Basic/DiagnosticSerialization.h"
|
#include "clang/Basic/DiagnosticSerialization.h"
|
||||||
#include "clang/Basic/DiagnosticRefactoring.h"
|
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
template <size_t SizeOfStr, typename FieldType>
|
template <size_t SizeOfStr, typename FieldType> class StringSizerHelper {
|
||||||
class StringSizerHelper {
|
|
||||||
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
|
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { Size = SizeOfStr };
|
enum { Size = SizeOfStr };
|
||||||
};
|
};
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \
|
#define STR_SIZE(str, fieldTy) \
|
||||||
fieldTy>::Size
|
clang::StringSizerHelper<sizeof(str) - 1, fieldTy>::Size
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -627,11 +627,23 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
|
|||||||
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
|
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
|
||||||
def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
|
|
||||||
def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">;
|
def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">;
|
||||||
def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
|
def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
|
||||||
|
|
||||||
|
def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
|
def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
|
def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
||||||
|
def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
||||||
|
def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
|
||||||
|
def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||||
|
def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||||
|
def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
||||||
|
def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
||||||
|
def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
|
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
|
||||||
@ -654,46 +666,6 @@ let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
|
|||||||
def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">;
|
def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
|
||||||
def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
|
||||||
def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
|
||||||
def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
|
||||||
def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
|
||||||
def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
|
||||||
def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
|
||||||
def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
|
||||||
def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
|
|
||||||
def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
|
|
||||||
def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
|
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
|
||||||
def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
|
def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
|
||||||
}
|
}
|
||||||
|
@ -885,4 +885,9 @@ def warn_drv_openacc_without_cir
|
|||||||
: Warning<"OpenACC directives will result in no runtime behavior; use "
|
: Warning<"OpenACC directives will result in no runtime behavior; use "
|
||||||
"-fclangir to enable runtime effect">,
|
"-fclangir to enable runtime effect">,
|
||||||
InGroup<SourceUsesOpenACC>;
|
InGroup<SourceUsesOpenACC>;
|
||||||
|
|
||||||
|
def warn_drv_gcc_install_dir_libstdcxx : Warning<
|
||||||
|
"future releases of the clang compiler will prefer GCC installations "
|
||||||
|
"containing libstdc++ include directories; '%0' would be chosen over '%1'">,
|
||||||
|
InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;
|
||||||
}
|
}
|
||||||
|
@ -23,76 +23,78 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class DiagnosticsEngine;
|
class DiagnosticsEngine;
|
||||||
class DiagnosticBuilder;
|
class DiagnosticBuilder;
|
||||||
class LangOptions;
|
class LangOptions;
|
||||||
class SourceLocation;
|
class SourceLocation;
|
||||||
|
|
||||||
// Import the diagnostic enums themselves.
|
// Import the diagnostic enums themselves.
|
||||||
namespace diag {
|
namespace diag {
|
||||||
enum class Group;
|
enum class Group;
|
||||||
|
|
||||||
// Size of each of the diagnostic categories.
|
// Size of each of the diagnostic categories.
|
||||||
enum {
|
enum {
|
||||||
DIAG_SIZE_COMMON = 300,
|
DIAG_SIZE_COMMON = 300,
|
||||||
DIAG_SIZE_DRIVER = 400,
|
DIAG_SIZE_DRIVER = 400,
|
||||||
DIAG_SIZE_FRONTEND = 200,
|
DIAG_SIZE_FRONTEND = 200,
|
||||||
DIAG_SIZE_SERIALIZATION = 120,
|
DIAG_SIZE_SERIALIZATION = 120,
|
||||||
DIAG_SIZE_LEX = 500,
|
DIAG_SIZE_LEX = 500,
|
||||||
DIAG_SIZE_PARSE = 800,
|
DIAG_SIZE_PARSE = 800,
|
||||||
DIAG_SIZE_AST = 300,
|
DIAG_SIZE_AST = 300,
|
||||||
DIAG_SIZE_COMMENT = 100,
|
DIAG_SIZE_COMMENT = 100,
|
||||||
DIAG_SIZE_CROSSTU = 100,
|
DIAG_SIZE_CROSSTU = 100,
|
||||||
DIAG_SIZE_SEMA = 5000,
|
DIAG_SIZE_SEMA = 5000,
|
||||||
DIAG_SIZE_ANALYSIS = 100,
|
DIAG_SIZE_ANALYSIS = 100,
|
||||||
DIAG_SIZE_REFACTORING = 1000,
|
DIAG_SIZE_REFACTORING = 1000,
|
||||||
DIAG_SIZE_INSTALLAPI = 100,
|
DIAG_SIZE_INSTALLAPI = 100,
|
||||||
};
|
};
|
||||||
// Start position for diagnostics.
|
// Start position for diagnostics.
|
||||||
enum {
|
// clang-format off
|
||||||
DIAG_START_COMMON = 0,
|
enum {
|
||||||
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
|
DIAG_START_COMMON = 0,
|
||||||
DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
|
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
|
||||||
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
|
DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
|
||||||
DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
|
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
|
||||||
DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
|
DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
|
||||||
DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
|
DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
|
||||||
DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
|
DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
|
||||||
DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
|
DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
|
||||||
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
|
DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
|
||||||
DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
|
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
|
||||||
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
|
DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
|
||||||
DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
|
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
|
||||||
DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
|
DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
|
||||||
};
|
DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
class CustomDiagInfo;
|
class CustomDiagInfo;
|
||||||
|
|
||||||
/// All of the diagnostics that can be emitted by the frontend.
|
/// All of the diagnostics that can be emitted by the frontend.
|
||||||
typedef unsigned kind;
|
typedef unsigned kind;
|
||||||
|
|
||||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||||
/// to either Ignore (nothing), Remark (emit a remark), Warning
|
/// to either Ignore (nothing), Remark (emit a remark), Warning
|
||||||
/// (emit a warning) or Error (emit as an error). It allows clients to
|
/// (emit a warning) or Error (emit as an error). It allows clients to
|
||||||
/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
|
/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
|
||||||
enum class Severity : uint8_t {
|
enum class Severity : uint8_t {
|
||||||
// NOTE: 0 means "uncomputed".
|
// NOTE: 0 means "uncomputed".
|
||||||
Ignored = 1, ///< Do not present this diagnostic, ignore it.
|
Ignored = 1, ///< Do not present this diagnostic, ignore it.
|
||||||
Remark = 2, ///< Present this diagnostic as a remark.
|
Remark = 2, ///< Present this diagnostic as a remark.
|
||||||
Warning = 3, ///< Present this diagnostic as a warning.
|
Warning = 3, ///< Present this diagnostic as a warning.
|
||||||
Error = 4, ///< Present this diagnostic as an error.
|
Error = 4, ///< Present this diagnostic as an error.
|
||||||
Fatal = 5 ///< Present this diagnostic as a fatal error.
|
Fatal = 5 ///< Present this diagnostic as a fatal error.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Flavors of diagnostics we can emit. Used to filter for a particular
|
/// Flavors of diagnostics we can emit. Used to filter for a particular
|
||||||
/// kind of diagnostic (for instance, for -W/-R flags).
|
/// kind of diagnostic (for instance, for -W/-R flags).
|
||||||
enum class Flavor {
|
enum class Flavor {
|
||||||
WarningOrError, ///< A diagnostic that indicates a problem or potential
|
WarningOrError, ///< A diagnostic that indicates a problem or potential
|
||||||
///< problem. Can be made fatal by -Werror.
|
///< problem. Can be made fatal by -Werror.
|
||||||
Remark ///< A diagnostic that indicates normal progress through
|
Remark ///< A diagnostic that indicates normal progress through
|
||||||
///< compilation.
|
///< compilation.
|
||||||
};
|
};
|
||||||
} // end namespace diag
|
} // end namespace diag
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
// This has to be included *after* the DIAG_START_ enums above are defined.
|
// This has to be included *after* the DIAG_START_ enums above are defined.
|
||||||
@ -173,7 +175,8 @@ public:
|
|||||||
|
|
||||||
/// Used for handling and querying diagnostic IDs.
|
/// Used for handling and querying diagnostic IDs.
|
||||||
///
|
///
|
||||||
/// Can be used and shared by multiple Diagnostics for multiple translation units.
|
/// Can be used and shared by multiple Diagnostics for multiple translation
|
||||||
|
/// units.
|
||||||
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
|
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
|
||||||
public:
|
public:
|
||||||
/// The level of the diagnostic, after it has been through mapping.
|
/// The level of the diagnostic, after it has been through mapping.
|
||||||
@ -498,6 +501,6 @@ private:
|
|||||||
friend class DiagnosticsEngine;
|
friend class DiagnosticsEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
class AttrBuilder;
|
class AttrBuilder;
|
||||||
class Constant;
|
class Constant;
|
||||||
|
class ConstantInt;
|
||||||
class Function;
|
class Function;
|
||||||
class FunctionType;
|
class FunctionType;
|
||||||
class Type;
|
class Type;
|
||||||
@ -126,6 +127,12 @@ uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD);
|
|||||||
uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
|
uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
|
||||||
QualType FunctionType);
|
QualType FunctionType);
|
||||||
|
|
||||||
|
/// Return a signed constant pointer.
|
||||||
|
llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM,
|
||||||
|
llvm::Constant *Pointer, unsigned Key,
|
||||||
|
llvm::Constant *StorageAddress,
|
||||||
|
llvm::ConstantInt *OtherDiscriminator);
|
||||||
|
|
||||||
/// Given the language and code-generation options that Clang was configured
|
/// Given the language and code-generation options that Clang was configured
|
||||||
/// with, set the default LLVM IR attributes for a function definition.
|
/// with, set the default LLVM IR attributes for a function definition.
|
||||||
/// The attributes set here are mostly global target-configuration and
|
/// The attributes set here are mostly global target-configuration and
|
||||||
|
@ -224,9 +224,6 @@ protected:
|
|||||||
static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
|
static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
|
||||||
llvm::opt::ArgStringList &CC1Args,
|
llvm::opt::ArgStringList &CC1Args,
|
||||||
const Twine &Path);
|
const Twine &Path);
|
||||||
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
|
|
||||||
llvm::opt::ArgStringList &CC1Args,
|
|
||||||
const Twine &Path);
|
|
||||||
static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs,
|
static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs,
|
||||||
llvm::opt::ArgStringList &CC1Args,
|
llvm::opt::ArgStringList &CC1Args,
|
||||||
const Twine &Path);
|
const Twine &Path);
|
||||||
@ -246,6 +243,9 @@ protected:
|
|||||||
///@}
|
///@}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
|
||||||
|
llvm::opt::ArgStringList &CC1Args,
|
||||||
|
const Twine &Path);
|
||||||
virtual ~ToolChain();
|
virtual ~ToolChain();
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
|
@ -341,6 +341,8 @@ public:
|
|||||||
QualType getType() const {
|
QualType getType() const {
|
||||||
if (isTypeidPointer())
|
if (isTypeidPointer())
|
||||||
return QualType(Typeid.TypeInfoType, 0);
|
return QualType(Typeid.TypeInfoType, 0);
|
||||||
|
if (isFunctionPointer())
|
||||||
|
return asFunctionPointer().getFunction()->getDecl()->getType();
|
||||||
|
|
||||||
if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
|
if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
|
||||||
// Unfortunately, complex and vector types are not array types in clang,
|
// Unfortunately, complex and vector types are not array types in clang,
|
||||||
|
@ -11669,13 +11669,24 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
|||||||
case clang::X86::BI__builtin_ia32_pmulhuw512:
|
case clang::X86::BI__builtin_ia32_pmulhuw512:
|
||||||
case clang::X86::BI__builtin_ia32_pmulhw128:
|
case clang::X86::BI__builtin_ia32_pmulhw128:
|
||||||
case clang::X86::BI__builtin_ia32_pmulhw256:
|
case clang::X86::BI__builtin_ia32_pmulhw256:
|
||||||
case clang::X86::BI__builtin_ia32_pmulhw512: {
|
case clang::X86::BI__builtin_ia32_pmulhw512:
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv2di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv4di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv4si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv8si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrav4si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrav8si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv2di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv4di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv4si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv8si:{
|
||||||
APValue SourceLHS, SourceRHS;
|
APValue SourceLHS, SourceRHS;
|
||||||
if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
|
if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
|
||||||
!EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
|
!EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
|
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
|
||||||
|
bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType();
|
||||||
unsigned SourceLen = SourceLHS.getVectorLength();
|
unsigned SourceLen = SourceLHS.getVectorLength();
|
||||||
SmallVector<APValue, 4> ResultElements;
|
SmallVector<APValue, 4> ResultElements;
|
||||||
ResultElements.reserve(SourceLen);
|
ResultElements.reserve(SourceLen);
|
||||||
@ -11687,12 +11698,12 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
|||||||
case Builtin::BI__builtin_elementwise_add_sat:
|
case Builtin::BI__builtin_elementwise_add_sat:
|
||||||
ResultElements.push_back(APValue(
|
ResultElements.push_back(APValue(
|
||||||
APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS),
|
APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS),
|
||||||
DestEltTy->isUnsignedIntegerOrEnumerationType())));
|
DestUnsigned)));
|
||||||
break;
|
break;
|
||||||
case Builtin::BI__builtin_elementwise_sub_sat:
|
case Builtin::BI__builtin_elementwise_sub_sat:
|
||||||
ResultElements.push_back(APValue(
|
ResultElements.push_back(APValue(
|
||||||
APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS),
|
APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS),
|
||||||
DestEltTy->isUnsignedIntegerOrEnumerationType())));
|
DestUnsigned)));
|
||||||
break;
|
break;
|
||||||
case clang::X86::BI__builtin_ia32_pmulhuw128:
|
case clang::X86::BI__builtin_ia32_pmulhuw128:
|
||||||
case clang::X86::BI__builtin_ia32_pmulhuw256:
|
case clang::X86::BI__builtin_ia32_pmulhuw256:
|
||||||
@ -11706,6 +11717,40 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
|||||||
ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS),
|
ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS),
|
||||||
/*isUnsigned=*/false)));
|
/*isUnsigned=*/false)));
|
||||||
break;
|
break;
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv2di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv4di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv4si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psllv8si:
|
||||||
|
if (RHS.uge(RHS.getBitWidth())) {
|
||||||
|
ResultElements.push_back(
|
||||||
|
APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ResultElements.push_back(
|
||||||
|
APValue(APSInt(LHS.shl(RHS.getZExtValue()), DestUnsigned)));
|
||||||
|
break;
|
||||||
|
case clang::X86::BI__builtin_ia32_psrav4si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrav8si:
|
||||||
|
if (RHS.uge(RHS.getBitWidth())) {
|
||||||
|
ResultElements.push_back(
|
||||||
|
APValue(APSInt(LHS.ashr(RHS.getBitWidth() - 1), DestUnsigned)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ResultElements.push_back(
|
||||||
|
APValue(APSInt(LHS.ashr(RHS.getZExtValue()), DestUnsigned)));
|
||||||
|
break;
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv2di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv4di:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv4si:
|
||||||
|
case clang::X86::BI__builtin_ia32_psrlv8si:
|
||||||
|
if (RHS.uge(RHS.getBitWidth())) {
|
||||||
|
ResultElements.push_back(
|
||||||
|
APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ResultElements.push_back(
|
||||||
|
APValue(APSInt(LHS.lshr(RHS.getZExtValue()), DestUnsigned)));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +174,9 @@ protected:
|
|||||||
DefineStd(Builder, "unix", Opts);
|
DefineStd(Builder, "unix", Opts);
|
||||||
if (this->HasFloat128)
|
if (this->HasFloat128)
|
||||||
Builder.defineMacro("__FLOAT128__");
|
Builder.defineMacro("__FLOAT128__");
|
||||||
|
|
||||||
|
if (Opts.C11)
|
||||||
|
Builder.defineMacro("__STDC_NO_THREADS__");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -73,21 +73,54 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr,
|
|||||||
|
|
||||||
// Casts:
|
// Casts:
|
||||||
if (auto const *ce = dyn_cast<CastExpr>(expr)) {
|
if (auto const *ce = dyn_cast<CastExpr>(expr)) {
|
||||||
if (isa<ExplicitCastExpr>(ce)) {
|
if (const auto *ece = dyn_cast<ExplicitCastExpr>(ce))
|
||||||
cgm.errorNYI(expr->getSourceRange(),
|
cgm.emitExplicitCastExprType(ece);
|
||||||
"emitPointerWithAlignment: explicit cast");
|
|
||||||
return Address::invalid();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ce->getCastKind()) {
|
switch (ce->getCastKind()) {
|
||||||
// Non-converting casts (but not C's implicit conversion from void*).
|
// Non-converting casts (but not C's implicit conversion from void*).
|
||||||
case CK_BitCast:
|
case CK_BitCast:
|
||||||
case CK_NoOp:
|
case CK_NoOp:
|
||||||
case CK_AddressSpaceConversion: {
|
case CK_AddressSpaceConversion: {
|
||||||
cgm.errorNYI(expr->getSourceRange(),
|
if (const auto *ptrTy =
|
||||||
"emitPointerWithAlignment: noop cast");
|
ce->getSubExpr()->getType()->getAs<PointerType>()) {
|
||||||
return Address::invalid();
|
if (ptrTy->getPointeeType()->isVoidType())
|
||||||
} break;
|
break;
|
||||||
|
|
||||||
|
LValueBaseInfo innerBaseInfo;
|
||||||
|
assert(!cir::MissingFeatures::opTBAA());
|
||||||
|
Address addr =
|
||||||
|
emitPointerWithAlignment(ce->getSubExpr(), &innerBaseInfo);
|
||||||
|
if (baseInfo)
|
||||||
|
*baseInfo = innerBaseInfo;
|
||||||
|
|
||||||
|
if (isa<ExplicitCastExpr>(ce)) {
|
||||||
|
LValueBaseInfo targetTypeBaseInfo;
|
||||||
|
|
||||||
|
const QualType pointeeType = expr->getType()->getPointeeType();
|
||||||
|
const CharUnits align =
|
||||||
|
cgm.getNaturalTypeAlignment(pointeeType, &targetTypeBaseInfo);
|
||||||
|
|
||||||
|
// If the source l-value is opaque, honor the alignment of the
|
||||||
|
// casted-to type.
|
||||||
|
if (innerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) {
|
||||||
|
if (baseInfo)
|
||||||
|
baseInfo->mergeForCast(targetTypeBaseInfo);
|
||||||
|
addr = Address(addr.getPointer(), addr.getElementType(), align);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!cir::MissingFeatures::sanitizers());
|
||||||
|
|
||||||
|
const mlir::Type eltTy =
|
||||||
|
convertTypeForMem(expr->getType()->getPointeeType());
|
||||||
|
addr = getBuilder().createElementBitCast(getLoc(expr->getSourceRange()),
|
||||||
|
addr, eltTy);
|
||||||
|
assert(!cir::MissingFeatures::addressSpace());
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
|
// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
|
||||||
case CK_ArrayToPointerDecay:
|
case CK_ArrayToPointerDecay:
|
||||||
@ -551,6 +584,37 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) {
|
|||||||
return RValue::get(nullptr);
|
return RValue::get(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
|
||||||
|
assert(!cir::MissingFeatures::weakRefReference());
|
||||||
|
return cgm.getAddrOfFunction(gd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LValue emitFunctionDeclLValue(CIRGenFunction &cgf, const Expr *e,
|
||||||
|
GlobalDecl gd) {
|
||||||
|
const FunctionDecl *fd = cast<FunctionDecl>(gd.getDecl());
|
||||||
|
cir::FuncOp funcOp = emitFunctionDeclPointer(cgf.cgm, gd);
|
||||||
|
mlir::Location loc = cgf.getLoc(e->getSourceRange());
|
||||||
|
CharUnits align = cgf.getContext().getDeclAlign(fd);
|
||||||
|
|
||||||
|
assert(!cir::MissingFeatures::sanitizers());
|
||||||
|
|
||||||
|
mlir::Type fnTy = funcOp.getFunctionType();
|
||||||
|
mlir::Type ptrTy = cir::PointerType::get(fnTy);
|
||||||
|
mlir::Value addr = cgf.getBuilder().create<cir::GetGlobalOp>(
|
||||||
|
loc, ptrTy, funcOp.getSymName());
|
||||||
|
|
||||||
|
if (funcOp.getFunctionType() != cgf.convertType(fd->getType())) {
|
||||||
|
fnTy = cgf.convertType(fd->getType());
|
||||||
|
ptrTy = cir::PointerType::get(fnTy);
|
||||||
|
|
||||||
|
addr = cir::CastOp::create(cgf.getBuilder(), addr.getLoc(), ptrTy,
|
||||||
|
cir::CastKind::bitcast, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgf.makeAddrLValue(Address(addr, fnTy, align), e->getType(),
|
||||||
|
AlignmentSource::Decl);
|
||||||
|
}
|
||||||
|
|
||||||
LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
|
LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
|
||||||
const NamedDecl *nd = e->getDecl();
|
const NamedDecl *nd = e->getDecl();
|
||||||
QualType ty = e->getType();
|
QualType ty = e->getType();
|
||||||
@ -607,6 +671,16 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
|
|||||||
return emitLValue(bd->getBinding());
|
return emitLValue(bd->getBinding());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const auto *fd = dyn_cast<FunctionDecl>(nd)) {
|
||||||
|
LValue lv = emitFunctionDeclLValue(*this, e, fd);
|
||||||
|
|
||||||
|
// Emit debuginfo for the function declaration if the target wants to.
|
||||||
|
if (getContext().getTargetInfo().allowDebugInfoForExternalRef())
|
||||||
|
assert(!cir::MissingFeatures::generateDebugInfo());
|
||||||
|
|
||||||
|
return lv;
|
||||||
|
}
|
||||||
|
|
||||||
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
|
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
|
||||||
return LValue();
|
return LValue();
|
||||||
}
|
}
|
||||||
@ -1401,11 +1475,6 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot) {
|
|||||||
llvm_unreachable("bad evaluation kind");
|
llvm_unreachable("bad evaluation kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
|
|
||||||
assert(!cir::MissingFeatures::weakRefReference());
|
|
||||||
return cgm.getAddrOfFunction(gd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect the unusual situation where an inline version is shadowed by a
|
// Detect the unusual situation where an inline version is shadowed by a
|
||||||
// non-inline version. In that case we should pick the external one
|
// non-inline version. In that case we should pick the external one
|
||||||
// everywhere. That's GCC behavior too.
|
// everywhere. That's GCC behavior too.
|
||||||
|
@ -1905,6 +1905,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
|
|||||||
cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy),
|
cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy),
|
||||||
Visit(subExpr));
|
Visit(subExpr));
|
||||||
}
|
}
|
||||||
|
case CK_FunctionToPointerDecay:
|
||||||
|
return cgf.emitLValue(subExpr).getPointer();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
|
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
|
||||||
|
@ -4184,7 +4184,14 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionMap[RD].reset(RealDecl);
|
if (auto *CTSD =
|
||||||
|
dyn_cast<ClassTemplateSpecializationDecl>(Ty->getOriginalDecl())) {
|
||||||
|
CXXRecordDecl *TemplateDecl =
|
||||||
|
CTSD->getSpecializedTemplate()->getTemplatedDecl();
|
||||||
|
RegionMap[TemplateDecl].reset(RealDecl);
|
||||||
|
} else {
|
||||||
|
RegionMap[RD].reset(RealDecl);
|
||||||
|
}
|
||||||
TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
|
TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
|
||||||
|
|
||||||
if (const auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
|
if (const auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
|
||||||
|
@ -466,6 +466,14 @@ llvm::Constant *CodeGenModule::getConstantSignedPointer(
|
|||||||
OtherDiscriminator);
|
OtherDiscriminator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Constant *
|
||||||
|
CodeGen::getConstantSignedPointer(CodeGenModule &CGM, llvm::Constant *Pointer,
|
||||||
|
unsigned Key, llvm::Constant *StorageAddress,
|
||||||
|
llvm::ConstantInt *OtherDiscriminator) {
|
||||||
|
return CGM.getConstantSignedPointer(Pointer, Key, StorageAddress,
|
||||||
|
OtherDiscriminator);
|
||||||
|
}
|
||||||
|
|
||||||
/// If applicable, sign a given constant function pointer with the ABI rules for
|
/// If applicable, sign a given constant function pointer with the ABI rules for
|
||||||
/// functionType.
|
/// functionType.
|
||||||
llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
|
llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
|
||||||
|
@ -1409,13 +1409,6 @@ void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
|
|||||||
CC1Args.push_back(DriverArgs.MakeArgString(Path));
|
CC1Args.push_back(DriverArgs.MakeArgString(Path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Utility function to add a system include directory to CC1 arguments.
|
|
||||||
void ToolChain::addSystemInclude(const ArgList &DriverArgs,
|
|
||||||
ArgStringList &CC1Args, const Twine &Path) {
|
|
||||||
CC1Args.push_back("-internal-isystem");
|
|
||||||
CC1Args.push_back(DriverArgs.MakeArgString(Path));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Utility function to add a system include directory with extern "C"
|
/// Utility function to add a system include directory with extern "C"
|
||||||
/// semantics to CC1 arguments.
|
/// semantics to CC1 arguments.
|
||||||
///
|
///
|
||||||
@ -1438,6 +1431,14 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
|
|||||||
addExternCSystemInclude(DriverArgs, CC1Args, Path);
|
addExternCSystemInclude(DriverArgs, CC1Args, Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Utility function to add a system include directory to CC1 arguments.
|
||||||
|
/*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs,
|
||||||
|
ArgStringList &CC1Args,
|
||||||
|
const Twine &Path) {
|
||||||
|
CC1Args.push_back("-internal-isystem");
|
||||||
|
CC1Args.push_back(DriverArgs.MakeArgString(Path));
|
||||||
|
}
|
||||||
|
|
||||||
/// Utility function to add a list of system framework directories to CC1.
|
/// Utility function to add a list of system framework directories to CC1.
|
||||||
void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs,
|
void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs,
|
||||||
ArgStringList &CC1Args,
|
ArgStringList &CC1Args,
|
||||||
|
@ -2123,10 +2123,11 @@ void Generic_GCC::GCCInstallationDetector::init(
|
|||||||
StringRef TripleText =
|
StringRef TripleText =
|
||||||
llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir));
|
llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir));
|
||||||
|
|
||||||
Version = GCCVersion::Parse(VersionText);
|
SelectedInstallation.Version = GCCVersion::Parse(VersionText);
|
||||||
GCCTriple.setTriple(TripleText);
|
SelectedInstallation.GCCTriple.setTriple(TripleText);
|
||||||
GCCInstallPath = std::string(InstallDir);
|
SelectedInstallation.GCCInstallPath = std::string(InstallDir);
|
||||||
GCCParentLibPath = GCCInstallPath + "/../../..";
|
SelectedInstallation.GCCParentLibPath =
|
||||||
|
SelectedInstallation.GCCInstallPath + "/../../..";
|
||||||
IsValid = true;
|
IsValid = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -2186,7 +2187,7 @@ void Generic_GCC::GCCInstallationDetector::init(
|
|||||||
// Loop over the various components which exist and select the best GCC
|
// Loop over the various components which exist and select the best GCC
|
||||||
// installation available. GCC installs are ranked by version number.
|
// installation available. GCC installs are ranked by version number.
|
||||||
const GCCVersion VersionZero = GCCVersion::Parse("0.0.0");
|
const GCCVersion VersionZero = GCCVersion::Parse("0.0.0");
|
||||||
Version = VersionZero;
|
SelectedInstallation.Version = VersionZero;
|
||||||
for (const std::string &Prefix : Prefixes) {
|
for (const std::string &Prefix : Prefixes) {
|
||||||
auto &VFS = D.getVFS();
|
auto &VFS = D.getVFS();
|
||||||
if (!VFS.exists(Prefix))
|
if (!VFS.exists(Prefix))
|
||||||
@ -2214,7 +2215,7 @@ void Generic_GCC::GCCInstallationDetector::init(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip other prefixes once a GCC installation is found.
|
// Skip other prefixes once a GCC installation is found.
|
||||||
if (Version > VersionZero)
|
if (SelectedInstallation.Version > VersionZero)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2223,14 +2224,17 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
|
|||||||
for (const auto &InstallPath : CandidateGCCInstallPaths)
|
for (const auto &InstallPath : CandidateGCCInstallPaths)
|
||||||
OS << "Found candidate GCC installation: " << InstallPath << "\n";
|
OS << "Found candidate GCC installation: " << InstallPath << "\n";
|
||||||
|
|
||||||
if (!GCCInstallPath.empty())
|
if (!SelectedInstallation.GCCInstallPath.empty())
|
||||||
OS << "Selected GCC installation: " << GCCInstallPath << "\n";
|
OS << "Selected GCC installation: " << SelectedInstallation.GCCInstallPath
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
for (const auto &Multilib : Multilibs)
|
for (const auto &Multilib : Multilibs)
|
||||||
OS << "Candidate multilib: " << Multilib << "\n";
|
OS << "Candidate multilib: " << Multilib << "\n";
|
||||||
|
|
||||||
if (Multilibs.size() != 0 || !SelectedMultilib.isDefault())
|
if (Multilibs.size() != 0 ||
|
||||||
OS << "Selected multilib: " << SelectedMultilib << "\n";
|
!SelectedInstallation.SelectedMultilib.isDefault())
|
||||||
|
OS << "Selected multilib: " << SelectedInstallation.SelectedMultilib
|
||||||
|
<< "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
|
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
|
||||||
@ -2768,14 +2772,50 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Multilibs = Detected.Multilibs;
|
Multilibs = Detected.Multilibs;
|
||||||
SelectedMultilib = Detected.SelectedMultilibs.empty()
|
SelectedInstallation.SelectedMultilib =
|
||||||
? Multilib()
|
Detected.SelectedMultilibs.empty() ? Multilib()
|
||||||
: Detected.SelectedMultilibs.back();
|
: Detected.SelectedMultilibs.back();
|
||||||
BiarchSibling = Detected.BiarchSibling;
|
BiarchSibling = Detected.BiarchSibling;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Generic_GCC::GCCInstallationDetector::SelectGCCInstallationDirectory(
|
||||||
|
const SmallVector<Generic_GCC::GCCInstallCandidate, 3> &Installations,
|
||||||
|
const ArgList &Args,
|
||||||
|
Generic_GCC::GCCInstallCandidate &SelectedInstallation) const {
|
||||||
|
if (Installations.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SelectedInstallation =
|
||||||
|
*max_element(Installations, [](const auto &Max, const auto &I) {
|
||||||
|
return I.Version > Max.Version;
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME Start selecting installation with libstdc++ in clang 22,
|
||||||
|
// using the current way of selecting the installation as a fallback
|
||||||
|
// only. For now, warn if the installation with libstdc++ differs
|
||||||
|
// from SelectedInstallation.
|
||||||
|
const GCCInstallCandidate *InstallWithIncludes = nullptr;
|
||||||
|
for (const auto &I : Installations) {
|
||||||
|
if ((!InstallWithIncludes || I.Version > InstallWithIncludes->Version) &&
|
||||||
|
GCCInstallationHasLibStdcxxIncludePaths(I, Args))
|
||||||
|
InstallWithIncludes = &I;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InstallWithIncludes && SelectedInstallation.GCCInstallPath !=
|
||||||
|
InstallWithIncludes->GCCInstallPath)
|
||||||
|
D.Diag(diag::warn_drv_gcc_install_dir_libstdcxx)
|
||||||
|
<< InstallWithIncludes->GCCInstallPath
|
||||||
|
<< SelectedInstallation.GCCInstallPath;
|
||||||
|
|
||||||
|
// TODO Warn if SelectedInstallation does not contain libstdc++ includes
|
||||||
|
// although compiler flags indicate that it is required (C++ compilation,
|
||||||
|
// libstdc++ not explicitly disabled).
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
|
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
|
||||||
const llvm::Triple &TargetTriple, const ArgList &Args,
|
const llvm::Triple &TargetTriple, const ArgList &Args,
|
||||||
const std::string &LibDir, StringRef CandidateTriple,
|
const std::string &LibDir, StringRef CandidateTriple,
|
||||||
@ -2805,6 +2845,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
|
|||||||
TargetTriple.getVendor() == llvm::Triple::Freescale ||
|
TargetTriple.getVendor() == llvm::Triple::Freescale ||
|
||||||
TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}};
|
TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}};
|
||||||
|
|
||||||
|
SmallVector<GCCInstallCandidate, 3> Installations;
|
||||||
for (auto &Suffix : Suffixes) {
|
for (auto &Suffix : Suffixes) {
|
||||||
if (!Suffix.Active)
|
if (!Suffix.Active)
|
||||||
continue;
|
continue;
|
||||||
@ -2822,23 +2863,31 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
|
|||||||
continue; // Saw this path before; no need to look at it again.
|
continue; // Saw this path before; no need to look at it again.
|
||||||
if (CandidateVersion.isOlderThan(4, 1, 1))
|
if (CandidateVersion.isOlderThan(4, 1, 1))
|
||||||
continue;
|
continue;
|
||||||
if (CandidateVersion <= Version)
|
if (CandidateVersion <= SelectedInstallation.Version && IsValid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(),
|
if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(),
|
||||||
NeedsBiarchSuffix))
|
NeedsBiarchSuffix))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Version = CandidateVersion;
|
GCCInstallCandidate Installation;
|
||||||
GCCTriple.setTriple(CandidateTriple);
|
Installation.Version = CandidateVersion;
|
||||||
|
Installation.GCCTriple.setTriple(CandidateTriple);
|
||||||
// FIXME: We hack together the directory name here instead of
|
// FIXME: We hack together the directory name here instead of
|
||||||
// using LI to ensure stable path separators across Windows and
|
// using LI to ensure stable path separators across Windows and
|
||||||
// Linux.
|
// Linux.
|
||||||
GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str();
|
Installation.GCCInstallPath =
|
||||||
GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str();
|
(LibDir + "/" + LibSuffix + "/" + VersionText).str();
|
||||||
IsValid = true;
|
Installation.GCCParentLibPath =
|
||||||
|
(Installation.GCCInstallPath + "/../" + Suffix.ReversePath).str();
|
||||||
|
Installation.SelectedMultilib = getMultilib();
|
||||||
|
|
||||||
|
Installations.push_back(Installation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsValid |=
|
||||||
|
SelectGCCInstallationDirectory(Installations, Args, SelectedInstallation);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs(
|
bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs(
|
||||||
@ -2916,10 +2965,12 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
|
|||||||
NeedsBiarchSuffix))
|
NeedsBiarchSuffix))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Version = GCCVersion::Parse(ActiveVersion.second);
|
SelectedInstallation.Version =
|
||||||
GCCInstallPath = GentooPath;
|
GCCVersion::Parse(ActiveVersion.second);
|
||||||
GCCParentLibPath = GentooPath + std::string("/../../..");
|
SelectedInstallation.GCCInstallPath = GentooPath;
|
||||||
GCCTriple.setTriple(ActiveVersion.first);
|
SelectedInstallation.GCCParentLibPath =
|
||||||
|
GentooPath + std::string("/../../..");
|
||||||
|
SelectedInstallation.GCCTriple.setTriple(ActiveVersion.first);
|
||||||
IsValid = true;
|
IsValid = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3122,8 +3173,9 @@ void Generic_GCC::AddMultilibIncludeArgs(const ArgList &DriverArgs,
|
|||||||
// gcc TOOL_INCLUDE_DIR.
|
// gcc TOOL_INCLUDE_DIR.
|
||||||
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
|
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
|
||||||
std::string LibPath(GCCInstallation.getParentLibPath());
|
std::string LibPath(GCCInstallation.getParentLibPath());
|
||||||
addSystemInclude(DriverArgs, CC1Args,
|
ToolChain::addSystemInclude(DriverArgs, CC1Args,
|
||||||
Twine(LibPath) + "/../" + GCCTriple.str() + "/include");
|
Twine(LibPath) + "/../" + GCCTriple.str() +
|
||||||
|
"/include");
|
||||||
|
|
||||||
const auto &Callback = Multilibs.includeDirsCallback();
|
const auto &Callback = Multilibs.includeDirsCallback();
|
||||||
if (Callback) {
|
if (Callback) {
|
||||||
@ -3210,12 +3262,14 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
static bool addLibStdCXXIncludePaths(llvm::vfs::FileSystem &vfs,
|
||||||
Twine IncludeSuffix,
|
Twine IncludeDir, StringRef Triple,
|
||||||
const llvm::opt::ArgList &DriverArgs,
|
Twine IncludeSuffix,
|
||||||
llvm::opt::ArgStringList &CC1Args,
|
const llvm::opt::ArgList &DriverArgs,
|
||||||
bool DetectDebian) const {
|
llvm::opt::ArgStringList &CC1Args,
|
||||||
if (!getVFS().exists(IncludeDir))
|
bool DetectDebian = false) {
|
||||||
|
|
||||||
|
if (!vfs.exists(IncludeDir))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Debian native gcc uses g++-multiarch-incdir.diff which uses
|
// Debian native gcc uses g++-multiarch-incdir.diff which uses
|
||||||
@ -3227,39 +3281,48 @@ bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
|||||||
std::string Path =
|
std::string Path =
|
||||||
(Include + "/" + Triple + Dir.substr(Include.size()) + IncludeSuffix)
|
(Include + "/" + Triple + Dir.substr(Include.size()) + IncludeSuffix)
|
||||||
.str();
|
.str();
|
||||||
if (DetectDebian && !getVFS().exists(Path))
|
if (DetectDebian && !vfs.exists(Path))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// GPLUSPLUS_INCLUDE_DIR
|
// GPLUSPLUS_INCLUDE_DIR
|
||||||
addSystemInclude(DriverArgs, CC1Args, IncludeDir);
|
ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir);
|
||||||
// GPLUSPLUS_TOOL_INCLUDE_DIR. If Triple is not empty, add a target-dependent
|
// GPLUSPLUS_TOOL_INCLUDE_DIR. If Triple is not empty, add a target-dependent
|
||||||
// include directory.
|
// include directory.
|
||||||
if (DetectDebian)
|
if (DetectDebian)
|
||||||
addSystemInclude(DriverArgs, CC1Args, Path);
|
ToolChain::addSystemInclude(DriverArgs, CC1Args, Path);
|
||||||
else if (!Triple.empty())
|
else if (!Triple.empty())
|
||||||
addSystemInclude(DriverArgs, CC1Args,
|
ToolChain::addSystemInclude(DriverArgs, CC1Args,
|
||||||
IncludeDir + "/" + Triple + IncludeSuffix);
|
IncludeDir + "/" + Triple + IncludeSuffix);
|
||||||
// GPLUSPLUS_BACKWARD_INCLUDE_DIR
|
// GPLUSPLUS_BACKWARD_INCLUDE_DIR
|
||||||
addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward");
|
ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Generic_GCC::addGCCLibStdCxxIncludePaths(
|
bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
||||||
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
|
Twine IncludeSuffix,
|
||||||
StringRef DebianMultiarch) const {
|
const llvm::opt::ArgList &DriverArgs,
|
||||||
assert(GCCInstallation.isValid());
|
llvm::opt::ArgStringList &CC1Args,
|
||||||
|
bool DetectDebian) const {
|
||||||
|
return ::addLibStdCXXIncludePaths(getVFS(), IncludeDir, Triple, IncludeSuffix,
|
||||||
|
DriverArgs, CC1Args, DetectDebian);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Generic_GCC::GCCInstallCandidate::addGCCLibStdCxxIncludePaths(
|
||||||
|
llvm::vfs::FileSystem &vfs, const llvm::opt::ArgList &DriverArgs,
|
||||||
|
llvm::opt::ArgStringList &CC1Args, StringRef DebianMultiarch) const {
|
||||||
|
|
||||||
// By default, look for the C++ headers in an include directory adjacent to
|
// By default, look for the C++ headers in an include directory adjacent to
|
||||||
// the lib directory of the GCC installation. Note that this is expect to be
|
// the lib directory of the GCC installation. Note that this is expect to be
|
||||||
// equivalent to '/usr/include/c++/X.Y' in almost all cases.
|
// equivalent to '/usr/include/c++/X.Y' in almost all cases.
|
||||||
StringRef LibDir = GCCInstallation.getParentLibPath();
|
StringRef LibDir = getParentLibPath();
|
||||||
StringRef InstallDir = GCCInstallation.getInstallPath();
|
StringRef InstallDir = getInstallPath();
|
||||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
StringRef TripleStr = getTriple().str();
|
||||||
const Multilib &Multilib = GCCInstallation.getMultilib();
|
const Multilib &Multilib = getMultilib();
|
||||||
const GCCVersion &Version = GCCInstallation.getVersion();
|
const GCCVersion &Version = getVersion();
|
||||||
|
|
||||||
// Try /../$triple/include/c++/$version (gcc --print-multiarch is not empty).
|
// Try /../$triple/include/c++/$version (gcc --print-multiarch is not empty).
|
||||||
if (addLibStdCXXIncludePaths(
|
if (::addLibStdCXXIncludePaths(
|
||||||
|
vfs,
|
||||||
LibDir.str() + "/../" + TripleStr + "/include/c++/" + Version.Text,
|
LibDir.str() + "/../" + TripleStr + "/include/c++/" + Version.Text,
|
||||||
TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args))
|
TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args))
|
||||||
return true;
|
return true;
|
||||||
@ -3267,22 +3330,24 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths(
|
|||||||
// Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not
|
// Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not
|
||||||
// empty). Like above but for GCC built with
|
// empty). Like above but for GCC built with
|
||||||
// --enable-version-specific-runtime-libs.
|
// --enable-version-specific-runtime-libs.
|
||||||
if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" +
|
if (::addLibStdCXXIncludePaths(vfs,
|
||||||
Version.Text + "/include/c++/",
|
LibDir.str() + "/gcc/" + TripleStr + "/" +
|
||||||
TripleStr, Multilib.includeSuffix(), DriverArgs,
|
Version.Text + "/include/c++/",
|
||||||
CC1Args))
|
TripleStr, Multilib.includeSuffix(),
|
||||||
|
DriverArgs, CC1Args))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Detect Debian g++-multiarch-incdir.diff.
|
// Detect Debian g++-multiarch-incdir.diff.
|
||||||
if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
|
if (::addLibStdCXXIncludePaths(
|
||||||
DebianMultiarch, Multilib.includeSuffix(),
|
vfs, LibDir.str() + "/../include/c++/" + Version.Text,
|
||||||
DriverArgs, CC1Args, /*Debian=*/true))
|
DebianMultiarch, Multilib.includeSuffix(), DriverArgs, CC1Args,
|
||||||
|
/*Debian=*/true))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Try /../include/c++/$version (gcc --print-multiarch is empty).
|
// Try /../include/c++/$version (gcc --print-multiarch is empty).
|
||||||
if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
|
if (::addLibStdCXXIncludePaths(
|
||||||
TripleStr, Multilib.includeSuffix(), DriverArgs,
|
vfs, LibDir.str() + "/../include/c++/" + Version.Text, TripleStr,
|
||||||
CC1Args))
|
Multilib.includeSuffix(), DriverArgs, CC1Args))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Otherwise, fall back on a bunch of options which don't use multiarch
|
// Otherwise, fall back on a bunch of options which don't use multiarch
|
||||||
@ -3297,20 +3362,50 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
|
for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
|
||||||
if (addLibStdCXXIncludePaths(IncludePath, TripleStr,
|
if (::addLibStdCXXIncludePaths(vfs, IncludePath, TripleStr,
|
||||||
Multilib.includeSuffix(), DriverArgs, CC1Args))
|
Multilib.includeSuffix(), DriverArgs,
|
||||||
|
CC1Args))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Generic_GCC::GCCInstallationDetector::
|
||||||
|
GCCInstallationHasLibStdcxxIncludePaths(
|
||||||
|
const GCCInstallCandidate &GCCInstallation,
|
||||||
|
const llvm::opt::ArgList &DriverArgs) const {
|
||||||
|
StringRef DebianMultiarch =
|
||||||
|
TripleToDebianMultiarch(GCCInstallation.getTriple());
|
||||||
|
|
||||||
|
// The following function checks for libstdc++ include paths and
|
||||||
|
// adds them to the provided argument list. Here we just need the
|
||||||
|
// check.
|
||||||
|
llvm::opt::ArgStringList dummyCC1Args;
|
||||||
|
return GCCInstallation.addGCCLibStdCxxIncludePaths(
|
||||||
|
D.getVFS(), DriverArgs, dummyCC1Args, DebianMultiarch);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Generic_GCC::addGCCLibStdCxxIncludePaths(
|
||||||
|
const llvm::opt::ArgList &DriverArgs,
|
||||||
|
llvm::opt::ArgStringList &CC1Args) const {
|
||||||
|
assert(GCCInstallation.isValid());
|
||||||
|
|
||||||
|
// Detect Debian g++-multiarch-incdir.diff.
|
||||||
|
StringRef DebianMultiarch =
|
||||||
|
GCCInstallation.TripleToDebianMultiarch(GCCInstallation.getTriple());
|
||||||
|
|
||||||
|
return GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths(
|
||||||
|
getVFS(), DriverArgs, CC1Args, DebianMultiarch);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||||
llvm::opt::ArgStringList &CC1Args) const {
|
llvm::opt::ArgStringList &CC1Args) const {
|
||||||
if (GCCInstallation.isValid()) {
|
if (!GCCInstallation.isValid())
|
||||||
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args,
|
return;
|
||||||
GCCInstallation.getTriple().str());
|
|
||||||
}
|
GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths(
|
||||||
|
getVFS(), DriverArgs, CC1Args, GCCInstallation.getTriple().str());
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::opt::DerivedArgList *
|
llvm::opt::DerivedArgList *
|
||||||
|
@ -184,46 +184,18 @@ public:
|
|||||||
bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
|
bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is a class to find a viable GCC installation for Clang to
|
struct GCCInstallCandidate {
|
||||||
/// use.
|
|
||||||
///
|
|
||||||
/// This class tries to find a GCC installation on the system, and report
|
|
||||||
/// information about it. It starts from the host information provided to the
|
|
||||||
/// Driver, and has logic for fuzzing that where appropriate.
|
|
||||||
class GCCInstallationDetector {
|
|
||||||
bool IsValid;
|
|
||||||
llvm::Triple GCCTriple;
|
|
||||||
const Driver &D;
|
|
||||||
|
|
||||||
// FIXME: These might be better as path objects.
|
// FIXME: These might be better as path objects.
|
||||||
std::string GCCInstallPath;
|
std::string GCCInstallPath;
|
||||||
std::string GCCParentLibPath;
|
std::string GCCParentLibPath;
|
||||||
|
|
||||||
|
llvm::Triple GCCTriple;
|
||||||
|
|
||||||
/// The primary multilib appropriate for the given flags.
|
/// The primary multilib appropriate for the given flags.
|
||||||
Multilib SelectedMultilib;
|
Multilib SelectedMultilib;
|
||||||
/// On Biarch systems, this corresponds to the default multilib when
|
|
||||||
/// targeting the non-default multilib. Otherwise, it is empty.
|
|
||||||
std::optional<Multilib> BiarchSibling;
|
|
||||||
|
|
||||||
GCCVersion Version;
|
GCCVersion Version;
|
||||||
|
|
||||||
// We retain the list of install paths that were considered and rejected in
|
|
||||||
// order to print out detailed information in verbose mode.
|
|
||||||
std::set<std::string> CandidateGCCInstallPaths;
|
|
||||||
|
|
||||||
/// The set of multilibs that the detected installation supports.
|
|
||||||
MultilibSet Multilibs;
|
|
||||||
|
|
||||||
// Gentoo-specific toolchain configurations are stored here.
|
|
||||||
const std::string GentooConfigDir = "/etc/env.d/gcc";
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
|
|
||||||
void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args);
|
|
||||||
|
|
||||||
/// Check whether we detected a valid GCC install.
|
|
||||||
bool isValid() const { return IsValid; }
|
|
||||||
|
|
||||||
/// Get the GCC triple for the detected install.
|
/// Get the GCC triple for the detected install.
|
||||||
const llvm::Triple &getTriple() const { return GCCTriple; }
|
const llvm::Triple &getTriple() const { return GCCTriple; }
|
||||||
|
|
||||||
@ -236,6 +208,88 @@ public:
|
|||||||
/// Get the detected Multilib
|
/// Get the detected Multilib
|
||||||
const Multilib &getMultilib() const { return SelectedMultilib; }
|
const Multilib &getMultilib() const { return SelectedMultilib; }
|
||||||
|
|
||||||
|
/// Get the detected GCC version string.
|
||||||
|
const GCCVersion &getVersion() const { return Version; }
|
||||||
|
|
||||||
|
bool addGCCLibStdCxxIncludePaths(llvm::vfs::FileSystem &vfs,
|
||||||
|
const llvm::opt::ArgList &DriverArgs,
|
||||||
|
llvm::opt::ArgStringList &CC1Args,
|
||||||
|
StringRef DebianMultiarch) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This is a class to find a viable GCC installation for Clang to
|
||||||
|
/// use.
|
||||||
|
///
|
||||||
|
/// This class tries to find a GCC installation on the system, and report
|
||||||
|
/// information about it. It starts from the host information provided to the
|
||||||
|
/// Driver, and has logic for fuzzing that where appropriate.
|
||||||
|
class GCCInstallationDetector {
|
||||||
|
bool IsValid;
|
||||||
|
|
||||||
|
const Driver &D;
|
||||||
|
|
||||||
|
GCCInstallCandidate SelectedInstallation;
|
||||||
|
|
||||||
|
/// On Biarch systems, this corresponds to the default multilib when
|
||||||
|
/// targeting the non-default multilib. Otherwise, it is empty.
|
||||||
|
std::optional<Multilib> BiarchSibling;
|
||||||
|
|
||||||
|
// We retain the list of install paths that were considered and rejected in
|
||||||
|
// order to print out detailed information in verbose mode.
|
||||||
|
std::set<std::string> CandidateGCCInstallPaths;
|
||||||
|
|
||||||
|
/// The set of multilibs that the detected installation supports.
|
||||||
|
MultilibSet Multilibs;
|
||||||
|
|
||||||
|
// Gentoo-specific toolchain configurations are stored here.
|
||||||
|
const std::string GentooConfigDir = "/etc/env.d/gcc";
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Function for converting a triple to a Debian multiarch. The
|
||||||
|
/// toolchains use this to adjust the target specific component of
|
||||||
|
/// include paths for Debian.
|
||||||
|
std::function<StringRef(const llvm::Triple &)> TripleToDebianMultiarch =
|
||||||
|
[](const llvm::Triple &T) {
|
||||||
|
StringRef S = T.str();
|
||||||
|
return S;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
|
||||||
|
|
||||||
|
void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args);
|
||||||
|
|
||||||
|
// TODO Replace isValid by changing SelectedInstallation into
|
||||||
|
// std::optional<SelectedInstallation>
|
||||||
|
// and move all accessors for fields of GCCInstallCandidate into
|
||||||
|
// that struct.
|
||||||
|
|
||||||
|
/// Check whether we detected a valid GCC install.
|
||||||
|
bool isValid() const { return IsValid; }
|
||||||
|
|
||||||
|
const GCCInstallCandidate &getSelectedInstallation() const {
|
||||||
|
return SelectedInstallation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the GCC triple for the detected install.
|
||||||
|
const llvm::Triple &getTriple() const {
|
||||||
|
return SelectedInstallation.GCCTriple;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the detected GCC installation path.
|
||||||
|
StringRef getInstallPath() const {
|
||||||
|
return SelectedInstallation.GCCInstallPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the detected GCC parent lib path.
|
||||||
|
StringRef getParentLibPath() const {
|
||||||
|
return SelectedInstallation.GCCParentLibPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the detected Multilib
|
||||||
|
const Multilib &getMultilib() const {
|
||||||
|
return SelectedInstallation.SelectedMultilib;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the whole MultilibSet
|
/// Get the whole MultilibSet
|
||||||
const MultilibSet &getMultilibs() const { return Multilibs; }
|
const MultilibSet &getMultilibs() const { return Multilibs; }
|
||||||
|
|
||||||
@ -244,7 +298,9 @@ public:
|
|||||||
bool getBiarchSibling(Multilib &M) const;
|
bool getBiarchSibling(Multilib &M) const;
|
||||||
|
|
||||||
/// Get the detected GCC version string.
|
/// Get the detected GCC version string.
|
||||||
const GCCVersion &getVersion() const { return Version; }
|
const GCCVersion &getVersion() const {
|
||||||
|
return SelectedInstallation.Version;
|
||||||
|
}
|
||||||
|
|
||||||
/// Print information about the detected GCC installation.
|
/// Print information about the detected GCC installation.
|
||||||
void print(raw_ostream &OS) const;
|
void print(raw_ostream &OS) const;
|
||||||
@ -262,6 +318,19 @@ public:
|
|||||||
SmallVectorImpl<std::string> &Prefixes,
|
SmallVectorImpl<std::string> &Prefixes,
|
||||||
StringRef SysRoot);
|
StringRef SysRoot);
|
||||||
|
|
||||||
|
/// Checks if the \p GCCInstallation has libstdc++ include
|
||||||
|
/// directories.
|
||||||
|
bool GCCInstallationHasLibStdcxxIncludePaths(
|
||||||
|
const GCCInstallCandidate &GCCInstallation,
|
||||||
|
const llvm::opt::ArgList &DriverArgs) const;
|
||||||
|
|
||||||
|
/// Select a GCC installation directory from \p Installations and
|
||||||
|
/// set \p SelectedInstallation accordingly.
|
||||||
|
bool SelectGCCInstallationDirectory(
|
||||||
|
const SmallVector<GCCInstallCandidate, 3> &Installations,
|
||||||
|
const llvm::opt::ArgList &Args,
|
||||||
|
GCCInstallCandidate &SelectedInstallation) const;
|
||||||
|
|
||||||
bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple,
|
bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple,
|
||||||
const llvm::opt::ArgList &Args, StringRef Path,
|
const llvm::opt::ArgList &Args, StringRef Path,
|
||||||
bool NeedsBiarchSuffix = false);
|
bool NeedsBiarchSuffix = false);
|
||||||
@ -348,8 +417,7 @@ protected:
|
|||||||
llvm::opt::ArgStringList &CC1Args) const;
|
llvm::opt::ArgStringList &CC1Args) const;
|
||||||
|
|
||||||
bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||||
llvm::opt::ArgStringList &CC1Args,
|
llvm::opt::ArgStringList &CC) const;
|
||||||
StringRef DebianMultiarch) const;
|
|
||||||
|
|
||||||
bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
|
||||||
Twine IncludeSuffix,
|
Twine IncludeSuffix,
|
||||||
|
@ -71,6 +71,13 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
|
|||||||
|
|
||||||
Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
||||||
: Generic_ELF(D, Triple, Args) {
|
: Generic_ELF(D, Triple, Args) {
|
||||||
|
GCCInstallation.TripleToDebianMultiarch = [](const llvm::Triple &T) {
|
||||||
|
StringRef TripleStr = T.str();
|
||||||
|
StringRef DebianMultiarch =
|
||||||
|
T.getArch() == llvm::Triple::x86 ? "i386-gnu" : TripleStr;
|
||||||
|
return DebianMultiarch;
|
||||||
|
};
|
||||||
|
|
||||||
GCCInstallation.init(Triple, Args);
|
GCCInstallation.init(Triple, Args);
|
||||||
Multilibs = GCCInstallation.getMultilibs();
|
Multilibs = GCCInstallation.getMultilibs();
|
||||||
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
|
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
|
||||||
@ -207,12 +214,7 @@ void Hurd::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
|||||||
if (!GCCInstallation.isValid())
|
if (!GCCInstallation.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args);
|
||||||
StringRef DebianMultiarch =
|
|
||||||
GCCInstallation.getTriple().getArch() == llvm::Triple::x86 ? "i386-gnu"
|
|
||||||
: TripleStr;
|
|
||||||
|
|
||||||
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, DebianMultiarch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hurd::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
|
void Hurd::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
|
||||||
|
@ -211,6 +211,13 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
|
|||||||
|
|
||||||
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
||||||
: Generic_ELF(D, Triple, Args) {
|
: Generic_ELF(D, Triple, Args) {
|
||||||
|
GCCInstallation.TripleToDebianMultiarch = [](const llvm::Triple &T) {
|
||||||
|
StringRef TripleStr = T.str();
|
||||||
|
StringRef DebianMultiarch =
|
||||||
|
T.getArch() == llvm::Triple::x86 ? "i386-linux-gnu" : TripleStr;
|
||||||
|
return DebianMultiarch;
|
||||||
|
};
|
||||||
|
|
||||||
GCCInstallation.init(Triple, Args);
|
GCCInstallation.init(Triple, Args);
|
||||||
Multilibs = GCCInstallation.getMultilibs();
|
Multilibs = GCCInstallation.getMultilibs();
|
||||||
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
|
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
|
||||||
@ -693,22 +700,15 @@ void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
|||||||
if (!GCCInstallation.isValid())
|
if (!GCCInstallation.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Detect Debian g++-multiarch-incdir.diff.
|
|
||||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
|
||||||
StringRef DebianMultiarch =
|
|
||||||
GCCInstallation.getTriple().getArch() == llvm::Triple::x86
|
|
||||||
? "i386-linux-gnu"
|
|
||||||
: TripleStr;
|
|
||||||
|
|
||||||
// Try generic GCC detection first.
|
// Try generic GCC detection first.
|
||||||
if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args,
|
if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args))
|
||||||
DebianMultiarch))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StringRef LibDir = GCCInstallation.getParentLibPath();
|
StringRef LibDir = GCCInstallation.getParentLibPath();
|
||||||
const Multilib &Multilib = GCCInstallation.getMultilib();
|
const Multilib &Multilib = GCCInstallation.getMultilib();
|
||||||
const GCCVersion &Version = GCCInstallation.getVersion();
|
const GCCVersion &Version = GCCInstallation.getVersion();
|
||||||
|
|
||||||
|
StringRef TripleStr = GCCInstallation.getTriple().str();
|
||||||
const std::string LibStdCXXIncludePathCandidates[] = {
|
const std::string LibStdCXXIncludePathCandidates[] = {
|
||||||
// Android standalone toolchain has C++ headers in yet another place.
|
// Android standalone toolchain has C++ headers in yet another place.
|
||||||
LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
|
LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
|
||||||
|
@ -193,10 +193,8 @@ void Managarm::addLibStdCxxIncludePaths(
|
|||||||
if (!GCCInstallation.isValid())
|
if (!GCCInstallation.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StringRef TripleStr = GCCInstallation.getTriple().str();
|
|
||||||
|
|
||||||
// Try generic GCC detection.
|
// Try generic GCC detection.
|
||||||
Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, TripleStr);
|
addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
SanitizerMask Managarm::getSupportedSanitizers() const {
|
SanitizerMask Managarm::getSupportedSanitizers() const {
|
||||||
|
@ -3721,7 +3721,7 @@ _mm_maskstore_epi64(long long *__X, __m128i __M, __m128i __Y)
|
|||||||
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
|
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
||||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||||
_mm256_sllv_epi32(__m256i __X, __m256i __Y)
|
_mm256_sllv_epi32(__m256i __X, __m256i __Y)
|
||||||
{
|
{
|
||||||
return (__m256i)__builtin_ia32_psllv8si((__v8si)__X, (__v8si)__Y);
|
return (__m256i)__builtin_ia32_psllv8si((__v8si)__X, (__v8si)__Y);
|
||||||
@ -3743,7 +3743,7 @@ _mm256_sllv_epi32(__m256i __X, __m256i __Y)
|
|||||||
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
|
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
||||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||||
_mm_sllv_epi32(__m128i __X, __m128i __Y)
|
_mm_sllv_epi32(__m128i __X, __m128i __Y)
|
||||||
{
|
{
|
||||||
return (__m128i)__builtin_ia32_psllv4si((__v4si)__X, (__v4si)__Y);
|
return (__m128i)__builtin_ia32_psllv4si((__v4si)__X, (__v4si)__Y);
|
||||||
@ -3765,7 +3765,7 @@ _mm_sllv_epi32(__m128i __X, __m128i __Y)
|
|||||||
/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in
|
/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 256-bit vector of [4 x i64] containing the result.
|
/// \returns A 256-bit vector of [4 x i64] containing the result.
|
||||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||||
_mm256_sllv_epi64(__m256i __X, __m256i __Y)
|
_mm256_sllv_epi64(__m256i __X, __m256i __Y)
|
||||||
{
|
{
|
||||||
return (__m256i)__builtin_ia32_psllv4di((__v4di)__X, (__v4di)__Y);
|
return (__m256i)__builtin_ia32_psllv4di((__v4di)__X, (__v4di)__Y);
|
||||||
@ -3787,7 +3787,7 @@ _mm256_sllv_epi64(__m256i __X, __m256i __Y)
|
|||||||
/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in
|
/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 128-bit vector of [2 x i64] containing the result.
|
/// \returns A 128-bit vector of [2 x i64] containing the result.
|
||||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||||
_mm_sllv_epi64(__m128i __X, __m128i __Y)
|
_mm_sllv_epi64(__m128i __X, __m128i __Y)
|
||||||
{
|
{
|
||||||
return (__m128i)__builtin_ia32_psllv2di((__v2di)__X, (__v2di)__Y);
|
return (__m128i)__builtin_ia32_psllv2di((__v2di)__X, (__v2di)__Y);
|
||||||
@ -3810,7 +3810,7 @@ _mm_sllv_epi64(__m128i __X, __m128i __Y)
|
|||||||
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
|
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
||||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||||
_mm256_srav_epi32(__m256i __X, __m256i __Y)
|
_mm256_srav_epi32(__m256i __X, __m256i __Y)
|
||||||
{
|
{
|
||||||
return (__m256i)__builtin_ia32_psrav8si((__v8si)__X, (__v8si)__Y);
|
return (__m256i)__builtin_ia32_psrav8si((__v8si)__X, (__v8si)__Y);
|
||||||
@ -3833,7 +3833,7 @@ _mm256_srav_epi32(__m256i __X, __m256i __Y)
|
|||||||
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
|
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
||||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||||
_mm_srav_epi32(__m128i __X, __m128i __Y)
|
_mm_srav_epi32(__m128i __X, __m128i __Y)
|
||||||
{
|
{
|
||||||
return (__m128i)__builtin_ia32_psrav4si((__v4si)__X, (__v4si)__Y);
|
return (__m128i)__builtin_ia32_psrav4si((__v4si)__X, (__v4si)__Y);
|
||||||
@ -3855,7 +3855,7 @@ _mm_srav_epi32(__m128i __X, __m128i __Y)
|
|||||||
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
|
/// A 256-bit vector of [8 x i32] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
/// \returns A 256-bit vector of [8 x i32] containing the result.
|
||||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||||
_mm256_srlv_epi32(__m256i __X, __m256i __Y)
|
_mm256_srlv_epi32(__m256i __X, __m256i __Y)
|
||||||
{
|
{
|
||||||
return (__m256i)__builtin_ia32_psrlv8si((__v8si)__X, (__v8si)__Y);
|
return (__m256i)__builtin_ia32_psrlv8si((__v8si)__X, (__v8si)__Y);
|
||||||
@ -3877,7 +3877,7 @@ _mm256_srlv_epi32(__m256i __X, __m256i __Y)
|
|||||||
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
|
/// A 128-bit vector of [4 x i32] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
/// \returns A 128-bit vector of [4 x i32] containing the result.
|
||||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||||
_mm_srlv_epi32(__m128i __X, __m128i __Y)
|
_mm_srlv_epi32(__m128i __X, __m128i __Y)
|
||||||
{
|
{
|
||||||
return (__m128i)__builtin_ia32_psrlv4si((__v4si)__X, (__v4si)__Y);
|
return (__m128i)__builtin_ia32_psrlv4si((__v4si)__X, (__v4si)__Y);
|
||||||
@ -3899,7 +3899,7 @@ _mm_srlv_epi32(__m128i __X, __m128i __Y)
|
|||||||
/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in
|
/// A 256-bit vector of [4 x i64] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 256-bit vector of [4 x i64] containing the result.
|
/// \returns A 256-bit vector of [4 x i64] containing the result.
|
||||||
static __inline__ __m256i __DEFAULT_FN_ATTRS256
|
static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR
|
||||||
_mm256_srlv_epi64(__m256i __X, __m256i __Y)
|
_mm256_srlv_epi64(__m256i __X, __m256i __Y)
|
||||||
{
|
{
|
||||||
return (__m256i)__builtin_ia32_psrlv4di((__v4di)__X, (__v4di)__Y);
|
return (__m256i)__builtin_ia32_psrlv4di((__v4di)__X, (__v4di)__Y);
|
||||||
@ -3921,7 +3921,7 @@ _mm256_srlv_epi64(__m256i __X, __m256i __Y)
|
|||||||
/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in
|
/// A 128-bit vector of [2 x i64] containing the unsigned shift counts (in
|
||||||
/// bits).
|
/// bits).
|
||||||
/// \returns A 128-bit vector of [2 x i64] containing the result.
|
/// \returns A 128-bit vector of [2 x i64] containing the result.
|
||||||
static __inline__ __m128i __DEFAULT_FN_ATTRS128
|
static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR
|
||||||
_mm_srlv_epi64(__m128i __X, __m128i __Y)
|
_mm_srlv_epi64(__m128i __X, __m128i __Y)
|
||||||
{
|
{
|
||||||
return (__m128i)__builtin_ia32_psrlv2di((__v2di)__X, (__v2di)__Y);
|
return (__m128i)__builtin_ia32_psrlv2di((__v2di)__X, (__v2di)__Y);
|
||||||
|
@ -5601,8 +5601,10 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
|
|||||||
TheCall->getArg(1)->getEndLoc()));
|
TheCall->getArg(1)->getEndLoc()));
|
||||||
} else if (numElements != numResElements) {
|
} else if (numElements != numResElements) {
|
||||||
QualType eltType = LHSType->castAs<VectorType>()->getElementType();
|
QualType eltType = LHSType->castAs<VectorType>()->getElementType();
|
||||||
resType =
|
resType = resType->isExtVectorType()
|
||||||
Context.getVectorType(eltType, numResElements, VectorKind::Generic);
|
? Context.getExtVectorType(eltType, numResElements)
|
||||||
|
: Context.getVectorType(eltType, numResElements,
|
||||||
|
VectorKind::Generic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ using FourFloatsExtVec __attribute__((ext_vector_type(4))) = float;
|
|||||||
using FourDoublesExtVec __attribute__((ext_vector_type(4))) = double;
|
using FourDoublesExtVec __attribute__((ext_vector_type(4))) = double;
|
||||||
using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128;
|
using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128;
|
||||||
|
|
||||||
|
|
||||||
// Next a series of tests to make sure these operations are usable in
|
// Next a series of tests to make sure these operations are usable in
|
||||||
// constexpr functions. Template instantiations don't emit Winvalid-constexpr,
|
// constexpr functions. Template instantiations don't emit Winvalid-constexpr,
|
||||||
// so we have to do these as macros.
|
// so we have to do these as macros.
|
||||||
@ -875,3 +874,9 @@ void BoolVecUsage() {
|
|||||||
constexpr auto k = ~FourBoolsExtVec{true, false, true, false};
|
constexpr auto k = ~FourBoolsExtVec{true, false, true, false};
|
||||||
static_assert(k[0] == false && k[1] == true && k[2] == false && k[3] == true, "");
|
static_assert(k[0] == false && k[1] == true && k[2] == false && k[3] == true, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using EightBoolsExtVec __attribute__((ext_vector_type(8))) = bool;
|
||||||
|
void BoolVecShuffle() {
|
||||||
|
constexpr EightBoolsExtVec a = __builtin_shufflevector(
|
||||||
|
FourBoolsExtVec{}, FourBoolsExtVec{}, 0, 1, 2, 3, 4, 5, 6, 7);
|
||||||
|
}
|
||||||
|
@ -732,3 +732,8 @@ namespace LocalVarForParmVarDecl {
|
|||||||
}
|
}
|
||||||
static_assert(foo(), "");
|
static_assert(foo(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PtrPtrCast {
|
||||||
|
void foo() { ; }
|
||||||
|
void bar(int *a) { a = (int *)(void *)(foo); }
|
||||||
|
}
|
||||||
|
47
clang/test/CIR/CodeGen/function-to-pointer-decay.c
Normal file
47
clang/test/CIR/CodeGen/function-to-pointer-decay.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
|
||||||
|
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
|
||||||
|
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
|
||||||
|
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
|
||||||
|
|
||||||
|
void f(void);
|
||||||
|
|
||||||
|
void f1() {
|
||||||
|
(void (*)())f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void f2() {
|
||||||
|
(*(void (*)(void))f)();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_lvalue_cast() {
|
||||||
|
(*(void (*)(int))f)(42);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CIR-LABEL: cir.func{{.*}} @f()
|
||||||
|
// CIR: cir.func{{.*}} @f1()
|
||||||
|
// CIR: cir.return{{.*}}
|
||||||
|
|
||||||
|
// CIR-LABEL: cir.func{{.*}} @f2()
|
||||||
|
// CIR: cir.call @f() : () -> ()
|
||||||
|
|
||||||
|
// CIR-LABEL: cir.func{{.*}} @test_lvalue_cast()
|
||||||
|
// CIR: %[[S0:.+]] = {{.*}}@f : !cir.ptr<!cir.func<()>>{{.*}}
|
||||||
|
// CIR: %[[S1:.+]] = cir.cast{{.*}}%[[S0]] : !cir.ptr<!cir.func<()>>{{.*}}
|
||||||
|
// CIR: %[[S2:.+]] = cir.const #cir.int<42> : !s32i
|
||||||
|
// CIR: cir.call %[[S1]](%[[S2]]) : (!cir.ptr<!cir.func<(!s32i)>>, !s32i) -> ()
|
||||||
|
|
||||||
|
// LLVM-LABEL: define{{.*}} void @f1()
|
||||||
|
// LLVM: ret void
|
||||||
|
// LLVM: define{{.*}} void @f2()
|
||||||
|
// LLVM: call void @f()
|
||||||
|
// LLVM: define{{.*}} void @test_lvalue_cast()
|
||||||
|
// LLVM: call void @f(i32 42)
|
||||||
|
|
||||||
|
// OGCG-LABEL: define{{.*}} void @f1()
|
||||||
|
// OGCG: ret void
|
||||||
|
// OGCG: define{{.*}} void @f2()
|
||||||
|
// OGCG: call void @f()
|
||||||
|
// OGCG: define{{.*}} void @test_lvalue_cast()
|
||||||
|
// OGCG: call void @f(i32 noundef 42)
|
@ -327,7 +327,6 @@ __m256i test_mm256_cvtepi8_epi16(__m128i a) {
|
|||||||
// CHECK: sext <16 x i8> %{{.*}} to <16 x i16>
|
// CHECK: sext <16 x i8> %{{.*}} to <16 x i16>
|
||||||
return _mm256_cvtepi8_epi16(a);
|
return _mm256_cvtepi8_epi16(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v16hi(_mm256_cvtepi8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12));
|
TEST_CONSTEXPR(match_v16hi(_mm256_cvtepi8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepi8_epi32(__m128i a) {
|
__m256i test_mm256_cvtepi8_epi32(__m128i a) {
|
||||||
@ -336,7 +335,6 @@ __m256i test_mm256_cvtepi8_epi32(__m128i a) {
|
|||||||
// CHECK: sext <8 x i8> %{{.*}} to <8 x i32>
|
// CHECK: sext <8 x i8> %{{.*}} to <8 x i32>
|
||||||
return _mm256_cvtepi8_epi32(a);
|
return _mm256_cvtepi8_epi32(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v8si(_mm256_cvtepi8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4));
|
TEST_CONSTEXPR(match_v8si(_mm256_cvtepi8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0, 1, -2, 3, -4));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepi8_epi64(__m128i a) {
|
__m256i test_mm256_cvtepi8_epi64(__m128i a) {
|
||||||
@ -345,7 +343,6 @@ __m256i test_mm256_cvtepi8_epi64(__m128i a) {
|
|||||||
// CHECK: sext <4 x i8> %{{.*}} to <4 x i64>
|
// CHECK: sext <4 x i8> %{{.*}} to <4 x i64>
|
||||||
return _mm256_cvtepi8_epi64(a);
|
return _mm256_cvtepi8_epi64(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0));
|
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), -3, 2, -1, 0));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepi16_epi32(__m128i a) {
|
__m256i test_mm256_cvtepi16_epi32(__m128i a) {
|
||||||
@ -353,7 +350,6 @@ __m256i test_mm256_cvtepi16_epi32(__m128i a) {
|
|||||||
// CHECK: sext <8 x i16> %{{.*}} to <8 x i32>
|
// CHECK: sext <8 x i16> %{{.*}} to <8 x i32>
|
||||||
return _mm256_cvtepi16_epi32(a);
|
return _mm256_cvtepi16_epi32(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v8si(_mm256_cvtepi16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0, 1, -2, 3, -4));
|
TEST_CONSTEXPR(match_v8si(_mm256_cvtepi16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0, 1, -2, 3, -4));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepi16_epi64(__m128i a) {
|
__m256i test_mm256_cvtepi16_epi64(__m128i a) {
|
||||||
@ -362,7 +358,6 @@ __m256i test_mm256_cvtepi16_epi64(__m128i a) {
|
|||||||
// CHECK: sext <4 x i16> %{{.*}} to <4 x i64>
|
// CHECK: sext <4 x i16> %{{.*}} to <4 x i64>
|
||||||
return _mm256_cvtepi16_epi64(a);
|
return _mm256_cvtepi16_epi64(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0));
|
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), -300, 2, -1, 0));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepi32_epi64(__m128i a) {
|
__m256i test_mm256_cvtepi32_epi64(__m128i a) {
|
||||||
@ -370,7 +365,6 @@ __m256i test_mm256_cvtepi32_epi64(__m128i a) {
|
|||||||
// CHECK: sext <4 x i32> %{{.*}} to <4 x i64>
|
// CHECK: sext <4 x i32> %{{.*}} to <4 x i64>
|
||||||
return _mm256_cvtepi32_epi64(a);
|
return _mm256_cvtepi32_epi64(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), -70000, 2, -1, 0));
|
TEST_CONSTEXPR(match_v4di(_mm256_cvtepi32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), -70000, 2, -1, 0));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepu8_epi16(__m128i a) {
|
__m256i test_mm256_cvtepu8_epi16(__m128i a) {
|
||||||
@ -378,7 +372,6 @@ __m256i test_mm256_cvtepu8_epi16(__m128i a) {
|
|||||||
// CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
|
// CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
|
||||||
return _mm256_cvtepu8_epi16(a);
|
return _mm256_cvtepu8_epi16(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v16hi(_mm256_cvtepu8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252, 5, 250, 7, 248, 9, 246, 11, 244));
|
TEST_CONSTEXPR(match_v16hi(_mm256_cvtepu8_epi16(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252, 5, 250, 7, 248, 9, 246, 11, 244));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepu8_epi32(__m128i a) {
|
__m256i test_mm256_cvtepu8_epi32(__m128i a) {
|
||||||
@ -387,7 +380,6 @@ __m256i test_mm256_cvtepu8_epi32(__m128i a) {
|
|||||||
// CHECK: zext <8 x i8> %{{.*}} to <8 x i32>
|
// CHECK: zext <8 x i8> %{{.*}} to <8 x i32>
|
||||||
return _mm256_cvtepu8_epi32(a);
|
return _mm256_cvtepu8_epi32(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v8si(_mm256_cvtepu8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252));
|
TEST_CONSTEXPR(match_v8si(_mm256_cvtepu8_epi32(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0, 1, 254, 3, 252));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepu8_epi64(__m128i a) {
|
__m256i test_mm256_cvtepu8_epi64(__m128i a) {
|
||||||
@ -396,7 +388,6 @@ __m256i test_mm256_cvtepu8_epi64(__m128i a) {
|
|||||||
// CHECK: zext <4 x i8> %{{.*}} to <4 x i64>
|
// CHECK: zext <4 x i8> %{{.*}} to <4 x i64>
|
||||||
return _mm256_cvtepu8_epi64(a);
|
return _mm256_cvtepu8_epi64(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0));
|
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu8_epi64(_mm_setr_epi8(-3, 2, -1, 0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12)), 253, 2, 255, 0));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepu16_epi32(__m128i a) {
|
__m256i test_mm256_cvtepu16_epi32(__m128i a) {
|
||||||
@ -404,7 +395,6 @@ __m256i test_mm256_cvtepu16_epi32(__m128i a) {
|
|||||||
// CHECK: zext <8 x i16> {{.*}} to <8 x i32>
|
// CHECK: zext <8 x i16> {{.*}} to <8 x i32>
|
||||||
return _mm256_cvtepu16_epi32(a);
|
return _mm256_cvtepu16_epi32(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v8si(_mm256_cvtepu16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0, 1, 65534, 3, 65532));
|
TEST_CONSTEXPR(match_v8si(_mm256_cvtepu16_epi32(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0, 1, 65534, 3, 65532));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepu16_epi64(__m128i a) {
|
__m256i test_mm256_cvtepu16_epi64(__m128i a) {
|
||||||
@ -413,7 +403,6 @@ __m256i test_mm256_cvtepu16_epi64(__m128i a) {
|
|||||||
// CHECK: zext <4 x i16> %{{.*}} to <4 x i64>
|
// CHECK: zext <4 x i16> %{{.*}} to <4 x i64>
|
||||||
return _mm256_cvtepu16_epi64(a);
|
return _mm256_cvtepu16_epi64(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0));
|
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu16_epi64(_mm_setr_epi16(-300, 2, -1, 0, 1, -2, 3, -4)), 65236, 2, 65535, 0));
|
||||||
|
|
||||||
__m256i test_mm256_cvtepu32_epi64(__m128i a) {
|
__m256i test_mm256_cvtepu32_epi64(__m128i a) {
|
||||||
@ -421,7 +410,6 @@ __m256i test_mm256_cvtepu32_epi64(__m128i a) {
|
|||||||
// CHECK: zext <4 x i32> %{{.*}} to <4 x i64>
|
// CHECK: zext <4 x i32> %{{.*}} to <4 x i64>
|
||||||
return _mm256_cvtepu32_epi64(a);
|
return _mm256_cvtepu32_epi64(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), 4294897296, 2, 4294967295, 0));
|
TEST_CONSTEXPR(match_v4di(_mm256_cvtepu32_epi64(_mm_setr_epi32(-70000, 2, -1, 0)), 4294897296, 2, 4294967295, 0));
|
||||||
|
|
||||||
__m128i test0_mm256_extracti128_si256_0(__m256i a) {
|
__m128i test0_mm256_extracti128_si256_0(__m256i a) {
|
||||||
@ -1120,24 +1108,28 @@ __m128i test_mm_sllv_epi32(__m128i a, __m128i b) {
|
|||||||
// CHECK: call <4 x i32> @llvm.x86.avx2.psllv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
|
// CHECK: call <4 x i32> @llvm.x86.avx2.psllv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
|
||||||
return _mm_sllv_epi32(a, b);
|
return _mm_sllv_epi32(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_v4si(_mm_sllv_epi32((__m128i)(__v4si){1, -2, 3, -4}, (__m128i)(__v4si){1, 2, 3, -4}), 2, -8, 24, 0));
|
||||||
|
|
||||||
__m256i test_mm256_sllv_epi32(__m256i a, __m256i b) {
|
__m256i test_mm256_sllv_epi32(__m256i a, __m256i b) {
|
||||||
// CHECK-LABEL: test_mm256_sllv_epi32
|
// CHECK-LABEL: test_mm256_sllv_epi32
|
||||||
// CHECK: call <8 x i32> @llvm.x86.avx2.psllv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
// CHECK: call <8 x i32> @llvm.x86.avx2.psllv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
||||||
return _mm256_sllv_epi32(a, b);
|
return _mm256_sllv_epi32(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_v8si(_mm256_sllv_epi32((__m256i)(__v8si){1, -2, 3, -4, 5, -6, 7, -8}, (__m256i)(__v8si){1, 2, 3, 4, -17, 31, 33, 29}), 2, -8, 24, -64, 0, 0, 0, 0));
|
||||||
|
|
||||||
__m128i test_mm_sllv_epi64(__m128i a, __m128i b) {
|
__m128i test_mm_sllv_epi64(__m128i a, __m128i b) {
|
||||||
// CHECK-LABEL: test_mm_sllv_epi64
|
// CHECK-LABEL: test_mm_sllv_epi64
|
||||||
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psllv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
|
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psllv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
|
||||||
return _mm_sllv_epi64(a, b);
|
return _mm_sllv_epi64(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_m128i(_mm_sllv_epi64((__m128i)(__v2di){1, -3}, (__m128i)(__v2di){8, 63}), 256, 0x8000000000000000ULL));
|
||||||
|
|
||||||
__m256i test_mm256_sllv_epi64(__m256i a, __m256i b) {
|
__m256i test_mm256_sllv_epi64(__m256i a, __m256i b) {
|
||||||
// CHECK-LABEL: test_mm256_sllv_epi64
|
// CHECK-LABEL: test_mm256_sllv_epi64
|
||||||
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psllv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
|
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psllv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
|
||||||
return _mm256_sllv_epi64(a, b);
|
return _mm256_sllv_epi64(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_m256i(_mm256_sllv_epi64((__m256i)(__v4di){1, -2, 3, -4}, (__m256i)(__v4di){1, 2, 3, -4}), 2, -8, 24, 0));
|
||||||
|
|
||||||
__m256i test_mm256_sra_epi16(__m256i a, __m128i b) {
|
__m256i test_mm256_sra_epi16(__m256i a, __m128i b) {
|
||||||
// CHECK-LABEL: test_mm256_sra_epi16
|
// CHECK-LABEL: test_mm256_sra_epi16
|
||||||
@ -1180,12 +1172,14 @@ __m128i test_mm_srav_epi32(__m128i a, __m128i b) {
|
|||||||
// CHECK: call <4 x i32> @llvm.x86.avx2.psrav.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
|
// CHECK: call <4 x i32> @llvm.x86.avx2.psrav.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
|
||||||
return _mm_srav_epi32(a, b);
|
return _mm_srav_epi32(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_v4si(_mm_srav_epi32((__m128i)(__v4si){1, -2, 3, -4}, (__m128i)(__v4si){1, 2, 3, -4}), 0, -1, 0, -1));
|
||||||
|
|
||||||
__m256i test_mm256_srav_epi32(__m256i a, __m256i b) {
|
__m256i test_mm256_srav_epi32(__m256i a, __m256i b) {
|
||||||
// CHECK-LABEL: test_mm256_srav_epi32
|
// CHECK-LABEL: test_mm256_srav_epi32
|
||||||
// CHECK: call <8 x i32> @llvm.x86.avx2.psrav.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
// CHECK: call <8 x i32> @llvm.x86.avx2.psrav.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
||||||
return _mm256_srav_epi32(a, b);
|
return _mm256_srav_epi32(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_v8si(_mm256_srav_epi32((__m256i)(__v8si){1, -2, 3, -4, 5, -6, 7, -8}, (__m256i)(__v8si){1, 2, 3, 4, -17, 31, 33, 29}), 0, -1, 0, -1, 0, -1, 0, -1));
|
||||||
|
|
||||||
__m256i test_mm256_srl_epi16(__m256i a, __m128i b) {
|
__m256i test_mm256_srl_epi16(__m256i a, __m128i b) {
|
||||||
// CHECK-LABEL: test_mm256_srl_epi16
|
// CHECK-LABEL: test_mm256_srl_epi16
|
||||||
@ -1252,24 +1246,28 @@ __m128i test_mm_srlv_epi32(__m128i a, __m128i b) {
|
|||||||
// CHECK: call <4 x i32> @llvm.x86.avx2.psrlv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
|
// CHECK: call <4 x i32> @llvm.x86.avx2.psrlv.d(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
|
||||||
return _mm_srlv_epi32(a, b);
|
return _mm_srlv_epi32(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_v4si(_mm_srlv_epi32((__m128i)(__v4si){1, -2, 3, -4}, (__m128i)(__v4si){1, 2, 3, -4}), 0, 1073741823, 0, 0));
|
||||||
|
|
||||||
__m256i test_mm256_srlv_epi32(__m256i a, __m256i b) {
|
__m256i test_mm256_srlv_epi32(__m256i a, __m256i b) {
|
||||||
// CHECK-LABEL: test_mm256_srlv_epi32
|
// CHECK-LABEL: test_mm256_srlv_epi32
|
||||||
// CHECK: call <8 x i32> @llvm.x86.avx2.psrlv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
// CHECK: call <8 x i32> @llvm.x86.avx2.psrlv.d.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}})
|
||||||
return _mm256_srlv_epi32(a, b);
|
return _mm256_srlv_epi32(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_v8si(_mm256_srlv_epi32((__m256i)(__v8si){1, -2, 3, -4, 5, -6, 7, -8}, (__m256i)(__v8si){1, 2, 3, 4, -17, 31, 33, 29}), 0, 1073741823, 0, 268435455, 0, 1, 0, 7));
|
||||||
|
|
||||||
__m128i test_mm_srlv_epi64(__m128i a, __m128i b) {
|
__m128i test_mm_srlv_epi64(__m128i a, __m128i b) {
|
||||||
// CHECK-LABEL: test_mm_srlv_epi64
|
// CHECK-LABEL: test_mm_srlv_epi64
|
||||||
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psrlv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
|
// CHECK: call {{.*}}<2 x i64> @llvm.x86.avx2.psrlv.q(<2 x i64> %{{.*}}, <2 x i64> %{{.*}})
|
||||||
return _mm_srlv_epi64(a, b);
|
return _mm_srlv_epi64(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_m128i(_mm_srlv_epi64((__m128i)(__v2di){1, -3}, (__m128i)(__v2di){8, 63}), 0, 1));
|
||||||
|
|
||||||
__m256i test_mm256_srlv_epi64(__m256i a, __m256i b) {
|
__m256i test_mm256_srlv_epi64(__m256i a, __m256i b) {
|
||||||
// CHECK-LABEL: test_mm256_srlv_epi64
|
// CHECK-LABEL: test_mm256_srlv_epi64
|
||||||
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psrlv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
|
// CHECK: call {{.*}}<4 x i64> @llvm.x86.avx2.psrlv.q.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}})
|
||||||
return _mm256_srlv_epi64(a, b);
|
return _mm256_srlv_epi64(a, b);
|
||||||
}
|
}
|
||||||
|
TEST_CONSTEXPR(match_m256i(_mm256_srlv_epi64((__m256i)(__v4di){1, -2, 3, -4}, (__m256i)(__v4di){1, 2, 3, -4}), 0, 0x3FFFFFFFFFFFFFFFULL, 0, 0));
|
||||||
|
|
||||||
__m256i test_mm256_stream_load_si256(__m256i const *a) {
|
__m256i test_mm256_stream_load_si256(__m256i const *a) {
|
||||||
// CHECK-LABEL: test_mm256_stream_load_si256
|
// CHECK-LABEL: test_mm256_stream_load_si256
|
||||||
|
12
clang/test/DebugInfo/CXX/dependent-template-type-scope.cpp
Normal file
12
clang/test/DebugInfo/CXX/dependent-template-type-scope.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -debug-info-kind=standalone -o - %s | FileCheck %s
|
||||||
|
|
||||||
|
template <typename T = int>
|
||||||
|
struct Y {
|
||||||
|
typedef int outside;
|
||||||
|
outside o;
|
||||||
|
};
|
||||||
|
|
||||||
|
Y<> y;
|
||||||
|
|
||||||
|
// CHECK: ![[Y:.*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Y<int>", {{.*}}identifier: "_ZTS1YIiE")
|
||||||
|
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "outside", scope: ![[Y]],
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user