227 changes: 178 additions & 49 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,7 @@ void RewriteInstance::discoverFileObjects() {
continue;

if (cantFail(Symbol.getType()) == SymbolRef::ST_File) {
FileSymbols.emplace_back(Symbol);
StringRef Name =
cantFail(std::move(NameOrError), "cannot get symbol name for file");
// Ignore Clang LTO artificial FILE symbol as it is not always generated,
Expand Down Expand Up @@ -1062,6 +1063,11 @@ void RewriteInstance::discoverFileObjects() {
continue;
}

if (SymName == getBOLTReservedStart() || SymName == getBOLTReservedEnd()) {
registerName(SymbolSize);
continue;
}

LLVM_DEBUG(dbgs() << "BOLT-DEBUG: considering symbol " << UniqueName
<< " for function\n");

Expand Down Expand Up @@ -1340,6 +1346,7 @@ void RewriteInstance::discoverFileObjects() {
}

registerFragments();
FileSymbols.clear();
}

Error RewriteInstance::discoverRtFiniAddress() {
Expand Down Expand Up @@ -1417,50 +1424,134 @@ void RewriteInstance::registerFragments() {
if (!BC->HasSplitFunctions)
return;

// Process fragments with ambiguous parents separately as they are typically a
// vanishing minority of cases and require expensive symbol table lookups.
std::vector<std::pair<StringRef, BinaryFunction *>> AmbiguousFragments;
for (auto &BFI : BC->getBinaryFunctions()) {
BinaryFunction &Function = BFI.second;
if (!Function.isFragment())
continue;
unsigned ParentsFound = 0;
for (StringRef Name : Function.getNames()) {
StringRef BaseName, Suffix;
std::tie(BaseName, Suffix) = Name.split('/');
StringRef BaseName = NR.restore(Name);
const bool IsGlobal = BaseName == Name;
const size_t ColdSuffixPos = BaseName.find(".cold");
if (ColdSuffixPos == StringRef::npos)
continue;
// For cold function with local (foo.cold/1) symbol, prefer a parent with
// local symbol as well (foo/1) over global symbol (foo).
std::string ParentName = BaseName.substr(0, ColdSuffixPos).str();
StringRef ParentName = BaseName.substr(0, ColdSuffixPos);
const BinaryData *BD = BC->getBinaryDataByName(ParentName);
if (Suffix != "") {
ParentName.append(Twine("/", Suffix).str());
const BinaryData *BDLocal = BC->getBinaryDataByName(ParentName);
if (BDLocal || !BD)
BD = BDLocal;
}
if (!BD) {
if (opts::Verbosity >= 1)
BC->outs() << "BOLT-INFO: parent function not found for " << Name
<< "\n";
const uint64_t NumPossibleLocalParents =
NR.getUniquifiedNameCount(ParentName);
// The most common case: single local parent fragment.
if (!BD && NumPossibleLocalParents == 1) {
BD = BC->getBinaryDataByName(NR.getUniqueName(ParentName, 1));
} else if (BD && (!NumPossibleLocalParents || IsGlobal)) {
// Global parent and either no local candidates (second most common), or
// the fragment is global as well (uncommon).
} else {
// Any other case: need to disambiguate using FILE symbols.
AmbiguousFragments.emplace_back(ParentName, &Function);
continue;
}
const uint64_t Address = BD->getAddress();
BinaryFunction *BF = BC->getBinaryFunctionAtAddress(Address);
if (!BF) {
if (opts::Verbosity >= 1)
BC->outs() << formatv(
"BOLT-INFO: parent function not found at {0:x}\n", Address);
continue;
if (BD) {
BinaryFunction *BF = BC->getFunctionForSymbol(BD->getSymbol());
if (BF) {
BC->registerFragment(Function, *BF);
continue;
}
}
BC->registerFragment(Function, *BF);
++ParentsFound;
}
if (!ParentsFound) {
BC->errs() << "BOLT-ERROR: parent function not found for " << Function
<< '\n';
exit(1);
}
}

if (AmbiguousFragments.empty())
return;

if (!BC->hasSymbolsWithFileName()) {
BC->errs() << "BOLT-ERROR: input file has split functions but does not "
"have FILE symbols. If the binary was stripped, preserve "
"FILE symbols with --keep-file-symbols strip option";
exit(1);
}

// The first global symbol is identified by the symbol table sh_info value.
// Used as local symbol search stopping point.
auto *ELF64LEFile = cast<ELF64LEObjectFile>(InputFile);
const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile();
auto *SymTab = llvm::find_if(cantFail(Obj.sections()), [](const auto &Sec) {
return Sec.sh_type == ELF::SHT_SYMTAB;
});
assert(SymTab);
// Symtab sh_info contains the value one greater than the symbol table index
// of the last local symbol.
ELFSymbolRef LocalSymEnd = ELF64LEFile->toSymbolRef(SymTab, SymTab->sh_info);

for (auto &[ParentName, BF] : AmbiguousFragments) {
const uint64_t Address = BF->getAddress();

// Get fragment's own symbol
const auto SymIt = FileSymRefs.find(Address);
if (SymIt == FileSymRefs.end()) {
BC->errs()
<< "BOLT-ERROR: symbol lookup failed for function at address 0x"
<< Twine::utohexstr(Address) << '\n';
exit(1);
}

// Find containing FILE symbol
ELFSymbolRef Symbol = SymIt->second;
auto FSI = llvm::upper_bound(FileSymbols, Symbol);
if (FSI == FileSymbols.begin()) {
BC->errs() << "BOLT-ERROR: owning FILE symbol not found for symbol "
<< cantFail(Symbol.getName()) << '\n';
exit(1);
}

ELFSymbolRef StopSymbol = LocalSymEnd;
if (FSI != FileSymbols.end())
StopSymbol = *FSI;

uint64_t ParentAddress{0};

// BOLT split fragment symbols are emitted just before the main function
// symbol.
for (ELFSymbolRef NextSymbol = Symbol; NextSymbol < StopSymbol;
NextSymbol.moveNext()) {
StringRef Name = cantFail(NextSymbol.getName());
if (Name == ParentName) {
ParentAddress = cantFail(NextSymbol.getValue());
goto registerParent;
}
if (Name.starts_with(ParentName))
// With multi-way splitting, there are multiple fragments with different
// suffixes. Parent follows the last fragment.
continue;
break;
}

// Iterate over local file symbols and check symbol names to match parent.
for (ELFSymbolRef Symbol(FSI[-1]); Symbol < StopSymbol; Symbol.moveNext()) {
if (cantFail(Symbol.getName()) == ParentName) {
ParentAddress = cantFail(Symbol.getAddress());
break;
}
}

registerParent:
// No local parent is found, use global parent function.
if (!ParentAddress)
if (BinaryData *ParentBD = BC->getBinaryDataByName(ParentName))
ParentAddress = ParentBD->getAddress();

if (BinaryFunction *ParentBF =
BC->getBinaryFunctionAtAddress(ParentAddress)) {
BC->registerFragment(*BF, *ParentBF);
continue;
}
BC->errs() << "BOLT-ERROR: parent function not found for " << *BF << '\n';
exit(1);
}
}

void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
Expand Down Expand Up @@ -3526,6 +3617,26 @@ void RewriteInstance::updateMetadata() {
void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) {
BC->deregisterUnusedSections();

// Check if the input has a space reserved for BOLT.
BinaryData *StartBD = BC->getBinaryDataByName(getBOLTReservedStart());
BinaryData *EndBD = BC->getBinaryDataByName(getBOLTReservedEnd());
if (!StartBD != !EndBD) {
BC->errs() << "BOLT-ERROR: one of the symbols is missing from the binary: "
<< getBOLTReservedStart() << ", " << getBOLTReservedEnd()
<< '\n';
exit(1);
}

if (StartBD) {
PHDRTableOffset = 0;
PHDRTableAddress = 0;
NewTextSegmentAddress = 0;
NewTextSegmentOffset = 0;
NextAvailableAddress = StartBD->getAddress();
BC->outs()
<< "BOLT-INFO: using reserved space for allocating new sections\n";
}

// If no new .eh_frame was written, remove relocated original .eh_frame.
BinarySection *RelocatedEHFrameSection =
getSection(".relocated" + getEHFrameSectionName());
Expand All @@ -3545,6 +3656,18 @@ void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) {

// Map the rest of the sections.
mapAllocatableSections(MapSection);

if (StartBD) {
const uint64_t ReservedSpace = EndBD->getAddress() - StartBD->getAddress();
const uint64_t AllocatedSize = NextAvailableAddress - StartBD->getAddress();
if (ReservedSpace < AllocatedSize) {
BC->errs() << "BOLT-ERROR: reserved space (" << ReservedSpace << " byte"
<< (ReservedSpace == 1 ? "" : "s")
<< ") is smaller than required for new allocations ("
<< AllocatedSize << " bytes)\n";
exit(1);
}
}
}

std::vector<BinarySection *> RewriteInstance::getCodeSections() {
Expand Down Expand Up @@ -3786,7 +3909,7 @@ void RewriteInstance::mapCodeSections(BOLTLinker::SectionMapper MapSection) {
// Add the new text section aggregating all existing code sections.
// This is pseudo-section that serves a purpose of creating a corresponding
// entry in section header table.
int64_t NewTextSectionSize =
const uint64_t NewTextSectionSize =
NextAvailableAddress - NewTextSectionStartAddress;
if (NewTextSectionSize) {
const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
Expand Down Expand Up @@ -3869,7 +3992,7 @@ void RewriteInstance::mapAllocatableSections(
if (PHDRTableAddress) {
// Segment size includes the size of the PHDR area.
NewTextSegmentSize = NextAvailableAddress - PHDRTableAddress;
} else {
} else if (NewTextSegmentAddress) {
// Existing PHDR table would be updated.
NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress;
}
Expand Down Expand Up @@ -3908,7 +4031,7 @@ void RewriteInstance::patchELFPHDRTable() {
assert(!PHDRTableAddress && "unexpected address for program header table");
PHDRTableOffset = Obj.getHeader().e_phoff;
if (NewWritableSegmentSize) {
BC->errs() << "Unable to add writable segment with UseGnuStack option\n";
BC->errs() << "BOLT-ERROR: unable to add writable segment\n";
exit(1);
}
}
Expand All @@ -3918,12 +4041,13 @@ void RewriteInstance::patchELFPHDRTable() {
if (!NewWritableSegmentSize) {
if (PHDRTableAddress)
NewTextSegmentSize = NextAvailableAddress - PHDRTableAddress;
else
else if (NewTextSegmentAddress)
NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress;
} else {
NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress;
}

const uint64_t SavedPos = OS.tell();
OS.seek(PHDRTableOffset);

auto createNewTextPhdr = [&]() {
Expand Down Expand Up @@ -3952,8 +4076,10 @@ void RewriteInstance::patchELFPHDRTable() {
};

auto writeNewSegmentPhdrs = [&]() {
ELF64LE::Phdr NewTextPhdr = createNewTextPhdr();
OS.write(reinterpret_cast<const char *>(&NewTextPhdr), sizeof(NewTextPhdr));
if (PHDRTableAddress || NewTextSegmentSize) {
ELF64LE::Phdr NewPhdr = createNewTextPhdr();
OS.write(reinterpret_cast<const char *>(&NewPhdr), sizeof(NewPhdr));
}

if (NewWritableSegmentSize) {
ELF64LEPhdrTy NewPhdr;
Expand Down Expand Up @@ -4026,6 +4152,8 @@ void RewriteInstance::patchELFPHDRTable() {
<< "BOLT-ERROR: could not find PT_GNU_STACK program header to modify\n";
exit(1);
}

OS.seek(SavedPos);
}

namespace {
Expand All @@ -4051,9 +4179,8 @@ void RewriteInstance::rewriteNoteSections() {
const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile();
raw_fd_ostream &OS = Out->os();

uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress);
assert(NextAvailableOffset >= FirstNonAllocatableOffset &&
"next available offset calculation failure");
uint64_t NextAvailableOffset = std::max(
getFileOffsetForAddress(NextAvailableAddress), FirstNonAllocatableOffset);
OS.seek(NextAvailableOffset);

// Copy over non-allocatable section contents and update file offsets.
Expand Down Expand Up @@ -4792,7 +4919,7 @@ void RewriteInstance::updateELFSymbolTable(
++NumHotDataSymsUpdated;
}

if (*SymbolName == "_end")
if (*SymbolName == "_end" && NextAvailableAddress > Symbol.st_value)
updateSymbolValue(*SymbolName, NextAvailableAddress);

if (IsDynSym)
Expand Down Expand Up @@ -4906,13 +5033,6 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
std::vector<uint32_t> NewSectionIndex;
getOutputSections(File, NewSectionIndex);

// Set pointer at the end of the output file, so we can pwrite old symbol
// tables if we need to.
uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress);
assert(NextAvailableOffset >= FirstNonAllocatableOffset &&
"next available offset calculation failure");
Out->os().seek(NextAvailableOffset);

// Update dynamic symbol table.
const ELFShdrTy *DynSymSection = nullptr;
for (const ELFShdrTy &Section : cantFail(Obj.sections())) {
Expand Down Expand Up @@ -5477,10 +5597,10 @@ void RewriteInstance::rewriteFile() {
auto Streamer = BC->createStreamer(OS);
// Make sure output stream has enough reserved space, otherwise
// pwrite() will fail.
uint64_t Offset = OS.seek(getFileOffsetForAddress(NextAvailableAddress));
(void)Offset;
assert(Offset == getFileOffsetForAddress(NextAvailableAddress) &&
"error resizing output file");
uint64_t Offset = std::max(getFileOffsetForAddress(NextAvailableAddress),
FirstNonAllocatableOffset);
Offset = OS.seek(Offset);
assert((Offset != (uint64_t)-1) && "Error resizing output file");

// Overwrite functions with fixed output address. This is mostly used by
// non-relocation mode, with one exception: injected functions are covered
Expand Down Expand Up @@ -5712,7 +5832,7 @@ void RewriteInstance::writeEHFrameHeader() {
std::vector<char> NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
RelocatedEHFrame, NewEHFrame, EHFrameHdrOutputAddress, FailedAddresses);

assert(Out->os().tell() == EHFrameHdrFileOffset && "offset mismatch");
Out->os().seek(EHFrameHdrFileOffset);
Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size());

const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
Expand All @@ -5732,6 +5852,15 @@ void RewriteInstance::writeEHFrameHeader() {

NextAvailableAddress += EHFrameHdrSec.getOutputSize();

if (const BinaryData *ReservedEnd =
BC->getBinaryDataByName(getBOLTReservedEnd())) {
if (NextAvailableAddress > ReservedEnd->getAddress()) {
BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName()
<< " into reserved space\n";
exit(1);
}
}

// Merge new .eh_frame with the relocated original so that gdb can locate all
// FDEs.
if (RelocatedEHFrameSection) {
Expand Down
54 changes: 44 additions & 10 deletions bolt/test/X86/fragment-lite.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,42 @@
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz.s -o %t.baz.o
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz2.s -o %t.baz2.o
# RUN: link_fdata %s %t.o %t.main.fdata
# RUN: link_fdata %s %t.baz.o %t.baz.fdata
# RUN: merge-fdata %t.main.fdata %t.baz.fdata > %t.fdata
# RUN: %clang %cflags %t.o %t.baz.o -o %t.exe -Wl,-q
# RUN: link_fdata %s %t.baz2.o %t.baz2.fdata
# RUN: merge-fdata %t.main.fdata %t.baz.fdata %t.baz2.fdata > %t.fdata
# RUN: %clang %cflags %t.o %t.baz.o %t.baz2.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.out --lite=1 --data %t.fdata -v=1 -print-cfg \
# RUN: 2>&1 | FileCheck %s

# CHECK: BOLT-INFO: processing main.cold.1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing foo.cold.1/1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing bar.cold.1/1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing foo.cold.1/1(*2) as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing bar.cold.1/1(*2) as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1/1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1/1(*2) as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1/2(*2) as a sibling of non-ignored function

# CHECK: Binary Function "main.cold.1" after building cfg
# CHECK: Parent : main

# CHECK: Binary Function "foo.cold.1/1" after building cfg
# CHECK: Binary Function "foo.cold.1/1(*2)" after building cfg
# CHECK: Parent : foo

# CHECK: Binary Function "bar.cold.1/1" after building cfg
# CHECK: Parent : bar/1
# CHECK: Binary Function "bar.cold.1/1(*2)" after building cfg
# CHECK: Parent : bar/1(*2)

# CHECK: Binary Function "baz.cold.1" after building cfg
# CHECK: Parent : baz{{$}}

# CHECK: Binary Function "baz.cold.1/1" after building cfg
# CHECK: Parent : baz/1
# CHECK: Binary Function "baz.cold.1/1(*2)" after building cfg
# CHECK: Parent : baz/1(*2)

# CHECK: Binary Function "baz.cold.1/2(*2)" after building cfg
# CHECK: Parent : baz/2(*2)

#--- main.s
.file "main.s"
.globl main
.type main, %function
main:
Expand Down Expand Up @@ -126,6 +133,7 @@ baz.cold.1:
.size baz.cold.1, .-baz.cold.1

#--- baz.s
.file "baz.s"
.local baz
.type baz, %function
baz:
Expand All @@ -149,3 +157,29 @@ baz.cold.1:
retq
.cfi_endproc
.size baz.cold.1, .-baz.cold.1

#--- baz2.s
.file "baz2.s"
.local baz
.type baz, %function
baz:
.cfi_startproc
# FDATA: 0 [unknown] 0 1 baz/2 0 1 0
cmpl $0x0, %eax
je baz.cold.1
retq
.cfi_endproc
.size baz, .-baz

.section .text.cold
.local baz.cold.1
.type baz.cold.1, %function
baz.cold.1:
.cfi_startproc
pushq %rbp
movq %rsp, %rbp
movl $0x0, %eax
popq %rbp
retq
.cfi_endproc
.size baz.cold.1, .-baz.cold.1
32 changes: 32 additions & 0 deletions bolt/test/X86/register-fragments-bolt-symbols.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Test the heuristics for matching BOLT-added split functions.

# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %S/cdsplit-symbol-names.s -o %t.main.o
# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.chain.o
# RUN: link_fdata %S/cdsplit-symbol-names.s %t.main.o %t.fdata
# RUN: sed -i 's|chain|chain/2|g' %t.fdata
# RUN: llvm-strip --strip-unneeded %t.main.o
# RUN: llvm-objcopy --localize-symbol=chain %t.main.o
# RUN: %clang %cflags %t.chain.o %t.main.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=randomN \
# RUN: --reorder-blocks=ext-tsp --enable-bat --bolt-seed=7 --data=%t.fdata
# RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS

# RUN: link_fdata %s %t.bolt %t.preagg PREAGG
# PREAGG: B X:0 #chain.cold.0# 1 0
# RUN: perf2bolt %t.bolt -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml -v=1 \
# RUN: | FileCheck %s --check-prefix=CHECK-REGISTER

# CHECK-SYMS: l df *ABS* [[#]] chain.s
# CHECK-SYMS: l F .bolt.org.text [[#]] chain
# CHECK-SYMS: l F .text.cold [[#]] chain.cold.0
# CHECK-SYMS: l F .text [[#]] chain
# CHECK-SYMS: l df *ABS* [[#]] bolt-pseudo.o

# CHECK-REGISTER: BOLT-INFO: marking chain.cold.0/1(*2) as a fragment of chain/2(*2)

.file "chain.s"
.text
.type chain, @function
chain:
ret
.size chain, .-chain
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,21 @@ static void addParantheses(const BinaryOperator *BinOp,
const clang::SourceLocation StartLoc = BinOp->getBeginLoc();
const clang::SourceLocation EndLoc =
clang::Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0, SM, LangOpts);
if (EndLoc.isInvalid())
return;

Check->diag(StartLoc,
"'%0' has higher precedence than '%1'; add parentheses to "
"explicitly specify the order of operations")
auto Diag =
Check->diag(StartLoc,
"'%0' has higher precedence than '%1'; add parentheses to "
"explicitly specify the order of operations")
<< (Precedence1 > Precedence2 ? BinOp->getOpcodeStr()
: ParentBinOp->getOpcodeStr())
<< (Precedence1 > Precedence2 ? ParentBinOp->getOpcodeStr()
: BinOp->getOpcodeStr())
<< FixItHint::CreateInsertion(StartLoc, "(")
<< FixItHint::CreateInsertion(EndLoc, ")")
<< SourceRange(StartLoc, EndLoc);

if (EndLoc.isValid()) {
Diag << FixItHint::CreateInsertion(StartLoc, "(")
<< FixItHint::CreateInsertion(EndLoc, ")");
}
}

addParantheses(dyn_cast<BinaryOperator>(BinOp->getLHS()->IgnoreImpCasts()),
Expand Down
8 changes: 4 additions & 4 deletions clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
EXPECT_DECLS("MemberExpr", "void foo()");

// Similar to above but base expression involves a function call.
Code = R"cpp(
Expand All @@ -872,7 +872,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
EXPECT_DECLS("MemberExpr", "void foo()");

// Similar to above but uses a function pointer.
Code = R"cpp(
Expand All @@ -891,7 +891,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
EXPECT_DECLS("MemberExpr", "void foo()");

// Base expression involves a member access into this.
Code = R"cpp(
Expand Down Expand Up @@ -962,7 +962,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
void Foo() { this->[[find]](); }
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
EXPECT_DECLS("MemberExpr", "void find()");
}

TEST_F(TargetDeclTest, DependentTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ sizeof...($TemplateParameter[[Elements]]);
struct $Class_def[[Foo]] {
int $Field_decl[[Waldo]];
void $Method_def[[bar]]() {
$Class[[Foo]]().$Field_dependentName[[Waldo]];
$Class[[Foo]]().$Field[[Waldo]];
}
template $Bracket[[<]]typename $TemplateParameter_def[[U]]$Bracket[[>]]
void $Method_def[[bar1]]() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ struct HeapArray { // Ok, since destruc

HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
other._data = nullptr; // Ok
// CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'
// FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types.
other.size = 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ template <class T>
struct Template {
Template() = default;
Template(const Template &Other) : Field(Other.Field) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
// CHECK-FIXES: Template(const Template &Other) = default;
Template &operator=(const Template &Other);
void foo(const T &t);
int Field;
Expand All @@ -269,8 +271,12 @@ Template<T> &Template<T>::operator=(const Template<T> &Other) {
Field = Other.Field;
return *this;
}
// CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default'
// CHECK-FIXES: Template<T> &Template<T>::operator=(const Template<T> &Other) = default;

Template<int> T1;


// Dependent types.
template <class T>
struct DT1 {
Expand All @@ -284,6 +290,9 @@ DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
Field = Other.Field;
return *this;
}
// CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default'
// CHECK-FIXES: DT1<T> &DT1<T>::operator=(const DT1<T> &Other) = default;

DT1<int> Dt1;

template <class T>
Expand All @@ -303,6 +312,9 @@ DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
struct T {
typedef int TT;
};
// CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default'
// CHECK-FIXES: DT2<T> &DT2<T>::operator=(const DT2<T> &Other) = default;

DT2<T> Dt2;

// Default arguments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ int bar(){
return 4;
}

int sink(int);
#define FUN(ARG) (sink(ARG))
#define FUN2(ARG) sink((ARG))
#define FUN3(ARG) sink(ARG)
#define FUN4(ARG) sink(1 + ARG)
#define FUN5(ARG) sink(4 * ARG)

class fun{
public:
int A;
Expand Down Expand Up @@ -117,4 +124,19 @@ void f(){
//CHECK-MESSAGES: :[[@LINE+2]]:94: warning: '/' has higher precedence than '-'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int q = (1 MACRO_ADD (2 MACRO_MULTIPLY 3)) MACRO_OR ((4 MACRO_AND 5) MACRO_XOR (6 MACRO_SUBTRACT (7 MACRO_DIVIDE 8)));
int q = 1 MACRO_ADD 2 MACRO_MULTIPLY 3 MACRO_OR 4 MACRO_AND 5 MACRO_XOR 6 MACRO_SUBTRACT 7 MACRO_DIVIDE 8; // No warning

//CHECK-MESSAGES: :[[@LINE+1]]:21: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int r = FUN(0 + 1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int s = FUN2(0 + 1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int t = FUN3(0 + 1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:18: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int u = FUN4(1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int v = FUN5(0 + 1);
}
10 changes: 7 additions & 3 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,8 @@ even-odd element pair with indices ``i * 2`` and ``i * 2 + 1`` with
power of 2, the vector is widened with neutral elements for the reduction
at the end to the next power of 2.

These reductions support both fixed-sized and scalable vector types.

Example:

.. code-block:: c++
Expand Down Expand Up @@ -2929,7 +2931,7 @@ Query for this feature with ``__has_builtin(__builtin_dump_struct)``
``__builtin_shufflevector`` is used to express generic vector
permutation/shuffle/swizzle operations. This builtin is also very important
for the implementation of various target-specific header files like
``<xmmintrin.h>``.
``<xmmintrin.h>``. This builtin can be used within constant expressions.
**Syntax**:
Expand All @@ -2956,7 +2958,7 @@ for the implementation of various target-specific header files like
// Concatenate every other element of 8-element vectors V1 and V2.
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
// Shuffle v1 with some elements being undefined
// Shuffle v1 with some elements being undefined. Not allowed in constexpr.
__builtin_shufflevector(v1, v1, 3, -1, 1, -1)
**Description**:
Expand All @@ -2969,6 +2971,7 @@ starting with the first vector, continuing into the second vector. Thus, if
``vec1`` is a 4-element vector, index 5 would refer to the second element of
``vec2``. An index of -1 can be used to indicate that the corresponding element
in the returned vector is a don't care and can be optimized by the backend.
Values of -1 are not supported in constant expressions.
The result of ``__builtin_shufflevector`` is a vector with the same element
type as ``vec1``/``vec2`` but that has an element count equal to the number of
Expand All @@ -2983,7 +2986,8 @@ Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
``__builtin_convertvector`` is used to express generic vector
type-conversion operations. The input vector and the output vector
type must have the same number of elements.
type must have the same number of elements. This builtin can be used within
constant expressions.
**Syntax**:
Expand Down
22 changes: 17 additions & 5 deletions clang/docs/LibTooling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,22 @@ and automatic location of the compilation database using source files paths.
#include "llvm/Support/CommandLine.h"

using namespace clang::tooling;
using namespace llvm;

// Apply a custom category to all command-line options so that they are the
// only ones displayed.
static llvm::cl::OptionCategory MyToolCategory("my-tool options");
static cl::OptionCategory MyToolCategory("my-tool options");

int main(int argc, const char **argv) {
// CommonOptionsParser constructor will parse arguments and create a
// CompilationDatabase. In case of error it will terminate the program.
CommonOptionsParser OptionsParser(argc, argv, MyToolCategory);
// CommonOptionsParser::create will parse arguments and create a
// CompilationDatabase.
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
if (!ExpectedParser) {
// Fail gracefully for unsupported options.
llvm::errs() << ExpectedParser.takeError();
return 1;
}
CommonOptionsParser& OptionsParser = ExpectedParser.get();
// Use OptionsParser.getCompilations() and OptionsParser.getSourcePathList()
// to retrieve CompilationDatabase and the list of input file paths.
Expand Down Expand Up @@ -133,7 +140,12 @@ version of this example tool is also checked into the clang tree at
static cl::extrahelp MoreHelp("\nMore help text...\n");

int main(int argc, const char **argv) {
CommonOptionsParser OptionsParser(argc, argv, MyToolCategory);
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
if (!ExpectedParser) {
llvm::errs() << ExpectedParser.takeError();
return 1;
}
CommonOptionsParser& OptionsParser = ExpectedParser.get();
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>().get());
Expand Down
40 changes: 40 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ ABI Changes in This Version
MSVC uses a different mangling for these objects, compatibility is not affected.
(#GH85423).

- Fixed Microsoft calling convention for returning certain classes with a
templated constructor. If a class has a templated constructor, it should
be returned indirectly even if it meets all the other requirements for
returning a class in a register. This affects some uses of std::pair.
(#GH86384).

AST Dumping Potentially Breaking Changes
----------------------------------------

Expand Down Expand Up @@ -145,6 +151,7 @@ C++2c Feature Support

- Implemented `P0609R3: Attributes for Structured Bindings <https://wg21.link/P0609R3>`_

- Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary <https://wg21.link/P2748R5>`_.

Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -221,6 +228,7 @@ Non-comprehensive list of changes in this release
- ``__typeof_unqual__`` is available in all C modes as an extension, which behaves
like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``.

- ``__builtin_reduce_{add|mul|xor|or|and|min|max}`` builtins now support scalable vectors.

* Shared libraries linked with either the ``-ffast-math``, ``-Ofast``, or
``-funsafe-math-optimizations`` flags will no longer enable flush-to-zero
Expand All @@ -231,6 +239,9 @@ Non-comprehensive list of changes in this release
* ``-fdenormal-fp-math=preserve-sign`` is no longer implied by ``-ffast-math``
on x86 systems.

- Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may
now be used within constant expressions.

New Compiler Flags
------------------
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
Expand All @@ -245,6 +256,10 @@ New Compiler Flags
- ``-fexperimental-modules-reduced-bmi`` enables the Reduced BMI for C++20 named modules.
See the document of standard C++ modules for details.

- ``-fexperimental-late-parse-attributes`` enables an experimental feature to
allow late parsing certain attributes in specific contexts where they would
not normally be late parsed.

Deprecated Compiler Flags
-------------------------

Expand Down Expand Up @@ -399,6 +414,18 @@ Improvements to Clang's diagnostics

- Clang now diagnoses requires expressions with explicit object parameters.

- Clang now looks up members of the current instantiation in the template definition context
if the current instantiation has no dependent base classes.

.. code-block:: c++

template<typename T>
struct A {
int f() {
return this->x; // error: no member named 'x' in 'A<T>'
}
};

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

Expand Down Expand Up @@ -445,6 +472,9 @@ Bug Fixes in This Version
- Clang now correctly generates overloads for bit-precise integer types for
builtin operators in C++. Fixes #GH82998.

- Fix crash when destructor definition is preceded with an equals sign.
Fixes (#GH89544).

- When performing mixed arithmetic between ``_Complex`` floating-point types and integers,
Clang now correctly promotes the integer to its corresponding real floating-point
type only rather than to the complex type (e.g. ``_Complex float / int`` is now evaluated
Expand Down Expand Up @@ -596,6 +626,10 @@ Bug Fixes to C++ Support
immediate function context.
- Fix CTAD for ``std::initializer_list``. This allows ``std::initializer_list{1, 2, 3}`` to be deduced as
``std::initializer_list<int>`` as intended.
- Fix a bug on template partial specialization whose template parameter is `decltype(auto)`.
- Fix a bug on template partial specialization with issue on deduction of nontype template parameter
whose type is `decltype(auto)`. Fixes (#GH68885).
- Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -648,6 +682,7 @@ Arm and AArch64 Support
* Arm Cortex-A78AE (cortex-a78ae).
* Arm Cortex-A520AE (cortex-a520ae).
* Arm Cortex-A720AE (cortex-a720ae).
* Arm Cortex-R82AE (cortex-r82ae).
* Arm Neoverse-N3 (neoverse-n3).
* Arm Neoverse-V3 (neoverse-v3).
* Arm Neoverse-V3AE (neoverse-v3ae).
Expand Down Expand Up @@ -707,6 +742,11 @@ AIX Support
WebAssembly Support
^^^^^^^^^^^^^^^^^^^

The -mcpu=generic configuration now enables multivalue and reference-types.These
proposals are standardized and available in all major engines. Enabling
multivalue here only enables the language feature but does not turn on the
multivalue ABI (this enables non-ABI uses of multivalue, like exnref).

AVR Support
^^^^^^^^^^^

Expand Down
16 changes: 9 additions & 7 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1452,8 +1452,6 @@ floating point semantic models: precise (the default), strict, and fast.
"fenv_access", "off", "on", "off"
"rounding_mode", "tonearest", "dynamic", "tonearest"
"contract", "on", "off", "fast"
"denormal_fp_math", "IEEE", "IEEE", "IEEE"
"denormal_fp32_math", "IEEE","IEEE", "IEEE"
"support_math_errno", "on", "on", "off"
"no_honor_nans", "off", "off", "on"
"no_honor_infinities", "off", "off", "on"
Expand All @@ -1462,6 +1460,14 @@ floating point semantic models: precise (the default), strict, and fast.
"allow_approximate_fns", "off", "off", "on"
"allow_reassociation", "off", "off", "on"

The ``-ffp-model`` option does not modify the ``fdenormal-fp-math``
setting, but it does have an impact on whether ``crtfastmath.o`` is
linked. Because linking ``crtfastmath.o`` has a global effect on the
program, and because the global denormal handling can be changed in
other ways, the state of ``fdenormal-fp-math`` handling cannot
be assumed in any function based on fp-model. See :ref:`crtfastmath.o`
for more details.

.. option:: -ffast-math

Enable fast-math mode. This option lets the
Expand Down Expand Up @@ -1537,7 +1543,6 @@ floating point semantic models: precise (the default), strict, and fast.
Also, this option resets following options to their target-dependent defaults.

* ``-f[no-]math-errno``
* ``-fdenormal-fp-math=<value>``

There is ambiguity about how ``-ffp-contract``, ``-ffast-math``,
and ``-fno-fast-math`` behave when combined. To keep the value of
Expand All @@ -1560,8 +1565,7 @@ floating point semantic models: precise (the default), strict, and fast.
``-ffp-contract`` setting is determined by the default value of
``-ffp-contract``.

Note: ``-fno-fast-math`` implies ``-fdenormal-fp-math=ieee``.
``-fno-fast-math`` causes ``crtfastmath.o`` to not be linked with code
Note: ``-fno-fast-math`` causes ``crtfastmath.o`` to not be linked with code
unless ``-mdaz-ftz`` is present.

.. option:: -fdenormal-fp-math=<value>
Expand Down Expand Up @@ -1692,9 +1696,7 @@ floating point semantic models: precise (the default), strict, and fast.
* ``-fno-associative-math``
* ``-fno-reciprocal-math``
* ``-fsigned-zeros``
* ``-ftrapping-math``
* ``-ffp-contract=on``
* ``-fdenormal-fp-math=ieee``

There is ambiguity about how ``-ffp-contract``,
``-funsafe-math-optimizations``, and ``-fno-unsafe-math-optimizations``
Expand Down
186 changes: 93 additions & 93 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,99 @@ checker).
Default value of the option is ``true``.
.. _unix-Stream:
unix.Stream (C)
"""""""""""""""
Check C stream handling functions:
``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``.
The checker maintains information about the C stream objects (``FILE *``) and
can detect error conditions related to use of streams. The following conditions
are detected:
* The ``FILE *`` pointer passed to the function is NULL (the single exception is
``fflush`` where NULL is allowed).
* Use of stream after close.
* Opened stream is not closed.
* Read from a stream after end-of-file. (This is not a fatal error but reported
by the checker. Stream remains in EOF state and the read operation fails.)
* Use of stream when the file position is indeterminate after a previous failed
operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are
allowed in this state.
* Invalid 3rd ("``whence``") argument to ``fseek``.
The stream operations are by this checker usually split into two cases, a success
and a failure case. However, in the case of write operations (like ``fwrite``,
``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of
unwanted reports on projects that don't have error checks around the write
operations, so by default the checker assumes that write operations always succeed.
This behavior can be controlled by the ``Pedantic`` flag: With
``-analyzer-config unix.Stream:Pedantic=true`` the checker will model the
cases where a write operation fails and report situations where this leads to
erroneous behavior. (The default is ``Pedantic=false``, where write operations
are assumed to succeed.)
.. code-block:: c
void test1() {
FILE *p = fopen("foo", "r");
} // warn: opened file is never closed
void test2() {
FILE *p = fopen("foo", "r");
fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL
fclose(p);
}
void test3() {
FILE *p = fopen("foo", "r");
if (p) {
fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR
fclose(p);
}
}
void test4() {
FILE *p = fopen("foo", "r");
if (!p)
return;
fclose(p);
fclose(p); // warn: stream already closed
}
void test5() {
FILE *p = fopen("foo", "r");
if (!p)
return;
fgetc(p);
if (!ferror(p))
fgetc(p); // warn: possible read after end-of-file
fclose(p);
}
void test6() {
FILE *p = fopen("foo", "r");
if (!p)
return;
fgetc(p);
if (!feof(p))
fgetc(p); // warn: file position may be indeterminate after I/O error
fclose(p);
}
**Limitations**
The checker does not track the correspondence between integer file descriptors
and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not
treated specially and are therefore often not recognized (because these streams
are usually not opened explicitly by the program, and are global variables).
.. _osx-checkers:
osx
Expand Down Expand Up @@ -3116,99 +3209,6 @@ Check for misuses of stream APIs. Check for misuses of stream APIs: ``fopen, fcl
fclose(F); // warn: closing a previously closed file stream
}
.. _alpha-unix-Stream:
alpha.unix.Stream (C)
"""""""""""""""""""""
Check C stream handling functions:
``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``.
The checker maintains information about the C stream objects (``FILE *``) and
can detect error conditions related to use of streams. The following conditions
are detected:
* The ``FILE *`` pointer passed to the function is NULL (the single exception is
``fflush`` where NULL is allowed).
* Use of stream after close.
* Opened stream is not closed.
* Read from a stream after end-of-file. (This is not a fatal error but reported
by the checker. Stream remains in EOF state and the read operation fails.)
* Use of stream when the file position is indeterminate after a previous failed
operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are
allowed in this state.
* Invalid 3rd ("``whence``") argument to ``fseek``.
The stream operations are by this checker usually split into two cases, a success
and a failure case. However, in the case of write operations (like ``fwrite``,
``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of
unwanted reports on projects that don't have error checks around the write
operations, so by default the checker assumes that write operations always succeed.
This behavior can be controlled by the ``Pedantic`` flag: With
``-analyzer-config alpha.unix.Stream:Pedantic=true`` the checker will model the
cases where a write operation fails and report situations where this leads to
erroneous behavior. (The default is ``Pedantic=false``, where write operations
are assumed to succeed.)
.. code-block:: c
void test1() {
FILE *p = fopen("foo", "r");
} // warn: opened file is never closed
void test2() {
FILE *p = fopen("foo", "r");
fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL
fclose(p);
}
void test3() {
FILE *p = fopen("foo", "r");
if (p) {
fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR
fclose(p);
}
}
void test4() {
FILE *p = fopen("foo", "r");
if (!p)
return;
fclose(p);
fclose(p); // warn: stream already closed
}
void test5() {
FILE *p = fopen("foo", "r");
if (!p)
return;
fgetc(p);
if (!ferror(p))
fgetc(p); // warn: possible read after end-of-file
fclose(p);
}
void test6() {
FILE *p = fopen("foo", "r");
if (!p)
return;
fgetc(p);
if (!feof(p))
fgetc(p); // warn: file position may be indeterminate after I/O error
fclose(p);
}
**Limitations**
The checker does not track the correspondence between integer file descriptors
and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not
treated specially and are therefore often not recognized (because these streams
are usually not opened explicitly by the program, and are global variables).
.. _alpha-unix-cstring-BufferOverlap:
alpha.unix.cstring.BufferOverlap (C)
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/AST/ASTNodeTraverser.h
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,12 @@ class ASTNodeTraverser
}
}

void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *E) {
if (E->hasExplicitTemplateArgs())
for (auto Arg : E->template_arguments())
Visit(Arg.getArgument());
}

void VisitRequiresExpr(const RequiresExpr *E) {
for (auto *D : E->getLocalParameters())
Visit(D);
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,8 @@ class CXXTemporary {
/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
/// }
/// \endcode
///
/// Destructor might be null if destructor declaration is not valid.
class CXXBindTemporaryExpr : public Expr {
CXXTemporary *Temp = nullptr;
Stmt *SubExpr = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/NestedNameSpecifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ class NestedNameSpecifierLoc {
explicit operator bool() const { return Qualifier; }

/// Evaluates true when this nested-name-specifier location is
/// empty.
/// non-empty.
bool hasQualifier() const { return Qualifier; }

/// Retrieve the nested-name-specifier to which this instance
Expand Down
91 changes: 64 additions & 27 deletions clang/include/clang/AST/OpenACCClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,51 +156,50 @@ class OpenACCSelfClause : public OpenACCClauseWithCondition {
Expr *ConditionExpr, SourceLocation EndLoc);
};

/// Represents a clause that has one or more IntExprs. It does not own the
/// IntExprs, but provides 'children' and other accessors.
class OpenACCClauseWithIntExprs : public OpenACCClauseWithParams {
MutableArrayRef<Expr *> IntExprs;
/// Represents a clause that has one or more expressions associated with it.
class OpenACCClauseWithExprs : public OpenACCClauseWithParams {
MutableArrayRef<Expr *> Exprs;

protected:
OpenACCClauseWithIntExprs(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
OpenACCClauseWithExprs(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc) {}

/// Used only for initialization, the leaf class can initialize this to
/// trailing storage.
void setIntExprs(MutableArrayRef<Expr *> NewIntExprs) {
assert(IntExprs.empty() && "Cannot change IntExprs list");
IntExprs = NewIntExprs;
void setExprs(MutableArrayRef<Expr *> NewExprs) {
assert(Exprs.empty() && "Cannot change Exprs list");
Exprs = NewExprs;
}

/// Gets the entire list of integer expressions, but leave it to the
/// Gets the entire list of expressions, but leave it to the
/// individual clauses to expose this how they'd like.
llvm::ArrayRef<Expr *> getIntExprs() const { return IntExprs; }
llvm::ArrayRef<Expr *> getExprs() const { return Exprs; }

public:
child_range children() {
return child_range(reinterpret_cast<Stmt **>(IntExprs.begin()),
reinterpret_cast<Stmt **>(IntExprs.end()));
return child_range(reinterpret_cast<Stmt **>(Exprs.begin()),
reinterpret_cast<Stmt **>(Exprs.end()));
}

const_child_range children() const {
child_range Children =
const_cast<OpenACCClauseWithIntExprs *>(this)->children();
const_cast<OpenACCClauseWithExprs *>(this)->children();
return const_child_range(Children.begin(), Children.end());
}
};

class OpenACCNumGangsClause final
: public OpenACCClauseWithIntExprs,
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCNumGangsClause, Expr *> {

OpenACCNumGangsClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc)
: OpenACCClauseWithIntExprs(OpenACCClauseKind::NumGangs, BeginLoc,
LParenLoc, EndLoc) {
: OpenACCClauseWithExprs(OpenACCClauseKind::NumGangs, BeginLoc, LParenLoc,
EndLoc) {
std::uninitialized_copy(IntExprs.begin(), IntExprs.end(),
getTrailingObjects<Expr *>());
setIntExprs(MutableArrayRef(getTrailingObjects<Expr *>(), IntExprs.size()));
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), IntExprs.size()));
}

public:
Expand All @@ -209,35 +208,35 @@ class OpenACCNumGangsClause final
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);

llvm::ArrayRef<Expr *> getIntExprs() {
return OpenACCClauseWithIntExprs::getIntExprs();
return OpenACCClauseWithExprs::getExprs();
}

llvm::ArrayRef<Expr *> getIntExprs() const {
return OpenACCClauseWithIntExprs::getIntExprs();
return OpenACCClauseWithExprs::getExprs();
}
};

/// Represents one of a handful of clauses that have a single integer
/// expression.
class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithIntExprs {
class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs {
Expr *IntExpr;

protected:
OpenACCClauseWithSingleIntExpr(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *IntExpr,
SourceLocation EndLoc)
: OpenACCClauseWithIntExprs(K, BeginLoc, LParenLoc, EndLoc),
: OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc),
IntExpr(IntExpr) {
setIntExprs(MutableArrayRef<Expr *>{&this->IntExpr, 1});
setExprs(MutableArrayRef<Expr *>{&this->IntExpr, 1});
}

public:
bool hasIntExpr() const { return !getIntExprs().empty(); }
bool hasIntExpr() const { return !getExprs().empty(); }
const Expr *getIntExpr() const {
return hasIntExpr() ? getIntExprs()[0] : nullptr;
return hasIntExpr() ? getExprs()[0] : nullptr;
}

Expr *getIntExpr() { return hasIntExpr() ? getIntExprs()[0] : nullptr; };
Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; };
};

class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr {
Expand All @@ -261,6 +260,40 @@ class OpenACCVectorLengthClause : public OpenACCClauseWithSingleIntExpr {
Expr *IntExpr, SourceLocation EndLoc);
};

/// Represents a clause with one or more 'var' objects, represented as an expr,
/// as its arguments. Var-list is expected to be stored in trailing storage.
/// For now, we're just storing the original expression in its entirety, unlike
/// OMP which has to do a bunch of work to create a private.
class OpenACCClauseWithVarList : public OpenACCClauseWithExprs {
protected:
OpenACCClauseWithVarList(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc) {}

public:
ArrayRef<Expr *> getVarList() { return getExprs(); }
ArrayRef<Expr *> getVarList() const { return getExprs(); }
};

class OpenACCPrivateClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCPrivateClause, Expr *> {

OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc,
LParenLoc, EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}

public:
static OpenACCPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};

template <class Impl> class OpenACCClauseVisitor {
Impl &getDerived() { return static_cast<Impl &>(*this); }

Expand Down Expand Up @@ -299,6 +332,9 @@ template <class Impl> class OpenACCClauseVisitor {
class OpenACCClausePrinter final
: public OpenACCClauseVisitor<OpenACCClausePrinter> {
raw_ostream &OS;
const PrintingPolicy &Policy;

void printExpr(const Expr *E);

public:
void VisitClauseList(ArrayRef<const OpenACCClause *> List) {
Expand All @@ -309,7 +345,8 @@ class OpenACCClausePrinter final
OS << ' ';
}
}
OpenACCClausePrinter(raw_ostream &OS) : OS(OS) {}
OpenACCClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy)
: OS(OS), Policy(Policy) {}

#define VISIT_CLAUSE(CLAUSE_NAME) \
void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause);
Expand Down
8 changes: 6 additions & 2 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ class Qualifiers {
}
void removeCVRQualifiers(unsigned mask) {
assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
Mask &= ~mask;
Mask &= ~static_cast<uint64_t>(mask);
}
void removeCVRQualifiers() {
removeCVRQualifiers(CVRMask);
Expand Down Expand Up @@ -609,7 +609,7 @@ class Qualifiers {
}
void removeFastQualifiers(unsigned mask) {
assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
Mask &= ~mask;
Mask &= ~static_cast<uint64_t>(mask);
}
void removeFastQualifiers() {
removeFastQualifiers(FastMask);
Expand Down Expand Up @@ -2378,6 +2378,10 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
/// 'riscv_rvv_vector_bits' type attribute as VectorType.
QualType getRVVEltType(const ASTContext &Ctx) const;

/// Returns the representative type for the element of a sizeless vector
/// builtin type.
QualType getSizelessVectorEltType(const ASTContext &Ctx) const;

/// Types are partitioned into 3 broad categories (C99 6.2.5p1):
/// object types, function types, and incomplete types.

Expand Down
79 changes: 61 additions & 18 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,49 @@ class AttrSubjectMatcherAggregateRule<AttrSubject subject> {

def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;

// Enumeration specifying what kind of behavior should be used for late
// parsing of attributes.
class LateAttrParseKind <int val> {
int Kind = val;
}

// Never late parsed
def LateAttrParseNever : LateAttrParseKind<0>;

// Standard late attribute parsing
//
// This is language dependent. For example:
//
// * For C++ enables late parsing of a declaration attributes
// * For C does not enable late parsing of attributes
//
def LateAttrParseStandard : LateAttrParseKind<1>;

// Experimental extension to standard late attribute parsing
//
// This extension behaves like `LateAttrParseStandard` but allows
// late parsing attributes in more contexts.
//
// In contexts where `LateAttrParseStandard` attributes are late
// parsed, `LateAttrParseExperimentalExt` attributes will also
// be late parsed.
//
// In contexts that only late parse `LateAttrParseExperimentalExt` attributes
// (see `LateParsedAttrList::lateAttrParseExperimentalExtOnly()`)
//
// * If `-fexperimental-late-parse-attributes`
// (`LangOpts.ExperimentalLateParseAttributes`) is enabled the attribute
// will be late parsed.
// * If `-fexperimental-late-parse-attributes`
// (`LangOpts.ExperimentalLateParseAttributes`) is disabled the attribute
// will **not** be late parsed (i.e parsed immediately).
//
// The following contexts are supported:
//
// * TODO: Add contexts here when they are implemented.
//
def LateAttrParseExperimentalExt : LateAttrParseKind<2>;

class Attr {
// The various ways in which an attribute can be spelled in source
list<Spelling> Spellings;
Expand All @@ -603,8 +646,8 @@ class Attr {
list<Accessor> Accessors = [];
// Specify targets for spellings.
list<TargetSpecificSpelling> TargetSpecificSpellings = [];
// Set to true for attributes with arguments which require delayed parsing.
bit LateParsed = 0;
// Specifies the late parsing kind.
LateAttrParseKind LateParsed = LateAttrParseNever;
// Set to false to prevent an attribute from being propagated from a template
// to the instantiation.
bit Clone = 1;
Expand Down Expand Up @@ -3173,7 +3216,7 @@ def DiagnoseIf : InheritableAttr {
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
DeclArgument<Named, "Parent", 0, /*fake*/ 1>];
let InheritEvenIfAlreadyPresent = 1;
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let AdditionalMembers = [{
bool isError() const { return diagnosticType == DT_Error; }
bool isWarning() const { return diagnosticType == DT_Warning; }
Expand Down Expand Up @@ -3472,7 +3515,7 @@ def AssertCapability : InheritableAttr {
let Spellings = [Clang<"assert_capability", 0>,
Clang<"assert_shared_capability", 0>];
let Subjects = SubjectList<[Function]>;
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3488,7 +3531,7 @@ def AcquireCapability : InheritableAttr {
GNU<"exclusive_lock_function">,
GNU<"shared_lock_function">];
let Subjects = SubjectList<[Function]>;
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3504,7 +3547,7 @@ def TryAcquireCapability : InheritableAttr {
Clang<"try_acquire_shared_capability", 0>];
let Subjects = SubjectList<[Function],
ErrorDiag>;
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3520,7 +3563,7 @@ def ReleaseCapability : InheritableAttr {
Clang<"release_generic_capability", 0>,
Clang<"unlock_function", 0>];
let Subjects = SubjectList<[Function]>;
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3539,7 +3582,7 @@ def RequiresCapability : InheritableAttr {
Clang<"requires_shared_capability", 0>,
Clang<"shared_locks_required", 0>];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3559,7 +3602,7 @@ def NoThreadSafetyAnalysis : InheritableAttr {
def GuardedBy : InheritableAttr {
let Spellings = [GNU<"guarded_by">];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3570,7 +3613,7 @@ def GuardedBy : InheritableAttr {
def PtGuardedBy : InheritableAttr {
let Spellings = [GNU<"pt_guarded_by">];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3581,7 +3624,7 @@ def PtGuardedBy : InheritableAttr {
def AcquiredAfter : InheritableAttr {
let Spellings = [GNU<"acquired_after">];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3592,7 +3635,7 @@ def AcquiredAfter : InheritableAttr {
def AcquiredBefore : InheritableAttr {
let Spellings = [GNU<"acquired_before">];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3603,7 +3646,7 @@ def AcquiredBefore : InheritableAttr {
def AssertExclusiveLock : InheritableAttr {
let Spellings = [GNU<"assert_exclusive_lock">];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3614,7 +3657,7 @@ def AssertExclusiveLock : InheritableAttr {
def AssertSharedLock : InheritableAttr {
let Spellings = [GNU<"assert_shared_lock">];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3627,7 +3670,7 @@ def AssertSharedLock : InheritableAttr {
def ExclusiveTrylockFunction : InheritableAttr {
let Spellings = [GNU<"exclusive_trylock_function">];
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3640,7 +3683,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
def SharedTrylockFunction : InheritableAttr {
let Spellings = [GNU<"shared_trylock_function">];
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand All @@ -3651,7 +3694,7 @@ def SharedTrylockFunction : InheritableAttr {
def LockReturned : InheritableAttr {
let Spellings = [GNU<"lock_returned">];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function]>;
Expand All @@ -3661,7 +3704,7 @@ def LockReturned : InheritableAttr {
def LocksExcluded : InheritableAttr {
let Spellings = [GNU<"locks_excluded">];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def err_no_matching_target : Error<"no matching target found for target variant
def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">;
def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">;
def err_unsupported_os : Error<"os '%0' is not supported: '%1'">;
def err_cannot_read_alias_list : Error<"could not read alias list '%0': %1">;
def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">;
} // end of command line category.

let CategoryName = "Verification" in {
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ def err_invalid_vector_long_long_decl_spec : Error <
"POWER7 or later) to be enabled">;
def err_invalid_vector_long_double_decl_spec : Error<
"cannot use 'long double' with '__vector'">;
def err_invalid_vector_complex_decl_spec : Error<
"cannot use '_Complex' with '__vector'">;
def warn_vector_long_decl_spec_combination : Warning<
"Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>;

Expand Down Expand Up @@ -9901,6 +9903,9 @@ def warn_format_invalid_annotation : Warning<
def warn_format_P_no_precision : Warning<
"using '%%P' format specifier without precision">,
InGroup<Format>;
def warn_format_P_with_objc_pointer : Warning<
"using '%%P' format specifier with an Objective-C pointer results in dumping runtime object structure, not object value">,
InGroup<Format>;
def warn_printf_ignored_flag: Warning<
"flag '%0' is ignored when flag '%1' is present">,
InGroup<Format>;
Expand Down Expand Up @@ -9950,6 +9955,8 @@ def warn_ret_stack_addr_ref : Warning<
def warn_ret_local_temp_addr_ref : Warning<
"returning %select{address of|reference to}0 local temporary object">,
InGroup<ReturnStackAddress>;
def err_ret_local_temp_ref : Error<
"returning reference to local temporary object">;
def warn_ret_addr_label : Warning<
"returning address of label, which is local">,
InGroup<ReturnStackAddress>;
Expand Down Expand Up @@ -10328,9 +10335,13 @@ def err_shufflevector_nonconstant_argument : Error<
def err_shufflevector_argument_too_large : Error<
"index for __builtin_shufflevector must be less than the total number "
"of vector elements">;
def err_shufflevector_minus_one_is_undefined_behavior_constexpr : Error<
"index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position %0 not permitted in a constexpr context.">;

def err_convertvector_non_vector : Error<
"first argument to __builtin_convertvector must be a vector">;
def err_convertvector_constexpr_unsupported_vector_cast : Error<
"unsupported vector cast from %0 to %1 in a constant expression.">;
def err_builtin_non_vector_type : Error<
"%0 argument to %1 must be of vector type">;
def err_convertvector_incompatible_vector : Error<
Expand Down Expand Up @@ -12296,4 +12307,7 @@ def err_acc_num_gangs_num_args
"OpenACC 'num_gangs' "
"%select{|clause: '%1' directive expects maximum of %2, %3 were "
"provided}0">;
def err_acc_not_a_var_ref
: Error<"OpenACC variable is not a valid variable name, sub-array, array "
"element, or composite variable member">;
} // end of sema component.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library fea
LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")

LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")

COMPATIBLE_LANGOPT(RecoveryAST, 1, 1, "Preserve expressions in AST when encountering errors")
COMPATIBLE_LANGOPT(RecoveryASTType, 1, 1, "Preserve the type in recovery expressions")
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/OpenACCClauses.def
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ VISIT_CLAUSE(If)
VISIT_CLAUSE(Self)
VISIT_CLAUSE(NumGangs)
VISIT_CLAUSE(NumWorkers)
VISIT_CLAUSE(Private)
VISIT_CLAUSE(VectorLength)

#undef VISIT_CLAUSE
24 changes: 18 additions & 6 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,13 @@ defm double_square_bracket_attributes : BoolFOption<"double-square-bracket-attri
LangOpts<"DoubleSquareBracketAttributes">, DefaultTrue, PosFlag<SetTrue>,
NegFlag<SetFalse>>;

defm experimental_late_parse_attributes : BoolFOption<"experimental-late-parse-attributes",
LangOpts<"ExperimentalLateParseAttributes">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Enable">,
NegFlag<SetFalse, [], [ClangOption], "Disable">,
BothFlags<[], [ClangOption, CC1Option],
" experimental late parsing of attributes">>;

defm autolink : BoolFOption<"autolink",
CodeGenOpts<"Autolink">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option],
Expand Down Expand Up @@ -2886,6 +2893,17 @@ def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Gr
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
def fapple_link_rtlib : Flag<["-"], "fapple-link-rtlib">, Group<f_Group>,
HelpText<"Force linking the clang builtins runtime library">;

/// ClangIR-specific options - BEGIN
defm clangir : BoolFOption<"clangir",
FrontendOpts<"UseClangIRPipeline">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Use the ClangIR pipeline to compile">,
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Use the AST -> LLVM pipeline to compile">,
BothFlags<[], [ClangOption, CC1Option], "">>;
def emit_cir : Flag<["-"], "emit-cir">, Visibility<[CC1Option]>,
Group<Action_Group>, HelpText<"Build ASTs and then lower to ClangIR">;
/// ClangIR-specific options - END

def flto_EQ : Joined<["-"], "flto=">,
Visibility<[ClangOption, CLOption, CC1Option, FC1Option, FlangOption]>,
Group<f_Group>,
Expand Down Expand Up @@ -6589,12 +6607,6 @@ def J : JoinedOrSeparate<["-"], "J">,
Group<gfortran_Group>,
Alias<module_dir>;

let Visibility = [FlangOption] in {
def no_fortran_main : Flag<["-"], "fno-fortran-main">,
Visibility<[FlangOption]>, Group<f_Group>,
HelpText<"Do not include Fortran_main.a (provided by Flang) when linking">;
} // let Visibility = [ FlangOption ]

//===----------------------------------------------------------------------===//
// FC1 Options
//===----------------------------------------------------------------------===//
Expand Down
9 changes: 8 additions & 1 deletion clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ enum ActionKind {
/// Translate input source into HTML.
EmitHTML,

/// Emit a .cir file
EmitCIR,

/// Emit a .ll file.
EmitLLVM,

Expand Down Expand Up @@ -408,6 +411,10 @@ class FrontendOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned GenReducedBMI : 1;

/// Use Clang IR pipeline to emit code
LLVM_PREFERRED_TYPE(bool)
unsigned UseClangIRPipeline : 1;

CodeCompleteOptions CodeCompleteOpts;

/// Specifies the output format of the AST.
Expand Down Expand Up @@ -590,7 +597,7 @@ class FrontendOptions {
EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false),
EmitSymbolGraphSymbolLabelsForTesting(false),
EmitPrettySymbolGraphs(false), GenReducedBMI(false),
TimeTraceGranularity(500) {}
UseClangIRPipeline(false), TimeTraceGranularity(500) {}

/// getInputKindForExtension - Return the appropriate input kind for a file
/// extension. For example, "c" would return Language::C.
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/InstallAPI/FileList.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ class FileListReader {
///
/// \param InputBuffer JSON input data.
/// \param Destination Container to load headers into.
/// \param FM Optional File Manager to validate input files exist.
static llvm::Error
loadHeaders(std::unique_ptr<llvm::MemoryBuffer> InputBuffer,
HeaderSeq &Destination);
HeaderSeq &Destination, clang::FileManager *FM = nullptr);

FileListReader() = delete;
};
Expand Down
22 changes: 16 additions & 6 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1398,12 +1398,21 @@ class Parser : public CodeCompletionHandler {
// A list of late-parsed attributes. Used by ParseGNUAttributes.
class LateParsedAttrList: public SmallVector<LateParsedAttribute *, 2> {
public:
LateParsedAttrList(bool PSoon = false) : ParseSoon(PSoon) { }
LateParsedAttrList(bool PSoon = false,
bool LateAttrParseExperimentalExtOnly = false)
: ParseSoon(PSoon),
LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly) {}

bool parseSoon() { return ParseSoon; }
/// returns true iff the attribute to be parsed should only be late parsed
/// if it is annotated with `LateAttrParseExperimentalExt`
bool lateAttrParseExperimentalExtOnly() {
return LateAttrParseExperimentalExtOnly;
}

private:
bool ParseSoon; // Are we planning to parse these shortly after creation?
bool ParseSoon; // Are we planning to parse these shortly after creation?
bool LateAttrParseExperimentalExtOnly;
};

/// Contains the lexed tokens of a member function definition
Expand Down Expand Up @@ -3645,11 +3654,12 @@ class Parser : public CodeCompletionHandler {
ExprResult ParseOpenACCIDExpression();
/// Parses the variable list for the `cache` construct.
void ParseOpenACCCacheVarList();

using OpenACCVarParseResult = std::pair<ExprResult, OpenACCParseCanContinue>;
/// Parses a single variable in a variable list for OpenACC.
bool ParseOpenACCVar();
/// Parses the variable list for the variety of clauses that take a var-list,
/// including the optional Special Token listed for some,based on clause type.
bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind);
OpenACCVarParseResult ParseOpenACCVar();
/// Parses the variable list for the variety of places that take a var-list.
llvm::SmallVector<Expr *> ParseOpenACCVarList();
/// Parses any parameters for an OpenACC Clause, including required/optional
/// parens.
OpenACCClauseParseResult
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -1811,15 +1811,15 @@ class DecompositionDeclarator {
: Bindings(nullptr), NumBindings(0), DeleteBindings(false) {}
DecompositionDeclarator(const DecompositionDeclarator &G) = delete;
DecompositionDeclarator &operator=(const DecompositionDeclarator &G) = delete;
~DecompositionDeclarator() {
if (DeleteBindings)
delete[] Bindings;
}
~DecompositionDeclarator() { clear(); }

void clear() {
LSquareLoc = RSquareLoc = SourceLocation();
if (DeleteBindings)
delete[] Bindings;
else
llvm::for_each(llvm::MutableArrayRef(Bindings, NumBindings),
[](Binding &B) { B.Attrs.reset(); });
Bindings = nullptr;
NumBindings = 0;
DeleteBindings = false;
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Sema/Lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,9 @@ class LookupResult {
/// Note that while no result was found in the current instantiation,
/// there were dependent base classes that could not be searched.
void setNotFoundInCurrentInstantiation() {
assert(ResultKind == NotFound && Decls.empty());
assert((ResultKind == NotFound ||
ResultKind == NotFoundInCurrentInstantiation) &&
Decls.empty());
ResultKind = NotFoundInCurrentInstantiation;
}

Expand Down
40 changes: 19 additions & 21 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4097,12 +4097,12 @@ class Sema final : public SemaBase {
SmallVectorImpl<QualType> &Exceptions,
FunctionProtoType::ExceptionSpecInfo &ESI);

/// Add an exception-specification to the given member function
/// (or member function template). The exception-specification was parsed
/// after the method itself was declared.
/// Add an exception-specification to the given member or friend function
/// (or function template). The exception-specification was parsed
/// after the function itself was declared.
void actOnDelayedExceptionSpecification(
Decl *Method, ExceptionSpecificationType EST,
SourceRange SpecificationRange, ArrayRef<ParsedType> DynamicExceptions,
Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange,
ArrayRef<ParsedType> DynamicExceptions,
ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr);

class InheritedConstructorInfo;
Expand Down Expand Up @@ -6978,12 +6978,6 @@ class Sema final : public SemaBase {
SourceLocation TemplateKWLoc,
UnqualifiedId &Member, Decl *ObjCImpDecl);

MemberExpr *BuildMemberExpr(
Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS,
SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
QualType Ty, ExprValueKind VK, ExprObjectKind OK,
const TemplateArgumentListInfo *TemplateArgs = nullptr);
MemberExpr *
BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc,
NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
Expand Down Expand Up @@ -7472,7 +7466,7 @@ class Sema final : public SemaBase {
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
CXXScopeSpec &SS);
bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
QualType ObjectType, bool AllowBuiltinCreation = false,
bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(
IdentifierInfo *II, SourceLocation IdLoc,
Expand Down Expand Up @@ -8881,11 +8875,13 @@ class Sema final : public SemaBase {
/// functions (but no function templates).
FoundFunctions,
};
bool LookupTemplateName(
LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
bool EnteringContext, bool &MemberOfUnknownSpecialization,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);

bool
LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr,
bool AllowTypoCorrection = true);

TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
bool hasTemplateKeyword,
Expand Down Expand Up @@ -9249,7 +9245,8 @@ class Sema final : public SemaBase {
void NoteTemplateParameterLocation(const NamedDecl &Decl);

ExprResult BuildExpressionFromDeclTemplateArgument(
const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc);
const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc,
NamedDecl *TemplateParam = nullptr);
ExprResult
BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc);
Expand Down Expand Up @@ -9572,9 +9569,10 @@ class Sema final : public SemaBase {

bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg);

TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
QualType NTTPType,
SourceLocation Loc);
TemplateArgumentLoc
getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType,
SourceLocation Loc,
NamedDecl *TemplateParam = nullptr);

/// Get a template argument mapping the given template parameter to itself,
/// e.g. for X in \c template<int X>, this would return an expression template
Expand Down
34 changes: 32 additions & 2 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ class SemaOpenACC : public SemaBase {
SmallVector<Expr *> IntExprs;
};

struct VarListDetails {
SmallVector<Expr *> VarList;
};

std::variant<std::monostate, DefaultDetails, ConditionDetails,
IntExprDetails>
IntExprDetails, VarListDetails>
Details = std::monostate{};

public:
Expand Down Expand Up @@ -112,6 +116,16 @@ class SemaOpenACC : public SemaBase {
return const_cast<OpenACCParsedClause *>(this)->getIntExprs();
}

ArrayRef<Expr *> getVarList() {
assert(ClauseKind == OpenACCClauseKind::Private &&
"Parsed clause kind does not have a var-list");
return std::get<VarListDetails>(Details).VarList;
}

ArrayRef<Expr *> getVarList() const {
return const_cast<OpenACCParsedClause *>(this)->getVarList();
}

void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }

Expand Down Expand Up @@ -147,7 +161,19 @@ class SemaOpenACC : public SemaBase {
ClauseKind == OpenACCClauseKind::NumWorkers ||
ClauseKind == OpenACCClauseKind::VectorLength) &&
"Parsed clause kind does not have a int exprs");
Details = IntExprDetails{IntExprs};
Details = IntExprDetails{std::move(IntExprs)};
}

void setVarListDetails(ArrayRef<Expr *> VarList) {
assert(ClauseKind == OpenACCClauseKind::Private &&
"Parsed clause kind does not have a var-list");
Details = VarListDetails{{VarList.begin(), VarList.end()}};
}

void setVarListDetails(llvm::SmallVector<Expr *> &&VarList) {
assert(ClauseKind == OpenACCClauseKind::Private &&
"Parsed clause kind does not have a var-list");
Details = VarListDetails{std::move(VarList)};
}
};

Expand Down Expand Up @@ -194,6 +220,10 @@ class SemaOpenACC : public SemaBase {
ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
SourceLocation Loc, Expr *IntExpr);

/// Called when encountering a 'var' for OpenACC, ensures it is actually a
/// declaration reference to a variable of the correct type.
ExprResult ActOnVar(Expr *VarExpr);

/// Checks and creates an Array Section used in an OpenACC construct/clause.
ExprResult ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc,
Expr *LowerBound,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTRecordReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ class ASTRecordReader
/// Read an OpenMP children, advancing Idx.
void readOMPChildren(OMPChildren *Data);

/// Read a list of Exprs used for a var-list.
llvm::SmallVector<Expr *> readOpenACCVarList();

/// Read an OpenACC clause, advancing Idx.
OpenACCClause *readOpenACCClause();

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTRecordWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define LLVM_CLANG_SERIALIZATION_ASTRECORDWRITER_H

#include "clang/AST/AbstractBasicWriter.h"
#include "clang/AST/OpenACCClause.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Serialization/SourceLocationEncoding.h"
Expand Down Expand Up @@ -293,6 +294,8 @@ class ASTRecordWriter
/// Writes data related to the OpenMP directives.
void writeOMPChildren(OMPChildren *Data);

void writeOpenACCVarList(const OpenACCClauseWithVarList *C);

/// Writes out a single OpenACC Clause.
void writeOpenACCClause(const OpenACCClause *C);

Expand Down
26 changes: 23 additions & 3 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ class ASTWriter : public ASTDeserializationListener,

/// Calculate hash of the pcm content.
std::pair<ASTFileSignature, ASTFileSignature> createSignature() const;
ASTFileSignature createSignatureForNamedModule() const;

void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
Expand Down Expand Up @@ -885,6 +886,8 @@ class ASTWriter : public ASTDeserializationListener,
/// AST and semantic-analysis consumer that generates a
/// precompiled header from the parsed source code.
class PCHGenerator : public SemaConsumer {
void anchor() override;

Preprocessor &PP;
std::string OutputFile;
std::string isysroot;
Expand Down Expand Up @@ -928,17 +931,34 @@ class PCHGenerator : public SemaConsumer {
bool hasEmittedPCH() const { return Buffer->IsComplete; }
};

class ReducedBMIGenerator : public PCHGenerator {
class CXX20ModulesGenerator : public PCHGenerator {
void anchor() override;

protected:
virtual Module *getEmittingModule(ASTContext &Ctx) override;

CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef OutputFile, bool GeneratingReducedBMI);

public:
ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef OutputFile);
CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef OutputFile)
: CXX20ModulesGenerator(PP, ModuleCache, OutputFile,
/*GeneratingReducedBMI=*/false) {}

void HandleTranslationUnit(ASTContext &Ctx) override;
};

class ReducedBMIGenerator : public CXX20ModulesGenerator {
void anchor() override;

public:
ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef OutputFile)
: CXX20ModulesGenerator(PP, ModuleCache, OutputFile,
/*GeneratingReducedBMI=*/true) {}
};

/// If we can elide the definition of \param D in reduced BMI.
///
/// Generally, we can elide the definition of a declaration if it won't affect
Expand Down
31 changes: 16 additions & 15 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,20 @@ def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
Dependencies<[DynamicMemoryModeling]>,
Documentation<HasDocumentation>;

// This must appear before StdCLibraryFunctionsChecker because a dependency.
def StreamChecker : Checker<"Stream">,
HelpText<"Check stream handling functions">,
WeakDependencies<[NonNullParamChecker]>,
CheckerOptions<[
CmdLineOption<Boolean,
"Pedantic",
"If false, assume that stream operations which are often not "
"checked for error do not fail.",
"false",
InAlpha>
]>,
Documentation<HasDocumentation>;

def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">,
HelpText<"Check for invalid arguments of C standard library functions, "
"and apply relations between arguments and return value">,
Expand All @@ -581,7 +595,7 @@ def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">,
"true",
InAlpha>
]>,
WeakDependencies<[CallAndMessageChecker, NonNullParamChecker]>,
WeakDependencies<[CallAndMessageChecker, NonNullParamChecker, StreamChecker]>,
Documentation<HasDocumentation>;

def VforkChecker : Checker<"Vfork">,
Expand All @@ -601,20 +615,6 @@ def PthreadLockChecker : Checker<"PthreadLock">,
Dependencies<[PthreadLockBase]>,
Documentation<HasDocumentation>;

def StreamChecker : Checker<"Stream">,
HelpText<"Check stream handling functions">,
WeakDependencies<[NonNullParamChecker]>,
CheckerOptions<[
CmdLineOption<Boolean,
"Pedantic",
"If false, assume that stream operations which are often not "
"checked for error do not fail."
"fail.",
"false",
InAlpha>
]>,
Documentation<HasDocumentation>;

def SimpleStreamChecker : Checker<"SimpleStream">,
HelpText<"Check for misuses of stream APIs">,
Documentation<HasDocumentation>;
Expand Down Expand Up @@ -1628,6 +1628,7 @@ def TaintTesterChecker : Checker<"TaintTest">,
def StreamTesterChecker : Checker<"StreamTester">,
HelpText<"Add test functions to StreamChecker for test and debugging "
"purposes.">,
WeakDependencies<[StreamChecker]>,
Documentation<NotDocumented>;

def ErrnoTesterChecker : Checker<"ErrnoTest">,
Expand Down
15 changes: 10 additions & 5 deletions clang/include/clang/Tooling/CommonOptionsParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,22 @@ namespace tooling {
/// using namespace clang::tooling;
/// using namespace llvm;
///
/// static cl::OptionCategory MyToolCategory("My tool options");
/// static cl::OptionCategory MyToolCategory("my-tool options");
/// static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
/// static cl::extrahelp MoreHelp("\nMore help text...\n");
/// static cl::opt<bool> YourOwnOption(...);
/// ...
///
/// int main(int argc, const char **argv) {
/// CommonOptionsParser OptionsParser(argc, argv, MyToolCategory);
/// auto ExpectedParser =
/// CommonOptionsParser::create(argc, argv, MyToolCategory);
/// if (!ExpectedParser) {
/// llvm::errs() << ExpectedParser.takeError();
/// return 1;
/// }
/// CommonOptionsParser& OptionsParser = ExpectedParser.get();
/// ClangTool Tool(OptionsParser.getCompilations(),
/// OptionsParser.getSourcePathList());
/// return Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
/// return Tool.run(
/// newFrontendActionFactory<clang::SyntaxOnlyAction>().get());
/// }
/// \endcode
class CommonOptionsParser {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,7 @@ int64_t Decl::getID() const {

const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
QualType Ty;
if (const auto *D = dyn_cast<BindingDecl>(this))
if (isa<BindingDecl>(this))
return nullptr;
else if (const auto *D = dyn_cast<ValueDecl>(this))
Ty = D->getType();
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
}
} else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
if (!ME->isArrow()) {
assert(ME->getBase()->getType()->isRecordType());
assert(ME->getBase()->getType()->getAsRecordDecl());
if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
E = ME->getBase();
Expand Down Expand Up @@ -3893,9 +3893,14 @@ namespace {
}

void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) {
if (E->getTemporary()->getDestructor()->isTrivial()) {
Inherited::VisitStmt(E);
return;
// Destructor of the temporary might be null if destructor declaration
// is not valid.
if (const CXXDestructorDecl *DtorDecl =
E->getTemporary()->getDestructor()) {
if (DtorDecl->isTrivial()) {
Inherited::VisitStmt(E);
return;
}
}

NonTrivial = true;
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/AST/ExprClassification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return ClassifyInternal(Ctx,
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());

case Expr::PackIndexingExprClass:
case Expr::PackIndexingExprClass: {
// A pack-index-expression always expands to an id-expression.
// Consider it as an LValue expression.
if (cast<PackIndexingExpr>(E)->isInstantiationDependent())
return Cl::CL_LValue;
return ClassifyInternal(Ctx, cast<PackIndexingExpr>(E)->getSelectedExpr());
}

// C, C++98 [expr.sub]p1: The result is an lvalue of type "T".
// C++11 (DR1213): in the case of an array operand, the result is an lvalue
Expand Down
134 changes: 129 additions & 5 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2706,7 +2706,11 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
QualType SrcType, QualType DestType,
APFloat &Result) {
assert(isa<CastExpr>(E) || isa<CompoundAssignOperator>(E));
assert((isa<CastExpr>(E) || isa<CompoundAssignOperator>(E) ||
isa<ConvertVectorExpr>(E)) &&
"HandleFloatToFloatCast has been checked with only CastExpr, "
"CompoundAssignOperator and ConvertVectorExpr. Please either validate "
"the new expression or address the root cause of this usage.");
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
APFloat::opStatus St;
APFloat Value = Result;
Expand Down Expand Up @@ -9237,9 +9241,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
bool HasValidResult = !Result.InvalidBase && !Result.Designator.Invalid &&
!Result.IsNullPtr;
bool VoidPtrCastMaybeOK =
HasValidResult &&
Info.Ctx.hasSameUnqualifiedType(Result.Designator.getType(Info.Ctx),
E->getType()->getPointeeType());
Result.IsNullPtr ||
(HasValidResult &&
Info.Ctx.hasSimilarType(Result.Designator.getType(Info.Ctx),
E->getType()->getPointeeType()));
// 1. We'll allow it in std::allocator::allocate, and anything which that
// calls.
// 2. HACK 2022-03-28: Work around an issue with libstdc++'s
Expand Down Expand Up @@ -10709,8 +10714,11 @@ namespace {
bool VisitUnaryImag(const UnaryOperator *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);

// FIXME: Missing: conditional operator (for GNU
// conditional select), shufflevector, ExtVectorElementExpr
// conditional select), ExtVectorElementExpr
};
} // end anonymous namespace

Expand Down Expand Up @@ -10961,6 +10969,122 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}

static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO,
const Expr *E, QualType SourceTy,
QualType DestTy, APValue const &Original,
APValue &Result) {
if (SourceTy->isIntegerType()) {
if (DestTy->isRealFloatingType()) {
Result = APValue(APFloat(0.0));
return HandleIntToFloatCast(Info, E, FPO, SourceTy, Original.getInt(),
DestTy, Result.getFloat());
}
if (DestTy->isIntegerType()) {
Result = APValue(
HandleIntToIntCast(Info, E, DestTy, SourceTy, Original.getInt()));
return true;
}
} else if (SourceTy->isRealFloatingType()) {
if (DestTy->isRealFloatingType()) {
Result = Original;
return HandleFloatToFloatCast(Info, E, SourceTy, DestTy,
Result.getFloat());
}
if (DestTy->isIntegerType()) {
Result = APValue(APSInt());
return HandleFloatToIntCast(Info, E, SourceTy, Original.getFloat(),
DestTy, Result.getInt());
}
}

Info.FFDiag(E, diag::err_convertvector_constexpr_unsupported_vector_cast)
<< SourceTy << DestTy;
return false;
}

bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
APValue Source;
QualType SourceVecType = E->getSrcExpr()->getType();
if (!EvaluateAsRValue(Info, E->getSrcExpr(), Source))
return false;

QualType DestTy = E->getType()->castAs<VectorType>()->getElementType();
QualType SourceTy = SourceVecType->castAs<VectorType>()->getElementType();

const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());

auto SourceLen = Source.getVectorLength();
SmallVector<APValue, 4> ResultElements;
ResultElements.reserve(SourceLen);
for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
APValue Elt;
if (!handleVectorElementCast(Info, FPO, E, SourceTy, DestTy,
Source.getVectorElt(EltNum), Elt))
return false;
ResultElements.push_back(std::move(Elt));
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}

static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E,
QualType ElemType, APValue const &VecVal1,
APValue const &VecVal2, unsigned EltNum,
APValue &Result) {
unsigned const TotalElementsInInputVector1 = VecVal1.getVectorLength();
unsigned const TotalElementsInInputVector2 = VecVal2.getVectorLength();

APSInt IndexVal = E->getShuffleMaskIdx(Info.Ctx, EltNum);
int64_t index = IndexVal.getExtValue();
// The spec says that -1 should be treated as undef for optimizations,
// but in constexpr we'd have to produce an APValue::Indeterminate,
// which is prohibited from being a top-level constant value. Emit a
// diagnostic instead.
if (index == -1) {
Info.FFDiag(
E, diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
<< EltNum;
return false;
}

if (index < 0 ||
index >= TotalElementsInInputVector1 + TotalElementsInInputVector2)
llvm_unreachable("Out of bounds shuffle index");

if (index >= TotalElementsInInputVector1)
Result = VecVal2.getVectorElt(index - TotalElementsInInputVector1);
else
Result = VecVal1.getVectorElt(index);
return true;
}

bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
APValue VecVal1;
const Expr *Vec1 = E->getExpr(0);
if (!EvaluateAsRValue(Info, Vec1, VecVal1))
return false;
APValue VecVal2;
const Expr *Vec2 = E->getExpr(1);
if (!EvaluateAsRValue(Info, Vec2, VecVal2))
return false;

VectorType const *DestVecTy = E->getType()->castAs<VectorType>();
QualType DestElTy = DestVecTy->getElementType();

auto TotalElementsInOutputVector = DestVecTy->getNumElements();

SmallVector<APValue, 4> ResultElements;
ResultElements.reserve(TotalElementsInOutputVector);
for (unsigned EltNum = 0; EltNum < TotalElementsInOutputVector; ++EltNum) {
APValue Elt;
if (!handleVectorShuffle(Info, E, DestElTy, VecVal1, VecVal2, EltNum, Elt))
return false;
ResultElements.push_back(std::move(Elt));
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}

//===----------------------------------------------------------------------===//
// Array Evaluation
//===----------------------------------------------------------------------===//
Expand Down
Loading