103 changes: 49 additions & 54 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,12 +757,11 @@ Error RewriteInstance::run() {
if (opts::Instrument && !BC->IsStaticExecutable)
updateRtFiniReloc();

if (BC->IsLinuxKernel) {
errs() << "BOLT-WARNING: not writing the output file for Linux Kernel\n";
return Error::success();
} else if (opts::OutputFilename == "/dev/null") {
if (opts::OutputFilename == "/dev/null") {
outs() << "BOLT-INFO: skipping writing final binary to disk\n";
return Error::success();
} else if (BC->IsLinuxKernel) {
errs() << "BOLT-WARNING: Linux kernel support is experimental\n";
}

// Rewrite allocatable contents and copy non-allocatable parts with mods.
Expand Down Expand Up @@ -1470,25 +1469,29 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
setPLTSymbol(BF, Symbol->getName());
}

void RewriteInstance::disassemblePLTSectionAArch64(BinarySection &Section) {
void RewriteInstance::disassemblePLTInstruction(const BinarySection &Section,
uint64_t InstrOffset,
MCInst &Instruction,
uint64_t &InstrSize) {
const uint64_t SectionAddress = Section.getAddress();
const uint64_t SectionSize = Section.getSize();
StringRef PLTContents = Section.getContents();
ArrayRef<uint8_t> PLTData(
reinterpret_cast<const uint8_t *>(PLTContents.data()), SectionSize);

auto disassembleInstruction = [&](uint64_t InstrOffset, MCInst &Instruction,
uint64_t &InstrSize) {
const uint64_t InstrAddr = SectionAddress + InstrOffset;
if (!BC->DisAsm->getInstruction(Instruction, InstrSize,
PLTData.slice(InstrOffset), InstrAddr,
nulls())) {
errs() << "BOLT-ERROR: unable to disassemble instruction in PLT section "
<< Section.getName() << " at offset 0x"
<< Twine::utohexstr(InstrOffset) << '\n';
exit(1);
}
};
const uint64_t InstrAddr = SectionAddress + InstrOffset;
if (!BC->DisAsm->getInstruction(Instruction, InstrSize,
PLTData.slice(InstrOffset), InstrAddr,
nulls())) {
errs() << "BOLT-ERROR: unable to disassemble instruction in PLT section "
<< Section.getName() << formatv(" at offset {0:x}\n", InstrOffset);
exit(1);
}
}

void RewriteInstance::disassemblePLTSectionAArch64(BinarySection &Section) {
const uint64_t SectionAddress = Section.getAddress();
const uint64_t SectionSize = Section.getSize();

uint64_t InstrOffset = 0;
// Locate new plt entry
Expand All @@ -1500,7 +1503,7 @@ void RewriteInstance::disassemblePLTSectionAArch64(BinarySection &Section) {
uint64_t InstrSize;
// Loop through entry instructions
while (InstrOffset < SectionSize) {
disassembleInstruction(InstrOffset, Instruction, InstrSize);
disassemblePLTInstruction(Section, InstrOffset, Instruction, InstrSize);
EntrySize += InstrSize;
if (!BC->MIB->isIndirectBranch(Instruction)) {
Instructions.emplace_back(Instruction);
Expand All @@ -1521,7 +1524,7 @@ void RewriteInstance::disassemblePLTSectionAArch64(BinarySection &Section) {

// Skip nops if any
while (InstrOffset < SectionSize) {
disassembleInstruction(InstrOffset, Instruction, InstrSize);
disassemblePLTInstruction(Section, InstrOffset, Instruction, InstrSize);
if (!BC->MIB->isNoop(Instruction))
break;

Expand Down Expand Up @@ -1578,29 +1581,13 @@ void RewriteInstance::disassemblePLTSectionX86(BinarySection &Section,
uint64_t EntrySize) {
const uint64_t SectionAddress = Section.getAddress();
const uint64_t SectionSize = Section.getSize();
StringRef PLTContents = Section.getContents();
ArrayRef<uint8_t> PLTData(
reinterpret_cast<const uint8_t *>(PLTContents.data()), SectionSize);

auto disassembleInstruction = [&](uint64_t InstrOffset, MCInst &Instruction,
uint64_t &InstrSize) {
const uint64_t InstrAddr = SectionAddress + InstrOffset;
if (!BC->DisAsm->getInstruction(Instruction, InstrSize,
PLTData.slice(InstrOffset), InstrAddr,
nulls())) {
errs() << "BOLT-ERROR: unable to disassemble instruction in PLT section "
<< Section.getName() << " at offset 0x"
<< Twine::utohexstr(InstrOffset) << '\n';
exit(1);
}
};

for (uint64_t EntryOffset = 0; EntryOffset + EntrySize <= SectionSize;
EntryOffset += EntrySize) {
MCInst Instruction;
uint64_t InstrSize, InstrOffset = EntryOffset;
while (InstrOffset < EntryOffset + EntrySize) {
disassembleInstruction(InstrOffset, Instruction, InstrSize);
disassemblePLTInstruction(Section, InstrOffset, Instruction, InstrSize);
// Check if the entry size needs adjustment.
if (EntryOffset == 0 && BC->MIB->isTerminateBranch(Instruction) &&
EntrySize == 8)
Expand Down Expand Up @@ -1860,6 +1847,11 @@ Error RewriteInstance::readSpecialSections() {
BC->HasRelocations =
HasTextRelocations && (opts::RelocationMode != cl::BOU_FALSE);

if (BC->IsLinuxKernel && BC->HasRelocations) {
outs() << "BOLT-INFO: disabling relocation mode for Linux kernel\n";
BC->HasRelocations = false;
}

BC->IsStripped = !HasSymbolTable;

if (BC->IsStripped && !opts::AllowStripped) {
Expand Down Expand Up @@ -4153,10 +4145,10 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,

// Keep track of section header entries attached to the corresponding section.
std::vector<std::pair<BinarySection *, ELFShdrTy>> OutputSections;
auto addSection = [&](const ELFShdrTy &Section, BinarySection *BinSec) {
auto addSection = [&](const ELFShdrTy &Section, BinarySection &BinSec) {
ELFShdrTy NewSection = Section;
NewSection.sh_name = SHStrTab.getOffset(BinSec->getOutputName());
OutputSections.emplace_back(BinSec, std::move(NewSection));
NewSection.sh_name = SHStrTab.getOffset(BinSec.getOutputName());
OutputSections.emplace_back(&BinSec, std::move(NewSection));
};

// Copy over entries for original allocatable sections using modified name.
Expand All @@ -4174,7 +4166,7 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
BinarySection *BinSec = BC->getSectionForSectionRef(SecRef);
assert(BinSec && "Matching BinarySection should exist.");

addSection(Section, BinSec);
addSection(Section, *BinSec);
}

for (BinarySection &Section : BC->allocatableSections()) {
Expand All @@ -4201,7 +4193,7 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
NewSection.sh_link = 0;
NewSection.sh_info = 0;
NewSection.sh_addralign = Section.getAlignment();
addSection(NewSection, &Section);
addSection(NewSection, Section);
}

// Sort all allocatable sections by their offset.
Expand All @@ -4215,19 +4207,19 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
for (auto &SectionKV : OutputSections) {
ELFShdrTy &Section = SectionKV.second;

// TBSS section does not take file or memory space. Ignore it for layout
// purposes.
if (Section.sh_type == ELF::SHT_NOBITS && (Section.sh_flags & ELF::SHF_TLS))
// Ignore TLS sections as they don't take any space in the file.
if (Section.sh_type == ELF::SHT_NOBITS)
continue;

// Note that address continuity is not guaranteed as sections could be
// placed in different loadable segments.
if (PrevSection &&
PrevSection->sh_addr + PrevSection->sh_size > Section.sh_addr) {
if (opts::Verbosity > 1)
PrevSection->sh_offset + PrevSection->sh_size > Section.sh_offset) {
if (opts::Verbosity > 1) {
outs() << "BOLT-INFO: adjusting size for section "
<< PrevBinSec->getOutputName() << '\n';
PrevSection->sh_size = Section.sh_addr > PrevSection->sh_addr
? Section.sh_addr - PrevSection->sh_addr
: 0;
}
PrevSection->sh_size = Section.sh_offset - PrevSection->sh_offset;
}

PrevSection = &Section;
Expand Down Expand Up @@ -4261,7 +4253,7 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
if (NewSection.sh_type == ELF::SHT_SYMTAB)
NewSection.sh_info = NumLocalSymbols;

addSection(NewSection, BinSec);
addSection(NewSection, *BinSec);

LastFileOffset = BinSec->getOutputFileOffset();
}
Expand All @@ -4286,7 +4278,7 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
NewSection.sh_info = 0;
NewSection.sh_addralign = Section.getAlignment();

addSection(NewSection, &Section);
addSection(NewSection, Section);
}

// Assign indices to sections.
Expand Down Expand Up @@ -4369,8 +4361,10 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *File) {
assert((NewEhdr.e_entry || !Obj.getHeader().e_entry) &&
"cannot find new address for entry point");
}
NewEhdr.e_phoff = PHDRTableOffset;
NewEhdr.e_phnum = Phnum;
if (PHDRTableOffset) {
NewEhdr.e_phoff = PHDRTableOffset;
NewEhdr.e_phnum = Phnum;
}
NewEhdr.e_shoff = SHTOffset;
NewEhdr.e_shnum = OutputSections.size();
NewEhdr.e_shstrndx = NewSectionIndex[NewEhdr.e_shstrndx];
Expand Down Expand Up @@ -5505,7 +5499,8 @@ void RewriteInstance::rewriteFile() {
addBATSection();

// Patch program header table.
patchELFPHDRTable();
if (!BC->IsLinuxKernel)
patchELFPHDRTable();

// Finalize memory image of section string table.
finalizeSectionStringTable();
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Target/X86/X86MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2197,7 +2197,7 @@ class X86MCPlusBuilder : public MCPlusBuilder {
MO->BaseRegNum != X86::RIP && MO->BaseRegNum != X86::RBP &&
MO->BaseRegNum != X86::NoRegister &&
MO->IndexRegNum == X86::NoRegister &&
MO->SegRegNum == X86::NoRegister && MO->BaseRegNum != X86::RIP) {
MO->SegRegNum == X86::NoRegister) {
VtableRegNum = MO->BaseRegNum;
MethodOffset = MO->DispImm;
MethodFetchInsns.push_back(&CurInst);
Expand Down
2 changes: 2 additions & 0 deletions bolt/test/X86/linux-orc.s
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ bar:
.L4:
.size bar, .-bar

# CHECK: BOLT-WARNING: Linux kernel support is experimental

.section .orc_unwind,"a",@progbits
.align 4
.section .orc_unwind_ip,"a",@progbits
Expand Down
52 changes: 52 additions & 0 deletions bolt/test/X86/phdr-out-of-order.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## Check that llvm-bolt correctly processes a binary with program headers and
## corresponding sections specified in non-ascending address order.

RUN: split-file %s %t
RUN: yaml2obj %t/yaml -o %t.exe --max-size=0
RUN: llvm-bolt %t.exe -o %t.bolt --allow-stripped
RUN: llvm-readelf -WS %t.bolt | FileCheck %s

CHECK: .a PROGBITS 0000000000400000 [[#%.6x, OFFSET:]] 000001
CHECK-NEXT: .b PROGBITS 0000000000000000 [[#%.6x, OFFSET+1]] 000001
CHECK-NEXT: .c PROGBITS 0000000000600000 [[#%.6x, OFFSET+2]] 000001

#--- yaml
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
ProgramHeaders:
- Type: PT_LOAD
FirstSec: .a
LastSec: .a
VAddr: 0x400000
- Type: PT_LOAD
FirstSec: .b
LastSec: .b
VAddr: 0x0
- Type: PT_LOAD
FirstSec: .c
LastSec: .c
VAddr: 0x600000
Sections:
- Name: .a
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Content: 00
AddressAlign: 0x1
Address: 0x400000
- Name: .b
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Content: 00
AddressAlign: 0x1
Address: 0x0
- Name: .c
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Content: 00
AddressAlign: 0x1
Address: 0x600000
...
3 changes: 0 additions & 3 deletions clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include "LimitedRandomnessCheck.h"
#include "MutatingCopyCheck.h"
#include "NonTrivialTypesLibcMemoryCallsCheck.h"
#include "PostfixOperatorCheck.h"
#include "ProperlySeededRandomGeneratorCheck.h"
#include "SetLongJmpCheck.h"
#include "StaticObjectExceptionCheck.h"
Expand Down Expand Up @@ -239,8 +238,6 @@ class CERTModule : public ClangTidyModule {
CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
"cert-con54-cpp");
// DCL
CheckFactories.registerCheck<PostfixOperatorCheck>(
"cert-dcl21-cpp");
CheckFactories.registerCheck<VariadicFunctionDefCheck>("cert-dcl50-cpp");
CheckFactories.registerCheck<bugprone::ReservedIdentifierCheck>(
"cert-dcl51-cpp");
Expand Down
1 change: 0 additions & 1 deletion clang-tools-extra/clang-tidy/cert/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ add_clang_library(clangTidyCERTModule
LimitedRandomnessCheck.cpp
MutatingCopyCheck.cpp
NonTrivialTypesLibcMemoryCallsCheck.cpp
PostfixOperatorCheck.cpp
ProperlySeededRandomGeneratorCheck.cpp
SetLongJmpCheck.cpp
StaticObjectExceptionCheck.cpp
Expand Down
80 changes: 0 additions & 80 deletions clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.cpp

This file was deleted.

34 changes: 0 additions & 34 deletions clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.h

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,6 @@ static bool isNoReturnCallStatement(const Stmt *S) {
return Func->isNoReturn();
}

static bool isLiteral(const Expr *E) {
return isa<StringLiteral, CharacterLiteral, IntegerLiteral, FloatingLiteral,
CXXBoolLiteralExpr, CXXNullPtrLiteralExpr>(E);
}

static bool isUnaryExprOfLiteral(const Expr *E) {
if (const auto *UnOp = dyn_cast<UnaryOperator>(E))
return isLiteral(UnOp->getSubExpr());
return false;
}

static bool shouldBeDefaultMemberInitializer(const Expr *Value) {
if (isLiteral(Value) || isUnaryExprOfLiteral(Value))
return true;

if (const auto *DRE = dyn_cast<DeclRefExpr>(Value))
return isa<EnumConstantDecl>(DRE->getDecl());

return false;
}

namespace {

AST_MATCHER_P(FieldDecl, indexNotLessThan, unsigned, Index) {
Expand Down Expand Up @@ -166,19 +145,7 @@ isAssignmentToMemberOf(const CXXRecordDecl *Rec, const Stmt *S,

PreferMemberInitializerCheck::PreferMemberInitializerCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IsUseDefaultMemberInitEnabled(
Context->isCheckEnabled("modernize-use-default-member-init")),
UseAssignment(
Options.get("UseAssignment",
OptionsView("modernize-use-default-member-init",
Context->getOptions().CheckOptions, Context)
.get("UseAssignment", false))) {}

void PreferMemberInitializerCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "UseAssignment", UseAssignment);
}
: ClangTidyCheck(Name, Context) {}

void PreferMemberInitializerCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(cxxConstructorDecl(hasBody(compoundStmt()),
Expand Down Expand Up @@ -230,139 +197,99 @@ void PreferMemberInitializerCheck::check(
updateAssignmentLevel(Field, InitValue, Ctor, AssignedFields);
if (!canAdvanceAssignment(AssignedFields[Field]))
continue;
const bool IsInDefaultMemberInitializer =
IsUseDefaultMemberInitEnabled && getLangOpts().CPlusPlus11 &&
Ctor->isDefaultConstructor() &&
(getLangOpts().CPlusPlus20 || !Field->isBitField()) &&
!Field->hasInClassInitializer() &&
(!isa<RecordDecl>(Class->getDeclContext()) ||
!cast<RecordDecl>(Class->getDeclContext())->isUnion()) &&
shouldBeDefaultMemberInitializer(InitValue);
if (IsInDefaultMemberInitializer) {
bool InvalidFix = false;
SourceLocation FieldEnd =
Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0,
*Result.SourceManager, getLangOpts());
InvalidFix |= FieldEnd.isInvalid() || FieldEnd.isMacroID();
SourceLocation SemiColonEnd;
if (auto NextToken = Lexer::findNextToken(
S->getEndLoc(), *Result.SourceManager, getLangOpts()))
SemiColonEnd = NextToken->getEndLoc();
else
InvalidFix = true;
auto Diag =
diag(S->getBeginLoc(), "%0 should be initialized in an in-class"
" default member initializer")
<< Field;
if (InvalidFix)
continue;
CharSourceRange StmtRange =
CharSourceRange::getCharRange(S->getBeginLoc(), SemiColonEnd);

SmallString<128> Insertion(
{UseAssignment ? " = " : "{",
Lexer::getSourceText(Result.SourceManager->getExpansionRange(
InitValue->getSourceRange()),
*Result.SourceManager, getLangOpts()),
UseAssignment ? "" : "}"});

Diag << FixItHint::CreateInsertion(FieldEnd, Insertion)
<< FixItHint::CreateRemoval(StmtRange);

} else {
StringRef InsertPrefix = "";
bool HasInitAlready = false;
SourceLocation InsertPos;
SourceRange ReplaceRange;
bool AddComma = false;
bool InvalidFix = false;
unsigned Index = Field->getFieldIndex();
const CXXCtorInitializer *LastInListInit = nullptr;
for (const CXXCtorInitializer *Init : Ctor->inits()) {
if (!Init->isWritten() || Init->isInClassMemberInitializer())
continue;
if (Init->getMember() == Field) {
HasInitAlready = true;
if (isa<ImplicitValueInitExpr>(Init->getInit()))
InsertPos = Init->getRParenLoc();
else {
ReplaceRange = Init->getInit()->getSourceRange();
}
break;
}
if (Init->isMemberInitializer() &&
Index < Init->getMember()->getFieldIndex()) {
InsertPos = Init->getSourceLocation();
// There are initializers after the one we are inserting, so add a
// comma after this insertion in order to not break anything.
AddComma = true;
break;
StringRef InsertPrefix = "";
bool HasInitAlready = false;
SourceLocation InsertPos;
SourceRange ReplaceRange;
bool AddComma = false;
bool InvalidFix = false;
unsigned Index = Field->getFieldIndex();
const CXXCtorInitializer *LastInListInit = nullptr;
for (const CXXCtorInitializer *Init : Ctor->inits()) {
if (!Init->isWritten() || Init->isInClassMemberInitializer())
continue;
if (Init->getMember() == Field) {
HasInitAlready = true;
if (isa<ImplicitValueInitExpr>(Init->getInit()))
InsertPos = Init->getRParenLoc();
else {
ReplaceRange = Init->getInit()->getSourceRange();
}
LastInListInit = Init;
break;
}
if (HasInitAlready) {
if (InsertPos.isValid())
InvalidFix |= InsertPos.isMacroID();
else
InvalidFix |= ReplaceRange.getBegin().isMacroID() ||
ReplaceRange.getEnd().isMacroID();
} else {
if (InsertPos.isInvalid()) {
if (LastInListInit) {
InsertPos = Lexer::getLocForEndOfToken(
LastInListInit->getRParenLoc(), 0, *Result.SourceManager,
getLangOpts());
// Inserting after the last constructor initializer, so we need a
// comma.
InsertPrefix = ", ";
} else {
InsertPos = Lexer::getLocForEndOfToken(
Ctor->getTypeSourceInfo()
->getTypeLoc()
.getAs<clang::FunctionTypeLoc>()
.getLocalRangeEnd(),
0, *Result.SourceManager, getLangOpts());

// If this is first time in the loop, there are no initializers so
// `:` declares member initialization list. If this is a
// subsequent pass then we have already inserted a `:` so continue
// with a comma.
InsertPrefix = FirstToCtorInits ? " : " : ", ";
}
}
if (Init->isMemberInitializer() &&
Index < Init->getMember()->getFieldIndex()) {
InsertPos = Init->getSourceLocation();
// There are initializers after the one we are inserting, so add a
// comma after this insertion in order to not break anything.
AddComma = true;
break;
}
LastInListInit = Init;
}
if (HasInitAlready) {
if (InsertPos.isValid())
InvalidFix |= InsertPos.isMacroID();
else
InvalidFix |= ReplaceRange.getBegin().isMacroID() ||
ReplaceRange.getEnd().isMacroID();
} else {
if (InsertPos.isInvalid()) {
if (LastInListInit) {
InsertPos =
Lexer::getLocForEndOfToken(LastInListInit->getRParenLoc(), 0,
*Result.SourceManager, getLangOpts());
// Inserting after the last constructor initializer, so we need a
// comma.
InsertPrefix = ", ";
} else {
InsertPos = Lexer::getLocForEndOfToken(
Ctor->getTypeSourceInfo()
->getTypeLoc()
.getAs<clang::FunctionTypeLoc>()
.getLocalRangeEnd(),
0, *Result.SourceManager, getLangOpts());

// If this is first time in the loop, there are no initializers so
// `:` declares member initialization list. If this is a
// subsequent pass then we have already inserted a `:` so continue
// with a comma.
InsertPrefix = FirstToCtorInits ? " : " : ", ";
}
}
InvalidFix |= InsertPos.isMacroID();
}

SourceLocation SemiColonEnd;
if (auto NextToken = Lexer::findNextToken(
S->getEndLoc(), *Result.SourceManager, getLangOpts()))
SemiColonEnd = NextToken->getEndLoc();
SourceLocation SemiColonEnd;
if (auto NextToken = Lexer::findNextToken(
S->getEndLoc(), *Result.SourceManager, getLangOpts()))
SemiColonEnd = NextToken->getEndLoc();
else
InvalidFix = true;

auto Diag = diag(S->getBeginLoc(), "%0 should be initialized in a member"
" initializer of the constructor")
<< Field;
if (InvalidFix)
continue;
StringRef NewInit = Lexer::getSourceText(
Result.SourceManager->getExpansionRange(InitValue->getSourceRange()),
*Result.SourceManager, getLangOpts());
if (HasInitAlready) {
if (InsertPos.isValid())
Diag << FixItHint::CreateInsertion(InsertPos, NewInit);
else
InvalidFix = true;

auto Diag = diag(S->getBeginLoc(), "%0 should be initialized in a member"
" initializer of the constructor")
<< Field;
if (InvalidFix)
continue;
StringRef NewInit = Lexer::getSourceText(
Result.SourceManager->getExpansionRange(InitValue->getSourceRange()),
*Result.SourceManager, getLangOpts());
if (HasInitAlready) {
if (InsertPos.isValid())
Diag << FixItHint::CreateInsertion(InsertPos, NewInit);
else
Diag << FixItHint::CreateReplacement(ReplaceRange, NewInit);
} else {
SmallString<128> Insertion({InsertPrefix, Field->getName(), "(",
NewInit, AddComma ? "), " : ")"});
Diag << FixItHint::CreateInsertion(InsertPos, Insertion,
FirstToCtorInits);
FirstToCtorInits = areDiagsSelfContained();
}
Diag << FixItHint::CreateRemoval(
CharSourceRange::getCharRange(S->getBeginLoc(), SemiColonEnd));
Diag << FixItHint::CreateReplacement(ReplaceRange, NewInit);
} else {
SmallString<128> Insertion({InsertPrefix, Field->getName(), "(", NewInit,
AddComma ? "), " : ")"});
Diag << FixItHint::CreateInsertion(InsertPos, Insertion,
FirstToCtorInits);
FirstToCtorInits = areDiagsSelfContained();
}
Diag << FixItHint::CreateRemoval(
CharSourceRange::getCharRange(S->getBeginLoc(), SemiColonEnd));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,8 @@ class PreferMemberInitializerCheck : public ClangTidyCheck {
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;

const bool IsUseDefaultMemberInitEnabled;
const bool UseAssignment;
};

} // namespace clang::tidy::cppcoreguidelines
Expand Down
22 changes: 20 additions & 2 deletions clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

using namespace clang::ast_matchers;

namespace clang::tidy::modernize {

namespace {

AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) {
Expand All @@ -38,16 +40,32 @@ AST_MATCHER(clang::ParmVarDecl, isArgvOfMain) {

} // namespace

namespace clang::tidy::modernize {
AvoidCArraysCheck::AvoidCArraysCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
AllowStringArrays(Options.get("AllowStringArrays", false)) {}

void AvoidCArraysCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "AllowStringArrays", AllowStringArrays);
}

void AvoidCArraysCheck::registerMatchers(MatchFinder *Finder) {
ast_matchers::internal::Matcher<TypeLoc> IgnoreStringArrayIfNeededMatcher =
anything();
if (AllowStringArrays)
IgnoreStringArrayIfNeededMatcher =
unless(typeLoc(loc(hasCanonicalType(incompleteArrayType(
hasElementType(isAnyCharacter())))),
hasParent(varDecl(hasInitializer(stringLiteral()),
unless(parmVarDecl())))));

Finder->addMatcher(
typeLoc(hasValidBeginLoc(), hasType(arrayType()),
unless(anyOf(hasParent(parmVarDecl(isArgvOfMain())),
hasParent(varDecl(isExternC())),
hasParent(fieldDecl(
hasParent(recordDecl(isExternCContext())))),
hasAncestor(functionDecl(isExternC())))))
hasAncestor(functionDecl(isExternC())))),
std::move(IgnoreStringArrayIfNeededMatcher))
.bind("typeloc"),
this);
}
Expand Down
14 changes: 10 additions & 4 deletions clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ namespace clang::tidy::modernize {
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/avoid-c-arrays.html
class AvoidCArraysCheck : public ClangTidyCheck {
public:
AvoidCArraysCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
AvoidCArraysCheck(StringRef Name, ClangTidyContext *Context);
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus11;
}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}

private:
const bool AllowStringArrays;
};

} // namespace clang::tidy::modernize
Expand Down
1 change: 0 additions & 1 deletion clang-tools-extra/clangd/TidyFastChecks.inc
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ FAST(cert-con36-c, 2.0)
FAST(cert-con54-cpp, 3.0)
FAST(cert-dcl03-c, 2.0)
FAST(cert-dcl16-c, -1.0)
FAST(cert-dcl21-cpp, 0.0)
FAST(cert-dcl37-c, 3.0)
FAST(cert-dcl50-cpp, -1.0)
FAST(cert-dcl51-cpp, 1.0)
Expand Down
16 changes: 16 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,25 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^

- Cleaned up :doc:`cppcoreguidelines-prefer-member-initializer
<clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>`
by removing enforcement of rule `C.48
<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c48-prefer-in-class-initializers-to-member-initializers-in-constructors-for-constant-initializers>`_,
which was deprecated since :program:`clang-tidy` 17. This rule is now covered
by :doc:`cppcoreguidelines-use-default-member-init
<clang-tidy/checks/cppcoreguidelines/use-default-member-init>`.

- Improved :doc:`modernize-avoid-c-arrays
<clang-tidy/checks/modernize/avoid-c-arrays>` check by introducing the new
`AllowStringArrays` option, enabling the exclusion of array types with deduced
length initialized from string literals.

Removed checks
^^^^^^^^^^^^^^

- Removed `cert-dcl21-cpp`, which was deprecated since :program:`clang-tidy` 17,
since the rule DCL21-CPP has been removed from the CERT guidelines.

Improvements to include-fixer
-----------------------------

Expand Down
28 changes: 0 additions & 28 deletions clang-tools-extra/docs/clang-tidy/checks/cert/dcl21-cpp.rst

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,11 @@ This check implements `C.49
<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c49-prefer-initialization-to-assignment-in-constructors>`_
from the C++ Core Guidelines.

If the language version is `C++ 11` or above, the constructor is the default
constructor of the class, the field is not a bitfield (only in case of earlier
language version than `C++ 20`), furthermore the assigned value is a literal,
negated literal or ``enum`` constant then the preferred place of the
initialization is at the class member declaration.

This latter rule is `C.48
Please note, that this check does not enforce rule `C.48
<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c48-prefer-in-class-initializers-to-member-initializers-in-constructors-for-constant-initializers>`_
from the C++ Core Guidelines.

Please note, that this check does not enforce this latter rule for
initializations already implemented as member initializers. For that purpose
from the C++ Core Guidelines. For that purpose
see check :doc:`modernize-use-default-member-init <../modernize/use-default-member-init>`.

.. note::

Enforcement of rule C.48 in this check is deprecated, to be removed in
:program:`clang-tidy` version 19 (only C.49 will be enforced by this check then).
Please use :doc:`cppcoreguidelines-use-default-member-init <../cppcoreguidelines/use-default-member-init>`
to enforce rule C.48.

Example 1
---------

Expand All @@ -51,16 +35,16 @@ Example 1
}
};

Here ``n`` can be initialized using a default member initializer, unlike
Here ``n`` can be initialized in the constructor initializer list, unlike
``m``, as ``m``'s initialization follows a control statement (``if``):

.. code-block:: c++

class C {
int n{1};
int n;
int m;
public:
C() {
C(): n(1) {
if (dice())
return;
m = 1;
Expand All @@ -84,7 +68,7 @@ Example 2
}
};

Here ``n`` can be initialized in the constructor initialization list, unlike
Here ``n`` can be initialized in the constructor initializer list, unlike
``m``, as ``m``'s initialization follows a control statement (``if``):

.. code-block:: c++
Expand All @@ -94,29 +78,3 @@ Here ``n`` can be initialized in the constructor initialization list, unlike
return;
m = mm;
}

.. option:: UseAssignment

Note: this option is deprecated, to be removed in :program:`clang-tidy`
version 19. Please use the `UseAssignment` option from
:doc:`cppcoreguidelines-use-default-member-init <../cppcoreguidelines/use-default-member-init>`
instead.

If this option is set to `true` (by default `UseAssignment` from
:doc:`modernize-use-default-member-init
<../modernize/use-default-member-init>` will be used),
the check will initialize members with an assignment.
In this case the fix of the first example looks like this:

.. code-block:: c++

class C {
int n = 1;
int m;
public:
C() {
if (dice())
return;
m = 1;
}
};
1 change: 0 additions & 1 deletion clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ Clang-Tidy Checks
:doc:`bugprone-unused-return-value <bugprone/unused-return-value>`,
:doc:`bugprone-use-after-move <bugprone/use-after-move>`,
:doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes"
:doc:`cert-dcl21-cpp <cert/dcl21-cpp>`, "Yes"
:doc:`cert-dcl50-cpp <cert/dcl50-cpp>`,
:doc:`cert-dcl58-cpp <cert/dcl58-cpp>`,
:doc:`cert-env33-c <cert/env33-c>`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,14 @@ such headers between C code, and C++ code.
Similarly, the ``main()`` function is ignored. Its second and third parameters
can be either ``char* argv[]`` or ``char** argv``, but cannot be
``std::array<>``.

.. option:: AllowStringArrays

When set to `true` (default is `false`), variables of character array type
with deduced length, initialized directly from string literals, will be ignored.
This option doesn't affect cases where length can't be deduced, resembling
pointers, as seen in class members and parameters. Example:

.. code:: c++

const char name[] = "Some name";
134 changes: 0 additions & 134 deletions clang-tools-extra/test/clang-tidy/checkers/cert/dcl21-cpp.cpp

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t -- \
// RUN: -config='{CheckOptions: { modernize-avoid-c-arrays.AllowStringArrays: true }}'

const char name[] = "name";
const char array[] = {'n', 'a', 'm', 'e', '\0'};
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]

void takeCharArray(const char name[]);
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,9 @@ struct Bar {
int j[1];
};
}

const char name[] = "Some string";
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]

void takeCharArray(const char name[]);
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
42 changes: 9 additions & 33 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5277,15 +5277,9 @@ the configuration (without a prefix: ``Auto``).
Possible values:

* ``SBPO_Never`` (in configuration: ``Never``)
Never put a space before opening parentheses.

.. code-block:: c++

void f() {
if(true) {
f();
}
}
This is **deprecated** and replaced by ``Custom`` below, with all
``SpaceBeforeParensOptions`` but ``AfterPlacementOperator`` set to
``false``.

* ``SBPO_ControlStatements`` (in configuration: ``ControlStatements``)
Put a space before opening parentheses only after control statement
Expand Down Expand Up @@ -5425,32 +5419,14 @@ the configuration (without a prefix: ``Auto``).
void operator++ (int a); vs. void operator++(int a);
object.operator++ (10); object.operator++(10);

* ``AfterPlacementOperatorStyle AfterPlacementOperator`` :versionbadge:`clang-format 18`

Defines in which cases to put a space between ``new/delete`` operators
and opening parentheses.

Possible values:

* ``APO_Never`` (in configuration: ``Never``)
Remove space after ``new/delete`` operators and before ``(``.

.. code-block:: c++

new(buf) T;
delete(buf) T;

* ``APO_Always`` (in configuration: ``Always``)
Always add space after ``new/delete`` operators and before ``(``.
* ``bool AfterPlacementOperator`` If ``true``, put a space between operator ``new``/``delete`` and opening
parenthesis.

.. code-block:: c++

new (buf) T;
delete (buf) T;

* ``APO_Leave`` (in configuration: ``Leave``)
Leave placement ``new/delete`` expressions as they are.
.. code-block:: c++

true: false:
new (buf) T; vs. new(buf) T;
delete (buf) T; delete(buf) T;

* ``bool AfterRequiresInClause`` If ``true``, put space between requires keyword in a requires clause and
opening parentheses, if there is one.
Expand Down
4 changes: 2 additions & 2 deletions clang/docs/HIPSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ Predefined Macros
* - ``HIP_API_PER_THREAD_DEFAULT_STREAM``
- Alias to ``__HIP_API_PER_THREAD_DEFAULT_STREAM__``. Deprecated.

Note that some architecture specific AMDGPU macros will have default values when
used from the HIP host compilation. Other :doc:`AMDGPU macros <AMDGPUSupport>`
Note that some architecture specific AMDGPU macros will have default values when
used from the HIP host compilation. Other :doc:`AMDGPU macros <AMDGPUSupport>`
like ``__AMDGCN_WAVEFRONT_SIZE__`` will default to 64 for example.

Compilation Modes
Expand Down
16 changes: 11 additions & 5 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ AST Dumping Potentially Breaking Changes

Clang Frontend Potentially Breaking Changes
-------------------------------------------
- Removed support for constructing on-stack ``TemplateArgumentList``s; interfaces should instead
use ``ArrayRef<TemplateArgument>`` to pass template arguments. Transitioning internal uses to
``ArrayRef<TemplateArgument>`` reduces AST memory usage by 0.4% when compiling clang, and is
expected to show similar improvements on other workloads.

Target OS macros extension
^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -82,7 +86,8 @@ C++20 Feature Support

- Clang won't perform ODR checks for decls in the global module fragment any
more to ease the implementation and improve the user's using experience.
This follows the MSVC's behavior.
This follows the MSVC's behavior. Users interested in testing the more strict
behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
(`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).

C++23 Feature Support
Expand Down Expand Up @@ -143,6 +148,8 @@ Improvements to Clang's diagnostics
- Clang now applies syntax highlighting to the code snippets it
prints.

- Clang now diagnoses member template declarations with multiple declarators.

Improvements to Clang's time-trace
----------------------------------

Expand All @@ -164,10 +171,6 @@ Bug Fixes to C++ Support

- Fix crash when using lifetimebound attribute in function with trailing return.
Fixes (`#73619 <https://github.com/llvm/llvm-project/issues/73619>`_)
- Fix a crash when specializing an out-of-line member function with a default
parameter where we did an incorrect specialization of the initialization of
the default parameter.
Fixes (`#68490 <https://github.com/llvm/llvm-project/issues/68490>`_)
- Addressed an issue where constraints involving injected class types are perceived
distinct from its specialization types.
(`#56482 <https://github.com/llvm/llvm-project/issues/56482>`_)
Expand Down Expand Up @@ -268,6 +271,9 @@ Improvements

- Support importing C++20 modules in clang-repl.

- Added support for ``TypeLoc::dump()`` for easier debugging, and improved
textual and JSON dumping for various ``TypeLoc``-related nodes.

Moved checkers
^^^^^^^^^^^^^^

Expand Down
23 changes: 23 additions & 0 deletions clang/docs/StandardCPlusPlusModules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,29 @@ Note that **currently** the compiler doesn't consider inconsistent macro definit
Currently Clang would accept the above example. But it may produce surprising results if the
debugging code depends on consistent use of ``NDEBUG`` also in other translation units.

Definitions consistency
^^^^^^^^^^^^^^^^^^^^^^^

The C++ language defines that same declarations in different translation units should have
the same definition, as known as ODR (One Definition Rule). Prior to modules, the translation
units don't dependent on each other and the compiler itself can't perform a strong
ODR violation check. With the introduction of modules, now the compiler have
the chance to perform ODR violations with language semantics across translation units.

However, in the practice, we found the existing ODR checking mechanism is not stable
enough. Many people suffers from the false positive ODR violation diagnostics, AKA,
the compiler are complaining two identical declarations have different definitions
incorrectly. Also the true positive ODR violations are rarely reported.
Also we learned that MSVC don't perform ODR check for declarations in the global module
fragment.

So in order to get better user experience, save the time checking ODR and keep consistent
behavior with MSVC, we disabled the ODR check for the declarations in the global module
fragment by default. Users who want more strict check can still use the
``-Xclang -fno-skip-odr-check-in-gmf`` flag to get the ODR check enabled. It is also
encouraged to report issues if users find false positive ODR violations or false negative ODR
violations with the flag enabled.

ABI Impacts
-----------

Expand Down
32 changes: 22 additions & 10 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,9 @@ Controlling Diagnostics via Pragmas
Clang can also control what diagnostics are enabled through the use of
pragmas in the source code. This is useful for turning off specific
warnings in a section of source code. Clang supports GCC's pragma for
compatibility with existing source code, as well as several extensions.
compatibility with existing source code, so ``#pragma GCC diagnostic``
and ``#pragma clang diagnostic`` are synonyms for Clang. GCC will ignore
``#pragma clang diagnostic``, though.

The pragma may control any warning that can be used from the command
line. Warnings may be set to ignored, warning, error, or fatal. The
Expand All @@ -1143,8 +1145,7 @@ warnings:
#pragma GCC diagnostic ignored "-Wall"
In addition to all of the functionality provided by GCC's pragma, Clang
also allows you to push and pop the current warning state. This is
Clang also allows you to push and pop the current warning state. This is
particularly useful when writing a header file that will be compiled by
other people, because you don't know what warning flags they build with.

Expand All @@ -1157,23 +1158,34 @@ existed.
#if foo
#endif foo // warning: extra tokens at end of #endif directive
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wextra-tokens"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wextra-tokens"
#if foo
#endif foo // no warning
#pragma clang diagnostic pop
#pragma GCC diagnostic pop
The push and pop pragmas will save and restore the full diagnostic state
of the compiler, regardless of how it was set. That means that it is
possible to use push and pop around GCC compatible diagnostics and Clang
will push and pop them appropriately, while GCC will ignore the pushes
and pops as unknown pragmas. It should be noted that while Clang
of the compiler, regardless of how it was set. It should be noted that while Clang
supports the GCC pragma, Clang and GCC do not support the exact same set
of warnings, so even when using GCC compatible #pragmas there is no
guarantee that they will have identical behaviour on both compilers.

Clang also doesn't yet support GCC behavior for ``#pragma diagnostic pop``
that doesn't have a corresponding ``#pragma diagnostic push``. In this case
GCC pretends that there is a ``#pragma diagnostic push`` at the very beginning
of the source file, so "unpaired" ``#pragma diagnostic pop`` matches that
implicit push. This makes a difference for ``#pragma GCC diagnostic ignored``
which are not guarded by push and pop. Refer to
`GCC documentation <https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html>`_
for details.

Like GCC, Clang accepts ``ignored``, ``warning``, ``error``, and ``fatal``
severity levels. They can be used to change severity of a particular diagnostic
for a region of source file. A notable difference from GCC is that diagnostic
not enabled via command line arguments can't be enabled this way yet.

In addition to controlling warnings and errors generated by the compiler, it is
possible to generate custom warning and error messages through the following
pragmas:
Expand Down
2 changes: 0 additions & 2 deletions clang/docs/tools/clang-formatted-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -985,8 +985,6 @@ clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp
clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.h
clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.h
clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.cpp
clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.h
clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp
clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.h
clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp
Expand Down
82 changes: 79 additions & 3 deletions clang/include/clang/AST/ASTNodeTraverser.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateArgumentVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h"
#include "llvm/Support/SaveAndRestore.h"

namespace clang {

Expand All @@ -48,6 +50,7 @@ struct {
void Visit(const Stmt *Node);
void Visit(const Type *T);
void Visit(QualType T);
void Visit(TypeLoc);
void Visit(const Decl *D);
void Visit(const CXXCtorInitializer *Init);
void Visit(const OMPClause *C);
Expand All @@ -64,13 +67,22 @@ class ASTNodeTraverser
public comments::ConstCommentVisitor<Derived, void,
const comments::FullComment *>,
public TypeVisitor<Derived>,
public TypeLocVisitor<Derived>,
public ConstAttrVisitor<Derived>,
public ConstTemplateArgumentVisitor<Derived> {

/// Indicates whether we should trigger deserialization of nodes that had
/// not already been loaded.
bool Deserialize = false;

/// Tracks whether we should dump TypeLocs etc.
///
/// Detailed location information such as TypeLoc nodes is not usually
/// included in the dump (too verbose).
/// But when explicitly asked to dump a Loc node, we do so recursively,
/// including e.g. FunctionTypeLoc => ParmVarDecl => TypeLoc.
bool VisitLocs = false;

TraversalKind Traversal = TraversalKind::TK_AsIs;

NodeDelegateType &getNodeDelegate() {
Expand All @@ -85,7 +97,7 @@ class ASTNodeTraverser
void SetTraversalKind(TraversalKind TK) { Traversal = TK; }
TraversalKind GetTraversalKind() const { return Traversal; }

void Visit(const Decl *D) {
void Visit(const Decl *D, bool VisitLocs = false) {
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit())
return;

Expand All @@ -94,7 +106,10 @@ class ASTNodeTraverser
if (!D)
return;

ConstDeclVisitor<Derived>::Visit(D);
{
llvm::SaveAndRestore RestoreVisitLocs(this->VisitLocs, VisitLocs);
ConstDeclVisitor<Derived>::Visit(D);
}

for (const auto &A : D->attrs())
Visit(A);
Expand Down Expand Up @@ -181,6 +196,17 @@ class ASTNodeTraverser
});
}

void Visit(TypeLoc T) {
getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(T);
if (T.isNull())
return;
TypeLocVisitor<Derived>::Visit(T);
if (auto Inner = T.getNextTypeLoc())
Visit(Inner);
});
}

void Visit(const Attr *A) {
getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(A);
Expand Down Expand Up @@ -286,6 +312,8 @@ class ASTNodeTraverser
Visit(*QT);
else if (const auto *T = N.get<Type>())
Visit(T);
else if (const auto *TL = N.get<TypeLoc>())
Visit(*TL);
else if (const auto *C = N.get<CXXCtorInitializer>())
Visit(C);
else if (const auto *C = N.get<OMPClause>())
Expand Down Expand Up @@ -346,7 +374,7 @@ class ASTNodeTraverser

void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); }
void VisitLocInfoType(const LocInfoType *T) {
Visit(T->getTypeSourceInfo()->getType());
Visit(T->getTypeSourceInfo()->getTypeLoc());
}
void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); }
void VisitBlockPointerType(const BlockPointerType *T) {
Expand Down Expand Up @@ -421,9 +449,55 @@ class ASTNodeTraverser
if (!T->isSugared())
Visit(T->getPattern());
}
void VisitAutoType(const AutoType *T) {
for (const auto &Arg : T->getTypeConstraintArguments())
Visit(Arg);
}
// FIXME: ElaboratedType, DependentNameType,
// DependentTemplateSpecializationType, ObjCObjectType

// For TypeLocs, we automatically visit the inner type loc (pointee type etc).
// We must explicitly visit other lexically-nested nodes.
void VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
TypeLocVisitor<Derived>::VisitFunctionTypeLoc(TL);
for (const auto *Param : TL.getParams())
Visit(Param, /*VisitTypeLocs=*/true);
}
void VisitAutoTypeLoc(AutoTypeLoc TL) {
if (const auto *CR = TL.getConceptReference()) {
if (auto *Args = CR->getTemplateArgsAsWritten())
for (const auto &Arg : Args->arguments())
dumpTemplateArgumentLoc(Arg);
}
}
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
Visit(TL.getClassTInfo()->getTypeLoc());
}
void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
Visit(TL.getSizeExpr());
}
void VisitDependentSizedArrayTypeLoc(DependentSizedArrayTypeLoc TL) {
Visit(TL.getSizeExpr());
}
void VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) {
Visit(cast<DependentSizedExtVectorType>(TL.getType())->getSizeExpr());
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
Visit(TL.getUnderlyingExpr());
}
void VisitDecltypeType(DecltypeType TL) {
Visit(TL.getUnderlyingExpr());
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I)
dumpTemplateArgumentLoc(TL.getArgLoc(I));
}
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I)
dumpTemplateArgumentLoc(TL.getArgLoc(I));
}

void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); }

void VisitEnumConstantDecl(const EnumConstantDecl *D) {
Expand Down Expand Up @@ -468,6 +542,8 @@ class ASTNodeTraverser
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isCXXForRangeDecl())
return;

if (const auto *TSI = D->getTypeSourceInfo(); VisitLocs && TSI)
Visit(TSI->getTypeLoc());
if (D->hasInit())
Visit(D->getInit());
}
Expand Down
26 changes: 3 additions & 23 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,6 @@ class FixedSizeTemplateParameterListStorage
/// A template argument list.
class TemplateArgumentList final
: private llvm::TrailingObjects<TemplateArgumentList, TemplateArgument> {
/// The template argument list.
const TemplateArgument *Arguments;

/// The number of template arguments in this template
/// argument list.
unsigned NumArguments;
Expand All @@ -258,30 +255,11 @@ class TemplateArgumentList final
TemplateArgumentList(const TemplateArgumentList &) = delete;
TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;

/// Type used to indicate that the template argument list itself is a
/// stack object. It does not own its template arguments.
enum OnStackType { OnStack };

/// Create a new template argument list that copies the given set of
/// template arguments.
static TemplateArgumentList *CreateCopy(ASTContext &Context,
ArrayRef<TemplateArgument> Args);

/// Construct a new, temporary template argument list on the stack.
///
/// The template argument list does not own the template arguments
/// provided.
explicit TemplateArgumentList(OnStackType, ArrayRef<TemplateArgument> Args)
: Arguments(Args.data()), NumArguments(Args.size()) {}

/// Produces a shallow copy of the given template argument list.
///
/// This operation assumes that the input argument list outlives it.
/// This takes the list as a pointer to avoid looking like a copy
/// constructor, since this really isn't safe to use that way.
explicit TemplateArgumentList(const TemplateArgumentList *Other)
: Arguments(Other->data()), NumArguments(Other->size()) {}

/// Retrieve the template argument at a given index.
const TemplateArgument &get(unsigned Idx) const {
assert(Idx < NumArguments && "Invalid template argument index");
Expand All @@ -301,7 +279,9 @@ class TemplateArgumentList final
unsigned size() const { return NumArguments; }

/// Retrieve a pointer to the template argument list.
const TemplateArgument *data() const { return Arguments; }
const TemplateArgument *data() const {
return getTrailingObjects<TemplateArgument>();
}
};

void *allocateDefaultArgStorageChain(const ASTContext &C);
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/JSONNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class JSONNodeDumper
void Visit(const Type *T);
void Visit(QualType T);
void Visit(const Decl *D);
void Visit(TypeLoc TL);

void Visit(const comments::Comment *C, const comments::FullComment *FC);
void Visit(const TemplateArgument &TA, SourceRange R = {},
Expand All @@ -207,6 +208,7 @@ class JSONNodeDumper
void Visit(const GenericSelectionExpr::ConstAssociation &A);
void Visit(const concepts::Requirement *R);
void Visit(const APValue &Value, QualType Ty);
void Visit(const ConceptReference *);

void VisitAliasAttr(const AliasAttr *AA);
void VisitCleanupAttr(const CleanupAttr *CA);
Expand Down
40 changes: 40 additions & 0 deletions clang/include/clang/AST/OpenMPClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -2513,6 +2513,46 @@ class OMPRelaxedClause final : public OMPClause {
}
};

/// This represents 'weak' clause in the '#pragma omp atomic'
/// directives.
///
/// \code
/// #pragma omp atomic compare weak
/// \endcode
/// In this example directive '#pragma omp atomic' has 'weak' clause.
class OMPWeakClause final : public OMPClause {
public:
/// Build 'weak' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPWeakClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPClause(llvm::omp::OMPC_weak, StartLoc, EndLoc) {}

/// Build an empty clause.
OMPWeakClause()
: OMPClause(llvm::omp::OMPC_weak, SourceLocation(), SourceLocation()) {}

child_range children() {
return child_range(child_iterator(), child_iterator());
}

const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}

child_range used_children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range used_children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}

static bool classof(const OMPClause *T) {
return T->getClauseKind() == llvm::omp::OMPC_weak;
}
};

/// This represents 'fail' clause in the '#pragma omp atomic'
/// directive.
///
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3436,6 +3436,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPRelaxedClause(OMPRelaxedClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPWeakClause(OMPWeakClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
return true;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateArgumentVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h"

namespace clang {
Expand Down Expand Up @@ -132,6 +133,7 @@ class TextNodeDumper
public ConstTemplateArgumentVisitor<TextNodeDumper>,
public ConstStmtVisitor<TextNodeDumper>,
public TypeVisitor<TextNodeDumper>,
public TypeLocVisitor<TextNodeDumper>,
public ConstDeclVisitor<TextNodeDumper> {
raw_ostream &OS;
const bool ShowColors;
Expand Down Expand Up @@ -179,6 +181,8 @@ class TextNodeDumper

void Visit(QualType T);

void Visit(TypeLoc);

void Visit(const Decl *D);

void Visit(const CXXCtorInitializer *Init);
Expand Down Expand Up @@ -339,6 +343,8 @@ class TextNodeDumper
void VisitObjCInterfaceType(const ObjCInterfaceType *T);
void VisitPackExpansionType(const PackExpansionType *T);

void VisitTypeLoc(TypeLoc TL);

void VisitLabelDecl(const LabelDecl *D);
void VisitTypedefDecl(const TypedefDecl *D);
void VisitEnumDecl(const EnumDecl *D);
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ class TypeLoc {
/// __nullable, or __null_unspecifier), if there is one.
SourceLocation findNullabilityLoc() const;

void dump() const;
void dump(llvm::raw_ostream &, const ASTContext &) const;

private:
static bool isKind(const TypeLoc&) {
return true;
Expand Down
34 changes: 17 additions & 17 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -292,23 +292,23 @@ TARGET_BUILTIN(__builtin_amdgcn_s_wait_event_export_ready, "v", "n", "gfx11-inst
// Postfix w32 indicates the builtin requires wavefront size of 32.
// Postfix w64 indicates the builtin requires wavefront size of 64.
//===----------------------------------------------------------------------===//
TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_f16_w32, "V8fV16hV16hV8f", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_bf16_w32, "V8fV16sV16sV8f", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_w32, "V16hV16hV16hV16hIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w32, "V16sV16sV16sV16sIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_tied_w32, "V16hV16hV16hV16hIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_tied_w32, "V16sV16sV16sV16sIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu8_w32, "V8iIbV4iIbV4iV8iIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu4_w32, "V8iIbV2iIbV2iV8iIb", "nc", "gfx11-insts")

TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_f16_w64, "V4fV16hV16hV4f", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_bf16_w64, "V4fV16sV16sV4f", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_w64, "V8hV16hV16hV8hIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w64, "V8sV16sV16sV8sIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_tied_w64, "V8hV16hV16hV8hIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_tied_w64, "V8sV16sV16sV8sIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu8_w64, "V4iIbV4iIbV4iV4iIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu4_w64, "V4iIbV2iIbV2iV4iIb", "nc", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_f16_w32, "V8fV16hV16hV8f", "nc", "gfx11-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_bf16_w32, "V8fV16sV16sV8f", "nc", "gfx11-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_w32, "V16hV16hV16hV16hIb", "nc", "gfx11-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w32, "V16sV16sV16sV16sIb", "nc", "gfx11-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_tied_w32, "V16hV16hV16hV16hIb", "nc", "gfx11-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_tied_w32, "V16sV16sV16sV16sIb", "nc", "gfx11-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu8_w32, "V8iIbV4iIbV4iV8iIb", "nc", "gfx11-insts,wavefrontsize32")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu4_w32, "V8iIbV2iIbV2iV8iIb", "nc", "gfx11-insts,wavefrontsize32")

TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_f16_w64, "V4fV16hV16hV4f", "nc", "gfx11-insts,wavefrontsize64")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f32_16x16x16_bf16_w64, "V4fV16sV16sV4f", "nc", "gfx11-insts,wavefrontsize64")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_w64, "V8hV16hV16hV8hIb", "nc", "gfx11-insts,wavefrontsize64")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w64, "V8sV16sV16sV8sIb", "nc", "gfx11-insts,wavefrontsize64")
TARGET_BUILTIN(__builtin_amdgcn_wmma_f16_16x16x16_f16_tied_w64, "V8hV16hV16hV8hIb", "nc", "gfx11-insts,wavefrontsize64")
TARGET_BUILTIN(__builtin_amdgcn_wmma_bf16_16x16x16_bf16_tied_w64, "V8sV16sV16sV8sIb", "nc", "gfx11-insts,wavefrontsize64")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu8_w64, "V4iIbV4iIbV4iV4iIb", "nc", "gfx11-insts,wavefrontsize64")
TARGET_BUILTIN(__builtin_amdgcn_wmma_i32_16x16x16_iu4_w64, "V4iIbV2iIbV2iV4iIb", "nc", "gfx11-insts,wavefrontsize64")

TARGET_BUILTIN(__builtin_amdgcn_s_sendmsg_rtn, "UiUIi", "n", "gfx11-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_sendmsg_rtnl, "UWiUIi", "n", "gfx11-insts")
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ ENUM_CODEGENOPT(InlineAsmDialect, InlineAsmDialectKind, 1, IAD_ATT)
CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
///< are required.
CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled.
CODEGENOPT(BBAddrMap , 1, 0) ///< Set when -fbasic-block-address-map is enabled.
CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is
///< enabled.
CODEGENOPT(InstrumentFunctionsAfterInlining , 1, 0) ///< Set when
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -11042,7 +11042,8 @@ def note_omp_atomic_compare: Note<
"expect lvalue for result value|expect scalar value|expect integer value|unexpected 'else' statement|expect '==' operator|expect an assignment statement 'v = x'|"
"expect a 'if' statement|expect no more than two statements|expect a compound statement|expect 'else' statement|expect a form 'r = x == e; if (r) ...'}0">;
def err_omp_atomic_fail_wrong_or_no_clauses : Error<"expected a memory order clause">;
def err_omp_atomic_fail_no_compare : Error<"expected 'compare' clause with the 'fail' modifier">;
def err_omp_atomic_no_compare : Error<"expected 'compare' clause with the '%0' modifier">;
def err_omp_atomic_weak_no_equality : Error<"expected '==' operator for 'weak' clause">;
def err_omp_atomic_several_clauses : Error<
"directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause">;
def err_omp_several_mem_order_clauses : Error<
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ LANGOPT(MathErrno , 1, 1, "errno in math functions")
BENIGN_LANGOPT(HeinousExtensions , 1, 0, "extensions that we really don't like and may be ripped out at any time")
LANGOPT(Modules , 1, 0, "modules semantics")
COMPATIBLE_LANGOPT(CPlusPlusModules, 1, 0, "C++ modules syntax")
LANGOPT(SkipODRCheckInGMF, 1, 0, "Skip ODR checks for decls in the global module fragment")
LANGOPT(BuiltinHeadersInSystemModules, 1, 0, "builtin headers belong to system modules, and _Builtin_ modules are ignored for cstdlib headers")
BENIGN_ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 3, CMK_None,
"compiling a module interface")
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2985,6 +2985,14 @@ def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">;

defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf",
LangOpts<"SkipODRCheckInGMF">, DefaultFalse,
PosFlag<SetTrue, [], [CC1Option],
"Skip ODR checks for decls in the global module fragment.">,
NegFlag<SetFalse, [], [CC1Option],
"Perform ODR checks for decls in the global module fragment.">>,
Group<f_Group>;

def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>,
Visibility<[ClangOption, CC1Option]>, MetaVarName<"<seconds>">,
HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">,
Expand Down Expand Up @@ -3980,6 +3988,10 @@ defm function_sections : BoolFOption<"function-sections",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Place each function in its own section">,
NegFlag<SetFalse>>;
defm basic_block_address_map : BoolFOption<"basic-block-address-map",
CodeGenOpts<"BBAddrMap">, DefaultFalse,
PosFlag<SetTrue, [], [CC1Option], "Emit the basic block address map section.">,
NegFlag<SetFalse>>;
def fbasic_block_sections_EQ : Joined<["-"], "fbasic-block-sections=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, CC1AsOption]>,
HelpText<"Place each function's basic blocks in unique sections (ELF Only)">,
Expand Down
43 changes: 12 additions & 31 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -4157,14 +4157,9 @@ struct FormatStyle {

/// Different ways to put a space before opening parentheses.
enum SpaceBeforeParensStyle : int8_t {
/// Never put a space before opening parentheses.
/// \code
/// void f() {
/// if(true) {
/// f();
/// }
/// }
/// \endcode
/// This is **deprecated** and replaced by ``Custom`` below, with all
/// ``SpaceBeforeParensOptions`` but ``AfterPlacementOperator`` set to
/// ``false``.
SBPO_Never,
/// Put a space before opening parentheses only after control statement
/// keywords (``for/if/while...``).
Expand Down Expand Up @@ -4273,28 +4268,14 @@ struct FormatStyle {
/// object.operator++ (10); object.operator++(10);
/// \endcode
bool AfterOverloadedOperator;
/// Styles for adding spacing between ``new/delete`` operators and opening
/// parentheses.
enum AfterPlacementOperatorStyle : int8_t {
/// Remove space after ``new/delete`` operators and before ``(``.
/// \code
/// new(buf) T;
/// delete(buf) T;
/// \endcode
APO_Never,
/// Always add space after ``new/delete`` operators and before ``(``.
/// \code
/// new (buf) T;
/// delete (buf) T;
/// \endcode
APO_Always,
/// Leave placement ``new/delete`` expressions as they are.
APO_Leave,
};
/// Defines in which cases to put a space between ``new/delete`` operators
/// and opening parentheses.
/// \version 18
AfterPlacementOperatorStyle AfterPlacementOperator;
/// If ``true``, put a space between operator ``new``/``delete`` and opening
/// parenthesis.
/// \code
/// true: false:
/// new (buf) T; vs. new(buf) T;
/// delete (buf) T; delete(buf) T;
/// \endcode
bool AfterPlacementOperator;
/// If ``true``, put space between requires keyword in a requires clause and
/// opening parentheses, if there is one.
/// \code
Expand Down Expand Up @@ -4327,7 +4308,7 @@ struct FormatStyle {
: AfterControlStatements(false), AfterForeachMacros(false),
AfterFunctionDeclarationName(false),
AfterFunctionDefinitionName(false), AfterIfMacros(false),
AfterOverloadedOperator(false), AfterPlacementOperator(APO_Leave),
AfterOverloadedOperator(false), AfterPlacementOperator(true),
AfterRequiresInClause(false), AfterRequiresInExpression(false),
BeforeNonEmptyParentheses(false) {}

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Lex/Token.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
namespace clang {

class IdentifierInfo;
class LangOptions;

/// Token - This structure provides full information about a lexed token.
/// It is not intended to be space efficient, it is intended to return as much
Expand Down Expand Up @@ -288,6 +289,8 @@ class Token {
/// Return the ObjC keyword kind.
tok::ObjCKeywordKind getObjCKeywordID() const;

bool isSimpleTypeSpecifier(const LangOptions &LangOpts) const;

/// Return true if this token has trigraphs or escaped newlines in it.
bool needsCleaning() const { return getFlag(NeedsCleaning); }

Expand Down
32 changes: 16 additions & 16 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2423,6 +2423,7 @@ class Parser : public CodeCompletionHandler {
bool MightBeDeclarator(DeclaratorContext Context);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
ParsedAttributes &Attrs,
ParsedTemplateInfo &TemplateInfo,
SourceLocation *DeclEnd = nullptr,
ForRangeInit *FRI = nullptr);
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
Expand Down Expand Up @@ -3615,16 +3616,15 @@ class Parser : public CodeCompletionHandler {
// C++ 14: Templates [temp]

// C++ 14.1: Template Parameters [temp.param]
Decl *ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs,
AccessSpecifier AS = AS_none);
Decl *ParseTemplateDeclarationOrSpecialization(DeclaratorContext Context,
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs,
AccessSpecifier AS);
Decl *ParseSingleDeclarationAfterTemplate(
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
DeclGroupPtrTy
ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs);
DeclGroupPtrTy ParseTemplateDeclarationOrSpecialization(
DeclaratorContext Context, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS);
DeclGroupPtrTy ParseDeclarationAfterTemplate(
DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none);
bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth,
Expand Down Expand Up @@ -3673,12 +3673,12 @@ class Parser : public CodeCompletionHandler {
TemplateTy Template, SourceLocation OpenLoc);
ParsedTemplateArgument ParseTemplateTemplateArgument();
ParsedTemplateArgument ParseTemplateArgument();
Decl *ParseExplicitInstantiation(DeclaratorContext Context,
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs,
AccessSpecifier AS = AS_none);
DeclGroupPtrTy ParseExplicitInstantiation(DeclaratorContext Context,
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs,
AccessSpecifier AS = AS_none);
// C++2a: Template, concept definition [temp]
Decl *
ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
Expand Down
15 changes: 13 additions & 2 deletions clang/include/clang/Rewrite/Core/HTMLRewrite.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ class RewriteBuffer;
class Preprocessor;

namespace html {
struct RelexRewriteCache;
using RelexRewriteCacheRef = std::shared_ptr<RelexRewriteCache>;

/// If you need to rewrite the same file multiple times, you can instantiate
/// a RelexRewriteCache and refer functions such as SyntaxHighlight()
/// and HighlightMacros() to it so that to avoid re-lexing the file each time.
/// The cache may outlive the rewriter as long as cached FileIDs and source
/// locations continue to make sense for the translation unit as a whole.
RelexRewriteCacheRef instantiateRelexRewriteCache();

/// HighlightRange - Highlight a range in the source code with the specified
/// start/end tags. B/E must be in the same file. This ensures that
Expand Down Expand Up @@ -67,13 +76,15 @@ namespace html {

/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
/// information about keywords, comments, etc.
void SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP);
void SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP,
RelexRewriteCacheRef Cache = nullptr);

/// HighlightMacros - This uses the macro table state from the end of the
/// file, to reexpand macros and insert (into the HTML) information about the
/// macro expansions. This won't be perfectly perfect, but it will be
/// reasonably close.
void HighlightMacros(Rewriter &R, FileID FID, const Preprocessor &PP);
void HighlightMacros(Rewriter &R, FileID FID, const Preprocessor &PP,
RelexRewriteCacheRef Cache = nullptr);

} // end html namespace
} // end clang namespace
Expand Down
13 changes: 7 additions & 6 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2683,8 +2683,6 @@ class Sema final {

void DiagnoseUseOfUnimplementedSelectors();

bool isSimpleTypeSpecifier(const Token &Tok) const;

ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec *SS = nullptr,
bool isClassName = false, bool HasTrailingDot = false,
Expand Down Expand Up @@ -9331,12 +9329,12 @@ class Sema final {

TemplateDeductionResult
DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &Info);

TemplateDeductionResult
DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &Info);

TemplateDeductionResult SubstituteExplicitTemplateArguments(
Expand Down Expand Up @@ -9509,7 +9507,7 @@ class Sema final {

MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
const TemplateArgumentList *Innermost = nullptr,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false,
bool SkipForSpecialization = false);
Expand Down Expand Up @@ -10539,7 +10537,7 @@ class Sema final {
bool AtEndOfTU = false);
VarTemplateSpecializationDecl *BuildVarTemplateInstantiation(
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
const TemplateArgumentList &TemplateArgList,
const TemplateArgumentList *PartialSpecArgs,
const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
SourceLocation PointOfInstantiation,
Expand Down Expand Up @@ -12377,6 +12375,9 @@ class Sema final {
/// Called on well-formed 'relaxed' clause.
OMPClause *ActOnOpenMPRelaxedClause(SourceLocation StartLoc,
SourceLocation EndLoc);
/// Called on well-formed 'weak' clause.
OMPClause *ActOnOpenMPWeakClause(SourceLocation StartLoc,
SourceLocation EndLoc);

/// Called on well-formed 'init' clause.
OMPClause *
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -2456,8 +2456,10 @@ class BitsUnpacker {
uint32_t CurrentBitsIndex = ~0;
};

inline bool isFromExplicitGMF(const Decl *D) {
return D->getOwningModule() && D->getOwningModule()->isExplicitGlobalModule();
inline bool shouldSkipCheckingODR(const Decl *D) {
return D->getOwningModule() &&
D->getASTContext().getLangOpts().SkipODRCheckInGMF &&
D->getOwningModule()->isExplicitGlobalModule();
}

} // namespace clang
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/ADT/SmallVector.h"

namespace clang {
class ASTContext;
class Decl;

namespace ento {
Expand All @@ -27,6 +28,8 @@ class PathDiagnosticLocation;

class BugSuppression {
public:
explicit BugSuppression(const ASTContext &ACtx) : ACtx(ACtx) {}

using DiagnosticIdentifierList = llvm::ArrayRef<llvm::StringRef>;

/// Return true if the given bug report was explicitly suppressed by the user.
Expand All @@ -45,6 +48,8 @@ class BugSuppression {
llvm::SmallVector<SourceRange, EXPECTED_NUMBER_OF_SUPPRESSIONS>;

llvm::DenseMap<const Decl *, CachedRanges> CachedSuppressionLocations;

const ASTContext &ACtx;
};

} // end namespace ento
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1749,7 +1749,8 @@ TypeInfoChars ASTContext::getTypeInfoDataSizeInChars(QualType T) const {
// of a base-class subobject. We decide whether that's possible
// during class layout, so here we can just trust the layout results.
if (getLangOpts().CPlusPlus) {
if (const auto *RT = T->getAs<RecordType>()) {
if (const auto *RT = T->getAs<RecordType>();
RT && !RT->getDecl()->isInvalidDecl()) {
const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl());
Info.Width = layout.getDataSize();
}
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,19 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS,
QualType(this, 0).dump(OS, Context);
}

//===----------------------------------------------------------------------===//
// TypeLoc method implementations
//===----------------------------------------------------------------------===//

LLVM_DUMP_METHOD void TypeLoc::dump() const {
ASTDumper(llvm::errs(), /*ShowColors=*/false).Visit(*this);
}

LLVM_DUMP_METHOD void TypeLoc::dump(llvm::raw_ostream &OS,
const ASTContext &Context) const {
ASTDumper(OS, Context, Context.getDiagnostics().getShowColors()).Visit(*this);
}

//===----------------------------------------------------------------------===//
// Decl method implementations
//===----------------------------------------------------------------------===//
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ASTTypeTraits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ void DynTypedNode::dump(llvm::raw_ostream &OS,
T->dump(OS, Context);
else if (const ConceptReference *C = get<ConceptReference>())
C->dump(OS);
else if (const TypeLoc *TL = get<TypeLoc>())
TL->dump(OS, Context);
else
OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
}
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -871,8 +871,7 @@ void TemplateTemplateParmDecl::setDefaultArgument(
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
TemplateArgumentList::TemplateArgumentList(ArrayRef<TemplateArgument> Args)
: Arguments(getTrailingObjects<TemplateArgument>()),
NumArguments(Args.size()) {
: NumArguments(Args.size()) {
std::uninitialized_copy(Args.begin(), Args.end(),
getTrailingObjects<TemplateArgument>());
}
Expand Down
114 changes: 109 additions & 5 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
switch (CE->getCastKind()) {

case CK_LValueToRValue: {
if (DiscardResult)
return this->discard(SubExpr);

return dereference(
SubExpr, DerefKind::Read,
[](PrimType) {
Expand All @@ -86,9 +89,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
},
[this, CE](PrimType T) {
// Pointer on stack - dereference it.
if (!this->emitLoadPop(T, CE))
return false;
return DiscardResult ? this->emitPop(T, CE) : true;
return this->emitLoadPop(T, CE);
});
}

Expand Down Expand Up @@ -311,6 +312,63 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitInitElem(T, 1, SubExpr);
}

case CK_IntegralComplexCast:
case CK_FloatingComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_FloatingComplexToIntegralComplex: {
assert(CE->getType()->isAnyComplexType());
assert(SubExpr->getType()->isAnyComplexType());
if (DiscardResult)
return this->discard(SubExpr);

if (!Initializing) {
std::optional<unsigned> LocalIndex =
allocateLocal(CE, /*IsExtended=*/true);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, CE))
return false;
}

// Location for the SubExpr.
// Since SubExpr is of complex type, visiting it results in a pointer
// anyway, so we just create a temporary pointer variable.
std::optional<unsigned> SubExprOffset = allocateLocalPrimitive(
SubExpr, PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false);
if (!SubExprOffset)
return false;

if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(PT_Ptr, *SubExprOffset, CE))
return false;

PrimType SourceElemT = classifyComplexElementType(SubExpr->getType());
QualType DestElemType =
CE->getType()->getAs<ComplexType>()->getElementType();
PrimType DestElemT = classifyPrim(DestElemType);
// Cast both elements individually.
for (unsigned I = 0; I != 2; ++I) {
if (!this->emitGetLocal(PT_Ptr, *SubExprOffset, CE))
return false;
if (!this->emitConstUint8(I, CE))
return false;
if (!this->emitArrayElemPtrPopUint8(CE))
return false;
if (!this->emitLoadPop(SourceElemT, CE))
return false;

// Do the cast.
if (!this->emitPrimCast(SourceElemT, DestElemT, DestElemType, CE))
return false;

// Save the value.
if (!this->emitInitElem(DestElemT, I, CE))
return false;
}
return true;
}

case CK_ToVoid:
return discard(SubExpr);

Expand All @@ -336,6 +394,31 @@ bool ByteCodeExprGen<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) {
return this->emitConstFloat(E->getValue(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitImaginaryLiteral(
const ImaginaryLiteral *E) {
assert(E->getType()->isAnyComplexType());
if (DiscardResult)
return true;

if (!Initializing) {
std::optional<unsigned> LocalIndex = allocateLocal(E, /*IsExtended=*/false);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}

const Expr *SubExpr = E->getSubExpr();
PrimType SubExprT = classifyPrim(SubExpr->getType());

if (!this->visitZeroInitializer(SubExprT, SubExpr->getType(), SubExpr))
return false;
if (!this->emitInitElem(SubExprT, 0, SubExpr))
return false;
return this->visitArrayElemInit(1, SubExpr);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *E) {
return this->delegate(E->getSubExpr());
Expand Down Expand Up @@ -594,7 +677,14 @@ bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
assert(Initializing);
// Prepare storage for result.
if (!Initializing) {
std::optional<unsigned> LocalIndex = allocateLocal(E, /*IsExtended=*/false);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}

const Expr *LHS = E->getLHS();
const Expr *RHS = E->getRHS();
Expand Down Expand Up @@ -1579,7 +1669,9 @@ template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) {
if (DiscardResult)
return true;
return this->emitConstBool(E->getValue(), E);
if (E->getType()->isBooleanType())
return this->emitConstBool(E->getValue(), E);
return this->emitConst(E->getValue(), E);
}

template <class Emitter>
Expand Down Expand Up @@ -1851,6 +1943,17 @@ bool ByteCodeExprGen<Emitter>::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {
return this->emitConst(E->getPackLength(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitGenericSelectionExpr(
const GenericSelectionExpr *E) {
return this->delegate(E->getResultExpr());
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitChooseExpr(const ChooseExpr *E) {
return this->delegate(E->getChosenSubExpr());
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
if (E->containsErrors())
return false;
Expand Down Expand Up @@ -2819,6 +2922,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return false;
return this->visitZeroInitializer(*T, SubExpr->getType(), SubExpr);
}

if (!this->visit(SubExpr))
return false;
if (!this->emitConstUint8(1, E))
Expand Down
14 changes: 4 additions & 10 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ namespace interp {

template <class Emitter> class LocalScope;
template <class Emitter> class DestructorScope;
template <class Emitter> class RecordScope;
template <class Emitter> class VariableScope;
template <class Emitter> class DeclScope;
template <class Emitter> class OptionScope;
Expand Down Expand Up @@ -61,6 +60,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitCastExpr(const CastExpr *E);
bool VisitIntegerLiteral(const IntegerLiteral *E);
bool VisitFloatingLiteral(const FloatingLiteral *E);
bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
bool VisitParenExpr(const ParenExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitLogicalBinOp(const BinaryOperator *E);
Expand Down Expand Up @@ -108,6 +108,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
bool VisitChooseExpr(const ChooseExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand All @@ -128,15 +130,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
// If the function does not exist yet, it is compiled.
const Function *getFunction(const FunctionDecl *FD);

/// Classifies a type.
std::optional<PrimType> classify(const Expr *E) const {
if (E->isGLValue()) {
if (E->getType()->isFunctionType())
return PT_FnPtr;
return PT_Ptr;
}

return classify(E->getType());
return Ctx.classify(E);
}
std::optional<PrimType> classify(QualType Ty) const {
return Ctx.classify(Ty);
Expand Down Expand Up @@ -225,7 +220,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
friend class VariableScope<Emitter>;
friend class LocalScope<Emitter>;
friend class DestructorScope<Emitter>;
friend class RecordScope<Emitter>;
friend class DeclScope<Emitter>;
friend class OptionScope<Emitter>;
friend class ArrayIndexScope<Emitter>;
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,13 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
#endif

// Ensure global variables are fully initialized.
if (shouldBeGloballyIndexed(VD) && !Res.isInvalid() &&
(VD->getType()->isRecordType() || VD->getType()->isArrayType())) {
if (shouldBeGloballyIndexed(VD) &&
(VD->getType()->isRecordType() || VD->getType()->isArrayType() ||
VD->getType()->isAnyComplexType())) {
assert(Res.isLValue());

if (!Res.checkFullyInitialized(C.getState()))
if (!VD->getType()->isAnyComplexType() &&
!Res.checkFullyInitialized(C.getState()))
return false;

// lvalue-to-rvalue conversion.
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/AST/Interp/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,20 @@ class Context final {
/// Return the size of T in bits.
uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); }

/// Classifies an expression.
/// Classifies a type.
std::optional<PrimType> classify(QualType T) const;

/// Classifies an expression.
std::optional<PrimType> classify(const Expr *E) const {
if (E->isGLValue()) {
if (E->getType()->isFunctionType())
return PT_FnPtr;
return PT_Ptr;
}

return classify(E->getType());
}

const CXXMethodDecl *
getOverridingFunction(const CXXRecordDecl *DynamicDecl,
const CXXRecordDecl *StaticDecl,
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,12 @@ void EvaluationResult::dump() const {
OS << "\n";
break;
}

default:
llvm_unreachable("Can't print that.");
case Invalid:
OS << "Invalid\n";
break;
case Valid:
OS << "Valid\n";
break;
}
}

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
namespace clang {
namespace interp {
static void popArg(InterpState &S, const Expr *Arg) {
PrimType Ty = S.getContext().classify(Arg->getType()).value_or(PT_Ptr);
PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);
TYPE_SWITCH(Ty, S.Stk.discard<T>());
}

Expand Down Expand Up @@ -399,6 +399,8 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckLive(S, OpPC, Ptr, AK_Assign))
return false;
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckExtern(S, OpPC, Ptr))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Assign))
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,9 @@ enum class IncDecOp {

template <typename T, IncDecOp Op, PushVal DoPush>
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (Ptr.isDummy())
return false;

const T &Value = Ptr.deref<T>();
T Result;

Expand Down Expand Up @@ -1521,6 +1524,9 @@ bool SubOffset(InterpState &S, CodePtr OpPC) {
template <ArithOp Op>
static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
const Pointer &Ptr) {
if (Ptr.isDummy())
return false;

using OneT = Integral<8, false>;

const Pointer &P = Ptr.deref<Pointer>();
Expand Down
Loading