710 changes: 710 additions & 0 deletions bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-other.s

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions bolt/test/X86/dwarf4-df-input-lowpc-ranges-cus.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
; RUN: rm -rf %t
; RUN: mkdir %t
; RUN: cd %t
; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-main.s \
; RUN: -split-dwarf-file=main.dwo -o main.o
; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-other.s \
; RUN: -split-dwarf-file=mainOther.dwo -o other.o
; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o other.o -o main.exe
; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections
; RUN: llvm-dwarfdump --show-form --verbose --debug-ranges main.exe.bolt &> %t/foo.txt
; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt
; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s
; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo mainOther.dwo.dwo &> %t/mainddwodwo.txt
; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s

;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input and handles multiple CUs with ranges.

; BOLT: .debug_ranges
; BOLT-NEXT: 00000000 <End of list>
; BOLT-NEXT: 00000010
; BOLT-NEXT: 00000010
; BOLT-NEXT: 00000010
; BOLT-NEXT: 00000010 <End of list>
; BOLT-NEXT: 00000050
; BOLT-NEXT: 00000050
; BOLT-NEXT: 00000050
; BOLT-NEXT: 00000050 <End of list>
; BOLT-NEXT: 00000090 [[#%.16x,ADDR1:]] [[#%.16x,ADDRB1:]]
; BOLT-NEXT: 00000090 [[#%.16x,ADDR2:]] [[#%.16x,ADDRB2:]]
; BOLT-NEXT: 00000090 [[#%.16x,ADDR3:]] [[#%.16x,ADDRB3:]]
; BOLT-NEXT: 00000090 [[#%.16x,ADDR4:]] [[#%.16x,ADDRB4:]]
; BOLT-NEXT: 00000090 [[#%.16x,ADDR5:]] [[#%.16x,ADDRB5:]]
; BOLT-NEXT: 00000090 [[#%.16x,ADDR6:]] [[#%.16x,ADDRB6:]]
; BOLT-NEXT: 00000090 [[#%.16x,ADDR7:]] [[#%.16x,ADDRB7:]]
; BOLT-NEXT: 00000090 <End of list>
; BOLT-NEXT: 00000110
; BOLT-NEXT: 00000110
; BOLT-NEXT: 00000110
; BOLT-NEXT: 00000110 <End of list>
; BOLT-NEXT: 00000150
; BOLT-NEXT: 00000150
; BOLT-NEXT: 00000150
; BOLT-NEXT: 00000150 <End of list>
; BOLT-NEXT: 00000190 [[#%.16x,ADDR8:]] [[#%.16x,ADDRB8:]]
; BOLT-NEXT: 00000190 [[#%.16x,ADDR9:]] [[#%.16x,ADDRB9:]]
; BOLT-NEXT: 00000190 [[#%.16x,ADDR10:]] [[#%.16x,ADDRB10:]]
; BOLT-NEXT: 00000190 [[#%.16x,ADDR11:]] [[#%.16x,ADDRB11:]]
; BOLT-NEXT: 00000190 [[#%.16x,ADDR12:]] [[#%.16x,ADDRB12:]]
; BOLT-NEXT: 00000190 [[#%.16x,ADDR13:]] [[#%.16x,ADDRB13:]]
; BOLT-NEXT: 00000190 [[#%.16x,ADDR14:]] [[#%.16x,ADDRB14:]]
; BOLT-NEXT: 00000190 <End of list>

; BOLT: DW_TAG_compile_unit
; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "main.dwo.dwo")
; BOLT-NEXT: DW_AT_GNU_dwo_id
; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000010)
; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000090
; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDRB1]])
; BOLT-NEXT: [0x[[#ADDR2]], 0x[[#ADDRB2]])
; BOLT-NEXT: [0x[[#ADDR3]], 0x[[#ADDRB3]])
; BOLT-NEXT: [0x[[#ADDR4]], 0x[[#ADDRB4]])
; BOLT-NEXT: [0x[[#ADDR5]], 0x[[#ADDRB5]])
; BOLT-NEXT: [0x[[#ADDR6]], 0x[[#ADDRB6]])
; BOLT-NEXT: [0x[[#ADDR7]], 0x[[#ADDRB7]])
; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000000)

; BOLT: DW_TAG_compile_unit
; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "mainOther.dwo.dwo")
; BOLT-NEXT: DW_AT_GNU_dwo_id
; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000110)
; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000190
; BOLT-NEXT: [0x[[#ADDR8]], 0x[[#ADDRB8]])
; BOLT-NEXT: [0x[[#ADDR9]], 0x[[#ADDRB9]])
; BOLT-NEXT: [0x[[#ADDR10]], 0x[[#ADDRB10]])
; BOLT-NEXT: [0x[[#ADDR11]], 0x[[#ADDRB11]])
; BOLT-NEXT: [0x[[#ADDR12]], 0x[[#ADDRB12]])
; BOLT-NEXT: [0x[[#ADDR13]], 0x[[#ADDRB13]])
; BOLT-NEXT: [0x[[#ADDR14]], 0x[[#ADDRB14]])
; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000018)

; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040

; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN: DW_TAG_subprogram
; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040
14 changes: 8 additions & 6 deletions clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ void UseStdFormatCheck::registerPPCallbacks(const SourceManager &SM,
}

void UseStdFormatCheck::registerMatchers(MatchFinder *Finder) {
auto CharPointerType =
hasType(pointerType(pointee(matchers::isSimpleChar())));
Finder->addMatcher(
callExpr(argumentCountAtLeast(1),
hasArgument(0, stringLiteral(isOrdinary())),
callee(functionDecl(unless(cxxMethodDecl()),
matchers::matchesAnyListedName(
StrFormatLikeFunctions))
.bind("func_decl")))
callExpr(
argumentCountAtLeast(1), hasArgument(0, stringLiteral(isOrdinary())),
callee(functionDecl(
unless(cxxMethodDecl()), hasParameter(0, CharPointerType),
matchers::matchesAnyListedName(StrFormatLikeFunctions))
.bind("func_decl")))
.bind("strformat"),
this);
}
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,15 @@ unusedReturnValue(clang::ast_matchers::StatementMatcher MatchedCallExpr) {
}

void UseStdPrintCheck::registerMatchers(MatchFinder *Finder) {
auto CharPointerType =
hasType(pointerType(pointee(matchers::isSimpleChar())));
if (!PrintfLikeFunctions.empty())
Finder->addMatcher(
unusedReturnValue(
callExpr(argumentCountAtLeast(1),
hasArgument(0, stringLiteral(isOrdinary())),
callee(functionDecl(unless(cxxMethodDecl()),
hasParameter(0, CharPointerType),
matchers::matchesAnyListedName(
PrintfLikeFunctions))
.bind("func_decl")))
Expand All @@ -113,6 +116,7 @@ void UseStdPrintCheck::registerMatchers(MatchFinder *Finder) {
callExpr(argumentCountAtLeast(2),
hasArgument(1, stringLiteral(isOrdinary())),
callee(functionDecl(unless(cxxMethodDecl()),
hasParameter(1, CharPointerType),
matchers::matchesAnyListedName(
FprintfLikeFunctions))
.bind("func_decl")))
Expand Down
8 changes: 5 additions & 3 deletions clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,11 @@ FormatStringConverter::FormatStringConverter(ASTContext *ContextIn,
assert(ArgsOffset <= NumArgs);
FormatExpr = llvm::dyn_cast<StringLiteral>(
Args[FormatArgOffset]->IgnoreImplicitAsWritten());
assert(FormatExpr);
if (!FormatExpr->isOrdinary())
return; // No wide string support yet
if (!FormatExpr || !FormatExpr->isOrdinary()) {
// Function must have a narrow string literal as its first argument.
conversionNotPossible("first argument is not a narrow string literal");
return;
}
PrintfFormatString = FormatExpr->getString();

// Assume that the output will be approximately the same size as the input,
Expand Down
8 changes: 8 additions & 0 deletions clang-tools-extra/clang-tidy/utils/Matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
return pointerType(pointee(qualType(isConstQualified())));
}

// Returns QualType matcher for target char type only.
AST_MATCHER(QualType, isSimpleChar) {
const auto ActualType = Node.getTypePtr();
return ActualType &&
(ActualType->isSpecificBuiltinType(BuiltinType::Char_S) ||
ActualType->isSpecificBuiltinType(BuiltinType::Char_U));
}

AST_MATCHER(Expr, hasUnevaluatedContext) {
if (isa<CXXNoexceptExpr>(Node) || isa<RequiresExpr>(Node))
return true;
Expand Down
150 changes: 93 additions & 57 deletions clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,11 @@ deleteTokensWithKind(const syntax::TokenBuffer &TokBuf, tok::TokenKind Kind,
// looked up in the context containing the function/method.
// FIXME: Drop attributes in function signature.
llvm::Expected<std::string>
getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext,
const syntax::TokenBuffer &TokBuf,
const HeuristicResolver *Resolver) {
auto &AST = FD->getASTContext();
auto &SM = AST.getSourceManager();
auto TargetContext = findContextForNS(TargetNamespace, FD->getDeclContext());
if (!TargetContext)
return error("define outline: couldn't find a context for target");

llvm::Error Errors = llvm::Error::success();
tooling::Replacements DeclarationCleanups;
Expand Down Expand Up @@ -216,7 +213,7 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
}
const NamedDecl *ND = Ref.Targets.front();
const std::string Qualifier =
getQualification(AST, *TargetContext,
getQualification(AST, TargetContext,
SM.getLocForStartOfFile(SM.getMainFileID()), ND);
if (auto Err = DeclarationCleanups.add(
tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier)))
Expand All @@ -232,7 +229,7 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
if (const auto *Destructor = llvm::dyn_cast<CXXDestructorDecl>(FD)) {
if (auto Err = DeclarationCleanups.add(tooling::Replacement(
SM, Destructor->getLocation(), 0,
getQualification(AST, *TargetContext,
getQualification(AST, TargetContext,
SM.getLocForStartOfFile(SM.getMainFileID()),
Destructor))))
Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
Expand Down Expand Up @@ -319,29 +316,9 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
}

struct InsertionPoint {
std::string EnclosingNamespace;
const DeclContext *EnclosingNamespace = nullptr;
size_t Offset;
};
// Returns the most natural insertion point for \p QualifiedName in \p Contents.
// This currently cares about only the namespace proximity, but in feature it
// should also try to follow ordering of declarations. For example, if decls
// come in order `foo, bar, baz` then this function should return some point
// between foo and baz for inserting bar.
llvm::Expected<InsertionPoint> getInsertionPoint(llvm::StringRef Contents,
llvm::StringRef QualifiedName,
const LangOptions &LangOpts) {
auto Region = getEligiblePoints(Contents, QualifiedName, LangOpts);

assert(!Region.EligiblePoints.empty());
// FIXME: This selection can be made smarter by looking at the definition
// locations for adjacent decls to Source. Unfortunately pseudo parsing in
// getEligibleRegions only knows about namespace begin/end events so we
// can't match function start/end positions yet.
auto Offset = positionToOffset(Contents, Region.EligiblePoints.back());
if (!Offset)
return Offset.takeError();
return InsertionPoint{Region.EnclosingNamespace, *Offset};
}

// Returns the range that should be deleted from declaration, which always
// contains function body. In addition to that it might contain constructor
Expand Down Expand Up @@ -409,14 +386,9 @@ class DefineOutline : public Tweak {
}

bool prepare(const Selection &Sel) override {
// Bail out if we are not in a header file.
// FIXME: We might want to consider moving method definitions below class
// definition even if we are inside a source file.
if (!isHeaderFile(Sel.AST->getSourceManager().getFilename(Sel.Cursor),
Sel.AST->getLangOpts()))
return false;

SameFile = !isHeaderFile(Sel.AST->tuPath(), Sel.AST->getLangOpts());
Source = getSelectedFunction(Sel.ASTSelection.commonAncestor());

// Bail out if the selection is not a in-line function definition.
if (!Source || !Source->doesThisDeclarationHaveABody() ||
Source->isOutOfLine())
Expand All @@ -429,19 +401,24 @@ class DefineOutline : public Tweak {
if (Source->getTemplateSpecializationInfo())
return false;

if (auto *MD = llvm::dyn_cast<CXXMethodDecl>(Source)) {
// Bail out in templated classes, as it is hard to spell the class name,
// i.e if the template parameter is unnamed.
if (MD->getParent()->isTemplated())
return false;

// The refactoring is meaningless for unnamed classes and definitions
// within unnamed namespaces.
for (const DeclContext *DC = MD->getParent(); DC; DC = DC->getParent()) {
if (auto *ND = llvm::dyn_cast<NamedDecl>(DC)) {
if (ND->getDeclName().isEmpty())
return false;
}
auto *MD = llvm::dyn_cast<CXXMethodDecl>(Source);
if (!MD) {
// Can't outline free-standing functions in the same file.
return !SameFile;
}

// Bail out in templated classes, as it is hard to spell the class name,
// i.e if the template parameter is unnamed.
if (MD->getParent()->isTemplated())
return false;

// The refactoring is meaningless for unnamed classes and namespaces,
// unless we're outlining in the same file
for (const DeclContext *DC = MD->getParent(); DC; DC = DC->getParent()) {
if (auto *ND = llvm::dyn_cast<NamedDecl>(DC)) {
if (ND->getDeclName().isEmpty() &&
(!SameFile || !llvm::dyn_cast<NamespaceDecl>(ND)))
return false;
}
}

Expand All @@ -453,8 +430,8 @@ class DefineOutline : public Tweak {

Expected<Effect> apply(const Selection &Sel) override {
const SourceManager &SM = Sel.AST->getSourceManager();
auto CCFile = getSourceFile(Sel.AST->tuPath(), Sel);

auto CCFile = SameFile ? Sel.AST->tuPath().str()
: getSourceFile(Sel.AST->tuPath(), Sel);
if (!CCFile)
return error("Couldn't find a suitable implementation file.");
assert(Sel.FS && "FS Must be set in apply");
Expand All @@ -464,8 +441,7 @@ class DefineOutline : public Tweak {
if (!Buffer)
return llvm::errorCodeToError(Buffer.getError());
auto Contents = Buffer->get()->getBuffer();
auto InsertionPoint = getInsertionPoint(
Contents, Source->getQualifiedNameAsString(), Sel.AST->getLangOpts());
auto InsertionPoint = getInsertionPoint(Contents, Sel);
if (!InsertionPoint)
return InsertionPoint.takeError();

Expand Down Expand Up @@ -499,17 +475,77 @@ class DefineOutline : public Tweak {
HeaderUpdates = HeaderUpdates.merge(*DelInline);
}

auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(), HeaderUpdates);
if (!HeaderFE)
return HeaderFE.takeError();

Effect->ApplyEdits.try_emplace(HeaderFE->first,
std::move(HeaderFE->second));
if (SameFile) {
tooling::Replacements &R = Effect->ApplyEdits[*CCFile].Replacements;
R = R.merge(HeaderUpdates);
} else {
auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(), HeaderUpdates);
if (!HeaderFE)
return HeaderFE.takeError();
Effect->ApplyEdits.try_emplace(HeaderFE->first,
std::move(HeaderFE->second));
}
return std::move(*Effect);
}

// Returns the most natural insertion point for \p QualifiedName in \p
// Contents. This currently cares about only the namespace proximity, but in
// feature it should also try to follow ordering of declarations. For example,
// if decls come in order `foo, bar, baz` then this function should return
// some point between foo and baz for inserting bar.
// FIXME: The selection can be made smarter by looking at the definition
// locations for adjacent decls to Source. Unfortunately pseudo parsing in
// getEligibleRegions only knows about namespace begin/end events so we
// can't match function start/end positions yet.
llvm::Expected<InsertionPoint> getInsertionPoint(llvm::StringRef Contents,
const Selection &Sel) {
// If the definition goes to the same file and there is a namespace,
// we should (and, in the case of anonymous namespaces, need to)
// put the definition into the original namespace block.
if (SameFile) {
auto *Klass = Source->getDeclContext()->getOuterLexicalRecordContext();
if (!Klass)
return error("moving to same file not supported for free functions");
const SourceLocation EndLoc = Klass->getBraceRange().getEnd();
const auto &TokBuf = Sel.AST->getTokens();
auto Tokens = TokBuf.expandedTokens();
auto It = llvm::lower_bound(
Tokens, EndLoc, [](const syntax::Token &Tok, SourceLocation EndLoc) {
return Tok.location() < EndLoc;
});
while (It != Tokens.end()) {
if (It->kind() != tok::semi) {
++It;
continue;
}
unsigned Offset = Sel.AST->getSourceManager()
.getDecomposedLoc(It->endLocation())
.second;
return InsertionPoint{Klass->getEnclosingNamespaceContext(), Offset};
}
return error(
"failed to determine insertion location: no end of class found");
}

auto Region = getEligiblePoints(
Contents, Source->getQualifiedNameAsString(), Sel.AST->getLangOpts());

assert(!Region.EligiblePoints.empty());
auto Offset = positionToOffset(Contents, Region.EligiblePoints.back());
if (!Offset)
return Offset.takeError();

auto TargetContext =
findContextForNS(Region.EnclosingNamespace, Source->getDeclContext());
if (!TargetContext)
return error("define outline: couldn't find a context for target");

return InsertionPoint{*TargetContext, *Offset};
}

private:
const FunctionDecl *Source = nullptr;
bool SameFile = false;
};

REGISTER_TWEAK(DefineOutline)
Expand Down
10 changes: 7 additions & 3 deletions clang-tools-extra/clangd/unittests/ReplayPeambleTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/FileEntry.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
Expand All @@ -42,7 +41,11 @@
#include <memory>
#include <vector>

namespace clang::clangd {
namespace clang {

class Module;

namespace clangd {
namespace {
struct Inclusion {
Inclusion(const SourceManager &SM, SourceLocation HashLoc,
Expand Down Expand Up @@ -170,4 +173,5 @@ TEST(ReplayPreambleTest, IncludesAndSkippedFiles) {
}
}
} // namespace
} // namespace clang::clangd
} // namespace clangd
} // namespace clang
73 changes: 71 additions & 2 deletions clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,47 @@ TWEAK_TEST(DefineOutline);

TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) {
FileName = "Test.cpp";
// Not available unless in a header file.
// Not available for free function unless in a header file.
EXPECT_UNAVAILABLE(R"cpp(
[[void [[f^o^o]]() [[{
return;
}]]]])cpp");

// Available in soure file.
EXPECT_AVAILABLE(R"cpp(
struct Foo {
void f^oo() {}
};
)cpp");

// Available within named namespace in source file.
EXPECT_AVAILABLE(R"cpp(
namespace N {
struct Foo {
void f^oo() {}
};
} // namespace N
)cpp");

// Available within anonymous namespace in source file.
EXPECT_AVAILABLE(R"cpp(
namespace {
struct Foo {
void f^oo() {}
};
} // namespace
)cpp");

// Not available for out-of-line method.
EXPECT_UNAVAILABLE(R"cpp(
class Bar {
void baz();
};
[[void [[Bar::[[b^a^z]]]]() [[{
return;
}]]]])cpp");

FileName = "Test.hpp";
// Not available unless function name or fully body is selected.
EXPECT_UNAVAILABLE(R"cpp(
Expand Down Expand Up @@ -100,7 +135,7 @@ TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) {
};
)cpp");

// Not available on definitions within unnamed namespaces
// Not available on definitions in header file within unnamed namespaces
EXPECT_UNAVAILABLE(R"cpp(
namespace {
struct Foo {
Expand Down Expand Up @@ -349,6 +384,40 @@ TEST_F(DefineOutlineTest, ApplyTest) {
}
}

TEST_F(DefineOutlineTest, InCppFile) {
FileName = "Test.cpp";

struct {
llvm::StringRef Test;
llvm::StringRef ExpectedSource;
} Cases[] = {
{
R"cpp(
namespace foo {
namespace {
struct Foo { void ba^r() {} };
struct Bar { void foo(); };
void Bar::foo() {}
}
}
)cpp",
R"cpp(
namespace foo {
namespace {
struct Foo { void bar() ; };void Foo::bar() {}
struct Bar { void foo(); };
void Bar::foo() {}
}
}
)cpp"},
};

for (const auto &Case : Cases) {
SCOPED_TRACE(Case.Test);
EXPECT_EQ(apply(Case.Test, nullptr), Case.ExpectedSource);
}
}

TEST_F(DefineOutlineTest, HandleMacros) {
llvm::StringMap<std::string> EditedFiles;
ExtraFiles["Test.cpp"] = "";
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,11 @@ Changes in existing checks
<clang-tidy/checks/modernize/use-starts-ends-with>` check to also handle
calls to ``compare`` method.

- Improved :doc:`modernize-use-std-print
<clang-tidy/checks/modernize/use-std-print>` check to not crash if the
format string parameter of the function to be replaced is not of the
expected type.

- Improved :doc:`modernize-use-using <clang-tidy/checks/modernize/use-using>`
check by adding support for detection of typedefs declared on function level.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: { \
// RUN: modernize-use-std-format.StrictMode: true, \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
// RUN: }}" \
// RUN: -- -isystem %clang_tidy_headers
// RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: { \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
// RUN: }}" \
Expand Down Expand Up @@ -50,3 +50,17 @@ std::string A(const std::string &in)
{
return "_" + in;
}

// Issue #92896: Ensure that the check doesn't assert if the argument is
// promoted to something that isn't a string.
struct S {
S(...);
};
std::string bad_format_type_strprintf(const S &, ...);

std::string unsupported_format_parameter_type()
{
// No fixes here because the format parameter of the function called is not a
// string.
return bad_format_type_strprintf("");
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %check_clang_tidy -std=c++23 %s modernize-use-std-print %t -- \
// RUN: -config="{CheckOptions: \
// RUN: { \
// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2', \
// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2' \
// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; bad_format_type_printf', \
// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; bad_format_type_fprintf' \
// RUN: } \
// RUN: }" \
// RUN: -- -isystem %clang_tidy_headers
Expand Down Expand Up @@ -86,3 +86,25 @@ void no_name(const std::string &in)
{
"A" + in;
}

int myprintf(const wchar_t *, ...);

void wide_string_not_supported() {
myprintf(L"wide string %s", L"string");
}

// Issue #92896: Ensure that the check doesn't assert if the argument is
// promoted to something that isn't a string.
struct S {
S(...) {}
};
int bad_format_type_printf(const S &, ...);
int bad_format_type_fprintf(FILE *, const S &, ...);

void unsupported_format_parameter_type()
{
// No fixes here because the format parameter of the function called is not a
// string.
bad_format_type_printf("Hello %s", "world");
bad_format_type_fprintf(stderr, "Hello %s", "world");
}
70 changes: 35 additions & 35 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1799,8 +1799,8 @@ the configuration (without a prefix: ``Auto``).
Never merge functions into a single line.

* ``SFS_InlineOnly`` (in configuration: ``InlineOnly``)
Only merge functions defined inside a class. Same as "inline",
except it does not implies "empty": i.e. top level empty functions
Only merge functions defined inside a class. Same as ``inline``,
except it does not implies ``empty``: i.e. top level empty functions
are not merged either.

.. code-block:: c++
Expand All @@ -1825,7 +1825,7 @@ the configuration (without a prefix: ``Auto``).
}

* ``SFS_Inline`` (in configuration: ``Inline``)
Only merge functions defined inside a class. Implies "empty".
Only merge functions defined inside a class. Implies ``empty``.

.. code-block:: c++

Expand Down Expand Up @@ -2042,7 +2042,7 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: yaml
AttributeMacros: ['__capability', '__output', '__unused']
AttributeMacros: [__capability, __output, __unused]
.. _BinPackArguments:

Expand Down Expand Up @@ -3802,7 +3802,7 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: yaml
ForEachMacros: ['RANGES_FOR', 'FOREACH']
ForEachMacros: [RANGES_FOR, FOREACH]
For example: BOOST_FOREACH.

Expand All @@ -3825,7 +3825,7 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: yaml
IfMacros: ['IF']
IfMacros: [IF]
For example: `KJ_IF_MAYBE
<https://github.com/capnproto/capnproto/blob/master/kjdoc/tour.md#maybes>`_
Expand Down Expand Up @@ -4374,7 +4374,7 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: yaml
JavaImportGroups: ['com.example', 'com', 'org']
JavaImportGroups: [com.example, com, org]
.. code-block:: java
Expand Down Expand Up @@ -4438,7 +4438,7 @@ the configuration (without a prefix: ``Auto``).
VeryLongImportsAreAnnoying,
VeryLongImportsAreAnnoying,
VeryLongImportsAreAnnoying,
} from 'some/module.js'
} from "some/module.js"
false:
import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js"
Expand Down Expand Up @@ -5088,7 +5088,7 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: yaml
QualifierOrder: ['inline', 'static', 'type', 'const']
QualifierOrder: [inline, static, type, const]
.. code-block:: c++
Expand Down Expand Up @@ -5117,16 +5117,16 @@ the configuration (without a prefix: ``Auto``).

.. note::

it MUST contain 'type'.
It **must** contain ``type``.

Items to the left of 'type' will be placed to the left of the type and
aligned in the order supplied. Items to the right of 'type' will be
Items to the left of ``type`` will be placed to the left of the type and
aligned in the order supplied. Items to the right of ``type`` will be
placed to the right of the type and aligned in the order supplied.


.. code-block:: yaml
QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ]
QualifierOrder: [inline, static, type, const, volatile]
.. _RawStringFormats:

Expand All @@ -5138,10 +5138,10 @@ the configuration (without a prefix: ``Auto``).
name will be reformatted assuming the specified language based on the
style for that language defined in the .clang-format file. If no style has
been defined in the .clang-format file for the specific language, a
predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not
found, the formatting is based on llvm style. A matching delimiter takes
precedence over a matching enclosing function name for determining the
language of the raw string contents.
predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is
not found, the formatting is based on ``LLVM`` style. A matching delimiter
takes precedence over a matching enclosing function name for determining
the language of the raw string contents.

If a canonical delimiter is specified, occurrences of other delimiters for
the same language will be updated to the canonical if possible.
Expand All @@ -5156,17 +5156,17 @@ the configuration (without a prefix: ``Auto``).
RawStringFormats:
- Language: TextProto
Delimiters:
- 'pb'
- 'proto'
- pb
- proto
EnclosingFunctions:
- 'PARSE_TEXT_PROTO'
- PARSE_TEXT_PROTO
BasedOnStyle: google
- Language: Cpp
Delimiters:
- 'cc'
- 'cpp'
BasedOnStyle: llvm
CanonicalDelimiter: 'cc'
- cc
- cpp
BasedOnStyle: LLVM
CanonicalDelimiter: cc
.. _ReferenceAlignment:

Expand Down Expand Up @@ -5533,7 +5533,7 @@ the configuration (without a prefix: ``Auto``).

This determines the maximum length of short namespaces by counting
unwrapped lines (i.e. containing neither opening nor closing
namespace brace) and makes "FixNamespaceComments" omit adding
namespace brace) and makes ``FixNamespaceComments`` omit adding
end comments for those.

.. code-block:: c++
Expand Down Expand Up @@ -5645,7 +5645,7 @@ the configuration (without a prefix: ``Auto``).

* ``SUD_Lexicographic`` (in configuration: ``Lexicographic``)
Using declarations are sorted in the order defined as follows:
Split the strings by "::" and discard any initial empty strings. Sort
Split the strings by ``::`` and discard any initial empty strings. Sort
the lists of names lexicographically, and within those groups, names are
in case-insensitive lexicographic order.

Expand All @@ -5659,7 +5659,7 @@ the configuration (without a prefix: ``Auto``).

* ``SUD_LexicographicNumeric`` (in configuration: ``LexicographicNumeric``)
Using declarations are sorted in the order defined as follows:
Split the strings by "::" and discard any initial empty strings. The
Split the strings by ``::`` and discard any initial empty strings. The
last element of each list is a non-namespace name; all others are
namespace names. Sort the lists of names lexicographically, where the
sort order of individual names is that all non-namespace names come
Expand Down Expand Up @@ -5699,7 +5699,7 @@ the configuration (without a prefix: ``Auto``).
.. _SpaceAfterTemplateKeyword:

**SpaceAfterTemplateKeyword** (``Boolean``) :versionbadge:`clang-format 4` :ref:`¶ <SpaceAfterTemplateKeyword>`
If ``true``, a space will be inserted after the 'template' keyword.
If ``true``, a space will be inserted after the ``template`` keyword.

.. code-block:: c++

Expand Down Expand Up @@ -5860,7 +5860,7 @@ the configuration (without a prefix: ``Auto``).

* ``SBPO_NonEmptyParentheses`` (in configuration: ``NonEmptyParentheses``)
Put a space before opening parentheses only if the parentheses are not
empty i.e. '()'
empty.

.. code-block:: c++

Expand Down Expand Up @@ -6245,7 +6245,7 @@ the configuration (without a prefix: ``Auto``).
true: false:
x = ( int32 )y vs. x = (int32)y

* ``bool InEmptyParentheses`` Put a space in parentheses only if the parentheses are empty i.e. '()'
* ``bool InEmptyParentheses`` Insert a space in empty parentheses, i.e. ``()``.

.. code-block:: c++

Expand Down Expand Up @@ -6409,10 +6409,10 @@ the configuration (without a prefix: ``Auto``).
.. code-block:: yaml
TableGenBreakInsideDAGArg: BreakAll
TableGenBreakingDAGArgOperators: ['ins', 'outs']
TableGenBreakingDAGArgOperators: [ins, outs]
makes the line break only occurs inside DAGArgs beginning with the
specified identifiers 'ins' and 'outs'.
specified identifiers ``ins`` and ``outs``.


.. code-block:: c++
Expand Down Expand Up @@ -6450,7 +6450,7 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: yaml
TypenameMacros: ['STACK_OF', 'LIST']
TypenameMacros: [STACK_OF, LIST]
For example: OpenSSL STACK_OF, BSD LIST_ENTRY.

Expand Down Expand Up @@ -6518,7 +6518,7 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: yaml
WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE']
WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE]
For example: BOOST_PP_STRINGIZE

Expand All @@ -6538,7 +6538,7 @@ The goal of the clang-format project is more on the side of supporting a
limited set of styles really well as opposed to supporting every single style
used by a codebase somewhere in the wild. Of course, we do want to support all
major projects and thus have established the following bar for adding style
options. Each new style option must ..
options. Each new style option must:

* be used in a project of significant size (have dozens of contributors)
* have a publicly accessible style guide
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,8 @@ Bug Fixes to C++ Support
- Fix a regression introduced in Clang 18 causing incorrect overload resolution in the presence of functions only
differering by their constraints when only one of these function was variadic.
- Fix a crash when a variable is captured by a block nested inside a lambda. (Fixes #GH93625).
- Fixed a type constraint substitution issue involving a generic lambda expression. (#GH93821)
- Fix a crash caused by improper use of ``__array_extent``. (#GH80474)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
87 changes: 44 additions & 43 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,50 @@ Check calls to various UNIX/Posix functions: ``open, pthread_once, calloc, mallo
.. literalinclude:: checkers/unix_api_example.c
:language: c
.. _unix-BlockInCriticalSection:
unix.BlockInCriticalSection (C, C++)
""""""""""""""""""""""""""""""""""""
Check for calls to blocking functions inside a critical section.
Blocking functions detected by this checker: ``sleep, getc, fgets, read, recv``.
Critical section handling functions modeled by this checker:
``lock, unlock, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock``.
.. code-block:: c
void pthread_lock_example(pthread_mutex_t *m) {
pthread_mutex_lock(m); // note: entering critical section here
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
pthread_mutex_unlock(m);
}
.. code-block:: cpp
void overlapping_critical_sections(mtx_t *m1, std::mutex &m2) {
std::lock_guard lg{m2}; // note: entering critical section here
mtx_lock(m1); // note: entering critical section here
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
mtx_unlock(m1);
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
// still inside of the critical section of the std::lock_guard
}
**Limitations**
* The ``trylock`` and ``timedlock`` versions of acquiring locks are currently assumed to always succeed.
This can lead to false positives.
.. code-block:: c
void trylock_example(pthread_mutex_t *m) {
if (pthread_mutex_trylock(m) == 0) { // assume trylock always succeeds
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
pthread_mutex_unlock(m);
} else {
sleep(10); // false positive: Incorrect warning about blocking function inside critical section.
}
}
.. _unix-Errno:
unix.Errno (C)
Expand Down Expand Up @@ -3130,49 +3174,6 @@ For a more detailed description of configuration options, please see the
alpha.unix
^^^^^^^^^^
.. _alpha-unix-BlockInCriticalSection:
alpha.unix.BlockInCriticalSection (C)
"""""""""""""""""""""""""""""""""""""
Check for calls to blocking functions inside a critical section.
Blocking functions detected by this checker: ``sleep, getc, fgets, read, recv``.
Critical section handling functions modelled by this checker: ``lock, unlock, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock``.
.. code-block:: c
void pthread_lock_example(pthread_mutex_t *m) {
pthread_mutex_lock(m); // note: entering critical section here
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
pthread_mutex_unlock(m);
}
.. code-block:: cpp
void overlapping_critical_sections(mtx_t *m1, std::mutex &m2) {
std::lock_guard lg{m2}; // note: entering critical section here
mtx_lock(m1); // note: entering critical section here
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
mtx_unlock(m1);
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
// still inside of the critical section of the std::lock_guard
}
**Limitations**
* The ``trylock`` and ``timedlock`` versions of acquiring locks are currently assumed to always succeed.
This can lead to false positives.
.. code-block:: c
void trylock_example(pthread_mutex_t *m) {
if (pthread_mutex_trylock(m) == 0) { // assume trylock always succeeds
sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
pthread_mutex_unlock(m);
} else {
sleep(10); // false positive: Incorrect warning about blocking function inside critical section.
}
}
.. _alpha-unix-Chroot:
alpha.unix.Chroot (C)
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/APINotes/APINotesManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H
#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H

#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
Expand All @@ -24,6 +23,7 @@ namespace clang {
class DirectoryEntry;
class FileEntry;
class LangOptions;
class Module;
class SourceManager;

namespace api_notes {
Expand Down
47 changes: 47 additions & 0 deletions clang/include/clang/Analysis/FlowSensitive/ASTOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "llvm/ADT/DenseSet.h"
Expand Down Expand Up @@ -80,6 +81,52 @@ class RecordInitListHelper {
std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion;
};

/// Specialization of `RecursiveASTVisitor` that visits those nodes that are
/// relevant to the dataflow analysis; generally, these are the ones that also
/// appear in the CFG.
/// To start the traversal, call `TraverseStmt()` on the statement or body of
/// the function to analyze. Don't call `TraverseDecl()` on the function itself;
/// this won't work as `TraverseDecl()` contains code to avoid traversing nested
/// functions.
template <class Derived>
class AnalysisASTVisitor : public RecursiveASTVisitor<Derived> {
public:
bool shouldVisitImplicitCode() { return true; }

bool shouldVisitLambdaBody() const { return false; }

bool TraverseDecl(Decl *D) {
// Don't traverse nested record or function declarations.
// - We won't be analyzing code contained in these anyway
// - We don't model fields that are used only in these nested declaration,
// so trying to propagate a result object to initializers of such fields
// would cause an error.
if (isa_and_nonnull<RecordDecl>(D) || isa_and_nonnull<FunctionDecl>(D))
return true;

return RecursiveASTVisitor<Derived>::TraverseDecl(D);
}

// Don't traverse expressions in unevaluated contexts, as we don't model
// fields that are only used in these.
// Note: The operand of the `noexcept` operator is an unevaluated operand, but
// nevertheless it appears in the Clang CFG, so we don't exclude it here.
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; }
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
return true;
}

bool TraverseBindingDecl(BindingDecl *BD) {
// `RecursiveASTVisitor` doesn't traverse holding variables for
// `BindingDecl`s by itself, so we need to tell it to.
if (VarDecl *HoldingVar = BD->getHoldingVar())
TraverseDecl(HoldingVar);
return RecursiveASTVisitor<Derived>::TraverseBindingDecl(BD);
}
};

/// A collection of several types of declarations, all referenced from the same
/// function.
struct ReferencedDecls {
Expand Down
52 changes: 52 additions & 0 deletions clang/include/clang/Basic/ASTSourceDescriptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===- ASTSourceDescriptor.h -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Defines the clang::ASTSourceDescriptor class, which abstracts clang modules
/// and precompiled header files
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H
#define LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H

#include "clang/Basic/Module.h"
#include "llvm/ADT/StringRef.h"
#include <string>
#include <utility>

namespace clang {

/// Abstracts clang modules and precompiled header files and holds
/// everything needed to generate debug info for an imported module
/// or PCH.
class ASTSourceDescriptor {
StringRef PCHModuleName;
StringRef Path;
StringRef ASTFile;
ASTFileSignature Signature;
Module *ClangModule = nullptr;

public:
ASTSourceDescriptor() = default;
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
ASTFileSignature Signature)
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
ASTFile(std::move(ASTFile)), Signature(Signature) {}
ASTSourceDescriptor(Module &M);

std::string getModuleName() const;
StringRef getPath() const { return Path; }
StringRef getASTFile() const { return ASTFile; }
ASTFileSignature getSignature() const { return Signature; }
Module *getModuleOrNull() const { return ClangModule; }
};

} // namespace clang

#endif // LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H
26 changes: 0 additions & 26 deletions clang/include/clang/Basic/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -868,32 +868,6 @@ class VisibleModuleSet {
unsigned Generation = 0;
};

/// Abstracts clang modules and precompiled header files and holds
/// everything needed to generate debug info for an imported module
/// or PCH.
class ASTSourceDescriptor {
StringRef PCHModuleName;
StringRef Path;
StringRef ASTFile;
ASTFileSignature Signature;
Module *ClangModule = nullptr;

public:
ASTSourceDescriptor() = default;
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
ASTFileSignature Signature)
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
ASTFile(std::move(ASTFile)), Signature(Signature) {}
ASTSourceDescriptor(Module &M);

std::string getModuleName() const;
StringRef getPath() const { return Path; }
StringRef getASTFile() const { return ASTFile; }
ASTFileSignature getSignature() const { return Signature; }
Module *getModuleOrNull() const { return ClangModule; }
};


} // namespace clang

#endif // LLVM_CLANG_BASIC_MODULE_H
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H
#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H

#include "clang/Basic/Module.h"
#include "clang/ExtractAPI/API.h"
#include "clang/ExtractAPI/APIIgnoresList.h"
#include "clang/ExtractAPI/Serialization/APISetVisitor.h"
Expand Down
68 changes: 34 additions & 34 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -814,8 +814,8 @@ struct FormatStyle {
enum ShortFunctionStyle : int8_t {
/// Never merge functions into a single line.
SFS_None,
/// Only merge functions defined inside a class. Same as "inline",
/// except it does not implies "empty": i.e. top level empty functions
/// Only merge functions defined inside a class. Same as ``inline``,
/// except it does not implies ``empty``: i.e. top level empty functions
/// are not merged either.
/// \code
/// class Foo {
Expand All @@ -836,7 +836,7 @@ struct FormatStyle {
/// }
/// \endcode
SFS_Empty,
/// Only merge functions defined inside a class. Implies "empty".
/// Only merge functions defined inside a class. Implies ``empty``.
/// \code
/// class Foo {
/// void f() { foo(); }
Expand Down Expand Up @@ -1167,7 +1167,7 @@ struct FormatStyle {
///
/// In the .clang-format configuration file, this can be configured like:
/// \code{.yaml}
/// AttributeMacros: ['__capability', '__output', '__unused']
/// AttributeMacros: [__capability, __output, __unused]
/// \endcode
///
/// \version 12
Expand Down Expand Up @@ -2631,7 +2631,7 @@ struct FormatStyle {
///
/// In the .clang-format configuration file, this can be configured like:
/// \code{.yaml}
/// ForEachMacros: ['RANGES_FOR', 'FOREACH']
/// ForEachMacros: [RANGES_FOR, FOREACH]
/// \endcode
///
/// For example: BOOST_FOREACH.
Expand All @@ -2653,7 +2653,7 @@ struct FormatStyle {
///
/// In the .clang-format configuration file, this can be configured like:
/// \code{.yaml}
/// IfMacros: ['IF']
/// IfMacros: [IF]
/// \endcode
///
/// For example: `KJ_IF_MAYBE
Expand Down Expand Up @@ -3030,7 +3030,7 @@ struct FormatStyle {
/// in the following yaml example. This will result in imports being
/// formatted as in the Java example below.
/// \code{.yaml}
/// JavaImportGroups: ['com.example', 'com', 'org']
/// JavaImportGroups: [com.example, com, org]
/// \endcode
///
/// \code{.java}
Expand Down Expand Up @@ -3086,7 +3086,7 @@ struct FormatStyle {
/// VeryLongImportsAreAnnoying,
/// VeryLongImportsAreAnnoying,
/// VeryLongImportsAreAnnoying,
/// } from 'some/module.js'
/// } from "some/module.js"
///
/// false:
/// import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js"
Expand Down Expand Up @@ -3615,7 +3615,7 @@ struct FormatStyle {
/// Change specifiers/qualifiers to be aligned based on ``QualifierOrder``.
/// With:
/// \code{.yaml}
/// QualifierOrder: ['inline', 'static', 'type', 'const']
/// QualifierOrder: [inline, static, type, const]
/// \endcode
///
/// \code
Expand Down Expand Up @@ -3650,15 +3650,15 @@ struct FormatStyle {
/// * type
///
/// \note
/// it MUST contain 'type'.
/// It **must** contain ``type``.
/// \endnote
///
/// Items to the left of 'type' will be placed to the left of the type and
/// aligned in the order supplied. Items to the right of 'type' will be
/// Items to the left of ``type`` will be placed to the left of the type and
/// aligned in the order supplied. Items to the right of ``type`` will be
/// placed to the right of the type and aligned in the order supplied.
///
/// \code{.yaml}
/// QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ]
/// QualifierOrder: [inline, static, type, const, volatile]
/// \endcode
/// \version 14
std::vector<std::string> QualifierOrder;
Expand Down Expand Up @@ -3692,10 +3692,10 @@ struct FormatStyle {
/// name will be reformatted assuming the specified language based on the
/// style for that language defined in the .clang-format file. If no style has
/// been defined in the .clang-format file for the specific language, a
/// predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not
/// found, the formatting is based on llvm style. A matching delimiter takes
/// precedence over a matching enclosing function name for determining the
/// language of the raw string contents.
/// predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is
/// not found, the formatting is based on ``LLVM`` style. A matching delimiter
/// takes precedence over a matching enclosing function name for determining
/// the language of the raw string contents.
///
/// If a canonical delimiter is specified, occurrences of other delimiters for
/// the same language will be updated to the canonical if possible.
Expand All @@ -3708,17 +3708,17 @@ struct FormatStyle {
/// RawStringFormats:
/// - Language: TextProto
/// Delimiters:
/// - 'pb'
/// - 'proto'
/// - pb
/// - proto
/// EnclosingFunctions:
/// - 'PARSE_TEXT_PROTO'
/// - PARSE_TEXT_PROTO
/// BasedOnStyle: google
/// - Language: Cpp
/// Delimiters:
/// - 'cc'
/// - 'cpp'
/// BasedOnStyle: llvm
/// CanonicalDelimiter: 'cc'
/// - cc
/// - cpp
/// BasedOnStyle: LLVM
/// CanonicalDelimiter: cc
/// \endcode
/// \version 6
std::vector<RawStringFormat> RawStringFormats;
Expand Down Expand Up @@ -4046,7 +4046,7 @@ struct FormatStyle {
///
/// This determines the maximum length of short namespaces by counting
/// unwrapped lines (i.e. containing neither opening nor closing
/// namespace brace) and makes "FixNamespaceComments" omit adding
/// namespace brace) and makes ``FixNamespaceComments`` omit adding
/// end comments for those.
/// \code
/// ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0
Expand Down Expand Up @@ -4138,7 +4138,7 @@ struct FormatStyle {
/// \endcode
SUD_Never,
/// Using declarations are sorted in the order defined as follows:
/// Split the strings by "::" and discard any initial empty strings. Sort
/// Split the strings by ``::`` and discard any initial empty strings. Sort
/// the lists of names lexicographically, and within those groups, names are
/// in case-insensitive lexicographic order.
/// \code
Expand All @@ -4150,7 +4150,7 @@ struct FormatStyle {
/// \endcode
SUD_Lexicographic,
/// Using declarations are sorted in the order defined as follows:
/// Split the strings by "::" and discard any initial empty strings. The
/// Split the strings by ``::`` and discard any initial empty strings. The
/// last element of each list is a non-namespace name; all others are
/// namespace names. Sort the lists of names lexicographically, where the
/// sort order of individual names is that all non-namespace names come
Expand Down Expand Up @@ -4186,7 +4186,7 @@ struct FormatStyle {
/// \version 9
bool SpaceAfterLogicalNot;

/// If \c true, a space will be inserted after the 'template' keyword.
/// If \c true, a space will be inserted after the ``template`` keyword.
/// \code
/// true: false:
/// template <int> void foo(); vs. template<int> void foo();
Expand Down Expand Up @@ -4316,7 +4316,7 @@ struct FormatStyle {
/// \endcode
SBPO_ControlStatementsExceptControlMacros,
/// Put a space before opening parentheses only if the parentheses are not
/// empty i.e. '()'
/// empty.
/// \code
/// void() {
/// if (true) {
Expand Down Expand Up @@ -4668,7 +4668,7 @@ struct FormatStyle {
/// x = ( int32 )y vs. x = (int32)y
/// \endcode
bool InCStyleCasts;
/// Put a space in parentheses only if the parentheses are empty i.e. '()'
/// Insert a space in empty parentheses, i.e. ``()``.
/// \code
/// true: false:
/// void f( ) { vs. void f() {
Expand Down Expand Up @@ -4804,11 +4804,11 @@ struct FormatStyle {
/// For example the configuration,
/// \code{.yaml}
/// TableGenBreakInsideDAGArg: BreakAll
/// TableGenBreakingDAGArgOperators: ['ins', 'outs']
/// TableGenBreakingDAGArgOperators: [ins, outs]
/// \endcode
///
/// makes the line break only occurs inside DAGArgs beginning with the
/// specified identifiers 'ins' and 'outs'.
/// specified identifiers ``ins`` and ``outs``.
///
/// \code
/// let DAGArgIns = (ins
Expand Down Expand Up @@ -4873,7 +4873,7 @@ struct FormatStyle {
///
/// In the .clang-format configuration file, this can be configured like:
/// \code{.yaml}
/// TypenameMacros: ['STACK_OF', 'LIST']
/// TypenameMacros: [STACK_OF, LIST]
/// \endcode
///
/// For example: OpenSSL STACK_OF, BSD LIST_ENTRY.
Expand Down Expand Up @@ -4929,7 +4929,7 @@ struct FormatStyle {
///
/// In the .clang-format configuration file, this can be configured like:
/// \code{.yaml}
/// WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE']
/// WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE]
/// \endcode
///
/// For example: BOOST_PP_STRINGIZE
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Lex/DependencyDirectivesScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H
#define LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H

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

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

/// Print the previously scanned dependency directives as minimized source text.
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@ class ASTReader
FileManager &FileMgr;
const PCHContainerReader &PCHContainerRdr;
DiagnosticsEngine &Diags;
// Sema has duplicate logic, but SemaObj can sometimes be null so ASTReader
// has its own version.
bool WarnedStackExhausted = false;

/// The semantic analysis object that will be processing the
/// AST files and the translation unit that uses it.
Expand Down Expand Up @@ -2135,6 +2138,8 @@ class ASTReader
/// Report a diagnostic.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const;

void warnStackExhausted(SourceLocation Loc);

IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID);

IdentifierInfo *readIdentifier(ModuleFile &M, const RecordData &Record,
Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaConsumer.h"
Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/Serialization/ModuleManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#define LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H

#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Serialization/ModuleFile.h"
#include "llvm/ADT/DenseMap.h"
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,10 @@ def UnixAPIMisuseChecker : Checker<"API">,
HelpText<"Check calls to various UNIX/Posix functions">,
Documentation<HasDocumentation>;

def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">,
HelpText<"Check for calls to blocking functions inside a critical section">,
Documentation<HasDocumentation>;

def DynamicMemoryModeling: Checker<"DynamicMemoryModeling">,
HelpText<"The base of several malloc() related checkers. On it's own it "
"emits no reports, but adds valuable information to the analysis "
Expand Down Expand Up @@ -619,10 +623,6 @@ def SimpleStreamChecker : Checker<"SimpleStream">,
HelpText<"Check for misuses of stream APIs">,
Documentation<HasDocumentation>;

def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">,
HelpText<"Check for calls to blocking functions inside a critical section">,
Documentation<HasDocumentation>;

} // end "alpha.unix"

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

/// Check whether \p Path exists. By default checks cached result of \c
/// status(), and falls back on FS if unable to do so.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/APINotes/APINotesManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceMgrAdapter.h"
#include "clang/Basic/Version.h"
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "clang/AST/DeclLookups.h"
#include "clang/AST/JSONNodeDumper.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ExternalASTSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclarationName.h"
#include "clang/Basic/ASTSourceDescriptor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdint>
Expand Down
114 changes: 60 additions & 54 deletions clang/lib/Analysis/FlowSensitive/ASTOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,90 +188,96 @@ static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) {
return nullptr;
}

static void getReferencedDecls(const Decl &D, ReferencedDecls &Referenced) {
insertIfGlobal(D, Referenced.Globals);
insertIfFunction(D, Referenced.Functions);
if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
for (const auto *B : Decomp->bindings())
if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
// FIXME: should we be using `E->getFoundDecl()`?
if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
Referenced.Fields.insert(FD);
}
class ReferencedDeclsVisitor
: public AnalysisASTVisitor<ReferencedDeclsVisitor> {
public:
ReferencedDeclsVisitor(ReferencedDecls &Referenced)
: Referenced(Referenced) {}

void TraverseConstructorInits(const CXXConstructorDecl *Ctor) {
for (const CXXCtorInitializer *Init : Ctor->inits()) {
if (Init->isMemberInitializer()) {
Referenced.Fields.insert(Init->getMember());
} else if (Init->isIndirectMemberInitializer()) {
for (const auto *I : Init->getIndirectMember()->chain())
Referenced.Fields.insert(cast<FieldDecl>(I));
}

Expr *InitExpr = Init->getInit();

// Also collect declarations referenced in `InitExpr`.
TraverseStmt(InitExpr);

/// Traverses `S` and inserts into `Referenced` any declarations that are
/// declared in or referenced from sub-statements.
static void getReferencedDecls(const Stmt &S, ReferencedDecls &Referenced) {
for (auto *Child : S.children())
if (Child != nullptr)
getReferencedDecls(*Child, Referenced);
if (const auto *DefaultArg = dyn_cast<CXXDefaultArgExpr>(&S))
getReferencedDecls(*DefaultArg->getExpr(), Referenced);
if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S))
getReferencedDecls(*DefaultInit->getExpr(), Referenced);

if (auto *DS = dyn_cast<DeclStmt>(&S)) {
if (DS->isSingleDecl())
getReferencedDecls(*DS->getSingleDecl(), Referenced);
else
for (auto *D : DS->getDeclGroup())
getReferencedDecls(*D, Referenced);
} else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
// If this is a `CXXDefaultInitExpr`, also collect declarations referenced
// within the default expression.
if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
TraverseStmt(DefaultInit->getExpr());
}
}

bool VisitDecl(Decl *D) {
insertIfGlobal(*D, Referenced.Globals);
insertIfFunction(*D, Referenced.Functions);
return true;
}

bool VisitDeclRefExpr(DeclRefExpr *E) {
insertIfGlobal(*E->getDecl(), Referenced.Globals);
insertIfFunction(*E->getDecl(), Referenced.Functions);
} else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) {
return true;
}

bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C) {
// If this is a method that returns a member variable but does nothing else,
// model the field of the return value.
if (MemberExpr *E = getMemberForAccessor(*C))
if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
Referenced.Fields.insert(FD);
} else if (auto *E = dyn_cast<MemberExpr>(&S)) {
return true;
}

bool VisitMemberExpr(MemberExpr *E) {
// FIXME: should we be using `E->getFoundDecl()`?
const ValueDecl *VD = E->getMemberDecl();
insertIfGlobal(*VD, Referenced.Globals);
insertIfFunction(*VD, Referenced.Functions);
if (const auto *FD = dyn_cast<FieldDecl>(VD))
Referenced.Fields.insert(FD);
} else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
return true;
}

bool VisitInitListExpr(InitListExpr *InitList) {
if (InitList->getType()->isRecordType())
for (const auto *FD : getFieldsForInitListExpr(InitList))
Referenced.Fields.insert(FD);
} else if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(&S)) {
return true;
}

bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList) {
if (ParenInitList->getType()->isRecordType())
for (const auto *FD : getFieldsForInitListExpr(ParenInitList))
Referenced.Fields.insert(FD);
return true;
}
}

private:
ReferencedDecls &Referenced;
};

ReferencedDecls getReferencedDecls(const FunctionDecl &FD) {
ReferencedDecls Result;
// Look for global variable and field references in the
// constructor-initializers.
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD)) {
for (const auto *Init : CtorDecl->inits()) {
if (Init->isMemberInitializer()) {
Result.Fields.insert(Init->getMember());
} else if (Init->isIndirectMemberInitializer()) {
for (const auto *I : Init->getIndirectMember()->chain())
Result.Fields.insert(cast<FieldDecl>(I));
}
const Expr *E = Init->getInit();
assert(E != nullptr);
getReferencedDecls(*E, Result);
}
// Add all fields mentioned in default member initializers.
for (const FieldDecl *F : CtorDecl->getParent()->fields())
if (const auto *I = F->getInClassInitializer())
getReferencedDecls(*I, Result);
}
getReferencedDecls(*FD.getBody(), Result);
ReferencedDeclsVisitor Visitor(Result);
Visitor.TraverseStmt(FD.getBody());
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD))
Visitor.TraverseConstructorInits(CtorDecl);

return Result;
}

ReferencedDecls getReferencedDecls(const Stmt &S) {
ReferencedDecls Result;
getReferencedDecls(S, Result);
ReferencedDeclsVisitor Visitor(Result);
Visitor.TraverseStmt(const_cast<Stmt *>(&S));
return Result;
}

Expand Down
37 changes: 1 addition & 36 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ namespace {
// Visitor that builds a map from record prvalues to result objects.
// For each result object that it encounters, it propagates the storage location
// of the result object to all record prvalues that can initialize it.
class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
class ResultObjectVisitor : public AnalysisASTVisitor<ResultObjectVisitor> {
public:
// `ResultObjectMap` will be filled with a map from record prvalues to result
// object. If this visitor will traverse a function that returns a record by
Expand All @@ -310,10 +310,6 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
: ResultObjectMap(ResultObjectMap),
LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}

bool shouldVisitImplicitCode() { return true; }

bool shouldVisitLambdaBody() const { return false; }

// Traverse all member and base initializers of `Ctor`. This function is not
// called by `RecursiveASTVisitor`; it should be called manually if we are
// analyzing a constructor. `ThisPointeeLoc` is the storage location that
Expand Down Expand Up @@ -342,37 +338,6 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
}
}

bool TraverseDecl(Decl *D) {
// Don't traverse nested record or function declarations.
// - We won't be analyzing code contained in these anyway
// - We don't model fields that are used only in these nested declaration,
// so trying to propagate a result object to initializers of such fields
// would cause an error.
if (isa_and_nonnull<RecordDecl>(D) || isa_and_nonnull<FunctionDecl>(D))
return true;

return RecursiveASTVisitor<ResultObjectVisitor>::TraverseDecl(D);
}

// Don't traverse expressions in unevaluated contexts, as we don't model
// fields that are only used in these.
// Note: The operand of the `noexcept` operator is an unevaluated operand, but
// nevertheless it appears in the Clang CFG, so we don't exclude it here.
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; }
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
return true;
}

bool TraverseBindingDecl(BindingDecl *BD) {
// `RecursiveASTVisitor` doesn't traverse holding variables for
// `BindingDecl`s by itself, so we need to tell it to.
if (VarDecl *HoldingVar = BD->getHoldingVar())
TraverseDecl(HoldingVar);
return RecursiveASTVisitor<ResultObjectVisitor>::TraverseBindingDecl(BD);
}

bool VisitVarDecl(VarDecl *VD) {
if (VD->getType()->isRecordType() && VD->hasInit())
PropagateResultObject(
Expand Down
33 changes: 33 additions & 0 deletions clang/lib/Basic/ASTSourceDescriptor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===- ASTSourceDescriptor.cpp -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// Defines the clang::ASTSourceDescriptor class, which abstracts clang modules
/// and precompiled header files
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/ASTSourceDescriptor.h"

namespace clang {

ASTSourceDescriptor::ASTSourceDescriptor(Module &M)
: Signature(M.Signature), ClangModule(&M) {
if (M.Directory)
Path = M.Directory->getName();
if (auto File = M.getASTFile())
ASTFile = File->getName();
}

std::string ASTSourceDescriptor::getModuleName() const {
if (ClangModule)
return ClangModule->Name;
else
return std::string(PCHModuleName);
}

} // namespace clang
1 change: 1 addition & 0 deletions clang/lib/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ if(CLANG_VENDOR)
endif()

add_clang_library(clangBasic
ASTSourceDescriptor.cpp
Attributes.cpp
Builtins.cpp
CLWarnings.cpp
Expand Down
15 changes: 0 additions & 15 deletions clang/lib/Basic/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -724,18 +724,3 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
};
VisitModule({M, nullptr});
}

ASTSourceDescriptor::ASTSourceDescriptor(Module &M)
: Signature(M.Signature), ClangModule(&M) {
if (M.Directory)
Path = M.Directory->getName();
if (auto File = M.getASTFile())
ASTFile = File->getName();
}

std::string ASTSourceDescriptor::getModuleName() const {
if (ClangModule)
return ClangModule->Name;
else
return std::string(PCHModuleName);
}
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/ASTSourceDescriptor.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
Expand All @@ -38,6 +38,7 @@ class MDNode;
namespace clang {
class ClassTemplateSpecializationDecl;
class GlobalDecl;
class Module;
class ModuleMap;
class ObjCInterfaceDecl;
class UsingDecl;
Expand Down
1 change: 0 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include "clang/AST/Mangle.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/NoSanitizeList.h"
#include "clang/Basic/ProfileList.h"
#include "clang/Basic/TargetInfo.h"
Expand Down
1 change: 0 additions & 1 deletion clang/lib/ExtractAPI/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

#include "clang/ExtractAPI/API.h"
#include "clang/AST/RawCommentList.h"
#include "clang/Basic/Module.h"
#include "clang/Index/USRGeneration.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2236,7 +2236,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
bool InTemplateParameterList = false;

while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->isTypeName(LangOpts)) {
if (FormatTok->isTypeName(LangOpts) || FormatTok->isAttribute()) {
nextToken();
continue;
}
Expand Down
11 changes: 6 additions & 5 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,6 @@ std::unique_ptr<ASTConsumer>
GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
Consumers.push_back(std::make_unique<CXX20ModulesGenerator>(
CI.getPreprocessor(), CI.getModuleCache(),
CI.getFrontendOpts().OutputFile));

if (CI.getFrontendOpts().GenReducedBMI &&
!CI.getFrontendOpts().ModuleOutputPath.empty()) {
Expand All @@ -284,6 +281,10 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
CI.getFrontendOpts().ModuleOutputPath));
}

Consumers.push_back(std::make_unique<CXX20ModulesGenerator>(
CI.getPreprocessor(), CI.getModuleCache(),
CI.getFrontendOpts().OutputFile));

return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}

Expand Down Expand Up @@ -1168,8 +1169,8 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() {
llvm::SmallVector<dependency_directives_scan::Token, 16> Tokens;
llvm::SmallVector<dependency_directives_scan::Directive, 32> Directives;
if (scanSourceForDependencyDirectives(
FromFile.getBuffer(), Tokens, Directives, &CI.getDiagnostics(),
SM.getLocForStartOfFile(SM.getMainFileID()))) {
FromFile.getBuffer(), Tokens, Directives, CI.getLangOpts(),
&CI.getDiagnostics(), SM.getLocForStartOfFile(SM.getMainFileID()))) {
assert(CI.getDiagnostics().hasErrorOccurred() &&
"no errors reported for failure");

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Headers/cuda_wrappers/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ template <class __T>
__attribute__((enable_if(true, "")))
inline _CPP14_CONSTEXPR __host__ __device__ const __T &
min(const __T &__a, const __T &__b) {
return __a < __b ? __a : __b;
return __b < __a ? __b : __a;
}

#pragma pop_macro("_CPP14_CONSTEXPR")
Expand Down
22 changes: 13 additions & 9 deletions clang/lib/Lex/DependencyDirectivesScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@ struct DirectiveWithTokens {
struct Scanner {
Scanner(StringRef Input,
SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
DiagnosticsEngine *Diags, SourceLocation InputSourceLoc)
DiagnosticsEngine *Diags, SourceLocation InputSourceLoc,
const LangOptions &LangOpts)
: Input(Input), Tokens(Tokens), Diags(Diags),
InputSourceLoc(InputSourceLoc), LangOpts(getLangOptsForDepScanning()),
TheLexer(InputSourceLoc, LangOpts, Input.begin(), Input.begin(),
InputSourceLoc(InputSourceLoc),
LangOpts(getLangOptsForDepScanning(LangOpts)),
TheLexer(InputSourceLoc, this->LangOpts, Input.begin(), Input.begin(),
Input.end()) {}

static LangOptions getLangOptsForDepScanning() {
LangOptions LangOpts;
static LangOptions
getLangOptsForDepScanning(const LangOptions &invocationLangOpts) {
LangOptions LangOpts(invocationLangOpts);
// Set the lexer to use 'tok::at' for '@', instead of 'tok::unknown'.
LangOpts.ObjC = true;
LangOpts.LineComment = true;
Expand Down Expand Up @@ -700,7 +703,7 @@ bool Scanner::lex_Pragma(const char *&First, const char *const End) {
SmallVector<dependency_directives_scan::Token> DiscardTokens;
const char *Begin = Buffer.c_str();
Scanner PragmaScanner{StringRef(Begin, Buffer.size()), DiscardTokens, Diags,
InputSourceLoc};
InputSourceLoc, LangOptions()};

PragmaScanner.TheLexer.setParsingPreprocessorDirective(true);
if (PragmaScanner.lexPragma(Begin, Buffer.end()))
Expand Down Expand Up @@ -950,9 +953,10 @@ bool Scanner::scan(SmallVectorImpl<Directive> &Directives) {

bool clang::scanSourceForDependencyDirectives(
StringRef Input, SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
SmallVectorImpl<Directive> &Directives, DiagnosticsEngine *Diags,
SourceLocation InputSourceLoc) {
return Scanner(Input, Tokens, Diags, InputSourceLoc).scan(Directives);
SmallVectorImpl<Directive> &Directives, const LangOptions &LangOpts,
DiagnosticsEngine *Diags, SourceLocation InputSourceLoc) {
return Scanner(Input, Tokens, Diags, InputSourceLoc, LangOpts)
.scan(Directives);
}

void clang::printDependencyDirectivesAsSource(
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4011,6 +4011,9 @@ ExprResult Parser::ParseArrayTypeTrait() {
ExprResult DimExpr = ParseExpression();
T.consumeClose();

if (DimExpr.isInvalid())
return ExprError();

return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(),
T.getCloseLocation());
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5660,7 +5660,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
LocalInstantiationScope Scope(*this);

EnterExpressionEvaluationContext EECtx{
*this, ExpressionEvaluationContext::ConstantEvaluated, CSD};
*this, ExpressionEvaluationContext::Unevaluated, CSD};

if (!AreArgsDependent &&
CheckConstraintSatisfaction(
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5134,6 +5134,20 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
return true;
MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted,
/*Final=*/false);
// Build up an EvaluationContext with an ImplicitConceptSpecializationDecl so
// that the template arguments of the constraint can be preserved. For
// example:
//
// template <class T>
// concept C = []<D U = void>() { return true; }();
//
// We need the argument for T while evaluating type constraint D in
// building the CallExpr to the lambda.
EnterExpressionEvaluationContext EECtx(
S, Sema::ExpressionEvaluationContext::Unevaluated,
ImplicitConceptSpecializationDecl::Create(
S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(),
CanonicalConverted));
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
MLTAL, TypeLoc.getLocalSourceRange(),
Satisfaction))
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/ASTSourceDescriptor.h"
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticError.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/ExceptionSpecificationType.h"
Expand Down Expand Up @@ -9403,6 +9405,20 @@ DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const {
return Diags.Report(Loc, DiagID);
}

void ASTReader::warnStackExhausted(SourceLocation Loc) {
// When Sema is available, avoid duplicate errors.
if (SemaObj) {
SemaObj->warnStackExhausted(Loc);
return;
}

if (WarnedStackExhausted)
return;
WarnedStackExhausted = true;

Diag(Loc, diag::warn_stack_exhausted);
}

/// Retrieve the identifier table associated with the
/// preprocessor.
IdentifierTable &ASTReader::getIdentifierTable() {
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/Stack.h"
#include "clang/Sema/IdentifierResolver.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTRecordReader.h"
Expand Down Expand Up @@ -4127,7 +4128,10 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
// calls to Decl::getASTContext() by Decl's methods will find the
// TranslationUnitDecl without crashing.
D->setDeclContext(Context.getTranslationUnitDecl());
Reader.Visit(D);

// Reading some declarations can result in deep recursion.
clang::runWithSufficientStackSpace([&] { warnStackExhausted(DeclLoc); },
[&] { Reader.Visit(D); });

// If this declaration is also a declaration context, get the
// offsets for its tables of lexical and visible declarations.
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3205,9 +3205,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
}

// Sort by diag::kind for deterministic output.
llvm::sort(Mappings, [](const auto &LHS, const auto &RHS) {
return LHS.first < RHS.first;
});
llvm::sort(Mappings, llvm::less_first());

for (const auto &I : Mappings) {
Record.push_back(I.first);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1733,7 +1733,7 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (Writer.isGeneratingReducedBMI()) {
auto Name = Context.DeclarationNames.getCXXDeductionGuideName(D);
for (auto *DG : D->getDeclContext()->noload_lookup(Name))
Writer.GetDeclRef(DG);
Writer.GetDeclRef(DG->getCanonicalDecl());
}

Code = serialization::DECL_CLASS_TEMPLATE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ DependencyScanningWorkerFilesystem::readFile(StringRef Filename) {
}

bool DependencyScanningWorkerFilesystem::ensureDirectiveTokensArePopulated(
EntryRef Ref) {
EntryRef Ref, const LangOptions &LangOpts) {
auto &Entry = Ref.Entry;

if (Entry.isError() || Entry.isDirectory())
Expand All @@ -66,7 +66,7 @@ bool DependencyScanningWorkerFilesystem::ensureDirectiveTokensArePopulated(
// dependencies.
if (scanSourceForDependencyDirectives(Contents->Original->getBuffer(),
Contents->DepDirectiveTokens,
Directives)) {
Directives, LangOpts)) {
Contents->DepDirectiveTokens.clear();
// FIXME: Propagate the diagnostic if desired by the client.
Contents->DepDirectives.store(new std::optional<DependencyDirectivesTy>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,7 @@ static void canonicalizeDefines(PreprocessorOptions &PPOpts) {
++Index;
}

llvm::stable_sort(SimpleNames, [](const MacroOpt &A, const MacroOpt &B) {
return A.first < B.first;
});
llvm::stable_sort(SimpleNames, llvm::less_first());
// Keep the last instance of each macro name by going in reverse
auto NewEnd = std::unique(
SimpleNames.rbegin(), SimpleNames.rend(),
Expand Down Expand Up @@ -366,11 +364,12 @@ class DependencyScanningAction : public tooling::ToolAction {
// Use the dependency scanning optimized file system if requested to do so.
if (DepFS)
ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile =
[LocalDepFS = DepFS](FileEntryRef File)
[LocalDepFS = DepFS,
&LangOpts = ScanInstance.getLangOpts()](FileEntryRef File)
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
if (llvm::ErrorOr<EntryRef> Entry =
LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry, LangOpts))
return Entry->getDirectiveTokens();
return std::nullopt;
};
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Tooling/JSONCompilationDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
return Name;
}

// There are compiler-wrappers (ccache, distcc, gomacc) that take the "real"
// There are compiler-wrappers (ccache, distcc) that take the "real"
// compiler as an argument, e.g. distcc gcc -O3 foo.c.
// These end up in compile_commands.json when people set CC="distcc gcc".
// Clang's driver doesn't understand this, so we need to unwrap.
Expand All @@ -269,8 +269,7 @@ static bool unwrapCommand(std::vector<std::string> &Args) {
return false;
StringRef Wrapper =
stripExecutableExtension(llvm::sys::path::filename(Args.front()));
if (Wrapper == "distcc" || Wrapper == "gomacc" || Wrapper == "ccache" ||
Wrapper == "sccache") {
if (Wrapper == "distcc" || Wrapper == "ccache" || Wrapper == "sccache") {
// Most of these wrappers support being invoked 3 ways:
// `distcc g++ file.c` This is the mode we're trying to match.
// We need to drop `distcc`.
Expand Down
1 change: 1 addition & 0 deletions clang/test/Analysis/analyzer-enabled-checkers.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
// CHECK-NEXT: security.insecureAPI.mktemp
// CHECK-NEXT: security.insecureAPI.vfork
// CHECK-NEXT: unix.API
// CHECK-NEXT: unix.BlockInCriticalSection
// CHECK-NEXT: unix.cstring.CStringModeling
// CHECK-NEXT: unix.DynamicMemoryModeling
// CHECK-NEXT: unix.Errno
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/block-in-critical-section.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.BlockInCriticalSection -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.BlockInCriticalSection -verify %s
// expected-no-diagnostics

// This should not crash
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/block-in-critical-section.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 \
// RUN: -analyzer-checker=alpha.unix.BlockInCriticalSection \
// RUN: -analyzer-checker=unix.BlockInCriticalSection \
// RUN: -std=c++11 \
// RUN: -analyzer-output text \
// RUN: -verify %s
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/block-in-critical-section.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.BlockInCriticalSection -verify -Wno-objc-root-class %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.BlockInCriticalSection -verify -Wno-objc-root-class %s
// expected-no-diagnostics

@interface SomeClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
// CHECK-NEXT: security.insecureAPI.mktemp
// CHECK-NEXT: security.insecureAPI.vfork
// CHECK-NEXT: unix.API
// CHECK-NEXT: unix.BlockInCriticalSection
// CHECK-NEXT: unix.cstring.CStringModeling
// CHECK-NEXT: unix.DynamicMemoryModeling
// CHECK-NEXT: unix.Errno
Expand Down
14 changes: 7 additions & 7 deletions clang/test/CXX/drs/cwg24xx.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -std=c++98 %s -verify=expected
// RUN: %clang_cc1 -std=c++11 %s -verify=expected
// RUN: %clang_cc1 -std=c++14 %s -verify=expected
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx17
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx17
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx17
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx17
// RUN: %clang_cc1 -std=c++98 -pedantic-errors %s -verify=expected
// RUN: %clang_cc1 -std=c++11 -pedantic-errors %s -verify=expected
// RUN: %clang_cc1 -std=c++14 -pedantic-errors %s -verify=expected
// RUN: %clang_cc1 -std=c++17 -pedantic-errors %s -verify=expected,since-cxx17
// RUN: %clang_cc1 -std=c++20 -pedantic-errors %s -verify=expected,since-cxx17
// RUN: %clang_cc1 -std=c++23 -pedantic-errors %s -verify=expected,since-cxx17
// RUN: %clang_cc1 -std=c++2c -pedantic-errors %s -verify=expected,since-cxx17

#if __cplusplus <= 201402L
// expected-no-diagnostics
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CXX/drs/cwg2630.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// RUN: split-file --leading-lines %s %t
// RUN: %clang_cc1 -std=c++20 -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++20 -verify -fmodule-file=A=%t/module.pcm %t/main.cpp
// RUN: %clang_cc1 -std=c++23 -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++23 -verify -fmodule-file=A=%t/module.pcm %t/main.cpp
// RUN: %clang_cc1 -std=c++2c -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++2c -verify -fmodule-file=A=%t/module.pcm %t/main.cpp
// RUN: %clang_cc1 -std=c++20 -pedantic-errors -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++20 -pedantic-errors -verify -fmodule-file=A=%t/module.pcm %t/main.cpp
// RUN: %clang_cc1 -std=c++23 -pedantic-errors -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++23 -pedantic-errors -verify -fmodule-file=A=%t/module.pcm %t/main.cpp
// RUN: %clang_cc1 -std=c++2c -pedantic-errors -verify -emit-module-interface %t/module.cppm -o %t/module.pcm
// RUN: %clang_cc1 -std=c++2c -pedantic-errors -verify -fmodule-file=A=%t/module.pcm %t/main.cpp

//--- module.cppm
// expected-no-diagnostics
Expand Down
16 changes: 8 additions & 8 deletions clang/test/CXX/drs/cwg26xx.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11,cxx11
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23


namespace cwg2621 { // cwg2621: 16
Expand Down Expand Up @@ -129,7 +129,7 @@ int y = cwg2640_a\N{LOTUS});
namespace cwg2644 { // cwg2644: 8
#if __cplusplus >= 201103L
auto z = [a = 42](int a) {
// cxx11-warning@-1 {{initialized lambda captures are a C++14 extension}}
// cxx11-error@-1 {{initialized lambda captures are a C++14 extension}}
// since-cxx11-error@-2 {{a lambda parameter cannot shadow an explicitly captured entity}}
// since-cxx11-note@-3 {{variable 'a' is explicitly captured here}}
return 1;
Expand Down
14 changes: 7 additions & 7 deletions clang/test/CXX/drs/cwg27xx.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -verify=expected,since-cxx23 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -verify=expected,since-cxx23,since-cxx26 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -pedantic-errors -verify=expected,since-cxx23 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -pedantic-errors -verify=expected,since-cxx23,since-cxx26 %s

namespace cwg2718 { // cwg2718: 2.7
struct B {};
Expand Down
95 changes: 88 additions & 7 deletions clang/test/CXX/drs/cwg28xx.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -std=c++98 -verify=expected %s
// RUN: %clang_cc1 -std=c++11 -verify=expected %s
// RUN: %clang_cc1 -std=c++14 -verify=expected %s
// RUN: %clang_cc1 -std=c++17 -verify=expected %s
// RUN: %clang_cc1 -std=c++20 -verify=expected,since-cxx20 %s
// RUN: %clang_cc1 -std=c++23 -verify=expected,since-cxx20,since-cxx23 %s
// RUN: %clang_cc1 -std=c++2c -verify=expected,since-cxx20,since-cxx23,since-cxx26 %s
// RUN: %clang_cc1 -std=c++98 -pedantic-errors -verify=expected,cxx98 %s
// RUN: %clang_cc1 -std=c++11 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -std=c++14 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -std=c++17 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -std=c++20 -pedantic-errors -verify=expected,since-cxx20 %s
// RUN: %clang_cc1 -std=c++23 -pedantic-errors -verify=expected,since-cxx20,since-cxx23 %s
// RUN: %clang_cc1 -std=c++2c -pedantic-errors -verify=expected,since-cxx20,since-cxx23,since-cxx26 %s

namespace cwg2819 { // cwg2819: 19 tentatively ready 2023-12-01
#if __cpp_constexpr >= 202306L
Expand Down Expand Up @@ -110,6 +110,26 @@ struct A {

} // namespace cwg2858

namespace cwg2877 { // cwg2877: no tentatively ready 2024-05-31
#if __cplusplus >= 202002L
enum E { x };
void f() {
int E;
// FIXME: OK, names ::E
using enum E;
// since-cxx20-error@-1 {{unknown type name E}}
}
using F = E;
using enum F; // OK, designates ::E
template<class T> using EE = T;
void g() {
// FIXME: OK, designates ::E
using enum EE<E>;
// since-cxx20-error@-1 {{using enum requires an enum or typedef name}}
}
#endif
} // namespace cwg2877

namespace cwg2881 { // cwg2881: 19 tentatively ready 2024-04-19

#if __cplusplus >= 202302L
Expand Down Expand Up @@ -180,3 +200,64 @@ void f() {

} // namespace cwg2881

namespace cwg2882 { // cwg2882: 2.7 tentatively ready 2024-05-31
struct C {
operator void() = delete;
// expected-warning@-1 {{conversion function converting 'cwg2882::C' to 'void' will never be used}}
// cxx98-error@-2 {{deleted function definitions are a C++11 extension}}
};

void f(C c) {
(void)c;
}
} // namespace cwg2882

namespace cwg2883 { // cwg2883: no tentatively ready 2024-05-31
#if __cplusplus >= 201103L
void f() {
int x;
(void)[&] {
return x;
};
}
#endif
#if __cplusplus >= 202002L
struct A {
A() = default;
A(const A &) = delete; // #cwg2883-A-copy-ctor
constexpr operator int() { return 42; }
};
void g() {
constexpr A a;
// FIXME: OK, not odr-usable from a default template argument, and not odr-used
(void)[=]<typename T, int = a> {};
// since-cxx20-error@-1 {{call to deleted constructor of 'const A'}}
// since-cxx20-note@#cwg2883-A-copy-ctor {{'A' has been explicitly marked deleted here}}
}
#endif
} // namespace cwg2883

namespace cwg2885 { // cwg2885: 16 tentatively ready 2024-05-31
#if __cplusplus >= 202002L
template <class T>
struct A {
A() requires (false) = default;
A() : t(42) {}
T t;
};

struct B : A<int> {};
static_assert(!__is_trivially_constructible(B));
#endif
} // namespace cwg2885

namespace cwg2886 { // cwg2886: 9 tentatively ready 2024-05-31
#if __cplusplus >= 201103L
struct C {
C() = default;
~C() noexcept(false) = default;
};

static_assert(noexcept(C()), "");
#endif
} // namespace cwg2886
10 changes: 5 additions & 5 deletions clang/test/CodeGen/aarch64-sme-intrinsics/acle_sme_add-i64.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-i16i64 -S -O1 -Werror -o /dev/null %s
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-i16i64 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-i16i64 -S -O1 -Werror -o /dev/null %s

#include <arm_sme.h>

Expand Down
10 changes: 5 additions & 5 deletions clang/test/CodeGen/aarch64-sme-intrinsics/acle_sme_mopa-za64.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -S -O1 -Werror -o /dev/null %s
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -S -O1 -Werror -o /dev/null %s

#include <arm_sme.h>

Expand Down
10 changes: 5 additions & 5 deletions clang/test/CodeGen/aarch64-sme-intrinsics/acle_sme_mops-za64.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -S -O1 -Werror -o /dev/null %s
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,CHECK-C
// RUN: %clang_cc1 -fclang-abi-compat=latest -DSME_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -O1 -Werror -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,CHECK-CXX
// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f64f64 -target-feature +sme-i16i64 -target-feature +bf16 -S -O1 -Werror -o /dev/null %s

#include <arm_sme.h>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 \
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +bf16 -target-feature +sme -target-feature +sme2 \
// RUN: -disable-O0-optnone -Werror -emit-llvm -o - %s \
// RUN: | opt -S -passes=mem2reg \
// RUN: | opt -S -passes=inline \
Expand Down
Loading