diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 0b2e4e1be86d86..0da482457ad706 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -67,11 +67,11 @@ clang/test/AST/Interp/ @tbaederr
/mlir/include/mlir/Dialect/Linalg @dcaballe @nicolasvasilache @rengolin
/mlir/lib/Dialect/Linalg @dcaballe @nicolasvasilache @rengolin
/mlir/lib/Dialect/Linalg/Transforms/DecomposeLinalgOps.cpp @MaheshRavishankar @nicolasvasilache
-/mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp @MaheshRavishankar @nicolasvasilache
+/mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp @dcaballe @MaheshRavishankar @nicolasvasilache
/mlir/lib/Dialect/Linalg/Transforms/ElementwiseOpFusion.cpp @MaheshRavishankar @nicolasvasilache
/mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp @hanhanW @nicolasvasilache
-/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp @hanhanW @nicolasvasilache
-/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp @hanhanW @nicolasvasilache
+/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp @dcaballe @hanhanW @nicolasvasilache
+/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp @banach-space @dcaballe @hanhanW @nicolasvasilache
# MemRef Dialect in MLIR.
/mlir/lib/Dialect/MemRef/Transforms/EmulateNarrowType.cpp @MaheshRavishankar @nicolasvasilache
@@ -85,10 +85,10 @@ clang/test/AST/Interp/ @tbaederr
/mlir/**/*VectorToSCF* @banach-space @dcaballe @matthias-springer @nicolasvasilache
/mlir/**/*VectorToLLVM* @banach-space @dcaballe @nicolasvasilache
/mlir/**/*X86Vector* @aartbik @dcaballe @nicolasvasilache
-/mlir/include/mlir/Dialect/Vector @dcaballe @nicolasvasilache
-/mlir/lib/Dialect/Vector @dcaballe @nicolasvasilache
-/mlir/lib/Dialect/Vector/Transforms/* @hanhanW @nicolasvasilache
-/mlir/lib/Dialect/Vector/Transforms/VectorEmulateNarrowType.cpp @MaheshRavishankar @nicolasvasilache
+/mlir/include/mlir/Dialect/Vector @banach-space @dcaballe @nicolasvasilache
+/mlir/lib/Dialect/Vector @banach-space @dcaballe @nicolasvasilache
+/mlir/lib/Dialect/Vector/Transforms/* @banach-space @dcaballe @hanhanW @nicolasvasilache
+/mlir/lib/Dialect/Vector/Transforms/VectorEmulateNarrowType.cpp @banach-space @dcaballe @MaheshRavishankar @nicolasvasilache
/mlir/**/*EmulateNarrowType* @dcaballe @hanhanW
# Presburger library in MLIR
diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md
index 17c52c65e472fa..bd6e2ec01b53e7 100644
--- a/bolt/docs/CommandLineArgumentReference.md
+++ b/bolt/docs/CommandLineArgumentReference.md
@@ -283,6 +283,12 @@
List of functions to pad with amount of bytes
+- `--print-mappings`
+
+ Print mappings in the legend, between characters/blocks and text sections
+ (default false).
+
+
- `--profile-format=`
Format to dump profile output in aggregation mode, default is fdata
@@ -1240,4 +1246,4 @@
- `--print-options`
- Print non-default options after command line parsing
\ No newline at end of file
+ Print non-default options after command line parsing
diff --git a/bolt/docs/HeatmapHeader.png b/bolt/docs/HeatmapHeader.png
new file mode 100644
index 00000000000000..a519dc6215d8cf
Binary files /dev/null and b/bolt/docs/HeatmapHeader.png differ
diff --git a/bolt/docs/Heatmaps.md b/bolt/docs/Heatmaps.md
index 4bae8ed5410df2..bf68232ef7fee9 100644
--- a/bolt/docs/Heatmaps.md
+++ b/bolt/docs/Heatmaps.md
@@ -1,9 +1,9 @@
# Code Heatmaps
BOLT has gained the ability to print code heatmaps based on
-sampling-based LBR profiles generated by `perf`. The output is produced
-in colored ASCII to be displayed in a color-capable terminal. It looks
-something like this:
+sampling-based profiles generated by `perf`, either with `LBR` data or not.
+The output is produced in colored ASCII to be displayed in a color-capable
+terminal. It looks something like this:
![](./Heatmap.png)
@@ -32,16 +32,8 @@ $ llvm-bolt-heatmap -p perf.data
```
By default the heatmap will be dumped to *stdout*. You can change it
-with `-o ` option. Each character/block in the heatmap
-shows the execution data accumulated for corresponding 64 bytes of
-code. You can change this granularity with a `-block-size` option.
-E.g. set it to 4096 to see code usage grouped by 4K pages.
-Other useful options are:
+with `-o ` option.
-```bash
--line-size= - number of entries per line (default 256)
--max-address= - maximum address considered valid for heatmap (default 4GB)
-```
If you prefer to look at the data in a browser (or would like to share
it that way), then you can use an HTML conversion tool. E.g.:
@@ -49,3 +41,55 @@ it that way), then you can use an HTML conversion tool. E.g.:
```bash
$ aha -b -f > .html
```
+
+---
+
+## Background on heatmaps:
+A heatmap is effectively a histogram that is rendered into a grid for better
+visualization.
+In theory we can generate a heatmap using any binary and a perf profile.
+
+Each block/character in the heatmap shows the execution data accumulated for
+corresponding 64 bytes of code. You can change this granularity with a
+`-block-size` option.
+E.g. set it to 4096 to see code usage grouped by 4K pages.
+
+
+When a block is shown as a dot, it means that no samples were found for that
+address.
+When it is shown as a letter, it indicates a captured sample on a particular
+text section of the binary.
+To show a mapping between letters and text sections in the legend, use
+`-print-mappings`.
+When a sampled address does not belong to any of the text sections, the
+characters 'o' or 'O' will be shown.
+
+The legend shows by default the ranges in the heatmap according to the number
+of samples per block.
+A color is assigned per range, except the first two ranges that distinguished by
+lower and upper case letters.
+
+On the Y axis, each row/line starts with an actual address of the binary.
+Consecutive lines in the heatmap advance by the same amount, with the binary
+size covered by a line dependent on the block size and the line size.
+An empty new line is inserted for larger gaps between samples.
+
+On the X axis, the horizontally emitted hex numbers can help *estimate* where
+in the line the samples lie, but they cannot be combined to provide a full
+address, as they are relative to both the bucket and line sizes.
+
+In the example below, the highlighted `0x100` column is not an offset to each
+row's address, but instead, it points to the middle of the line.
+For the generation, the default bucket size was used with a line size of 128.
+
+
+![](./HeatmapHeader.png)
+
+
+Some useful options are:
+
+```
+-line-size= - number of entries per line (default 256)
+-max-address= - maximum address considered valid for heatmap (default 4GB)
+-print-mappings - print mappings in the legend, between characters/blocks and text sections (default false)
+```
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index 2324e577cc7c94..5935ffaa46af7d 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -256,7 +256,7 @@ class DebugRangeListsSectionWriter : public DebugRangesSectionWriter {
};
virtual ~DebugRangeListsSectionWriter(){};
- static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; }
+ void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; }
/// Add ranges with caching.
uint64_t addRanges(
@@ -284,7 +284,7 @@ class DebugRangeListsSectionWriter : public DebugRangesSectionWriter {
}
private:
- static DebugAddrWriter *AddrWriter;
+ DebugAddrWriter *AddrWriter = nullptr;
/// Used to find unique CU ID.
DWARFUnit *CU;
/// Current relative offset of range list entry within this CUs rangelist
@@ -336,21 +336,36 @@ using AddressSectionBuffer = SmallVector;
class DebugAddrWriter {
public:
DebugAddrWriter() = delete;
- DebugAddrWriter(BinaryContext *BC_);
+ DebugAddrWriter(BinaryContext *BC_) : DebugAddrWriter(BC_, UCHAR_MAX) {};
+ DebugAddrWriter(BinaryContext *BC_, uint8_t AddressByteSize);
virtual ~DebugAddrWriter(){};
/// Given an address returns an index in .debug_addr.
/// Adds Address to map.
uint32_t getIndexFromAddress(uint64_t Address, DWARFUnit &CU);
/// Write out entries in to .debug_addr section for CUs.
- virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs);
+ virtual std::optional finalize(const size_t BufferSize);
/// Return buffer with all the entries in .debug_addr already writen out using
/// update(...).
- virtual AddressSectionBuffer &finalize() { return *Buffer; }
+ virtual std::unique_ptr releaseBuffer() {
+ return std::move(Buffer);
+ }
+
+ /// Returns buffer size.
+ virtual size_t getBufferSize() const { return Buffer->size(); }
+
+ /// Returns True if Buffer is not empty.
+ bool isInitialized() const { return !Buffer->empty(); }
- /// Returns False if .debug_addr section was created..
- bool isInitialized() const { return !AddressMaps.empty(); }
+ /// Updates address base with the given Offset.
+ virtual void updateAddrBase(DIEBuilder &DIEBlder, DWARFUnit &CU,
+ const uint64_t Offset);
+
+ /// Appends an AddressSectionBuffer to the address writer's buffer.
+ void appendToAddressBuffer(const AddressSectionBuffer &Buffer) {
+ *AddressStream << Buffer;
+ }
protected:
class AddressForDWOCU {
@@ -407,23 +422,32 @@ class DebugAddrWriter {
}
BinaryContext *BC;
- /// Maps DWOID to AddressForDWOCU.
- std::unordered_map AddressMaps;
+ /// Address for the DWO CU associated with the address writer.
+ AddressForDWOCU Map;
+ uint8_t AddressByteSize;
/// Mutex used for parallel processing of debug info.
std::mutex WriterMutex;
std::unique_ptr Buffer;
std::unique_ptr AddressStream;
/// Used to track sections that were not modified so that they can be re-used.
- DenseMap UnmodifiedAddressOffsets;
+ static DenseMap UnmodifiedAddressOffsets;
};
class DebugAddrWriterDwarf5 : public DebugAddrWriter {
public:
DebugAddrWriterDwarf5() = delete;
DebugAddrWriterDwarf5(BinaryContext *BC) : DebugAddrWriter(BC) {}
+ DebugAddrWriterDwarf5(BinaryContext *BC, uint8_t AddressByteSize,
+ std::optional AddrOffsetSectionBase)
+ : DebugAddrWriter(BC, AddressByteSize),
+ AddrOffsetSectionBase(AddrOffsetSectionBase) {}
/// Write out entries in to .debug_addr section for CUs.
- virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs) override;
+ virtual std::optional finalize(const size_t BufferSize) override;
+
+ /// Updates address base with the given Offset.
+ virtual void updateAddrBase(DIEBuilder &DIEBlder, DWARFUnit &CU,
+ const uint64_t Offset) override;
protected:
/// Given DWARFUnit \p Unit returns either DWO ID or it's offset within
@@ -435,6 +459,10 @@ class DebugAddrWriterDwarf5 : public DebugAddrWriter {
}
return Unit.getOffset();
}
+
+private:
+ std::optional AddrOffsetSectionBase = std::nullopt;
+ static constexpr uint32_t HeaderSize = 8;
};
/// This class is NOT thread safe.
@@ -583,12 +611,10 @@ class DebugLoclistWriter : public DebugLocWriter {
public:
~DebugLoclistWriter() {}
DebugLoclistWriter() = delete;
- DebugLoclistWriter(DWARFUnit &Unit, uint8_t DV, bool SD)
- : DebugLocWriter(DV, LocWriterKind::DebugLoclistWriter), CU(Unit),
- IsSplitDwarf(SD) {
- assert(DebugLoclistWriter::AddrWriter &&
- "Please use SetAddressWriter to initialize "
- "DebugAddrWriter before instantiation.");
+ DebugLoclistWriter(DWARFUnit &Unit, uint8_t DV, bool SD,
+ DebugAddrWriter &AddrW)
+ : DebugLocWriter(DV, LocWriterKind::DebugLoclistWriter),
+ AddrWriter(AddrW), CU(Unit), IsSplitDwarf(SD) {
if (DwarfVersion >= 5) {
LocBodyBuffer = std::make_unique();
LocBodyStream = std::make_unique(*LocBodyBuffer);
@@ -600,8 +626,6 @@ class DebugLoclistWriter : public DebugLocWriter {
}
}
- static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; }
-
/// Stores location lists internally to be written out during finalize phase.
virtual void addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
DebugLocationsVector &LocList) override;
@@ -630,7 +654,7 @@ class DebugLoclistWriter : public DebugLocWriter {
/// Writes out locations in to a local buffer and applies debug info patches.
void finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die);
- static DebugAddrWriter *AddrWriter;
+ DebugAddrWriter &AddrWriter;
DWARFUnit &CU;
bool IsSplitDwarf{false};
// Used for DWARF5 to store location lists before being finalized.
diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index ab07f07e498455..c916c6f95751fc 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -2041,9 +2041,14 @@ class MCPlusBuilder {
return InstructionListType();
}
- virtual InstructionListType createDummyReturnFunction(MCContext *Ctx) const {
- llvm_unreachable("not implemented");
- return InstructionListType();
+ /// Returns a function body that contains only a return instruction. An
+ /// example usage is a workaround for the '__bolt_fini_trampoline' of
+ // Instrumentation.
+ virtual InstructionListType
+ createReturnInstructionList(MCContext *Ctx) const {
+ InstructionListType Insts(1);
+ createReturn(Insts[0]);
+ return Insts;
}
/// This method takes an indirect call instruction and splits it up into an
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index 4f576eaa95576a..abd18b56113b62 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -66,10 +66,6 @@ class DWARFRewriter {
/// .debug_aranges DWARF section.
std::unique_ptr ARangesSectionWriter;
- /// Stores and serializes information that will be put into the
- /// .debug_addr DWARF section.
- std::unique_ptr AddrWriter;
-
/// Stores and serializes information that will be put in to the
/// .debug_addr DWARF section.
/// Does not do de-duplication.
@@ -93,6 +89,10 @@ class DWARFRewriter {
std::unordered_map>
LegacyRangesWritersByCU;
+ /// Stores address writer for each CU.
+ std::unordered_map>
+ AddressWritersByCU;
+
std::mutex LocListDebugInfoPatchesMutex;
/// Dwo id specific its RangesBase.
@@ -115,6 +115,7 @@ class DWARFRewriter {
void updateUnitDebugInfo(DWARFUnit &Unit, DIEBuilder &DIEBldr,
DebugLocWriter &DebugLocWriter,
DebugRangesSectionWriter &RangesSectionWriter,
+ DebugAddrWriter &AddressWriter,
std::optional RangesBase = std::nullopt);
/// Patches the binary for an object's address ranges to be updated.
@@ -141,13 +142,15 @@ class DWARFRewriter {
/// Process and write out CUs that are passsed in.
void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
CUOffsetMap &CUMap,
- const std::list &CUs);
+ const std::list &CUs,
+ DebugAddrWriter &FinalAddrWriter);
/// Finalize debug sections in the main binary.
void finalizeDebugSections(DIEBuilder &DIEBlder,
DWARF5AcceleratorTable &DebugNamesTable,
DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
- CUOffsetMap &CUMap);
+ CUOffsetMap &CUMap,
+ DebugAddrWriter &FinalAddrWriter);
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
/// blocks) to be updated.
diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h
index 30e8bd777b3cac..baabeab577fb5e 100644
--- a/bolt/include/bolt/Utils/CommandLineOpts.h
+++ b/bolt/include/bolt/Utils/CommandLineOpts.h
@@ -40,6 +40,7 @@ extern llvm::cl::opt ExecutionCountThreshold;
extern llvm::cl::opt HeatmapBlock;
extern llvm::cl::opt HeatmapMaxAddress;
extern llvm::cl::opt HeatmapMinAddress;
+extern llvm::cl::opt HeatmapPrintMappings;
extern llvm::cl::opt HotData;
extern llvm::cl::opt HotFunctionsAtEnd;
extern llvm::cl::opt HotText;
diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index 6633eaa9574216..7815a305c05182 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -556,7 +556,17 @@ DWARFDie DIEBuilder::resolveDIEReference(
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
DWARFUnit *&RefCU, DWARFDebugInfoEntry &DwarfDebugInfoEntry) {
assert(RefValue.isFormClass(DWARFFormValue::FC_Reference));
- uint64_t RefOffset = *RefValue.getAsReference();
+ uint64_t RefOffset;
+ if (std::optional Off = RefValue.getAsRelativeReference()) {
+ RefOffset = RefValue.getUnit()->getOffset() + *Off;
+ } else if (Off = RefValue.getAsDebugInfoReference(); Off) {
+ RefOffset = *Off;
+ } else {
+ BC.errs()
+ << "BOLT-WARNING: [internal-dwarf-error]: unsupported reference type: "
+ << FormEncodingString(RefValue.getForm()) << ".\n";
+ return DWARFDie();
+ }
return resolveDIEReference(AttrSpec, RefOffset, RefCU, DwarfDebugInfoEntry);
}
@@ -607,7 +617,13 @@ void DIEBuilder::cloneDieReferenceAttribute(
DIE &Die, const DWARFUnit &U, const DWARFDie &InputDIE,
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
const DWARFFormValue &Val) {
- const uint64_t Ref = *Val.getAsReference();
+ uint64_t Ref;
+ if (std::optional Off = Val.getAsRelativeReference())
+ Ref = Val.getUnit()->getOffset() + *Off;
+ else if (Off = Val.getAsDebugInfoReference(); Off)
+ Ref = *Off;
+ else
+ return;
DIE *NewRefDie = nullptr;
DWARFUnit *RefUnit = nullptr;
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index 76c3545c63088c..002f58c4743466 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -184,8 +184,6 @@ void DebugRangesSectionWriter::appendToRangeBuffer(
*RangesStream << CUBuffer;
}
-DebugAddrWriter *DebugRangeListsSectionWriter::AddrWriter = nullptr;
-
uint64_t DebugRangeListsSectionWriter::addRanges(
DebugAddressRangesVector &&Ranges,
std::map &CachedRanges) {
@@ -390,7 +388,9 @@ void DebugARangesSectionWriter::writeARangesSection(
}
}
-DebugAddrWriter::DebugAddrWriter(BinaryContext *BC) : BC(BC) {
+DebugAddrWriter::DebugAddrWriter(BinaryContext *BC,
+ const uint8_t AddressByteSize)
+ : BC(BC), AddressByteSize(AddressByteSize) {
Buffer = std::make_unique();
AddressStream = std::make_unique(*Buffer);
}
@@ -405,11 +405,6 @@ void DebugAddrWriter::AddressForDWOCU::dump() {
}
uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, DWARFUnit &CU) {
std::lock_guard Lock(WriterMutex);
- const uint64_t CUID = getCUID(CU);
- if (!AddressMaps.count(CUID))
- AddressMaps[CUID] = AddressForDWOCU();
-
- AddressForDWOCU &Map = AddressMaps[CUID];
auto Entry = Map.find(Address);
if (Entry == Map.end()) {
auto Index = Map.getNextIndex();
@@ -449,29 +444,23 @@ static void updateAddressBase(DIEBuilder &DIEBlder, DebugAddrWriter &AddrWriter,
}
}
-void DebugAddrWriter::update(DIEBuilder &DIEBlder, DWARFUnit &CU) {
- // Handling the case where debug information is a mix of Debug fission and
- // monolithic.
- if (!CU.getDWOId())
- return;
- const uint64_t CUID = getCUID(CU);
- auto AM = AddressMaps.find(CUID);
- // Adding to map even if it did not contribute to .debug_addr.
- // The Skeleton CU might still have DW_AT_GNU_addr_base.
- uint64_t Offset = Buffer->size();
- // If does not exist this CUs DWO section didn't contribute to .debug_addr.
- if (AM == AddressMaps.end())
- return;
- std::vector SortedMap(AM->second.indexToAddressBegin(),
- AM->second.indexToAdddessEnd());
+void DebugAddrWriter::updateAddrBase(DIEBuilder &DIEBlder, DWARFUnit &CU,
+ const uint64_t Offset) {
+ updateAddressBase(DIEBlder, *this, CU, Offset);
+}
+
+std::optional DebugAddrWriter::finalize(const size_t BufferSize) {
+ if (Map.begin() == Map.end())
+ return std::nullopt;
+ std::vector SortedMap(Map.indexToAddressBegin(),
+ Map.indexToAdddessEnd());
// Sorting address in increasing order of indices.
llvm::sort(SortedMap, llvm::less_first());
- uint8_t AddrSize = CU.getAddressByteSize();
uint32_t Counter = 0;
auto WriteAddress = [&](uint64_t Address) -> void {
++Counter;
- switch (AddrSize) {
+ switch (AddressByteSize) {
default:
assert(false && "Address Size is invalid.");
break;
@@ -490,10 +479,19 @@ void DebugAddrWriter::update(DIEBuilder &DIEBlder, DWARFUnit &CU) {
WriteAddress(0);
WriteAddress(Val.second);
}
- updateAddressBase(DIEBlder, *this, CU, Offset);
+ return std::nullopt;
+}
+
+void DebugAddrWriterDwarf5::updateAddrBase(DIEBuilder &DIEBlder, DWARFUnit &CU,
+ const uint64_t Offset) {
+ /// Header for DWARF5 has size 8, so we add it to the offset.
+ updateAddressBase(DIEBlder, *this, CU, Offset + HeaderSize);
}
-void DebugAddrWriterDwarf5::update(DIEBuilder &DIEBlder, DWARFUnit &CU) {
+DenseMap DebugAddrWriter::UnmodifiedAddressOffsets;
+
+std::optional
+DebugAddrWriterDwarf5::finalize(const size_t BufferSize) {
// Need to layout all sections within .debug_addr
// Within each section sort Address by index.
const endianness Endian = BC->DwCtx->isLittleEndian()
@@ -504,55 +502,44 @@ void DebugAddrWriterDwarf5::update(DIEBuilder &DIEBlder, DWARFUnit &CU) {
Endian == llvm::endianness::little, 0);
DWARFDebugAddrTable AddrTable;
DIDumpOptions DumpOpts;
- constexpr uint32_t HeaderSize = 8;
- const uint64_t CUID = getCUID(CU);
- const uint8_t AddrSize = CU.getAddressByteSize();
- auto AMIter = AddressMaps.find(CUID);
// A case where CU has entry in .debug_addr, but we don't modify addresses
// for it.
- if (AMIter == AddressMaps.end()) {
- AMIter = AddressMaps.insert({CUID, AddressForDWOCU()}).first;
- std::optional BaseOffset = CU.getAddrOffsetSectionBase();
- if (!BaseOffset)
- return;
+ if (Map.begin() == Map.end()) {
+ if (!AddrOffsetSectionBase)
+ return std::nullopt;
// Address base offset is to the first entry.
// The size of header is 8 bytes.
- uint64_t Offset = *BaseOffset - HeaderSize;
+ uint64_t Offset = *AddrOffsetSectionBase - HeaderSize;
auto Iter = UnmodifiedAddressOffsets.find(Offset);
- if (Iter != UnmodifiedAddressOffsets.end()) {
- updateAddressBase(DIEBlder, *this, CU, Iter->getSecond());
- return;
- }
- UnmodifiedAddressOffsets[Offset] = Buffer->size() + HeaderSize;
- if (Error Err = AddrTable.extract(AddrData, &Offset, 5, AddrSize,
+ if (Iter != UnmodifiedAddressOffsets.end())
+ return Iter->second;
+ UnmodifiedAddressOffsets[Offset] = BufferSize;
+ if (Error Err = AddrTable.extract(AddrData, &Offset, 5, AddressByteSize,
DumpOpts.WarningHandler)) {
DumpOpts.RecoverableErrorHandler(std::move(Err));
- return;
+ return std::nullopt;
}
-
uint32_t Index = 0;
for (uint64_t Addr : AddrTable.getAddressEntries())
- AMIter->second.insert(Addr, Index++);
+ Map.insert(Addr, Index++);
}
- updateAddressBase(DIEBlder, *this, CU, Buffer->size() + HeaderSize);
-
- std::vector SortedMap(AMIter->second.indexToAddressBegin(),
- AMIter->second.indexToAdddessEnd());
+ std::vector SortedMap(Map.indexToAddressBegin(),
+ Map.indexToAdddessEnd());
// Sorting address in increasing order of indices.
llvm::sort(SortedMap, llvm::less_first());
// Writing out Header
- const uint32_t Length = SortedMap.size() * AddrSize + 4;
+ const uint32_t Length = SortedMap.size() * AddressByteSize + 4;
support::endian::write(*AddressStream, Length, Endian);
support::endian::write(*AddressStream, static_cast(5), Endian);
- support::endian::write(*AddressStream, static_cast(AddrSize),
+ support::endian::write(*AddressStream, static_cast(AddressByteSize),
Endian);
support::endian::write(*AddressStream, static_cast(0), Endian);
uint32_t Counter = 0;
auto writeAddress = [&](uint64_t Address) -> void {
++Counter;
- switch (AddrSize) {
+ switch (AddressByteSize) {
default:
llvm_unreachable("Address Size is invalid.");
break;
@@ -571,6 +558,7 @@ void DebugAddrWriterDwarf5::update(DIEBuilder &DIEBlder, DWARFUnit &CU) {
writeAddress(0);
writeAddress(Val.second);
}
+ return std::nullopt;
}
void DebugLocWriter::init() {
@@ -723,11 +711,11 @@ void DebugLoclistWriter::addList(DIEBuilder &DIEBldr, DIE &Die,
DIEValue &AttrInfo,
DebugLocationsVector &LocList) {
if (DwarfVersion < 5)
- writeLegacyLocList(AttrInfo, LocList, DIEBldr, Die, *AddrWriter, *LocBuffer,
+ writeLegacyLocList(AttrInfo, LocList, DIEBldr, Die, AddrWriter, *LocBuffer,
CU, *LocStream);
else
writeDWARF5LocList(NumberOfEntries, AttrInfo, LocList, Die, DIEBldr,
- *AddrWriter, *LocBodyBuffer, RelativeLocListOffsets, CU,
+ AddrWriter, *LocBodyBuffer, RelativeLocListOffsets, CU,
*LocBodyStream);
}
@@ -789,8 +777,6 @@ void DebugLoclistWriter::finalize(DIEBuilder &DIEBldr, DIE &Die) {
finalizeDWARF5(DIEBldr, Die);
}
-DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr;
-
static std::string encodeLE(size_t ByteSize, uint64_t NewValue) {
std::string LE64(ByteSize, 0);
for (size_t I = 0; I < ByteSize; ++I) {
diff --git a/bolt/lib/Passes/Instrumentation.cpp b/bolt/lib/Passes/Instrumentation.cpp
index e824a42d826964..ebb3925749b4d2 100644
--- a/bolt/lib/Passes/Instrumentation.cpp
+++ b/bolt/lib/Passes/Instrumentation.cpp
@@ -754,7 +754,7 @@ void Instrumentation::createAuxiliaryFunctions(BinaryContext &BC) {
// with unknown symbol in runtime library. E.g. for static PIE
// executable
createSimpleFunction("__bolt_fini_trampoline",
- BC.MIB->createDummyReturnFunction(BC.Ctx.get()));
+ BC.MIB->createReturnInstructionList(BC.Ctx.get()));
}
}
}
diff --git a/bolt/lib/Profile/Heatmap.cpp b/bolt/lib/Profile/Heatmap.cpp
index 210a5cc98c1041..5fc3e0669352da 100644
--- a/bolt/lib/Profile/Heatmap.cpp
+++ b/bolt/lib/Profile/Heatmap.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include
@@ -164,6 +165,7 @@ void Heatmap::print(raw_ostream &OS) const {
// Print map legend
OS << "Legend:\n";
+ OS << "\nRanges:\n";
uint64_t PrevValue = 0;
for (unsigned I = 0; I < sizeof(Range) / sizeof(Range[0]); ++I) {
const uint64_t Value = Range[I];
@@ -172,6 +174,22 @@ void Heatmap::print(raw_ostream &OS) const {
OS << " : (" << PrevValue << ", " << Value << "]\n";
PrevValue = Value;
}
+ if (opts::HeatmapPrintMappings) {
+ OS << "\nSections:\n";
+ unsigned SectionIdx = 0;
+ for (auto TxtSeg : TextSections) {
+ const char Upper = static_cast('A' + ((SectionIdx++) % 26));
+ const char Lower = static_cast(std::tolower(Upper));
+ OS << formatv(" {0}/{1} : {2,-10} ", Lower, Upper, TxtSeg.Name);
+ if (MaxAddress > 0xffffffff)
+ OS << format("0x%016" PRIx64, TxtSeg.BeginAddress) << "-"
+ << format("0x%016" PRIx64, TxtSeg.EndAddress) << "\n";
+ else
+ OS << format("0x%08" PRIx64, TxtSeg.BeginAddress) << "-"
+ << format("0x%08" PRIx64, TxtSeg.EndAddress) << "\n";
+ }
+ OS << "\n";
+ }
// Pos - character position from right in hex form.
auto printHeader = [&](unsigned Pos) {
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 89168b4bd559cc..042c39a574561a 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -612,12 +612,15 @@ void DWARFRewriter::updateDebugInfo() {
errs() << "BOLT-WARNING: --deterministic-debuginfo is being deprecated\n";
}
+ /// Stores and serializes information that will be put into the
+ /// .debug_addr DWARF section.
+ std::unique_ptr FinalAddrWriter;
+
if (BC.isDWARF5Used()) {
- AddrWriter = std::make_unique(&BC);
+ FinalAddrWriter = std::make_unique(&BC);
RangeListsSectionWriter = std::make_unique();
- DebugRangeListsSectionWriter::setAddressWriter(AddrWriter.get());
} else {
- AddrWriter = std::make_unique(&BC);
+ FinalAddrWriter = std::make_unique(&BC);
}
if (BC.isDWARFLegacyUsed()) {
@@ -625,34 +628,42 @@ void DWARFRewriter::updateDebugInfo() {
LegacyRangesSectionWriter->initSection();
}
- DebugLoclistWriter::setAddressWriter(AddrWriter.get());
-
uint32_t CUIndex = 0;
std::mutex AccessMutex;
// Needs to be invoked in the same order as CUs are processed.
- auto createRangeLocList = [&](DWARFUnit &CU) -> DebugLocWriter * {
+ auto createRangeLocListAddressWriters =
+ [&](DWARFUnit &CU) -> DebugLocWriter * {
std::lock_guard Lock(AccessMutex);
const uint16_t DwarfVersion = CU.getVersion();
if (DwarfVersion >= 5) {
+ auto AddrW = std::make_unique(
+ &BC, CU.getAddressByteSize(), CU.getAddrOffsetSectionBase());
+ RangeListsSectionWriter->setAddressWriter(AddrW.get());
LocListWritersByCU[CUIndex] =
- std::make_unique(CU, DwarfVersion, false);
+ std::make_unique(CU, DwarfVersion, false, *AddrW);
if (std::optional DWOId = CU.getDWOId()) {
assert(RangeListsWritersByCU.count(*DWOId) == 0 &&
"RangeLists writer for DWO unit already exists.");
- auto RangeListsSectionWriter =
+ auto DWORangeListsSectionWriter =
std::make_unique();
- RangeListsSectionWriter->initSection(CU);
- RangeListsWritersByCU[*DWOId] = std::move(RangeListsSectionWriter);
+ DWORangeListsSectionWriter->initSection(CU);
+ DWORangeListsSectionWriter->setAddressWriter(AddrW.get());
+ RangeListsWritersByCU[*DWOId] = std::move(DWORangeListsSectionWriter);
}
+ AddressWritersByCU[CU.getOffset()] = std::move(AddrW);
} else {
+ auto AddrW =
+ std::make_unique(&BC, CU.getAddressByteSize());
+ AddressWritersByCU[CU.getOffset()] = std::move(AddrW);
LocListWritersByCU[CUIndex] = std::make_unique();
if (std::optional DWOId = CU.getDWOId()) {
assert(LegacyRangesWritersByCU.count(*DWOId) == 0 &&
"LegacyRangeLists writer for DWO unit already exists.");
auto LegacyRangesSectionWriterByCU =
std::make_unique();
+ LegacyRangesSectionWriterByCU->initSection(CU);
LegacyRangesWritersByCU[*DWOId] =
std::move(LegacyRangesSectionWriterByCU);
}
@@ -674,10 +685,12 @@ void DWARFRewriter::updateDebugInfo() {
std::optional DWOId = Unit->getDWOId();
if (DWOId)
SplitCU = BC.getDWOCU(*DWOId);
- DebugLocWriter *DebugLocWriter = createRangeLocList(*Unit);
+ DebugLocWriter *DebugLocWriter = createRangeLocListAddressWriters(*Unit);
DebugRangesSectionWriter *RangesSectionWriter =
Unit->getVersion() >= 5 ? RangeListsSectionWriter.get()
: LegacyRangesSectionWriter.get();
+ DebugAddrWriter *AddressWriter =
+ AddressWritersByCU[Unit->getOffset()].get();
// Skipping CUs that failed to load.
if (SplitCU) {
DIEBuilder DWODIEBuilder(BC, &(*SplitCU)->getContext(), DebugNamesTable,
@@ -698,7 +711,8 @@ void DWARFRewriter::updateDebugInfo() {
DWODIEBuilder.updateDWONameCompDirForTypes(DWOStrOffstsWriter,
DWOStrWriter, **SplitCU,
DwarfOutputPath, DWOName);
- DebugLoclistWriter DebugLocDWoWriter(*Unit, Unit->getVersion(), true);
+ DebugLoclistWriter DebugLocDWoWriter(*Unit, Unit->getVersion(), true,
+ *AddressWriter);
DebugRangesSectionWriter *TempRangesSectionWriter = RangesSectionWriter;
if (Unit->getVersion() >= 5) {
TempRangesSectionWriter = RangeListsWritersByCU[*DWOId].get();
@@ -709,7 +723,7 @@ void DWARFRewriter::updateDebugInfo() {
}
updateUnitDebugInfo(*(*SplitCU), DWODIEBuilder, DebugLocDWoWriter,
- *TempRangesSectionWriter);
+ *TempRangesSectionWriter, *AddressWriter);
DebugLocDWoWriter.finalize(DWODIEBuilder,
*DWODIEBuilder.getUnitDIEbyUnit(**SplitCU));
if (Unit->getVersion() >= 5)
@@ -728,11 +742,10 @@ void DWARFRewriter::updateDebugInfo() {
}
updateUnitDebugInfo(*Unit, *DIEBlder, *DebugLocWriter, *RangesSectionWriter,
- RangesBase);
+ *AddressWriter, RangesBase);
DebugLocWriter->finalize(*DIEBlder, *DIEBlder->getUnitDIEbyUnit(*Unit));
if (Unit->getVersion() >= 5)
RangesSectionWriter->finalizeSection();
- AddrWriter->update(*DIEBlder, *Unit);
};
DIEBuilder DIEBlder(BC, BC.DwCtx.get(), DebugNamesTable);
@@ -758,7 +771,7 @@ void DWARFRewriter::updateDebugInfo() {
for (DWARFUnit *CU : DIEBlder.getProcessedCUs())
processUnitDIE(CU, &DIEBlder);
finalizeCompileUnits(DIEBlder, *Streamer, OffsetMap,
- DIEBlder.getProcessedCUs());
+ DIEBlder.getProcessedCUs(), *FinalAddrWriter);
}
} else {
// Update unit debug info in parallel
@@ -773,8 +786,8 @@ void DWARFRewriter::updateDebugInfo() {
if (opts::WriteDWP)
finalizeDWP(State);
- finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS,
- OffsetMap);
+ finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS, OffsetMap,
+ *FinalAddrWriter);
GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex,
*ARangesSectionWriter);
}
@@ -782,7 +795,7 @@ void DWARFRewriter::updateDebugInfo() {
void DWARFRewriter::updateUnitDebugInfo(
DWARFUnit &Unit, DIEBuilder &DIEBldr, DebugLocWriter &DebugLocWriter,
DebugRangesSectionWriter &RangesSectionWriter,
- std::optional RangesBase) {
+ DebugAddrWriter &AddressWriter, std::optional RangesBase) {
// Cache debug ranges so that the offset for identical ranges could be reused.
std::map CachedRanges;
@@ -816,7 +829,7 @@ void DWARFRewriter::updateUnitDebugInfo(
if (FormLowPC == dwarf::DW_FORM_addrx ||
FormLowPC == dwarf::DW_FORM_GNU_addr_index)
- LowPC = AddrWriter->getIndexFromAddress(LowPC, Unit);
+ LowPC = AddressWriter.getIndexFromAddress(LowPC, Unit);
if (LowPCVal)
DIEBldr.replaceValue(Die, AttrLowPC, FormLowPC, DIEInteger(LowPC));
@@ -980,7 +993,7 @@ void DWARFRewriter::updateUnitDebugInfo(
if (AttrVal.getForm() == dwarf::DW_FORM_addrx) {
const uint32_t Index =
- AddrWriter->getIndexFromAddress(UpdatedAddress, Unit);
+ AddressWriter.getIndexFromAddress(UpdatedAddress, Unit);
DIEBldr.replaceValue(Die, AttrVal.getAttribute(), AttrVal.getForm(),
DIEInteger(Index));
} else if (AttrVal.getForm() == dwarf::DW_FORM_addr) {
@@ -1197,7 +1210,7 @@ void DWARFRewriter::updateUnitDebugInfo(
assert(EntryAddress && "Address is not found.");
assert(Index <= std::numeric_limits::max() &&
"Invalid Operand Index.");
- const uint32_t AddrIndex = AddrWriter->getIndexFromAddress(
+ const uint32_t AddrIndex = AddressWriter.getIndexFromAddress(
EntryAddress->Address, Unit);
// update Index into .debug_address section for DW_AT_location.
// The Size field is not stored in IR, we need to minus 1 in
@@ -1249,7 +1262,7 @@ void DWARFRewriter::updateUnitDebugInfo(
std::lock_guard Lock(DWARFRewriterMutex);
if (Form == dwarf::DW_FORM_addrx ||
Form == dwarf::DW_FORM_GNU_addr_index) {
- const uint32_t Index = AddrWriter->getIndexFromAddress(
+ const uint32_t Index = AddressWriter.getIndexFromAddress(
NewAddress ? NewAddress : Address, Unit);
DIEBldr.replaceValue(Die, LowPCAttrInfo.getAttribute(),
LowPCAttrInfo.getForm(), DIEInteger(Index));
@@ -1512,7 +1525,8 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
void DWARFRewriter::finalizeDebugSections(
DIEBuilder &DIEBlder, DWARF5AcceleratorTable &DebugNamesTable,
- DIEStreamer &Streamer, raw_svector_ostream &ObjOS, CUOffsetMap &CUMap) {
+ DIEStreamer &Streamer, raw_svector_ostream &ObjOS, CUOffsetMap &CUMap,
+ DebugAddrWriter &FinalAddrWriter) {
if (StrWriter->isInitialized()) {
RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
std::unique_ptr DebugStrSectionContents =
@@ -1565,13 +1579,12 @@ void DWARFRewriter::finalizeDebugSections(
LocationListSectionContents->size());
}
- // AddrWriter should be finalized after debug_loc since more addresses can be
- // added there.
- if (AddrWriter->isInitialized()) {
- AddressSectionBuffer AddressSectionContents = AddrWriter->finalize();
+ if (FinalAddrWriter.isInitialized()) {
+ std::unique_ptr AddressSectionContents =
+ FinalAddrWriter.releaseBuffer();
BC.registerOrUpdateNoteSection(".debug_addr",
- copyByteArray(AddressSectionContents),
- AddressSectionContents.size());
+ copyByteArray(*AddressSectionContents),
+ AddressSectionContents->size());
}
Streamer.emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion());
@@ -1624,8 +1637,26 @@ void DWARFRewriter::finalizeDebugSections(
void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
DIEStreamer &Streamer,
CUOffsetMap &CUMap,
- const std::list &CUs) {
+ const std::list &CUs,
+ DebugAddrWriter &FinalAddrWriter) {
for (DWARFUnit *CU : CUs) {
+ auto AddressWriterIterator = AddressWritersByCU.find(CU->getOffset());
+ assert(AddressWriterIterator != AddressWritersByCU.end() &&
+ "AddressWriter does not exist for CU");
+ DebugAddrWriter *AddressWriter = AddressWriterIterator->second.get();
+ const size_t BufferOffset = FinalAddrWriter.getBufferSize();
+ std::optional Offset = AddressWriter->finalize(BufferOffset);
+ /// If Offset already exists in UnmodifiedAddressOffsets, then update with
+ /// Offset, else update with BufferOffset.
+ if (Offset)
+ AddressWriter->updateAddrBase(DIEBlder, *CU, *Offset);
+ else if (AddressWriter->isInitialized())
+ AddressWriter->updateAddrBase(DIEBlder, *CU, BufferOffset);
+ if (AddressWriter->isInitialized()) {
+ std::unique_ptr AddressSectionContents =
+ AddressWriter->releaseBuffer();
+ FinalAddrWriter.appendToAddressBuffer(*AddressSectionContents);
+ }
if (CU->getVersion() != 4)
continue;
std::optional DWOId = CU->getDWOId();
@@ -2155,6 +2186,10 @@ void DWARFRewriter::convertToRangesPatchDebugInfo(
// when it's absent.
if (IsUnitDie) {
if (LowForm == dwarf::DW_FORM_addrx) {
+ auto AddrWriterIterator = AddressWritersByCU.find(Unit.getOffset());
+ assert(AddrWriterIterator != AddressWritersByCU.end() &&
+ "AddressWriter does not exist for CU");
+ DebugAddrWriter *AddrWriter = AddrWriterIterator->second.get();
const uint32_t Index = AddrWriter->getIndexFromAddress(0, Unit);
DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(),
LowPCAttrInfo.getForm(), DIEInteger(Index));
diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
index 37136f4a5c5518..e46c42533031cd 100644
--- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
+++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
@@ -3241,12 +3241,6 @@ class X86MCPlusBuilder : public MCPlusBuilder {
return Insts;
}
- InstructionListType createDummyReturnFunction(MCContext *Ctx) const override {
- InstructionListType Insts(1);
- createReturn(Insts[0]);
- return Insts;
- }
-
BlocksVectorTy indirectCallPromotion(
const MCInst &CallInst,
const std::vector> &Targets,
diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp
index b9bc79f408a6b2..47375abb2ad3b4 100644
--- a/bolt/lib/Utils/CommandLineOpts.cpp
+++ b/bolt/lib/Utils/CommandLineOpts.cpp
@@ -105,6 +105,12 @@ cl::opt HeatmapMinAddress(
cl::desc("minimum address considered valid for heatmap (default 0)"),
cl::Optional, cl::cat(HeatmapCategory));
+cl::opt HeatmapPrintMappings(
+ "print-mappings", cl::init(false),
+ cl::desc("print mappings in the legend, between characters/blocks and text "
+ "sections (default false)"),
+ cl::Optional, cl::cat(HeatmapCategory));
+
cl::opt HotData("hot-data",
cl::desc("hot data symbols support (relocation mode)"),
cl::cat(BoltCategory));
diff --git a/bolt/test/AArch64/dummy-return.s b/bolt/test/AArch64/dummy-return.s
new file mode 100644
index 00000000000000..a4463431617301
--- /dev/null
+++ b/bolt/test/AArch64/dummy-return.s
@@ -0,0 +1,28 @@
+# REQUIRES: system-linux,target=aarch64{{.*}}
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static
+# RUN: llvm-bolt -instrument -instrumentation-sleep-time=1 %t.exe \
+# RUN: -o %t.instr 2>&1 | FileCheck %s
+# RUN: llvm-objdump --disassemble-symbols=__bolt_fini_trampoline %t.instr -D \
+# RUN: | FileCheck %s -check-prefix=CHECK-ASM
+
+# CHECK: BOLT-INFO: output linked against instrumentation runtime library
+# CHECK-ASM: <__bolt_fini_trampoline>:
+# CHECK-ASM-NEXT: ret
+
+ .text
+ .align 4
+ .global _start
+ .type _start, %function
+_start:
+ bl foo
+ ret
+ .size _start, .-_start
+
+ .global foo
+ .type foo, %function
+foo:
+ mov w0, wzr
+ ret
+ .size foo, .-foo
diff --git a/bolt/test/X86/dwarf5-addr-section-reuse.s b/bolt/test/X86/dwarf5-addr-section-reuse.s
index 6b00ce0fdf8059..cf511d6d111e07 100644
--- a/bolt/test/X86/dwarf5-addr-section-reuse.s
+++ b/bolt/test/X86/dwarf5-addr-section-reuse.s
@@ -1,7 +1,7 @@
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-main-addr-section-reuse.s -o %tmain.o
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-helper1-addr-section-reuse.s -o %thelper1.o
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-helper2-addr-section-reuse.s -o %thelper2.o
-# RUN: %clang %cflags -dwarf-5 %tmain.o %thelper1.o %thelper2.o -o %t.exe -Wl,-q
+# RUN: %clang %cflags -dwarf-5 %thelper1.o %tmain.o %thelper2.o -o %t.exe -Wl,-q
# RUN: llvm-dwarfdump --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-bolt %t.exe -o %t.exe.bolt --update-debug-sections
# RUN: llvm-dwarfdump --debug-info %t.exe.bolt | FileCheck --check-prefix=POSTCHECK %s
@@ -14,5 +14,5 @@
# PRECHECK: DW_AT_addr_base (0x00000008)
# POSTCHECK: DW_AT_addr_base (0x00000008)
-# POSTCHECK: DW_AT_addr_base (0x00000020)
-# POSTCHECK: DW_AT_addr_base (0x00000020)
+# POSTCHECK: DW_AT_addr_base (0x00000018)
+# POSTCHECK: DW_AT_addr_base (0x00000008)
diff --git a/bolt/test/X86/match-functions-with-calls-as-anchors.test b/bolt/test/X86/match-functions-with-calls-as-anchors.test
index 7fef128453a075..984d614fbf85f9 100644
--- a/bolt/test/X86/match-functions-with-calls-as-anchors.test
+++ b/bolt/test/X86/match-functions-with-calls-as-anchors.test
@@ -1,6 +1,6 @@
## Tests blocks matching by called function names in inferStaleProfile.
-# REQUIRES: system-linux
+# REQUIRES: system-linux, asserts
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib
diff --git a/clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp
index 9351a1c90ae546..4022ea0cdaf5ee 100644
--- a/clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp
@@ -331,12 +331,15 @@ utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {
UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context)
: utils::UseRangesCheck(Name, Context),
- IncludeBoostSystem(Options.get("IncludeBoostSystem", true)) {}
+ IncludeBoostSystem(Options.get("IncludeBoostSystem", true)),
+ UseReversePipe(Options.get("UseReversePipe", false)) {}
void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
utils::UseRangesCheck::storeOptions(Opts);
Options.store(Opts, "IncludeBoostSystem", IncludeBoostSystem);
+ Options.store(Opts, "UseReversePipe", UseReversePipe);
}
+
DiagnosticBuilder UseRangesCheck::createDiag(const CallExpr &Call) {
DiagnosticBuilder D =
diag(Call.getBeginLoc(), "use a %0 version of this algorithm");
@@ -362,10 +365,10 @@ UseRangesCheck::getReverseDescriptor() const {
{"::boost::rbegin", "::boost::rend"},
{"::boost::const_rbegin", "::boost::const_rend"},
};
- return ReverseIteratorDescriptor{"boost::adaptors::reverse",
- IncludeBoostSystem
- ? ""
- : "boost/range/adaptor/reversed.hpp",
- Refs};
+ return ReverseIteratorDescriptor{
+ UseReversePipe ? "boost::adaptors::reversed" : "boost::adaptors::reverse",
+ IncludeBoostSystem ? ""
+ : "boost/range/adaptor/reversed.hpp",
+ Refs, UseReversePipe};
}
} // namespace clang::tidy::boost
diff --git a/clang-tools-extra/clang-tidy/boost/UseRangesCheck.h b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.h
index a59ced12a6c438..b081c4c479b92a 100644
--- a/clang-tools-extra/clang-tidy/boost/UseRangesCheck.h
+++ b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.h
@@ -36,6 +36,7 @@ class UseRangesCheck : public utils::UseRangesCheck {
private:
bool IncludeBoostSystem;
+ bool UseReversePipe;
};
} // namespace clang::tidy::boost
diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
index f578f7ea71c08d..0b38b182081947 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
@@ -95,7 +95,7 @@ static bool haveSameNamespaceOrTranslationUnit(const CXXRecordDecl *Decl1,
"ParentDecl2 declaration must be a namespace");
auto *Ns1 = NamespaceDecl::castFromDeclContext(ParentDecl1);
auto *Ns2 = NamespaceDecl::castFromDeclContext(ParentDecl2);
- return Ns1->getOriginalNamespace() == Ns2->getOriginalNamespace();
+ return Ns1->getFirstDecl() == Ns2->getFirstDecl();
}
static std::string getNameOfNamespace(const CXXRecordDecl *Decl) {
diff --git a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
index f99beac668ce72..46bf20e34ce041 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
@@ -42,6 +42,7 @@ ImplicitWideningOfMultiplicationResultCheck::
UseCXXStaticCastsInCppSources(
Options.get("UseCXXStaticCastsInCppSources", true)),
UseCXXHeadersInCppSources(Options.get("UseCXXHeadersInCppSources", true)),
+ IgnoreConstantIntExpr(Options.get("IgnoreConstantIntExpr", false)),
IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
utils::IncludeSorter::IS_LLVM),
areDiagsSelfContained()) {}
@@ -56,6 +57,7 @@ void ImplicitWideningOfMultiplicationResultCheck::storeOptions(
Options.store(Opts, "UseCXXStaticCastsInCppSources",
UseCXXStaticCastsInCppSources);
Options.store(Opts, "UseCXXHeadersInCppSources", UseCXXHeadersInCppSources);
+ Options.store(Opts, "IgnoreConstantIntExpr", IgnoreConstantIntExpr);
Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
}
@@ -84,6 +86,19 @@ void ImplicitWideningOfMultiplicationResultCheck::handleImplicitCastExpr(
if (TgtWidth <= SrcWidth)
return;
+ // Is the expression a compile-time constexpr that we know can fit in the
+ // source type?
+ if (IgnoreConstantIntExpr && ETy->isIntegerType() &&
+ !ETy->isUnsignedIntegerType()) {
+ if (const auto ConstExprResult = E->getIntegerConstantExpr(*Context)) {
+ const auto TypeSize = Context->getTypeSize(ETy);
+ llvm::APSInt WidenedResult = ConstExprResult->extOrTrunc(TypeSize);
+ if (WidenedResult <= llvm::APSInt::getMaxValue(TypeSize, false) &&
+ WidenedResult >= llvm::APSInt::getMinValue(TypeSize, false))
+ return;
+ }
+ }
+
// Does the index expression look like it might be unintentionally computed
// in a narrower-than-wanted type?
const Expr *LHS = getLHSOfMulBinOp(E);
diff --git a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.h b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.h
index 8b99930ae7a899..077a4b847cd9c5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.h
@@ -41,6 +41,7 @@ class ImplicitWideningOfMultiplicationResultCheck : public ClangTidyCheck {
private:
const bool UseCXXStaticCastsInCppSources;
const bool UseCXXHeadersInCppSources;
+ const bool IgnoreConstantIntExpr;
utils::IncludeInserter IncludeInserter;
};
diff --git a/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp
index 5c7b315f43173b..b0a31ad53be3f7 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp
@@ -166,6 +166,15 @@ utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {
return Result;
}
+UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context)
+ : utils::UseRangesCheck(Name, Context),
+ UseReversePipe(Options.get("UseReversePipe", false)) {}
+
+void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ utils::UseRangesCheck::storeOptions(Opts);
+ Options.store(Opts, "UseReversePipe", UseReversePipe);
+}
+
bool UseRangesCheck::isLanguageVersionSupported(
const LangOptions &LangOpts) const {
return LangOpts.CPlusPlus20;
@@ -180,6 +189,8 @@ std::optional
UseRangesCheck::getReverseDescriptor() const {
static const std::pair Refs[] = {
{"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}};
- return ReverseIteratorDescriptor{"std::views::reverse", "", Refs};
+ return ReverseIteratorDescriptor{UseReversePipe ? "std::views::reverse"
+ : "std::ranges::reverse_view",
+ "", Refs, UseReversePipe};
}
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h
index 2f7613dd1cd246..2f4cace653cf19 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h
@@ -20,7 +20,9 @@ namespace clang::tidy::modernize {
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-ranges.html
class UseRangesCheck : public utils::UseRangesCheck {
public:
- using utils::UseRangesCheck::UseRangesCheck;
+ UseRangesCheck(StringRef CheckName, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Options) override;
ReplacerMap getReplacerMap() const override;
@@ -31,6 +33,9 @@ class UseRangesCheck : public utils::UseRangesCheck {
getReverseDescriptor() const override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
+
+private:
+ bool UseReversePipe;
};
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
index c507043c367a86..5a4c2363bd8af0 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -75,7 +75,7 @@ void UnnecessaryValueParamCheck::registerMatchers(MatchFinder *Finder) {
functionDecl(hasBody(stmt()), isDefinition(), unless(isImplicit()),
unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))),
has(typeLoc(forEach(ExpensiveValueParamDecl))),
- unless(isInstantiated()), decl().bind("functionDecl"))),
+ decl().bind("functionDecl"))),
this);
}
@@ -133,12 +133,11 @@ void UnnecessaryValueParamCheck::check(const MatchFinder::MatchResult &Result) {
// 2. the function is virtual as it might break overrides
// 3. the function is referenced outside of a call expression within the
// compilation unit as the signature change could introduce build errors.
- // 4. the function is a primary template or an explicit template
- // specialization.
+ // 4. the function is an explicit template/ specialization.
const auto *Method = llvm::dyn_cast(Function);
if (Param->getBeginLoc().isMacroID() || (Method && Method->isVirtual()) ||
isReferencedOutsideOfCallExpr(*Function, *Result.Context) ||
- (Function->getTemplatedKind() != FunctionDecl::TK_NonTemplate))
+ Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
return;
for (const auto *FunctionDecl = Function; FunctionDecl != nullptr;
FunctionDecl = FunctionDecl->getPreviousDecl()) {
diff --git a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp
index 9c59e4651953ac..e2daa5010e2aeb 100644
--- a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp
@@ -242,16 +242,20 @@ void UseRangesCheck::check(const MatchFinder::MatchResult &Result) {
Diag << Inserter.createIncludeInsertion(
Result.SourceManager->getFileID(Call->getBeginLoc()),
*ReverseDescriptor->ReverseHeader);
+ StringRef ArgText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(ArgExpr->getSourceRange()),
+ Result.Context->getSourceManager(), Result.Context->getLangOpts());
+ SmallString<128> ReplaceText;
+ if (ReverseDescriptor->IsPipeSyntax)
+ ReplaceText.assign(
+ {ArgText, " | ", ReverseDescriptor->ReverseAdaptorName});
+ else
+ ReplaceText.assign(
+ {ReverseDescriptor->ReverseAdaptorName, "(", ArgText, ")"});
Diag << FixItHint::CreateReplacement(
Call->getArg(Replace == Indexes::Second ? Second : First)
->getSourceRange(),
- SmallString<128>{
- ReverseDescriptor->ReverseAdaptorName, "(",
- Lexer::getSourceText(
- CharSourceRange::getTokenRange(ArgExpr->getSourceRange()),
- Result.Context->getSourceManager(),
- Result.Context->getLangOpts()),
- ")"});
+ ReplaceText);
}
ToRemove.push_back(Replace == Indexes::Second ? First : Second);
}
diff --git a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h
index 8227d8f7bbbddf..927e9694b0ec7c 100644
--- a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h
+++ b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h
@@ -38,6 +38,7 @@ class UseRangesCheck : public ClangTidyCheck {
StringRef ReverseAdaptorName;
std::optional ReverseHeader;
ArrayRef> FreeReverseNames;
+ bool IsPipeSyntax = false;
};
class Replacer : public llvm::RefCountedBase {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index c1fa502534ea52..004811d2eca4f4 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -245,6 +245,11 @@ Changes in existing checks
`
check to ignore deleted constructors which won't hide other overloads.
+- Improved :doc:`bugprone-implicit-widening-of-multiplication-result
+ ` check
+ by adding an option to ignore constant expressions of signed integer types
+ that fit in the source expression type.
+
- Improved :doc:`bugprone-inc-dec-in-conditions
` check to ignore code
within unevaluated contexts, such as ``decltype``.
@@ -437,6 +442,12 @@ Changes in existing checks
Calls to mutable function where there exists a `const` overload are also
handled. Fix crash in the case of a non-member operator call.
+- Improved :doc:`performance-unnecessary-value-param
+ ` check
+ detecting more cases for template functions including lambdas with ``auto``.
+ E.g., ``std::sort(a.begin(), a.end(), [](auto x, auto y) { return a > b; });``
+ will be detected for expensive to copy types.
+
- Improved :doc:`readability-avoid-return-with-void-value
` check by adding
fix-its.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/boost/use-ranges.rst b/clang-tools-extra/docs/clang-tidy/checks/boost/use-ranges.rst
index 39be52fdcf7b91..4c032ad32f4fd8 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/boost/use-ranges.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/boost/use-ranges.rst
@@ -154,8 +154,8 @@ Transforms to:
.. code-block:: c++
- auto AreSame = std::equal(boost::adaptors::reverse(Items1),
- boost::adaptors::reverse(Items2));
+ auto AreSame = boost::range::equal(boost::adaptors::reverse(Items1),
+ boost::adaptors::reverse(Items2));
Options
-------
@@ -170,3 +170,18 @@ Options
If `true` (default value) the boost headers are included as system headers
with angle brackets (`#include `), otherwise quotes are used
(`#include "boost.hpp"`).
+
+.. option:: UseReversePipe
+
+ When `true` (default `false`), fixes which involve reverse ranges will use the
+ pipe adaptor syntax instead of the function syntax.
+
+ .. code-block:: c++
+
+ std::find(Items.rbegin(), Items.rend(), 0);
+
+ Transforms to:
+
+ .. code-block:: c++
+
+ boost::range::find(Items | boost::adaptors::reversed, 0);
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result.rst
index c4ddd02602b73d..117310d404f6f4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result.rst
@@ -45,6 +45,12 @@ Options
should ```` header be suggested, or ````.
Defaults to ``true``.
+.. option:: IgnoreConstantIntExpr
+
+ If the multiplication operands are compile-time constants (like literals or
+ are ``constexpr``) and fit within the source expression type, do not emit a
+ diagnostic or suggested fix. Only considers expressions where the source
+ expression is a signed integer type. Defaults to ``false``.
Examples:
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst
index 86af6b0eeb8e03..5c0b8058e4535f 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst
@@ -116,8 +116,8 @@ Transforms to:
.. code-block:: c++
- auto AreSame = std::equal(std::views::reverse(Items1),
- std::views::reverse(Items2));
+ auto AreSame = std::ranges::equal(std::ranges::reverse_view(Items1),
+ std::ranges::reverse_view(Items2));
Options
-------
@@ -127,3 +127,17 @@ Options
A string specifying which include-style is used, `llvm` or `google`. Default
is `llvm`.
+.. option:: UseReversePipe
+
+ When `true` (default `false`), fixes which involve reverse ranges will use the
+ pipe adaptor syntax instead of the function syntax.
+
+ .. code-block:: c++
+
+ std::find(Items.rbegin(), Items.rend(), 0);
+
+ Transforms to:
+
+ .. code-block:: c++
+
+ std::ranges::find(Items | std::views::reverse, 0);
diff --git a/clang-tools-extra/test/clang-doc/basic-project.test b/clang-tools-extra/test/clang-doc/basic-project.test
index bab5f8e1761bc6..51d3ac6ce6dcdb 100644
--- a/clang-tools-extra/test/clang-doc/basic-project.test
+++ b/clang-tools-extra/test/clang-doc/basic-project.test
@@ -54,306 +54,181 @@
// JSON-INDEX-NEXT: };
// JSON-INDEX-NEXT: }
-// HTML-SHAPE:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT: class Shape
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
class Shape
-// HTML-SHAPE-NEXT:
Defined at line 8 of file {{.*}}Shape.h
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
Provides a common interface for different types of shapes.
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
Functions
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
~Shape
-// HTML-SHAPE-NEXT:
public void ~Shape()
-// HTML-SHAPE-NEXT:
Defined at line 13 of file {{.*}}Shape.h
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
area
-// HTML-SHAPE-NEXT:
public double area()
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
perimeter
-// HTML-SHAPE-NEXT:
public double perimeter()
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
-// HTML-SHAPE-NEXT:
+// HTML-SHAPE: class Shape
+// HTML-SHAPE: Defined at line 8 of file {{.*}}Shape.h
+// HTML-SHAPE: Provides a common interface for different types of shapes.
+// HTML-SHAPE: Functions
+// HTML-SHAPE: ~Shape
+// HTML-SHAPE: public void ~Shape()
+// HTML-SHAPE: Defined at line 13 of file {{.*}}Shape.h
+// HTML-SHAPE: area
+// HTML-SHAPE: public double area()
+// HTML-SHAPE: perimeter
+// HTML-SHAPE: public double perimeter()
-// HTML-CALC:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT: class Calculator
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
class Calculator
-// HTML-CALC-NEXT:
Defined at line 8 of file {{.*}}Calculator.h
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
Provides basic arithmetic operations.
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
Functions
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
add
-// HTML-CALC-NEXT:
public int add(int a, int b)
-// HTML-CALC-NEXT:
Defined at line 3 of file {{.*}}Calculator.cpp
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
subtract
-// HTML-CALC-NEXT:
public int subtract(int a, int b)
-// HTML-CALC-NEXT:
Defined at line 7 of file {{.*}}Calculator.cpp
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
multiply
-// HTML-CALC-NEXT:
public int multiply(int a, int b)
-// HTML-CALC-NEXT:
Defined at line 11 of file {{.*}}Calculator.cpp
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
divide
-// HTML-CALC-NEXT:
public double divide(int a, int b)
-// HTML-CALC-NEXT:
Defined at line 15 of file {{.*}}Calculator.cpp
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
-// HTML-CALC-NEXT:
+// HTML-CALC: class Calculator
+// HTML-CALC: Defined at line 8 of file {{.*}}Calculator.h
+// HTML-CALC: Provides basic arithmetic operations.
+// HTML-CALC: Functions
+// HTML-CALC: add
+// HTML-CALC: public int add(int a, int b)
+// HTML-CALC: Defined at line 3 of file {{.*}}Calculator.cpp
+// HTML-CALC: subtract
+// HTML-CALC: public int subtract(int a, int b)
+// HTML-CALC: Defined at line 7 of file {{.*}}Calculator.cpp
+// HTML-CALC: multiply
+// HTML-CALC: public int multiply(int a, int b)
+// HTML-CALC: Defined at line 11 of file {{.*}}Calculator.cpp
+// HTML-CALC: divide
+// HTML-CALC: public double divide(int a, int b)
+// HTML-CALC: Defined at line 15 of file {{.*}}Calculator.cpp
-// HTML-RECTANGLE:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT: class Rectangle
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
class Rectangle
-// HTML-RECTANGLE-NEXT:
Defined at line 10 of file {{.*}}Rectangle.h
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
Represents a rectangle with a given width and height.
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT: Inherits from
-// HTML-RECTANGLE-NEXT: Shape
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
Members
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT: - private double width_
-// HTML-RECTANGLE-NEXT: - private double height_
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
Functions
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
Rectangle
-// HTML-RECTANGLE-NEXT:
public void Rectangle(double width, double height)
-// HTML-RECTANGLE-NEXT:
Defined at line 3 of file {{.*}}Rectangle.cpp
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
area
-// HTML-RECTANGLE-NEXT:
public double area()
-// HTML-RECTANGLE-NEXT:
Defined at line 6 of file {{.*}}Rectangle.cpp
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
perimeter
-// HTML-RECTANGLE-NEXT:
public double perimeter()
-// HTML-RECTANGLE-NEXT:
Defined at line 10 of file {{.*}}Rectangle.cpp
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
-// HTML-RECTANGLE-NEXT:
+// HTML-RECTANGLE: class Rectangle
+// HTML-RECTANGLE: Defined at line 10 of file {{.*}}Rectangle.h
+// HTML-RECTANGLE: Represents a rectangle with a given width and height.
+// HTML-RECTANGLE: Inherits from
+// HTML-RECTANGLE: Shape
+// HTML-RECTANGLE:
+// HTML-RECTANGLE: Members
+// HTML-RECTANGLE: private double width_
+// HTML-RECTANGLE: private double height_
+// HTML-RECTANGLE: Functions
+// HTML-RECTANGLE: Rectangle
+// HTML-RECTANGLE: public void Rectangle(double width, double height)
+// HTML-RECTANGLE: Defined at line 3 of file {{.*}}Rectangle.cpp
+// HTML-RECTANGLE: area
+// HTML-RECTANGLE: public double area()
+// HTML-RECTANGLE: Defined at line 6 of file {{.*}}Rectangle.cpp
+// HTML-RECTANGLE: perimeter
+// HTML-RECTANGLE: public double perimeter()
+// HTML-RECTANGLE: Defined at line 10 of file {{.*}}Rectangle.cpp
-// HTML-CIRCLE:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT: class Circle
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
class Circle
-// HTML-CIRCLE-NEXT:
Defined at line 10 of file {{.*}}Circle.h
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
Represents a circle with a given radius.
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT: Inherits from
-// HTML-CIRCLE-NEXT: Shape
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
Members
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT: - private double radius_
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
Functions
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
Circle
-// HTML-CIRCLE-NEXT:
public void Circle(double radius)
-// HTML-CIRCLE-NEXT:
Defined at line 3 of file {{.*}}Circle.cpp
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
area
-// HTML-CIRCLE-NEXT:
public double area()
-// HTML-CIRCLE-NEXT:
Defined at line 5 of file {{.*}}Circle.cpp
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
perimeter
-// HTML-CIRCLE-NEXT:
public double perimeter()
-// HTML-CIRCLE-NEXT:
Defined at line 9 of file {{.*}}Circle.cpp
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
-// HTML-CIRCLE-NEXT:
\ No newline at end of file
+// HTML-CIRCLE: class Circle
+// HTML-CIRCLE: Defined at line 10 of file {{.*}}Circle.h
+// HTML-CIRCLE: Represents a circle with a given radius.
+// HTML-CIRCLE:
+// HTML-CIRCLE: Inherits from
+// HTML-CIRCLE: Shape
+// HTML-CIRCLE:
+// HTML-CIRCLE: Members
+// HTML-CIRCLE: private double radius_
+// HTML-CIRCLE: Functions
+// HTML-CIRCLE: Circle
+// HTML-CIRCLE: public void Circle(double radius)
+// HTML-CIRCLE: Defined at line 3 of file {{.*}}Circle.cpp
+// HTML-CIRCLE: area
+// HTML-CIRCLE: public double area()
+// HTML-CIRCLE: Defined at line 5 of file {{.*}}Circle.cpp
+// HTML-CIRCLE: perimeter
+// HTML-CIRCLE: public double perimeter()
+// HTML-CIRCLE: Defined at line 9 of file {{.*}}Circle.cpp
+
+// MD-CALC: # class Calculator
+// MD-CALC: *Defined at .{{[\/]}}include{{[\/]}}Calculator.h#8*
+// MD-CALC: **brief** A simple calculator class.
+// MD-CALC: Provides basic arithmetic operations.
+// MD-CALC: ## Functions
+// MD-CALC: ### add
+// MD-CALC: *public int add(int a, int b)*
+// MD-CALC: *Defined at .{{[\/]}}src{{[\/]}}Calculator.cpp#3*
+// MD-CALC: **brief** Adds two integers.
+// MD-CALC: **a** First integer.
+// MD-CALC: **b** Second integer.
+// MD-CALC: **return** int The sum of a and b.
+// MD-CALC: ### subtract
+// MD-CALC: *public int subtract(int a, int b)*
+// MD-CALC: *Defined at .{{[\/]}}src{{[\/]}}Calculator.cpp#7*
+// MD-CALC: **brief** Subtracts the second integer from the first.
+// MD-CALC: **a** First integer.
+// MD-CALC: **b** Second integer.
+// MD-CALC: **return** int The result of a - b.
+// MD-CALC: ### multiply
+// MD-CALC: *public int multiply(int a, int b)*
+// MD-CALC: *Defined at .{{[\/]}}src{{[\/]}}Calculator.cpp#11*
+// MD-CALC: **brief** Multiplies two integers.
+// MD-CALC: **a** First integer.
+// MD-CALC: **b** Second integer.
+// MD-CALC: **return** int The product of a and b.
+// MD-CALC: ### divide
+// MD-CALC: *public double divide(int a, int b)*
+// MD-CALC: *Defined at .{{[\/]}}src{{[\/]}}Calculator.cpp#15*
+// MD-CALC: **brief** Divides the first integer by the second.
+// MD-CALC: **a** First integer.
+// MD-CALC: **b** Second integer.
+// MD-CALC: **return** double The result of a / b.
+// MD-CALC: **throw**if b is zero.
+
+// MD-CIRCLE: # class Circle
+// MD-CIRCLE: *Defined at .{{[\/]}}include{{[\/]}}Circle.h#10*
+// MD-CIRCLE: **brief** Circle class derived from Shape.
+// MD-CIRCLE: Represents a circle with a given radius.
+// MD-CIRCLE: Inherits from Shape
+// MD-CIRCLE: ## Members
+// MD-CIRCLE: private double radius_
+// MD-CIRCLE: ## Functions
+// MD-CIRCLE: ### Circle
+// MD-CIRCLE: *public void Circle(double radius)*
+// MD-CIRCLE: *Defined at .{{[\/]}}src{{[\/]}}Circle.cpp#3*
+// MD-CIRCLE: **brief** Constructs a new Circle object.
+// MD-CIRCLE: **radius** Radius of the circle.
+// MD-CIRCLE: ### area
+// MD-CIRCLE: *public double area()*
+// MD-CIRCLE: *Defined at .{{[\/]}}src{{[\/]}}Circle.cpp#5*
+// MD-CIRCLE: **brief** Calculates the area of the circle.
+// MD-CIRCLE: **return** double The area of the circle.
+// MD-CIRCLE: ### perimeter
+// MD-CIRCLE: *public double perimeter()*
+// MD-CIRCLE: *Defined at .{{[\/]}}src{{[\/]}}Circle.cpp#9*
+// MD-CIRCLE: **brief** Calculates the perimeter of the circle.
+// MD-CIRCLE: **return** double The perimeter of the circle.
+
+// MD-RECTANGLE: # class Rectangle
+// MD-RECTANGLE: *Defined at .{{[\/]}}include{{[\/]}}Rectangle.h#10*
+// MD-RECTANGLE: **brief** Rectangle class derived from Shape.
+// MD-RECTANGLE: Represents a rectangle with a given width and height.
+// MD-RECTANGLE: Inherits from Shape
+// MD-RECTANGLE: ## Members
+// MD-RECTANGLE: private double width_
+// MD-RECTANGLE: private double height_
+// MD-RECTANGLE: ## Functions
+// MD-RECTANGLE: ### Rectangle
+// MD-RECTANGLE: *public void Rectangle(double width, double height)*
+// MD-RECTANGLE: *Defined at .{{[\/]}}src{{[\/]}}Rectangle.cpp#3*
+// MD-RECTANGLE: **brief** Constructs a new Rectangle object.
+// MD-RECTANGLE: **width** Width of the rectangle.
+// MD-RECTANGLE: **height** Height of the rectangle.
+// MD-RECTANGLE: ### area
+// MD-RECTANGLE: *public double area()*
+// MD-RECTANGLE: *Defined at .{{[\/]}}src{{[\/]}}Rectangle.cpp#6*
+// MD-RECTANGLE: **brief** Calculates the area of the rectangle.
+// MD-RECTANGLE: **return** double The area of the rectangle.
+// MD-RECTANGLE: ### perimeter
+// MD-RECTANGLE: *public double perimeter()*
+// MD-RECTANGLE: *Defined at .{{[\/]}}src{{[\/]}}Rectangle.cpp#10*
+// MD-RECTANGLE: **brief** Calculates the perimeter of the rectangle.
+// MD-RECTANGLE: **return** double The perimeter of the rectangle.
+
+// MD-SHAPE: # class Shape
+// MD-SHAPE: *Defined at .{{[\/]}}include{{[\/]}}Shape.h#8*
+// MD-SHAPE: **brief** Abstract base class for shapes.
+// MD-SHAPE: Provides a common interface for different types of shapes.
+// MD-SHAPE: ## Functions
+// MD-SHAPE: ### ~Shape
+// MD-SHAPE: *public void ~Shape()*
+// MD-SHAPE: *Defined at .{{[\/]}}include{{[\/]}}Shape.h#13*
+// MD-SHAPE: **brief** Virtual destructor.
+// MD-SHAPE: ### area
+// MD-SHAPE: *public double area()*
+// MD-SHAPE: **brief** Calculates the area of the shape.
+// MD-SHAPE: **return** double The area of the shape.
+// MD-SHAPE: ### perimeter
+// MD-SHAPE: *public double perimeter()*
+// MD-SHAPE: **brief** Calculates the perimeter of the shape.
+// MD-SHAPE: **return** double The perimeter of the shape.
+
+// MD-ALL-FILES: # All Files
+// MD-ALL-FILES: ## [GlobalNamespace](GlobalNamespace{{[\/]}}index.md)
+
+// MD-INDEX: # C/C++ Reference
+// MD-INDEX: * Namespace: [GlobalNamespace](GlobalNamespace)
\ No newline at end of file
diff --git a/clang-tools-extra/test/clang-tidy/checkers/boost/Inputs/use-ranges/fake_boost.h b/clang-tools-extra/test/clang-tidy/checkers/boost/Inputs/use-ranges/fake_boost.h
new file mode 100644
index 00000000000000..3664367a601109
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/boost/Inputs/use-ranges/fake_boost.h
@@ -0,0 +1,29 @@
+#ifndef USE_RANGES_FAKE_BOOST_H
+#define USE_RANGES_FAKE_BOOST_H
+
+namespace boost {
+namespace range_adl_barrier {
+
+template void *begin(T &);
+template void *end(T &);
+template void *const_begin(const T &);
+template void *const_end(const T &);
+} // namespace range_adl_barrier
+
+using namespace range_adl_barrier;
+
+template void *rbegin(T &);
+template void *rend(T &);
+
+template void *const_rbegin(T &);
+template void *const_rend(T &);
+namespace algorithm {
+
+template
+T reduce(InputIterator first, InputIterator last, T init, BinaryOperation bOp) {
+ return init;
+}
+} // namespace algorithm
+} // namespace boost
+
+#endif // USE_RANGES_FAKE_BOOST_H
diff --git a/clang-tools-extra/test/clang-tidy/checkers/boost/Inputs/use-ranges/fake_std.h b/clang-tools-extra/test/clang-tidy/checkers/boost/Inputs/use-ranges/fake_std.h
new file mode 100644
index 00000000000000..7c3e39d6000d20
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/boost/Inputs/use-ranges/fake_std.h
@@ -0,0 +1,99 @@
+#ifndef USE_RANGES_FAKE_STD_H
+#define USE_RANGES_FAKE_STD_H
+namespace std {
+
+template class vector {
+public:
+ using iterator = T *;
+ using const_iterator = const T *;
+ using reverse_iterator = T*;
+ using reverse_const_iterator = const T*;
+
+ constexpr const_iterator begin() const;
+ constexpr const_iterator end() const;
+ constexpr const_iterator cbegin() const;
+ constexpr const_iterator cend() const;
+ constexpr iterator begin();
+ constexpr iterator end();
+ constexpr reverse_const_iterator rbegin() const;
+ constexpr reverse_const_iterator rend() const;
+ constexpr reverse_const_iterator crbegin() const;
+ constexpr reverse_const_iterator crend() const;
+ constexpr reverse_iterator rbegin();
+ constexpr reverse_iterator rend();
+};
+
+template constexpr auto begin(const Container &Cont) {
+ return Cont.begin();
+}
+
+template constexpr auto begin(Container &Cont) {
+ return Cont.begin();
+}
+
+template constexpr auto end(const Container &Cont) {
+ return Cont.end();
+}
+
+template constexpr auto end(Container &Cont) {
+ return Cont.end();
+}
+
+template constexpr auto cbegin(const Container &Cont) {
+ return Cont.cbegin();
+}
+
+template constexpr auto cend(const Container &Cont) {
+ return Cont.cend();
+}
+// Find
+template< class InputIt, class T >
+InputIt find(InputIt first, InputIt last, const T& value);
+
+template void reverse(Iter begin, Iter end);
+
+template
+bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
+
+template
+bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2,
+ ForwardIt2 last2);
+
+template
+bool next_permutation(BidirIt first, BidirIt last);
+
+inline namespace inline_test{
+
+template
+bool equal(ForwardIt1 first1, ForwardIt1 last1,
+ ForwardIt2 first2, ForwardIt2 last2);
+
+template
+void push_heap(RandomIt first, RandomIt last);
+
+template
+OutputIt copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPred pred);
+
+template
+ForwardIt is_sorted_until(ForwardIt first, ForwardIt last);
+
+template
+void reduce(InputIt first, InputIt last);
+
+template
+T reduce(InputIt first, InputIt last, T init);
+
+template
+T reduce(InputIt first, InputIt last, T init, BinaryOp op) {
+ // Need a definition to suppress undefined_internal_type when invoked with lambda
+ return init;
+}
+
+template
+T accumulate(InputIt first, InputIt last, T init);
+
+} // namespace inline_test
+
+} // namespace std
+
+#endif // USE_RANGES_FAKE_STD_H
diff --git a/clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges-pipe.cpp b/clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges-pipe.cpp
new file mode 100644
index 00000000000000..c0ce3748400981
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges-pipe.cpp
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy -std=c++14 %s boost-use-ranges %t -check-suffixes=,PIPE \
+// RUN: -config="{CheckOptions: { \
+// RUN: boost-use-ranges.UseReversePipe: true }}" -- -I %S/Inputs/use-ranges/
+// RUN: %check_clang_tidy -std=c++14 %s boost-use-ranges %t -check-suffixes=,NOPIPE -- -I %S/Inputs/use-ranges/
+
+// CHECK-FIXES: #include
+// CHECK-FIXES: #include
+
+#include "fake_std.h"
+
+void stdLib() {
+ std::vector I;
+ std::is_sorted_until(I.rbegin(), I.rend());
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use a boost version of this algorithm
+ // CHECK-FIXES-NOPIPE: boost::algorithm::is_sorted_until(boost::adaptors::reverse(I));
+ // CHECK-FIXES-PIPE: boost::algorithm::is_sorted_until(I | boost::adaptors::reversed);
+
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges.cpp b/clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges.cpp
index 3f3d6f1abec9f4..06e70267da83a7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges.cpp
@@ -1,5 +1,5 @@
-// RUN: %check_clang_tidy -std=c++14 %s boost-use-ranges %t
-// RUN: %check_clang_tidy -std=c++17 %s boost-use-ranges %t -check-suffixes=,CPP17
+// RUN: %check_clang_tidy -std=c++14 %s boost-use-ranges %t -- -- -I %S/Inputs/use-ranges/
+// RUN: %check_clang_tidy -std=c++17 %s boost-use-ranges %t -check-suffixes=,CPP17 -- -I %S/Inputs/use-ranges/
// CHECK-FIXES: #include
// CHECK-FIXES: #include
@@ -13,111 +13,8 @@
// CHECK-FIXES: #include
// CHECK-FIXES: #include
-namespace std {
-
-template class vector {
-public:
- using iterator = T *;
- using const_iterator = const T *;
- constexpr const_iterator begin() const;
- constexpr const_iterator end() const;
- constexpr const_iterator cbegin() const;
- constexpr const_iterator cend() const;
- constexpr iterator begin();
- constexpr iterator end();
-};
-
-template constexpr auto begin(const Container &Cont) {
- return Cont.begin();
-}
-
-template constexpr auto begin(Container &Cont) {
- return Cont.begin();
-}
-
-template constexpr auto end(const Container &Cont) {
- return Cont.end();
-}
-
-template constexpr auto end(Container &Cont) {
- return Cont.end();
-}
-
-template constexpr auto cbegin(const Container &Cont) {
- return Cont.cbegin();
-}
-
-template constexpr auto cend(const Container &Cont) {
- return Cont.cend();
-}
-// Find
-template< class InputIt, class T >
-InputIt find(InputIt first, InputIt last, const T& value);
-
-template void reverse(Iter begin, Iter end);
-
-template
-bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
-
-template
-bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2,
- ForwardIt2 last2);
-
-template
-bool next_permutation(BidirIt first, BidirIt last);
-
-template
-bool equal(ForwardIt1 first1, ForwardIt1 last1,
- ForwardIt2 first2, ForwardIt2 last2);
-
-template
-void push_heap(RandomIt first, RandomIt last);
-
-template
-OutputIt copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPred pred);
-
-template
-ForwardIt is_sorted_until(ForwardIt first, ForwardIt last);
-
-template
-void reduce(InputIt first, InputIt last);
-
-template
-T reduce(InputIt first, InputIt last, T init);
-
-template
-T reduce(InputIt first, InputIt last, T init, BinaryOp op) {
- // Need a definition to suppress undefined_internal_type when invoked with lambda
- return init;
-}
-
-template
-T accumulate(InputIt first, InputIt last, T init);
-
-} // namespace std
-
-namespace boost {
-namespace range_adl_barrier {
-template void *begin(T &);
-template void *end(T &);
-template void *const_begin(const T &);
-template void *const_end(const T &);
-} // namespace range_adl_barrier
-using namespace range_adl_barrier;
-
-template void *rbegin(T &);
-template void *rend(T &);
-
-template void *const_rbegin(T &);
-template void *const_rend(T &);
-namespace algorithm {
-
-template
-T reduce(InputIterator first, InputIterator last, T init, BinaryOperation bOp) {
- return init;
-}
-} // namespace algorithm
-} // namespace boost
+#include "fake_boost.h"
+#include "fake_std.h"
bool returnTrue(int val) {
return true;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-constants.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-constants.cpp
new file mode 100644
index 00000000000000..d7ab8a7a44fe68
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-constants.cpp
@@ -0,0 +1,56 @@
+// RUN: %check_clang_tidy %s bugprone-implicit-widening-of-multiplication-result %t -- \
+// RUN: -config='{CheckOptions: { \
+// RUN: bugprone-implicit-widening-of-multiplication-result.IgnoreConstantIntExpr: true \
+// RUN: }}' -- -target x86_64-unknown-unknown -x c++
+
+long t0() {
+ return 1 * 4;
+}
+
+unsigned long t1() {
+ const int a = 2;
+ const int b = 3;
+ return a * b;
+}
+
+long t2() {
+ constexpr int a = 16383; // ~1/2 of int16_t max
+ constexpr int b = 2;
+ return a * b;
+}
+
+constexpr int global_value() {
+ return 16;
+}
+
+unsigned long t3() {
+ constexpr int a = 3;
+ return a * global_value();
+}
+
+long t4() {
+ const char a = 3;
+ const short b = 2;
+ const int c = 5;
+ return c * b * a;
+}
+
+long t5() {
+ constexpr int min_int = (-2147483647 - 1); // A literal of -2147483648 evaluates to long
+ return 1 * min_int;
+}
+
+unsigned long n0() {
+ const int a = 1073741824; // 1/2 of int32_t max
+ const int b = 3;
+ return a * b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: performing an implicit widening conversion to type 'unsigned long' of a multiplication performed in type 'int'
+ // CHECK-MESSAGES: :[[@LINE-2]]:10: note: make conversion explicit to silence this warning
+ // CHECK-MESSAGES: static_cast( )
+ // CHECK-MESSAGES: :[[@LINE-4]]:10: note: perform multiplication in a wider type
+}
+
+double n1() {
+ const long a = 100000000;
+ return a * 400;
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h
new file mode 100644
index 00000000000000..987ee4e35b3bcd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h
@@ -0,0 +1,111 @@
+#ifndef USE_RANGES_FAKE_STD_H
+#define USE_RANGES_FAKE_STD_H
+
+namespace std {
+
+template class vector {
+public:
+ using iterator = T *;
+ using const_iterator = const T *;
+ using reverse_iterator = T*;
+ using reverse_const_iterator = const T*;
+
+ constexpr const_iterator begin() const;
+ constexpr const_iterator end() const;
+ constexpr const_iterator cbegin() const;
+ constexpr const_iterator cend() const;
+ constexpr iterator begin();
+ constexpr iterator end();
+ constexpr reverse_const_iterator rbegin() const;
+ constexpr reverse_const_iterator rend() const;
+ constexpr reverse_const_iterator crbegin() const;
+ constexpr reverse_const_iterator crend() const;
+ constexpr reverse_iterator rbegin();
+ constexpr reverse_iterator rend();
+};
+
+template constexpr auto begin(const Container &Cont) {
+ return Cont.begin();
+}
+
+template constexpr auto begin(Container &Cont) {
+ return Cont.begin();
+}
+
+template constexpr auto end(const Container &Cont) {
+ return Cont.end();
+}
+
+template constexpr auto end(Container &Cont) {
+ return Cont.end();
+}
+
+template constexpr auto cbegin(const Container &Cont) {
+ return Cont.cbegin();
+}
+
+template constexpr auto cend(const Container &Cont) {
+ return Cont.cend();
+}
+
+template constexpr auto rbegin(const Container &Cont) {
+ return Cont.rbegin();
+}
+
+template constexpr auto rbegin(Container &Cont) {
+ return Cont.rbegin();
+}
+
+template constexpr auto rend(const Container &Cont) {
+ return Cont.rend();
+}
+
+template constexpr auto rend(Container &Cont) {
+ return Cont.rend();
+}
+
+template constexpr auto crbegin(const Container &Cont) {
+ return Cont.crbegin();
+}
+
+template constexpr auto crend(const Container &Cont) {
+ return Cont.crend();
+}
+// Find
+template< class InputIt, class T >
+InputIt find( InputIt first, InputIt last, const T& value );
+
+// Reverse
+template void reverse(Iter begin, Iter end);
+
+// Includes
+template
+bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
+
+// IsPermutation
+template
+bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2);
+template
+bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2,
+ ForwardIt2 last2);
+
+// Equal
+template
+bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2);
+
+template
+bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
+
+template
+bool equal(InputIt1 first1, InputIt1 last1,
+ InputIt2 first2, InputIt2 last2, BinaryPred p) {
+ // Need a definition to suppress undefined_internal_type when invoked with lambda
+ return true;
+}
+
+template
+void iota(ForwardIt first, ForwardIt last, T value);
+
+} // namespace std
+
+#endif // USE_RANGES_FAKE_STD_H
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges-pipe.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges-pipe.cpp
new file mode 100644
index 00000000000000..f53fb70427e2d6
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges-pipe.cpp
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-ranges %t -check-suffixes=,PIPE \
+// RUN: -config="{CheckOptions: { \
+// RUN: modernize-use-ranges.UseReversePipe: true }}" -- -I %S/Inputs/use-ranges/
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-ranges %t -check-suffixes=,NOPIPE -- -I %S/Inputs/use-ranges/
+
+// CHECK-FIXES: #include
+// CHECK-FIXES: #include
+
+#include "fake_std.h"
+
+void stdLib() {
+ std::vector I;
+ std::find(I.rbegin(), I.rend(), 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use a ranges version of this algorithm
+ // CHECK-FIXES-NOPIPE: std::ranges::find(std::ranges::reverse_view(I), 0);
+ // CHECK-FIXES-PIPE: std::ranges::find(I | std::views::reverse, 0);
+
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges.cpp
index 623af26e3cdc73..e937e1e4e7d3b5 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges.cpp
@@ -1,116 +1,11 @@
-// RUN: %check_clang_tidy -std=c++20 %s modernize-use-ranges %t
-// RUN: %check_clang_tidy -std=c++23 %s modernize-use-ranges %t -check-suffixes=,CPP23
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-ranges %t -- -- -I %S/Inputs/use-ranges/
+// RUN: %check_clang_tidy -std=c++23 %s modernize-use-ranges %t -check-suffixes=,CPP23 -- -I %S/Inputs/use-ranges/
// CHECK-FIXES: #include
// CHECK-FIXES-CPP23: #include
// CHECK-FIXES: #include
-namespace std {
-
-template class vector {
-public:
- using iterator = T *;
- using const_iterator = const T *;
- using reverse_iterator = T*;
- using reverse_const_iterator = const T*;
-
- constexpr const_iterator begin() const;
- constexpr const_iterator end() const;
- constexpr const_iterator cbegin() const;
- constexpr const_iterator cend() const;
- constexpr iterator begin();
- constexpr iterator end();
- constexpr reverse_const_iterator rbegin() const;
- constexpr reverse_const_iterator rend() const;
- constexpr reverse_const_iterator crbegin() const;
- constexpr reverse_const_iterator crend() const;
- constexpr reverse_iterator rbegin();
- constexpr reverse_iterator rend();
-};
-
-template constexpr auto begin(const Container &Cont) {
- return Cont.begin();
-}
-
-template constexpr auto begin(Container &Cont) {
- return Cont.begin();
-}
-
-template constexpr auto end(const Container &Cont) {
- return Cont.end();
-}
-
-template constexpr auto end(Container &Cont) {
- return Cont.end();
-}
-
-template constexpr auto cbegin(const Container &Cont) {
- return Cont.cbegin();
-}
-
-template constexpr auto cend(const Container &Cont) {
- return Cont.cend();
-}
-
-template constexpr auto rbegin(const Container &Cont) {
- return Cont.rbegin();
-}
-
-template constexpr auto rbegin(Container &Cont) {
- return Cont.rbegin();
-}
-
-template constexpr auto rend(const Container &Cont) {
- return Cont.rend();
-}
-
-template constexpr auto rend(Container &Cont) {
- return Cont.rend();
-}
-
-template constexpr auto crbegin(const Container &Cont) {
- return Cont.crbegin();
-}
-
-template constexpr auto crend(const Container &Cont) {
- return Cont.crend();
-}
-// Find
-template< class InputIt, class T >
-InputIt find( InputIt first, InputIt last, const T& value );
-
-// Reverse
-template void reverse(Iter begin, Iter end);
-
-// Includes
-template
-bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
-
-// IsPermutation
-template
-bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2);
-template
-bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2,
- ForwardIt2 last2);
-
-// Equal
-template
-bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2);
-
-template
-bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
-
-template
-bool equal(InputIt1 first1, InputIt1 last1,
- InputIt2 first2, InputIt2 last2, BinaryPred p) {
- // Need a definition to suppress undefined_internal_type when invoked with lambda
- return true;
-}
-
-template
-void iota(ForwardIt first, ForwardIt last, T value);
-
-} // namespace std
+#include "fake_std.h"
void Positives() {
std::vector I, J;
@@ -179,15 +74,15 @@ void Reverse(){
std::vector I, J;
std::find(I.rbegin(), I.rend(), 0);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use a ranges version of this algorithm
- // CHECK-FIXES: std::ranges::find(std::views::reverse(I), 0);
+ // CHECK-FIXES: std::ranges::find(std::ranges::reverse_view(I), 0);
std::equal(std::rbegin(I), std::rend(I), J.begin(), J.end());
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use a ranges version of this algorithm
- // CHECK-FIXES: std::ranges::equal(std::views::reverse(I), J);
+ // CHECK-FIXES: std::ranges::equal(std::ranges::reverse_view(I), J);
std::equal(I.begin(), I.end(), std::crbegin(J), std::crend(J));
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use a ranges version of this algorithm
- // CHECK-FIXES: std::ranges::equal(I, std::views::reverse(J));
+ // CHECK-FIXES: std::ranges::equal(I, std::ranges::reverse_view(J));
}
void Negatives() {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-delayed.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-delayed.cpp
index 53ec8713be3389..6a872824896131 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-delayed.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-delayed.cpp
@@ -69,7 +69,8 @@ struct PositiveConstValueConstructor {
template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) {
// CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S'
- // CHECK-FIXES-NOT: template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) {
+ // CHECK-MESSAGES: [[@LINE-2]]:95: warning: the parameter 'V'
+ // CHECK-FIXES: template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, const T& V) {
}
void instantiated() {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-templates.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-templates.cpp
new file mode 100644
index 00000000000000..688c79bbaa9ac5
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param-templates.cpp
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy -std=c++14-or-later %s performance-unnecessary-value-param %t
+
+struct ExpensiveToCopyType {
+ virtual ~ExpensiveToCopyType();
+};
+
+template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) {
+ // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S'
+ // CHECK-MESSAGES: [[@LINE-2]]:95: warning: the parameter 'V'
+ // CHECK-FIXES: template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, const T& V) {
+}
+
+void instantiatedWithExpensiveValue() {
+ templateWithNonTemplatizedParameter(
+ ExpensiveToCopyType(), ExpensiveToCopyType());
+ templateWithNonTemplatizedParameter(ExpensiveToCopyType(), 5);
+}
+
+template void templateWithNonTemplatizedParameterCheapTemplate(const ExpensiveToCopyType S, T V) {
+ // CHECK-MESSAGES: [[@LINE-1]]:103: warning: the const qualified parameter 'S'
+ // CHECK-FIXES: template void templateWithNonTemplatizedParameterCheapTemplate(const ExpensiveToCopyType& S, T V) {
+}
+
+void instantiatedWithCheapValue() {
+ templateWithNonTemplatizedParameterCheapTemplate(ExpensiveToCopyType(), 5);
+}
+
+template void nonInstantiatedTemplateWithConstValue(const T S) {}
+template void nonInstantiatedTemplateWithNonConstValue(T S) {}
+
+template void instantiatedTemplateSpecialization(T NoSpecS) {}
+template <> void instantiatedTemplateSpecialization(int SpecSInt) {}
+// Updating template specialization would also require to update the main
+// template and other specializations. Such specializations may be
+// spreaded across different translation units.
+// For that reason we only issue a warning, but do not propose fixes.
+template <>
+void instantiatedTemplateSpecialization(
+ ExpensiveToCopyType SpecSExpensiveToCopy) {
+ // CHECK-MESSAGES: [[@LINE-1]]:25: warning: the parameter 'SpecSExpensiveToCopy'
+ // CHECK-FIXES-NOT: const T& NoSpecS
+ // CHECK-FIXES-NOT: const int& SpecSInt
+ // CHECK-FIXES-NOT: const ExpensiveToCopyType& SpecSExpensiveToCopy
+}
+
+void instantiatedTemplateSpecialization() {
+ instantiatedTemplateSpecialization(ExpensiveToCopyType());
+}
+
+template void instantiatedTemplateWithConstValue(const T S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:71: warning: the const qualified parameter 'S'
+ // CHECK-FIXES: template void instantiatedTemplateWithConstValue(const T& S) {
+}
+
+void instantiatedConstValue() {
+ instantiatedTemplateWithConstValue(ExpensiveToCopyType());
+}
+
+template void instantiatedTemplateWithNonConstValue(T S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:68: warning: the parameter 'S'
+ // CHECK-FIXES: template void instantiatedTemplateWithNonConstValue(const T& S) {
+}
+
+void instantiatedNonConstValue() {
+ instantiatedTemplateWithNonConstValue(ExpensiveToCopyType());
+}
+
+void lambdaConstValue() {
+ auto fn = [](const ExpensiveToCopyType S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:42: warning: the const qualified parameter 'S'
+ // CHECK-FIXES: auto fn = [](const ExpensiveToCopyType& S) {
+ };
+ fn(ExpensiveToCopyType());
+}
+
+void lambdaNonConstValue() {
+ auto fn = [](ExpensiveToCopyType S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:36: warning: the parameter 'S'
+ // CHECK-FIXES: auto fn = [](const ExpensiveToCopyType& S) {
+ };
+ fn(ExpensiveToCopyType());
+}
+
+void lambdaConstAutoValue() {
+ auto fn = [](const auto S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: the const qualified parameter 'S'
+ // CHECK-FIXES: auto fn = [](const auto& S) {
+ };
+ fn(ExpensiveToCopyType());
+}
+
+void lambdaNonConstAutoValue() {
+ auto fn = [](auto S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: the parameter 'S'
+ // CHECK-FIXES: auto fn = [](const auto& S) {
+ };
+ fn(ExpensiveToCopyType());
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp
index d578eedd94a390..0dffaefa213a45 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp
@@ -107,19 +107,6 @@ struct PositiveConstValueConstructor {
// CHECK-FIXES: PositiveConstValueConstructor(const ExpensiveToCopyType& ConstCopy) {}
};
-template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) {
- // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S'
- // CHECK-FIXES-NOT: template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) {
-}
-
-void instantiated() {
- templateWithNonTemplatizedParameter(ExpensiveToCopyType(), ExpensiveToCopyType());
- templateWithNonTemplatizedParameter(ExpensiveToCopyType(), 5);
-}
-
-template void negativeTemplateType(const T V) {
-}
-
void negativeArray(const ExpensiveToCopyType[]) {
}
@@ -370,35 +357,3 @@ void fun() {
ExpensiveToCopyType E;
NegativeUsingConstructor S(E);
}
-
-template
-void templateFunction(T) {
-}
-
-template<>
-void templateFunction(ExpensiveToCopyType E) {
- // CHECK-MESSAGES: [[@LINE-1]]:64: warning: the parameter 'E' is copied
- // CHECK-FIXES: void templateFunction(ExpensiveToCopyType E) {
- E.constReference();
-}
-
-template
-T templateSpecializationFunction(ExpensiveToCopyType E) {
- // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'E' is copied
- // CHECK-FIXES-NOT: T templateSpecializationFunction(const ExpensiveToCopyType& E) {
- return T();
-}
-
-template <>
-bool templateSpecializationFunction(ExpensiveToCopyType E) {
- // CHECK-MESSAGES: [[@LINE-1]]:57: warning: the parameter 'E' is copied
- // CHECK-FIXES-NOT: bool templateSpecializationFunction(const ExpensiveToCopyType& E) {
- return true;
-}
-
-template <>
-int templateSpecializationFunction(ExpensiveToCopyType E) {
- // CHECK-MESSAGES: [[@LINE-1]]:56: warning: the parameter 'E' is copied
- // CHECK-FIXES-NOT: int templateSpecializationFunction(const ExpensiveToCopyType& E) {
- return 0;
-}
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 1d3ab891904076..be024da5e005c8 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -1820,6 +1820,18 @@ def availability(self):
return AvailabilityKind.from_id(self._availability)
+ @property
+ def binary_operator(self):
+ """
+ Retrieves the opcode if this cursor points to a binary operator
+ :return:
+ """
+
+ if not hasattr(self, "_binopcode"):
+ self._binopcode = conf.lib.clang_Cursor_getBinaryOpcode(self)
+
+ return BinaryOperator.from_id(self._binopcode)
+
@property
def access_specifier(self):
"""
@@ -2110,6 +2122,55 @@ def from_cursor_result(res, fn, args):
return res
+class BinaryOperator(BaseEnumeration):
+ """
+ Describes the BinaryOperator of a declaration
+ """
+
+ def __nonzero__(self):
+ """Allows checks of the kind ```if cursor.binary_operator:```"""
+ return self.value != 0
+
+ @property
+ def is_assignment(self):
+ return BinaryOperator.Assign.value <= self.value < BinaryOperator.Comma.value
+
+ Invalid = 0
+ PtrMemD = 1
+ PtrMemI = 2
+ Mul = 3
+ Div = 4
+ Rem = 5
+ Add = 6
+ Sub = 7
+ Shl = 8
+ Shr = 9
+ Cmp = 10
+ LT = 11
+ GT = 12
+ LE = 13
+ GE = 14
+ EQ = 15
+ NE = 16
+ And = 17
+ Xor = 18
+ Or = 19
+ LAnd = 20
+ LOr = 21
+ Assign = 22
+ MulAssign = 23
+ DivAssign = 24
+ RemAssign = 25
+ AddAssign = 26
+ SubAssign = 27
+ ShlAssign = 28
+ ShrAssign = 29
+ AndAssign = 30
+ XorAssign = 31
+ OrAssign = 32
+ Comma = 33
+
+
class StorageClass(BaseEnumeration):
"""
Describes the storage class of a declaration
@@ -3847,6 +3908,7 @@ def write_main_file_to_stdout(self):
("clang_Cursor_getTemplateArgumentUnsignedValue", [Cursor, c_uint], c_ulonglong),
("clang_Cursor_isAnonymous", [Cursor], bool),
("clang_Cursor_isBitField", [Cursor], bool),
+ ("clang_Cursor_getBinaryOpcode", [Cursor], c_int),
("clang_Cursor_getBriefCommentText", [Cursor], _CXString, _CXString.from_result),
("clang_Cursor_getRawCommentText", [Cursor], _CXString, _CXString.from_result),
("clang_Cursor_getOffsetOfField", [Cursor], c_longlong),
@@ -4016,6 +4078,7 @@ def function_exists(self, name):
__all__ = [
"AvailabilityKind",
+ "BinaryOperator",
"Config",
"CodeCompletionResults",
"CompilationDatabase",
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index 84cd8139418447..7476947bde2ea6 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -13,6 +13,7 @@
from clang.cindex import TemplateArgumentKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
+from clang.cindex import BinaryOperator
from .util import get_cursor
from .util import get_cursors
from .util import get_tu
@@ -54,6 +55,64 @@ class C {
void foo<-7, float, true>();
"""
+kBinops = """\
+struct C {
+ int m;
+ };
+
+ void func(void){
+ int a, b;
+ int C::* p = &C::
+
+ C c;
+ c.*p;
+
+ C* pc;
+ pc->*p;
+
+ a * b;
+ a / b;
+ a % b;
+ a + b;
+ a - b;
+
+ a << b;
+ a >> b;
+
+ a < b;
+ a > b;
+
+ a <= b;
+ a >= b;
+ a == b;
+ a != b;
+
+ a & b;
+ a ^ b;
+ a | b;
+
+ a && b;
+ a || b;
+
+ a = b;
+
+ a *= b;
+ a /= b;
+ a %= b;
+ a += b;
+ a -= b;
+
+ a <<= b;
+ a >>= b;
+
+ a &= b;
+ a ^= b;
+ a |= b;
+ a , b;
+
+ }
+ """
+
class TestCursor(unittest.TestCase):
def test_get_children(self):
@@ -695,3 +754,48 @@ def test_mangled_name(self):
self.assertIn(
foo.mangled_name, ("_Z3fooii", "__Z3fooii", "?foo@@YAHHH", "?foo@@YAHHH@Z")
)
+
+ def test_binop(self):
+ tu = get_tu(kBinops, lang="cpp")
+
+ operators = {
+ # not exposed yet
+ # ".*" : BinaryOperator.PtrMemD,
+ "->*": BinaryOperator.PtrMemI,
+ "*": BinaryOperator.Mul,
+ "/": BinaryOperator.Div,
+ "%": BinaryOperator.Rem,
+ "+": BinaryOperator.Add,
+ "-": BinaryOperator.Sub,
+ "<<": BinaryOperator.Shl,
+ ">>": BinaryOperator.Shr,
+ # tests do not run in C++2a mode so this operator is not available
+ # "<=>" : BinaryOperator.Cmp,
+ "<": BinaryOperator.LT,
+ ">": BinaryOperator.GT,
+ "<=": BinaryOperator.LE,
+ ">=": BinaryOperator.GE,
+ "==": BinaryOperator.EQ,
+ "!=": BinaryOperator.NE,
+ "&": BinaryOperator.And,
+ "^": BinaryOperator.Xor,
+ "|": BinaryOperator.Or,
+ "&&": BinaryOperator.LAnd,
+ "||": BinaryOperator.LOr,
+ "=": BinaryOperator.Assign,
+ "*=": BinaryOperator.MulAssign,
+ "/=": BinaryOperator.DivAssign,
+ "%=": BinaryOperator.RemAssign,
+ "+=": BinaryOperator.AddAssign,
+ "-=": BinaryOperator.SubAssign,
+ "<<=": BinaryOperator.ShlAssign,
+ ">>=": BinaryOperator.ShrAssign,
+ "&=": BinaryOperator.AndAssign,
+ "^=": BinaryOperator.XorAssign,
+ "|=": BinaryOperator.OrAssign,
+ ",": BinaryOperator.Comma,
+ }
+
+ for op, typ in operators.items():
+ c = get_cursor(tu, op)
+ assert c.binary_operator == typ
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index d75052954820c8..63b2292c5d9bdc 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -12,6 +12,7 @@
LinkageKind,
TLSKind,
StorageClass,
+ BinaryOperator,
)
@@ -28,6 +29,7 @@ class TestEnums(unittest.TestCase):
LinkageKind,
TLSKind,
StorageClass,
+ BinaryOperator,
]
def test_from_id(self):
diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake
index b8c9db49863c60..04efd0683dbc4b 100644
--- a/clang/cmake/caches/Fuchsia-stage2.cmake
+++ b/clang/cmake/caches/Fuchsia-stage2.cmake
@@ -305,7 +305,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi)
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT "" CACHE STRING "")
- set(BUILTINS_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
+ set(BUILTINS_${target}_CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "")
foreach(lang C;CXX;ASM)
set(BUILTINS_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb")
if(${target} STREQUAL "armv8m.main-unknown-eabi")
@@ -322,10 +322,12 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi)
set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSROOT "" CACHE STRING "")
- set(RUNTIMES_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
+ set(RUNTIMES_${target}_CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
foreach(lang C;CXX;ASM)
- set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb -Wno-atomic-alignment" CACHE STRING "")
+ # TODO: The preprocessor defines workaround various issues in libc and libc++ integration.
+ # These should be addressed and removed over time.
+ set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb -Wno-atomic-alignment -D'vfprintf(stream, format, vlist)=vprintf(format, vlist)' -D'fprintf(stream, format, ...)=printf(format)' -D'timeval=struct timeval{int tv_sec; int tv_usec;}' -D'gettimeofday(tv, tz)' -D_LIBCPP_PRINT=1" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
@@ -335,7 +337,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi)
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
- set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
+ set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_LOCALIZATION OFF CACHE BOOL "")
@@ -357,7 +359,7 @@ foreach(target riscv32-unknown-elf)
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSTEM_PROCESSOR RISCV CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT "" CACHE STRING "")
- set(BUILTINS_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
+ set(BUILTINS_${target}_CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "")
foreach(lang C;CXX;ASM)
set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f" CACHE STRING "")
endforeach()
@@ -370,10 +372,12 @@ foreach(target riscv32-unknown-elf)
set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSTEM_PROCESSOR RISCV CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSROOT "" CACHE STRING "")
- set(RUNTIMES_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
+ set(RUNTIMES_${target}_CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
foreach(lang C;CXX;ASM)
- set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f" CACHE STRING "")
+ # TODO: The preprocessor defines workaround various issues in libc and libc++ integration.
+ # These should be addressed and removed over time.
+ set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f -D'vfprintf(stream, format, vlist)=vprintf(format, vlist)' -D'fprintf(stream, format, ...)=printf(format)' -D'timeval=struct timeval{int tv_sec; int tv_usec;}' -D'gettimeofday(tv, tz)' -D_LIBCPP_PRINT=1" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
@@ -383,7 +387,7 @@ foreach(target riscv32-unknown-elf)
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
- set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
+ set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_LOCALIZATION OFF CACHE BOOL "")
diff --git a/clang/docs/CommandGuide/clang.rst b/clang/docs/CommandGuide/clang.rst
index a348f3640c5eb8..29154292dc7a5e 100644
--- a/clang/docs/CommandGuide/clang.rst
+++ b/clang/docs/CommandGuide/clang.rst
@@ -400,6 +400,14 @@ number of cross compilers, or may only support a native target.
option is only supported on AArch64 and RISC-V. On RISC-V, this option also
prints out the ISA string of enabled extensions.
+.. option:: --print-supported-extensions
+
+ Prints the list of all extensions that are supported for every CPU target
+ for an architecture (specified through ``--target=`` or
+ :option:`-arch` ````). If no target is specified, the system
+ default target will be used. Currently, this option is only supported on
+ AArch64 and RISC-V.
+
Code Generation Options
~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/clang/docs/HLSL/ExpectedDifferences.rst b/clang/docs/HLSL/ExpectedDifferences.rst
index d1b6010f10f43a..a29b6348e0b8e7 100644
--- a/clang/docs/HLSL/ExpectedDifferences.rst
+++ b/clang/docs/HLSL/ExpectedDifferences.rst
@@ -67,12 +67,16 @@ behavior between Clang and DXC. Some examples include:
void takesDoubles(double, double, double);
cbuffer CB {
+ bool B;
uint U;
int I;
float X, Y, Z;
double3 A, B;
}
+ void twoParams(int, int);
+ void twoParams(float, float);
+
export void call() {
halfOrInt16(U); // DXC: Fails with call ambiguous between int16_t and uint16_t overloads
// Clang: Resolves to halfOrInt16(uint16_t).
@@ -98,6 +102,13 @@ behavior between Clang and DXC. Some examples include:
// FXC: Expands to compute double dot product with fmul/fadd
// Clang: Resolves to dot(float3, float3), emits conversion warnings.
+ #ifndef IGNORE_ERRORS
+ tan(B); // DXC: resolves to tan(float).
+ // Clang: Fails to resolve, ambiguous between integer types.
+
+ twoParams(I, X); // DXC: resolves twoParams(int, int).
+ // Clang: Fails to resolve ambiguous conversions.
+ #endif
}
.. note::
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5dc0f8b7e0bbb8..e51dc8d76ac0dd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -313,10 +313,6 @@ Resolutions to C++ Defect Reports
- Clang now considers ``noexcept(typeid(expr))`` more carefully, instead of always assuming that ``std::bad_typeid`` can be thrown.
(`CWG2191: Incorrect result for noexcept(typeid(v)) `_).
-- Clang now correctly implements lookup for the terminal name of a member-qualified nested-name-specifier.
- (`CWG1835: Dependent member lookup before < `_).
- The warning can be disabled via `-Wno-missing-dependent-template-keyword`.
-
C Language Changes
------------------
@@ -830,6 +826,8 @@ Bug Fixes in This Version
- ``__is_trivially_equality_comparable`` no longer returns true for types which
have a constrained defaulted comparison operator (#GH89293).
+- Fixed Clang from generating dangling StringRefs when deserializing Exprs & Stmts (#GH98667)
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1021,7 +1019,6 @@ Bug Fixes to C++ Support
(#GH88081), (#GH89496), (#GH90669), (#GH91633) and (#GH97453).
- Fixed a crash in constraint instantiation under nested lambdas with dependent parameters.
- Fixed handling of brace ellison when building deduction guides. (#GH64625), (#GH83368).
-- Clang now instantiates local constexpr functions eagerly for constant evaluators. (#GH35052), (#GH94849)
- Fixed a failed assertion when attempting to convert an integer representing the difference
between the addresses of two labels (a GNU extension) to a pointer within a constant expression. (#GH95366).
- Fix immediate escalation bugs in the presence of dependent call arguments. (#GH94935)
@@ -1041,6 +1038,9 @@ Bug Fixes to C++ Support
(#GH48937)
- Fix a crash when parsing an invalid type-requirement in a requires expression. (#GH51868)
- Fix parsing of built-in type-traits such as ``__is_pointer`` in libstdc++ headers. (#GH95598)
+- Fixed failed assertion when resolving context of defaulted comparison method outside of struct. (#GH96043).
+- Clang now diagnoses explicit object parameters in member pointers and other contexts where they should not appear.
+ Fixes (#GH85992).
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1078,6 +1078,25 @@ X86 Support
^^^^^^^^^^^
- Remove knl/knm specific ISA supports: AVX512PF, AVX512ER, PREFETCHWT1
+- Support has been removed for the AMD "3DNow!" instruction-set.
+ Neither modern AMD CPUs, nor any Intel CPUs implement these
+ instructions, and they were never widely used.
+
+ * The options ``-m3dnow`` and ``-m3dnowa`` are no longer honored, and will emit a warning if used.
+ * The macros ``__3dNOW__`` and ``__3dNOW_A__`` are no longer ever set by the compiler.
+ * The header ```` is deprecated, and emits a warning if included.
+ * The 3dNow intrinsic functions have been removed: ``_m_femms``,
+ ``_m_pavgusb``, ``_m_pf2id``, ``_m_pfacc``, ``_m_pfadd``,
+ ``_m_pfcmpeq``, ``_m_pfcmpge``, ``_m_pfcmpgt``, ``_m_pfmax``,
+ ``_m_pfmin``, ``_m_pfmul``, ``_m_pfrcp``, ``_m_pfrcpit1``,
+ ``_m_pfrcpit2``, ``_m_pfrsqrt``, ``_m_pfrsqrtit1``, ``_m_pfsub``,
+ ``_m_pfsubr``, ``_m_pi2fd``, ``_m_pmulhrw``, ``_m_pf2iw``,
+ ``_m_pfnacc``, ``_m_pfpnacc``, ``_m_pi2fw``, ``_m_pswapdsf``,
+ ``_m_pswapdsi``.
+ * The compiler builtins corresponding to each of the above
+ intrinsics have also been removed (``__builtin_ia32_femms``, and so on).
+ * "3DNow!" instructions remain supported in assembly code, including
+ inside inline-assembly.
Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^
@@ -1151,6 +1170,10 @@ RISC-V Support
- ``__attribute__((rvv_vector_bits(N)))`` is now supported for RVV vbool*_t types.
- Profile names in ``-march`` option are now supported.
- Passing empty structs/unions as arguments in C++ is now handled correctly. The behavior is similar to GCC's.
+- ``-m[no-]scalar-strict-align`` and ``-m[no-]vector-strict-align`` options have
+ been added to give separate control of whether scalar or vector misaligned
+ accesses may be created. ``-m[no-]strict-align`` applies to both scalar and
+ vector.
CUDA/HIP Language Changes
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1188,6 +1211,8 @@ DWARF Support in Clang
Floating Point Support in Clang
-------------------------------
+- Add ``__builtin__fmaf16`` builtin for floating point types.
+
Fixed Point Support in Clang
----------------------------
@@ -1306,6 +1331,8 @@ Python Binding Changes
- Exposed `CXRewriter` API as `class Rewriter`.
- Add some missing kinds from Index.h (CursorKind: 149-156, 272-320, 420-437.
TemplateArgumentKind: 5-9. TypeKind: 161-175 and 178).
+- Add support for retrieving binary operator information through
+ Cursor.binary_operator().
OpenMP Support
--------------
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index ce2282937f86cb..24ed23a6287286 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3750,6 +3750,59 @@ enum CX_StorageClass {
CX_SC_Register
};
+/**
+ * Represents a specific kind of binary operator which can appear at a cursor.
+ */
+enum CX_BinaryOperatorKind {
+ CX_BO_Invalid = 0,
+ CX_BO_PtrMemD = 1,
+ CX_BO_PtrMemI = 2,
+ CX_BO_Mul = 3,
+ CX_BO_Div = 4,
+ CX_BO_Rem = 5,
+ CX_BO_Add = 6,
+ CX_BO_Sub = 7,
+ CX_BO_Shl = 8,
+ CX_BO_Shr = 9,
+ CX_BO_Cmp = 10,
+ CX_BO_LT = 11,
+ CX_BO_GT = 12,
+ CX_BO_LE = 13,
+ CX_BO_GE = 14,
+ CX_BO_EQ = 15,
+ CX_BO_NE = 16,
+ CX_BO_And = 17,
+ CX_BO_Xor = 18,
+ CX_BO_Or = 19,
+ CX_BO_LAnd = 20,
+ CX_BO_LOr = 21,
+ CX_BO_Assign = 22,
+ CX_BO_MulAssign = 23,
+ CX_BO_DivAssign = 24,
+ CX_BO_RemAssign = 25,
+ CX_BO_AddAssign = 26,
+ CX_BO_SubAssign = 27,
+ CX_BO_ShlAssign = 28,
+ CX_BO_ShrAssign = 29,
+ CX_BO_AndAssign = 30,
+ CX_BO_XorAssign = 31,
+ CX_BO_OrAssign = 32,
+ CX_BO_Comma = 33,
+ CX_BO_LAST = CX_BO_Comma
+};
+
+/**
+ * \brief Returns the operator code for the binary operator.
+ */
+CINDEX_LINKAGE enum CX_BinaryOperatorKind
+clang_Cursor_getBinaryOpcode(CXCursor C);
+
+/**
+ * \brief Returns a string containing the spelling of the binary operator.
+ */
+CINDEX_LINKAGE CXString
+clang_Cursor_getBinaryOpcodeStr(enum CX_BinaryOperatorKind Op);
+
/**
* Returns the storage class for a function or variable declaration.
*
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index daf2f1897f46bd..b389aa8d56f167 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -263,13 +263,6 @@ class ContextInfo : public CommonTypeInfo {
SwiftObjCMembers = Value.value_or(false);
}
- /// Strip off any information within the class information structure that is
- /// module-local, such as 'audited' flags.
- void stripModuleLocalInfo() {
- HasDefaultNullability = false;
- DefaultNullability = 0;
- }
-
friend bool operator==(const ContextInfo &, const ContextInfo &);
ContextInfo &operator|=(const ContextInfo &RHS) {
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 5957f14098363e..561a9d872acfb0 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -542,12 +542,9 @@ class LabelDecl : public NamedDecl {
};
/// Represent a C++ namespace.
-class NamespaceDecl : public NamedDecl, public DeclContext,
- public Redeclarable
-{
-
- enum Flags : unsigned { F_Inline = 1 << 0, F_Nested = 1 << 1 };
-
+class NamespaceDecl : public NamedDecl,
+ public DeclContext,
+ public Redeclarable {
/// The starting location of the source range, pointing
/// to either the namespace or the inline keyword.
SourceLocation LocStart;
@@ -555,12 +552,8 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
/// The ending location of the source range.
SourceLocation RBraceLoc;
- /// A pointer to either the anonymous namespace that lives just inside
- /// this namespace or to the first namespace in the chain (the latter case
- /// only when this is not the first in the chain), along with a
- /// boolean value indicating whether this is an inline namespace.
- llvm::PointerIntPair
- AnonOrFirstNamespaceAndFlags;
+ /// The unnamed namespace that inhabits this namespace, if any.
+ NamespaceDecl *AnonymousNamespace = nullptr;
NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
@@ -607,35 +600,19 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
}
/// Returns true if this is an inline namespace declaration.
- bool isInline() const {
- return AnonOrFirstNamespaceAndFlags.getInt() & F_Inline;
- }
+ bool isInline() const { return NamespaceDeclBits.IsInline; }
/// Set whether this is an inline namespace declaration.
- void setInline(bool Inline) {
- unsigned F = AnonOrFirstNamespaceAndFlags.getInt();
- if (Inline)
- AnonOrFirstNamespaceAndFlags.setInt(F | F_Inline);
- else
- AnonOrFirstNamespaceAndFlags.setInt(F & ~F_Inline);
- }
+ void setInline(bool Inline) { NamespaceDeclBits.IsInline = Inline; }
/// Returns true if this is a nested namespace declaration.
/// \code
/// namespace outer::nested { }
/// \endcode
- bool isNested() const {
- return AnonOrFirstNamespaceAndFlags.getInt() & F_Nested;
- }
+ bool isNested() const { return NamespaceDeclBits.IsNested; }
/// Set whether this is a nested namespace declaration.
- void setNested(bool Nested) {
- unsigned F = AnonOrFirstNamespaceAndFlags.getInt();
- if (Nested)
- AnonOrFirstNamespaceAndFlags.setInt(F | F_Nested);
- else
- AnonOrFirstNamespaceAndFlags.setInt(F & ~F_Nested);
- }
+ void setNested(bool Nested) { NamespaceDeclBits.IsNested = Nested; }
/// Returns true if the inline qualifier for \c Name is redundant.
bool isRedundantInlineQualifierFor(DeclarationName Name) const {
@@ -649,34 +626,18 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
std::distance(Y.begin(), Y.end());
}
- /// Get the original (first) namespace declaration.
- NamespaceDecl *getOriginalNamespace();
-
- /// Get the original (first) namespace declaration.
- const NamespaceDecl *getOriginalNamespace() const;
-
- /// Return true if this declaration is an original (first) declaration
- /// of the namespace. This is false for non-original (subsequent) namespace
- /// declarations and anonymous namespaces.
- bool isOriginalNamespace() const;
-
- /// Retrieve the anonymous namespace nested inside this namespace,
- /// if any.
+ /// Retrieve the anonymous namespace that inhabits this namespace, if any.
NamespaceDecl *getAnonymousNamespace() const {
- return getOriginalNamespace()->AnonOrFirstNamespaceAndFlags.getPointer();
+ return getFirstDecl()->AnonymousNamespace;
}
void setAnonymousNamespace(NamespaceDecl *D) {
- getOriginalNamespace()->AnonOrFirstNamespaceAndFlags.setPointer(D);
+ getFirstDecl()->AnonymousNamespace = D;
}
/// Retrieves the canonical declaration of this namespace.
- NamespaceDecl *getCanonicalDecl() override {
- return getOriginalNamespace();
- }
- const NamespaceDecl *getCanonicalDecl() const {
- return getOriginalNamespace();
- }
+ NamespaceDecl *getCanonicalDecl() override { return getFirstDecl(); }
+ const NamespaceDecl *getCanonicalDecl() const { return getFirstDecl(); }
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(LocStart, RBraceLoc);
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 6c711cfe7927b2..40f01abf384e92 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -1487,6 +1487,27 @@ class DeclContext {
/// Number of bits in DeclContextBitfields.
enum { NumDeclContextBits = 13 };
+ /// Stores the bits used by NamespaceDecl.
+ /// If modified NumNamespaceDeclBits and the accessor
+ /// methods in NamespaceDecl should be updated appropriately.
+ class NamespaceDeclBitfields {
+ friend class NamespaceDecl;
+ /// For the bits in DeclContextBitfields
+ LLVM_PREFERRED_TYPE(DeclContextBitfields)
+ uint64_t : NumDeclContextBits;
+
+ /// True if this is an inline namespace.
+ LLVM_PREFERRED_TYPE(bool)
+ uint64_t IsInline : 1;
+
+ /// True if this is a nested-namespace-definition.
+ LLVM_PREFERRED_TYPE(bool)
+ uint64_t IsNested : 1;
+ };
+
+ /// Number of inherited and non-inherited bits in NamespaceDeclBitfields.
+ enum { NumNamespaceDeclBits = NumDeclContextBits + 2 };
+
/// Stores the bits used by TagDecl.
/// If modified NumTagDeclBits and the accessor
/// methods in TagDecl should be updated appropriately.
@@ -1985,6 +2006,7 @@ class DeclContext {
/// 8 bytes with static_asserts in the ctor of DeclContext.
union {
DeclContextBitfields DeclContextBits;
+ NamespaceDeclBitfields NamespaceDeclBits;
TagDeclBitfields TagDeclBits;
EnumDeclBitfields EnumDeclBits;
RecordDeclBitfields RecordDeclBits;
@@ -1998,6 +2020,8 @@ class DeclContext {
static_assert(sizeof(DeclContextBitfields) <= 8,
"DeclContextBitfields is larger than 8 bytes!");
+ static_assert(sizeof(NamespaceDeclBitfields) <= 8,
+ "NamespaceDeclBitfields is larger than 8 bytes!");
static_assert(sizeof(TagDeclBitfields) <= 8,
"TagDeclBitfields is larger than 8 bytes!");
static_assert(sizeof(EnumDeclBitfields) <= 8,
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index edaea6fe27cc3d..c2feac525c1ea6 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -3676,9 +3676,9 @@ class CXXUnresolvedConstructExpr final
/// an implicit access if a qualifier is provided.
class CXXDependentScopeMemberExpr final
: public Expr,
- private llvm::TrailingObjects<
- CXXDependentScopeMemberExpr, NestedNameSpecifierLoc, DeclAccessPair,
- ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> {
+ private llvm::TrailingObjects {
friend class ASTStmtReader;
friend class ASTStmtWriter;
friend TrailingObjects;
@@ -3691,15 +3691,17 @@ class CXXDependentScopeMemberExpr final
/// implicit accesses.
QualType BaseType;
+ /// The nested-name-specifier that precedes the member name, if any.
+ /// FIXME: This could be in principle store as a trailing object.
+ /// However the performance impact of doing so should be investigated first.
+ NestedNameSpecifierLoc QualifierLoc;
+
/// The member to which this member expression refers, which
/// can be name, overloaded operator, or destructor.
///
/// FIXME: could also be a template-id
DeclarationNameInfo MemberNameInfo;
- /// The location of the '->' or '.' operator.
- SourceLocation OperatorLoc;
-
// CXXDependentScopeMemberExpr is followed by several trailing objects,
// some of which optional. They are in order:
//
@@ -3719,16 +3721,8 @@ class CXXDependentScopeMemberExpr final
return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo;
}
- unsigned getNumUnqualifiedLookups() const {
- return CXXDependentScopeMemberExprBits.NumUnqualifiedLookups;
- }
-
- unsigned numTrailingObjects(OverloadToken) const {
- return hasQualifier();
- }
-
- unsigned numTrailingObjects(OverloadToken) const {
- return getNumUnqualifiedLookups();
+ bool hasFirstQualifierFoundInScope() const {
+ return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope;
}
unsigned numTrailingObjects(OverloadToken) const {
@@ -3739,32 +3733,33 @@ class CXXDependentScopeMemberExpr final
return getNumTemplateArgs();
}
+ unsigned numTrailingObjects(OverloadToken) const {
+ return hasFirstQualifierFoundInScope();
+ }
+
CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base,
QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
- ArrayRef UnqualifiedLookups,
+ NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
- CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasQualifier,
- unsigned NumUnqualifiedLookups,
- bool HasTemplateKWAndArgsInfo);
+ CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
+ bool HasFirstQualifierFoundInScope);
public:
static CXXDependentScopeMemberExpr *
Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- ArrayRef UnqualifiedLookups,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
static CXXDependentScopeMemberExpr *
- CreateEmpty(const ASTContext &Ctx, bool HasQualifier,
- unsigned NumUnqualifiedLookups, bool HasTemplateKWAndArgsInfo,
- unsigned NumTemplateArgs);
+ CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
+ unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope);
/// True if this is an implicit access, i.e. one in which the
/// member being accessed was not written in the source. The source
@@ -3789,35 +3784,34 @@ class CXXDependentScopeMemberExpr final
bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; }
/// Retrieve the location of the '->' or '.' operator.
- SourceLocation getOperatorLoc() const { return OperatorLoc; }
-
- /// Determines whether this member expression had a nested-name-specifier
- /// prior to the name of the member, e.g., x->Base::foo.
- bool hasQualifier() const {
- return CXXDependentScopeMemberExprBits.HasQualifier;
- }
-
- /// If the member name was qualified, retrieves the nested-name-specifier
- /// that precedes the member name, with source-location information.
- NestedNameSpecifierLoc getQualifierLoc() const {
- if (!hasQualifier())
- return NestedNameSpecifierLoc();
- return *getTrailingObjects();
+ SourceLocation getOperatorLoc() const {
+ return CXXDependentScopeMemberExprBits.OperatorLoc;
}
- /// If the member name was qualified, retrieves the
- /// nested-name-specifier that precedes the member name. Otherwise, returns
- /// NULL.
+ /// Retrieve the nested-name-specifier that qualifies the member name.
NestedNameSpecifier *getQualifier() const {
- return getQualifierLoc().getNestedNameSpecifier();
+ return QualifierLoc.getNestedNameSpecifier();
}
- /// Retrieve the declarations found by unqualified lookup for the first
- /// component name of the nested-name-specifier, if any.
- ArrayRef unqualified_lookups() const {
- if (!getNumUnqualifiedLookups())
- return std::nullopt;
- return {getTrailingObjects(), getNumUnqualifiedLookups()};
+ /// Retrieve the nested-name-specifier that qualifies the member
+ /// name, with source location information.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+
+ /// Retrieve the first part of the nested-name-specifier that was
+ /// found in the scope of the member access expression when the member access
+ /// was initially parsed.
+ ///
+ /// This function only returns a useful result when member access expression
+ /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration
+ /// returned by this function describes what was found by unqualified name
+ /// lookup for the identifier "Base" within the scope of the member access
+ /// expression itself. At template instantiation time, this information is
+ /// combined with the results of name lookup into the type of the object
+ /// expression itself (the class type of x).
+ NamedDecl *getFirstQualifierFoundInScope() const {
+ if (!hasFirstQualifierFoundInScope())
+ return nullptr;
+ return *getTrailingObjects();
}
/// Retrieve the name of the member that this expression refers to.
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 257a61c97c9c6d..9cd7a364cd3f1d 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1020,19 +1020,18 @@ class alignas(void *) Stmt {
LLVM_PREFERRED_TYPE(bool)
unsigned IsArrow : 1;
- /// True if this member expression used a nested-name-specifier to
- /// refer to the member, e.g., "x->Base::f".
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasQualifier : 1;
-
/// Whether this member expression has info for explicit template
/// keyword and arguments.
LLVM_PREFERRED_TYPE(bool)
unsigned HasTemplateKWAndArgsInfo : 1;
- /// Number of declarations found by unqualified lookup for the
- /// first component name of the nested-name-specifier.
- unsigned NumUnqualifiedLookups;
+ /// See getFirstQualifierFoundInScope() and the comment listing
+ /// the trailing objects.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasFirstQualifierFoundInScope : 1;
+
+ /// The location of the '->' or '.' operator.
+ SourceLocation OperatorLoc;
};
class OverloadExprBitfields {
diff --git a/clang/include/clang/AST/UnresolvedSet.h b/clang/include/clang/AST/UnresolvedSet.h
index ef44499ce59264..1369725ab4e96a 100644
--- a/clang/include/clang/AST/UnresolvedSet.h
+++ b/clang/include/clang/AST/UnresolvedSet.h
@@ -97,10 +97,6 @@ class UnresolvedSetImpl {
decls().push_back(DeclAccessPair::make(D, AS));
}
- void addAllDecls(ArrayRef Other) {
- append(iterator(Other.begin()), iterator(Other.end()));
- }
-
/// Replaces the given declaration with the new one, once.
///
/// \return true if the set changed
diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
index 925b99af9141a3..f9c923a36ad229 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
@@ -113,7 +113,11 @@ class AnalysisASTVisitor : public RecursiveASTVisitor {
// nevertheless it appears in the Clang CFG, so we don't exclude it here.
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
- bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; }
+ bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) {
+ if (TIE->isPotentiallyEvaluated())
+ return RecursiveASTVisitor::TraverseCXXTypeidExpr(TIE);
+ return true;
+ }
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
return true;
}
diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def
index 7074479786b973..a85e7918f4d7e0 100644
--- a/clang/include/clang/Basic/BuiltinsX86.def
+++ b/clang/include/clang/Basic/BuiltinsX86.def
@@ -37,36 +37,6 @@ TARGET_BUILTIN(__builtin_ia32_undef512, "V8d", "ncV:512:", "")
TARGET_BUILTIN(__builtin_ia32_readeflags_u32, "Ui", "n", "")
TARGET_BUILTIN(__builtin_ia32_writeeflags_u32, "vUi", "n", "")
-// 3DNow!
-//
-TARGET_BUILTIN(__builtin_ia32_femms, "v", "n", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "ncV:64:", "3dnow")
-TARGET_BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "ncV:64:", "3dnow")
-// 3DNow! Extensions (3dnowa).
-TARGET_BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "ncV:64:", "3dnowa")
-TARGET_BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "ncV:64:", "3dnowa")
-TARGET_BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "ncV:64:", "3dnowa")
-TARGET_BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "ncV:64:", "3dnowa")
-TARGET_BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "ncV:64:", "3dnowa")
-TARGET_BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "ncV:64:", "3dnowa")
-
// MMX
//
// All MMX instructions will be generated via builtins. Any MMX vector
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index f1ddd2276e816a..f671b780bcbeb1 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -38,6 +38,7 @@ VALUE_CODEGENOPT(Name, Bits, Default)
CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as
CODEGENOPT(Crel, 1, 0) ///< -Wa,--crel
CODEGENOPT(RelaxELFRelocations, 1, 1) ///< -Wa,-mrelax-relocations={yes,no}
+CODEGENOPT(SSE2AVX , 1, 0) ///< -msse2avx
CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm.
CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments.
CODEGENOPT(AssumeSaneOperatorNew , 1, 1) ///< implicit __attribute__((malloc)) operator new
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index e00cd47411cb31..12aab09f285567 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -895,9 +895,10 @@ def missing_template_arg_list_after_template_kw : Extension<
"keyword">, InGroup>,
DefaultError;
-def ext_missing_dependent_template_keyword : ExtWarn<
- "use 'template' keyword to treat '%0' as a dependent template name">,
- InGroup>;
+def err_missing_dependent_template_keyword : Error<
+ "use 'template' keyword to treat '%0' as a dependent template name">;
+def warn_missing_dependent_template_keyword : ExtWarn<
+ "use 'template' keyword to treat '%0' as a dependent template name">;
def ext_extern_template : Extension<
"extern templates are a C++11 extension">, InGroup;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0ea3677355169f..52ff4b026a60e2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7577,6 +7577,8 @@ def err_explicit_object_lambda_ambiguous_base : Error<
def err_explicit_object_lambda_inaccessible_base : Error<
"invalid explicit object parameter type %0 in lambda with capture; "
"the type must derive publicly from the lambda">;
+def err_explicit_object_parameter_invalid: Error<
+ "an explicit object parameter can only appear as the first parameter of a member function">;
def err_ref_qualifier_overload : Error<
"cannot overload a member function %select{without a ref-qualifier|with "
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index e6054425909098..7f4912b9bcd961 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -165,6 +165,9 @@ TOK(raw_identifier) // Used only in raw lexing mode.
// C99 6.4.4.2: Floating Constants
TOK(numeric_constant) // 0x123
+// Directly holds numerical value. Used to process C23 #embed.
+TOK(binary_data)
+
// C99 6.4.4: Character Constants
TOK(char_constant) // 'a'
TOK(wide_char_constant) // L'b'
diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h
index e5183a27d2bc5f..1b133dde895876 100644
--- a/clang/include/clang/Basic/TokenKinds.h
+++ b/clang/include/clang/Basic/TokenKinds.h
@@ -98,7 +98,7 @@ inline bool isLiteral(TokenKind K) {
return K == tok::numeric_constant || K == tok::char_constant ||
K == tok::wide_char_constant || K == tok::utf8_char_constant ||
K == tok::utf16_char_constant || K == tok::utf32_char_constant ||
- isStringLiteral(K) || K == tok::header_name;
+ isStringLiteral(K) || K == tok::header_name || K == tok::binary_data;
}
/// Return true if this is any of tok::annot_* kinds.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f1e8cb87e5321a..2400b193d4d38c 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4854,6 +4854,14 @@ def mstrict_align : Flag<["-"], "mstrict-align">, Group,
HelpText<"Force all memory accesses to be aligned (AArch64/LoongArch/RISC-V only)">;
def mno_strict_align : Flag<["-"], "mno-strict-align">, Group,
HelpText<"Allow memory accesses to be unaligned (AArch64/LoongArch/RISC-V only)">;
+def mscalar_strict_align : Flag<["-"], "mscalar-strict-align">, Group,
+ HelpText<"Force all scalar memory accesses to be aligned (RISC-V only)">;
+def mno_scalar_strict_align : Flag<["-"], "mno-scalar-strict-align">, Group,
+ HelpText<"Allow scalar memory accesses to be unaligned (RISC-V only)">;
+def mvector_strict_align : Flag<["-"], "mvector-strict-align">, Group,
+ HelpText<"Force all vector memory accesses to be aligned (RISC-V only)">;
+def mno_vector_strict_align : Flag<["-"], "mno-vector-strict-align">, Group,
+ HelpText<"Allow vector memory accesses to be unaligned (RISC-V only)">;
def mno_thumb : Flag<["-"], "mno-thumb">, Group;
def mrestrict_it: Flag<["-"], "mrestrict-it">, Group,
HelpText<"Disallow generation of complex IT blocks. It is off by default.">;
@@ -5171,6 +5179,13 @@ def mvx : Flag<["-"], "mvx">, Group;
def mno_vx : Flag<["-"], "mno-vx">, Group;
} // let Flags = [TargetSpecific]
+let Flags = [TargetSpecific] in {
+def msse2avx : Flag<["-"], "msse2avx">, Group,
+ Visibility<[ClangOption, CC1Option, CC1AsOption]>,
+ HelpText<"Specify that the assembler should encode SSE instructions with VEX prefix">,
+ MarshallingInfoFlag>;
+} // let Flags = [TargetSpecific]
+
defm zvector : BoolFOption<"zvector",
LangOpts<"ZVector">, DefaultFalse,
PosFlag, Flags<[]>,
HelpText<"Provide information about a particular module file">;
def mthumb : Flag<["-"], "mthumb">, Group;
def mtune_EQ : Joined<["-"], "mtune=">, Group,
+ Visibility<[ClangOption, FlangOption]>,
HelpText<"Only supported on AArch64, PowerPC, RISC-V, SPARC, SystemZ, and X86">;
def multi__module : Flag<["-"], "multi_module">;
def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">;
@@ -6119,10 +6135,6 @@ def mno_80387 : Flag<["-"], "mno-80387">, Alias;
def mno_fp_ret_in_387 : Flag<["-"], "mno-fp-ret-in-387">, Alias;
def mmmx : Flag<["-"], "mmmx">, Group;
def mno_mmx : Flag<["-"], "mno-mmx">, Group;
-def m3dnow : Flag<["-"], "m3dnow">, Group;
-def mno_3dnow : Flag<["-"], "mno-3dnow">, Group;
-def m3dnowa : Flag<["-"], "m3dnowa">, Group;
-def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group;
def mamx_bf16 : Flag<["-"], "mamx-bf16">, Group;
def mno_amx_bf16 : Flag<["-"], "mno-amx-bf16">, Group;
def mamx_complex : Flag<["-"], "mamx-complex">, Group;
@@ -6356,6 +6368,12 @@ def mvevpu : Flag<["-"], "mvevpu">, Group,
def mno_vevpu : Flag<["-"], "mno-vevpu">, Group;
} // let Flags = [TargetSpecific]
+// Unsupported X86 feature flags (triggers a warning)
+def m3dnow : Flag<["-"], "m3dnow">;
+def mno_3dnow : Flag<["-"], "mno-3dnow">;
+def m3dnowa : Flag<["-"], "m3dnowa">;
+def mno_3dnowa : Flag<["-"], "mno-3dnowa">;
+
// These are legacy user-facing driver-level option spellings. They are always
// aliases for options that are spelled using the more common Unix / GNU flag
// style of double-dash and equals-joined flags.
@@ -6768,9 +6786,6 @@ def emit_hlfir : Flag<["-"], "emit-hlfir">, Group,
let Visibility = [CC1Option, CC1AsOption] in {
-def tune_cpu : Separate<["-"], "tune-cpu">,
- HelpText<"Tune for a specific cpu type">,
- MarshallingInfoString>;
def target_abi : Separate<["-"], "target-abi">,
HelpText<"Target a particular ABI type">,
MarshallingInfoString>;
@@ -6797,6 +6812,9 @@ def darwin_target_variant_triple : Separate<["-"], "darwin-target-variant-triple
let Visibility = [CC1Option, CC1AsOption, FC1Option] in {
+def tune_cpu : Separate<["-"], "tune-cpu">,
+ HelpText<"Tune for a specific cpu type">,
+ MarshallingInfoString>;
def target_cpu : Separate<["-"], "target-cpu">,
HelpText<"Target a specific cpu type">,
MarshallingInfoString>;
diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index 76d7fd798bed3a..1b27027621666a 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -175,22 +175,25 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor {
// skip classes not inherited as public
if (BaseSpecifier.getAccessSpecifier() != AccessSpecifier::AS_public)
continue;
- SymbolReference BaseClass;
- if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) {
- BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString());
- if (auto *TTPTD = BaseSpecifier.getType()
- ->getAs()
- ->getDecl()) {
- SmallString<128> USR;
- index::generateUSRForDecl(TTPTD, USR);
- BaseClass.USR = API.copyString(USR);
- BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD));
- }
+ if (auto *BaseDecl = BaseSpecifier.getType()->getAsTagDecl()) {
+ Bases.emplace_back(createSymbolReferenceForDecl(*BaseDecl));
} else {
- BaseClass = createSymbolReferenceForDecl(
- *BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl());
+ SymbolReference BaseClass;
+ BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString(
+ Decl->getASTContext().getPrintingPolicy()));
+
+ if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) {
+ if (auto *TTPTD = BaseSpecifier.getType()
+ ->getAs()
+ ->getDecl()) {
+ SmallString<128> USR;
+ index::generateUSRForDecl(TTPTD, USR);
+ BaseClass.USR = API.copyString(USR);
+ BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD));
+ }
+ }
+ Bases.emplace_back(BaseClass);
}
- Bases.emplace_back(BaseClass);
}
return Bases;
}
@@ -352,7 +355,7 @@ bool ExtractAPIVisitorBase::VisitFunctionDecl(
return true;
// Collect symbol information.
- StringRef Name = Decl->getName();
+ auto Name = Decl->getNameAsString();
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
PresumedLoc Loc =
@@ -666,8 +669,8 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl(
if (FunctionTemplateDecl *TemplateDecl =
Decl->getDescribedFunctionTemplate()) {
API.createRecord(
- USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
- AvailabilityInfo::createFromDecl(Decl), Comment,
+ USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
+ Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
TemplateDecl),
SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl),
@@ -675,8 +678,8 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl(
Template(TemplateDecl), isInSystemHeader(Decl));
} else if (Decl->getTemplateSpecializationInfo())
API.createRecord(
- USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
- AvailabilityInfo::createFromDecl(Decl), Comment,
+ USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
+ Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::
getFragmentsForFunctionTemplateSpecialization(Decl),
SubHeading, Signature, Access, isInSystemHeader(Decl));
@@ -688,14 +691,14 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl(
SubHeading, Signature, Access, isInSystemHeader(Decl));
else if (Decl->isStatic())
API.createRecord(
- USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
- AvailabilityInfo::createFromDecl(Decl), Comment,
+ USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
+ Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
Signature, Access, isInSystemHeader(Decl));
else
API.createRecord(
- USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
- AvailabilityInfo::createFromDecl(Decl), Comment,
+ USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
+ Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
Signature, Access, isInSystemHeader(Decl));
@@ -977,7 +980,7 @@ bool ExtractAPIVisitorBase::VisitFunctionTemplateDecl(
return true;
// Collect symbol information.
- StringRef Name = Decl->getName();
+ auto Name = Decl->getNameAsString();
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
PresumedLoc Loc =
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index be3334b9807463..fc7d0053f2323b 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -2123,17 +2123,18 @@ class Preprocessor {
char
getSpellingOfSingleCharacterNumericConstant(const Token &Tok,
bool *Invalid = nullptr) const {
- assert(Tok.is(tok::numeric_constant) &&
+ assert((Tok.is(tok::numeric_constant) || Tok.is(tok::binary_data)) &&
Tok.getLength() == 1 && "Called on unsupported token");
assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1");
// If the token is carrying a literal data pointer, just use it.
if (const char *D = Tok.getLiteralData())
- return *D;
+ return (Tok.getKind() == tok::binary_data) ? *D : *D - '0';
+ assert(Tok.is(tok::numeric_constant) && "binary data with no data");
// Otherwise, fall back on getCharacterData, which is slower, but always
// works.
- return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid);
+ return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid) - '0';
}
/// Retrieve the name of the immediate macro expansion.
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index bb3f08aef0378b..93e60be512aae0 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2127,7 +2127,7 @@ class Parser : public CodeCompletionHandler {
};
ExprResult ParseInitializerWithPotentialDesignator(DesignatorCompletionInfo);
ExprResult createEmbedExpr();
- void ExpandEmbedDirective(SmallVectorImpl &Exprs);
+ void injectEmbedTokens();
//===--------------------------------------------------------------------===//
// clang Expressions
@@ -3372,11 +3372,15 @@ class Parser : public CodeCompletionHandler {
BaseResult ParseBaseSpecifier(Decl *ClassDecl);
AccessSpecifier getAccessSpecifierIfPresent() const;
- bool ParseUnqualifiedIdTemplateId(
- CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
- SourceLocation TemplateKWLoc, SourceLocation TildeLoc,
- IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext,
- UnqualifiedId &Id, bool AssumeTemplateId);
+ bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
+ ParsedType ObjectType,
+ bool ObjectHadErrors,
+ SourceLocation TemplateKWLoc,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool EnteringContext,
+ UnqualifiedId &Id,
+ bool AssumeTemplateId);
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Result);
@@ -3830,7 +3834,6 @@ class Parser : public CodeCompletionHandler {
AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
ImplicitTypenameContext AllowImplicitTypename,
bool IsClassName = false);
- void ExpandEmbedIntoTemplateArgList(TemplateArgList &TemplateArgs);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
TemplateTy Template, SourceLocation OpenLoc);
ParsedTemplateArgument ParseTemplateTemplateArgument();
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 9c22c35535ede7..425b6e2a0b30c9 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -75,7 +75,6 @@ class CXXScopeSpec {
SourceRange Range;
NestedNameSpecifierLocBuilder Builder;
ArrayRef TemplateParamLists;
- ArrayRef UnqualifiedLookups;
public:
SourceRange getRange() const { return Range; }
@@ -92,13 +91,6 @@ class CXXScopeSpec {
return TemplateParamLists;
}
- void setUnqualifiedLookups(ArrayRef Found) {
- UnqualifiedLookups = Found;
- }
- ArrayRef getUnqualifiedLookups() const {
- return UnqualifiedLookups;
- }
-
/// Retrieve the representation of the nested-name-specifier.
NestedNameSpecifier *getScopeRep() const {
return Builder.getRepresentation();
diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index 6b765ef3c980f6..b0a08a05ac6a0a 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -483,15 +483,11 @@ class LookupResult {
ResultKind = Found;
}
- void addAllDecls(ArrayRef Other) {
- Decls.addAllDecls(Other);
- ResultKind = Found;
- }
-
/// Add all the declarations from another set of lookup
/// results.
void addAllDecls(const LookupResult &Other) {
- addAllDecls(Other.Decls.pairs());
+ Decls.append(Other.Decls.begin(), Other.Decls.end());
+ ResultKind = Found;
}
/// Determine whether no result was found because we could not
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 4a5c9e8ca12295..9d8b797af66635 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -201,6 +201,9 @@ class Sema;
/// HLSL non-decaying array rvalue cast.
ICK_HLSL_Array_RValue,
+ // HLSL vector splat from scalar or boolean type.
+ ICK_HLSL_Vector_Splat,
+
/// The number of conversion kinds
ICK_Num_Conversion_Kinds,
};
@@ -213,15 +216,27 @@ class Sema;
/// Exact Match
ICR_Exact_Match = 0,
+ /// HLSL Scalar Widening
+ ICR_HLSL_Scalar_Widening,
+
/// Promotion
ICR_Promotion,
+ /// HLSL Scalar Widening with promotion
+ ICR_HLSL_Scalar_Widening_Promotion,
+
+ /// HLSL Matching Dimension Reduction
+ ICR_HLSL_Dimension_Reduction,
+
/// Conversion
ICR_Conversion,
/// OpenCL Scalar Widening
ICR_OCL_Scalar_Widening,
+ /// HLSL Scalar Widening with conversion
+ ICR_HLSL_Scalar_Widening_Conversion,
+
/// Complex <-> Real conversion
ICR_Complex_Real_Conversion,
@@ -233,11 +248,21 @@ class Sema;
/// Conversion not allowed by the C standard, but that we accept as an
/// extension anyway.
- ICR_C_Conversion_Extension
+ ICR_C_Conversion_Extension,
+
+ /// HLSL Dimension reduction with promotion
+ ICR_HLSL_Dimension_Reduction_Promotion,
+
+ /// HLSL Dimension reduction with conversion
+ ICR_HLSL_Dimension_Reduction_Conversion,
};
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
+ ImplicitConversionRank
+ GetDimensionConversionRank(ImplicitConversionRank Base,
+ ImplicitConversionKind Dimension);
+
/// NarrowingKind - The kind of narrowing conversion being performed by a
/// standard conversion sequence according to C++11 [dcl.init.list]p7.
enum NarrowingKind {
@@ -277,11 +302,10 @@ class Sema;
/// pointer-to-member conversion, or boolean conversion.
ImplicitConversionKind Second : 8;
- /// Element - Between the second and third conversion a vector or matrix
- /// element conversion may occur. If this is not ICK_Identity this
- /// conversion is applied element-wise to each element in the vector or
- /// matrix.
- ImplicitConversionKind Element : 8;
+ /// Dimension - Between the second and third conversion a vector or matrix
+ /// dimension conversion may occur. If this is not ICK_Identity this
+ /// conversion truncates the vector or matrix, or extends a scalar.
+ ImplicitConversionKind Dimension : 8;
/// Third - The third conversion can be a qualification conversion
/// or a function conversion.
@@ -379,7 +403,7 @@ class Sema;
void setAsIdentityConversion();
bool isIdentityConversion() const {
- return Second == ICK_Identity && Element == ICK_Identity &&
+ return Second == ICK_Identity && Dimension == ICK_Identity &&
Third == ICK_Identity;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6be6f6725e5b75..48dff1b76cc57f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -560,13 +560,14 @@ class Sema final : public SemaBase {
// 23. Statement Attribute Handling (SemaStmtAttr.cpp)
// 24. C++ Templates (SemaTemplate.cpp)
// 25. C++ Template Argument Deduction (SemaTemplateDeduction.cpp)
- // 26. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
- // 27. C++ Template Declaration Instantiation
+ // 26. C++ Template Deduction Guide (SemaTemplateDeductionGuide.cpp)
+ // 27. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
+ // 28. C++ Template Declaration Instantiation
// (SemaTemplateInstantiateDecl.cpp)
- // 28. C++ Variadic Templates (SemaTemplateVariadic.cpp)
- // 29. Constraints and Concepts (SemaConcept.cpp)
- // 30. Types (SemaType.cpp)
- // 31. FixIt Helpers (SemaFixItUtils.cpp)
+ // 29. C++ Variadic Templates (SemaTemplateVariadic.cpp)
+ // 30. Constraints and Concepts (SemaConcept.cpp)
+ // 31. Types (SemaType.cpp)
+ // 32. FixIt Helpers (SemaFixItUtils.cpp)
/// \name Semantic Analysis
/// Implementations are in Sema.cpp
@@ -2802,8 +2803,7 @@ class Sema final : public SemaBase {
/// (e.g., Base::), perform name lookup for that identifier as a
/// nested-name-specifier within the given scope, and return the result of
/// that name lookup.
- bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS,
- UnresolvedSetImpl &R);
+ NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
/// Keeps information about an identifier in a nested-name-spec.
///
@@ -2843,6 +2843,9 @@ class Sema final : public SemaBase {
/// \param EnteringContext If true, enter the context specified by the
/// nested-name-specifier.
/// \param SS Optional nested name specifier preceding the identifier.
+ /// \param ScopeLookupResult Provides the result of name lookup within the
+ /// scope of the nested-name-specifier that was computed at template
+ /// definition time.
/// \param ErrorRecoveryLookup Specifies if the method is called to improve
/// error recovery and what kind of recovery is performed.
/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
@@ -2851,6 +2854,11 @@ class Sema final : public SemaBase {
/// not '::'.
/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
+ /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
+ /// that it contains an extra parameter \p ScopeLookupResult, which provides
+ /// the result of name lookup within the scope of the nested-name-specifier
+ /// that was computed at template definition time.
+ ///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery. This means that it should not emit diagnostics, it should
/// just return true on failure. It also means it should only return a valid
@@ -2859,6 +2867,7 @@ class Sema final : public SemaBase {
/// specifier.
bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
bool EnteringContext, CXXScopeSpec &SS,
+ NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
bool *IsCorrectedToColon = nullptr,
bool OnlyNamespace = false);
@@ -8558,12 +8567,11 @@ class Sema final : public SemaBase {
const TemplateArgumentListInfo *TemplateArgs,
bool IsDefiniteInstance, const Scope *S);
- ExprResult
- ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow,
- SourceLocation OpLoc, const CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs);
+ ExprResult ActOnDependentMemberExpr(
+ Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs);
/// The main callback when the parser finds something like
/// expression . [nested-name-specifier] identifier
@@ -8619,14 +8627,15 @@ class Sema final : public SemaBase {
ExprResult BuildMemberReferenceExpr(
Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &NameInfo,
+ NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
ExprResult
BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc,
bool IsArrow, const CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc, LookupResult &R,
+ SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
const Scope *S, bool SuppressQualifierCheck = false,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
@@ -11114,14 +11123,15 @@ class Sema final : public SemaBase {
QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr,
- bool AllowTypoCorrection = true, bool MayBeNNS = false);
+ bool AllowTypoCorrection = true);
- TemplateNameKind
- isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword,
- const UnqualifiedId &Name, ParsedType ObjectType,
- bool EnteringContext, TemplateTy &Template,
- bool &MemberOfUnknownSpecialization,
- bool Disambiguation = false, bool MayBeNNS = false);
+ TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
+ bool hasTemplateKeyword,
+ const UnqualifiedId &Name,
+ ParsedType ObjectType, bool EnteringContext,
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization,
+ bool Disambiguation = false);
/// Try to resolve an undeclared template name as a type template.
///
@@ -11347,6 +11357,10 @@ class Sema final : public SemaBase {
bool &IsMemberSpecialization, bool &Invalid,
bool SuppressDiagnostic = false);
+ /// Returns the template parameter list with all default template argument
+ /// information.
+ TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD);
+
DeclResult CheckClassTemplate(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
@@ -11450,11 +11464,12 @@ class Sema final : public SemaBase {
/// For example, given "x.MetaFun::template apply", the scope specifier
/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
- TemplateNameKind
- ActOnTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- const UnqualifiedId &Name, ParsedType ObjectType,
- bool EnteringContext, TemplateTy &Template,
- bool AllowInjectedClassName = false, bool MayBeNNS = false);
+ TemplateNameKind ActOnTemplateName(Scope *S, CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ const UnqualifiedId &Name,
+ ParsedType ObjectType,
+ bool EnteringContext, TemplateTy &Template,
+ bool AllowInjectedClassName = false);
DeclResult ActOnClassTemplateSpecialization(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
@@ -12009,15 +12024,6 @@ class Sema final : public SemaBase {
unsigned TemplateDepth,
const Expr *Constraint);
- /// Declare implicit deduction guides for a class template if we've
- /// not already done so.
- void DeclareImplicitDeductionGuides(TemplateDecl *Template,
- SourceLocation Loc);
-
- FunctionTemplateDecl *DeclareAggregateDeductionGuideFromInitList(
- TemplateDecl *Template, MutableArrayRef ParamTypes,
- SourceLocation Loc);
-
/// Find the failed Boolean condition within a given Boolean
/// constant expression, and describe it with a string.
std::pair findFailedBooleanCondition(Expr *Cond);
@@ -12570,6 +12576,27 @@ class Sema final : public SemaBase {
//
//
+ /// \name C++ Template Deduction Guide
+ /// Implementations are in SemaTemplateDeductionGuide.cpp
+ ///@{
+
+ /// Declare implicit deduction guides for a class template if we've
+ /// not already done so.
+ void DeclareImplicitDeductionGuides(TemplateDecl *Template,
+ SourceLocation Loc);
+
+ FunctionTemplateDecl *DeclareAggregateDeductionGuideFromInitList(
+ TemplateDecl *Template, MutableArrayRef ParamTypes,
+ SourceLocation Loc);
+
+ ///@}
+
+ //
+ //
+ // -------------------------------------------------------------------------
+ //
+ //
+
/// \name C++ Template Instantiation
/// Implementations are in SemaTemplateInstantiate.cpp
///@{
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 497579dcc56b6e..6c89e3890ae3e8 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -7250,14 +7250,14 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
return NestedNameSpecifier::Create(*this, nullptr,
- NNS->getAsNamespace()->getOriginalNamespace());
+ NNS->getAsNamespace()->getFirstDecl());
case NestedNameSpecifier::NamespaceAlias:
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
- return NestedNameSpecifier::Create(*this, nullptr,
- NNS->getAsNamespaceAlias()->getNamespace()
- ->getOriginalNamespace());
+ return NestedNameSpecifier::Create(
+ *this, nullptr,
+ NNS->getAsNamespaceAlias()->getNamespace()->getFirstDecl());
// The difference between TypeSpec and TypeSpecWithTemplate is that the
// latter will have the 'template' keyword when printed.
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 9bb035c07b8ae1..4e1b3a5a94de76 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8439,14 +8439,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc());
auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc());
auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc());
-
- UnresolvedSet<8> ToUnqualifiedLookups;
- for (auto D : E->unqualified_lookups())
- if (auto ToDOrErr = import(D.getDecl()))
- ToUnqualifiedLookups.addDecl(*ToDOrErr);
- else
- return ToDOrErr.takeError();
-
+ auto ToFirstQualifierFoundInScope =
+ importChecked(Err, E->getFirstQualifierFoundInScope());
if (Err)
return std::move(Err);
@@ -8480,7 +8474,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
return CXXDependentScopeMemberExpr::Create(
Importer.getToContext(), ToBase, ToType, E->isArrow(), ToOperatorLoc,
- ToQualifierLoc, ToTemplateKeywordLoc, ToUnqualifiedLookups.pairs(),
+ ToQualifierLoc, ToTemplateKeywordLoc, ToFirstQualifierFoundInScope,
ToMemberNameInfo, ResInfo);
}
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index ef2c57e6204dc8..bc5a9206c0db28 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -1422,8 +1422,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::TranslationUnit:
return static_cast(this)->getFirstDecl();
case Decl::Namespace:
- // The original namespace is our primary context.
- return static_cast(this)->getOriginalNamespace();
+ return static_cast(this)->getFirstDecl();
case Decl::ObjCMethod:
return this;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index d5c140fd343895..72d68f39a97a53 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2941,7 +2941,7 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
NamedDecl *Used,
DeclContext *CommonAncestor) {
if (auto *NS = dyn_cast_or_null(Used))
- Used = NS->getOriginalNamespace();
+ Used = NS->getFirstDecl();
return new (C, DC) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc,
IdentLoc, Used, CommonAncestor);
}
@@ -2966,16 +2966,9 @@ NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
bool Nested)
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
redeclarable_base(C), LocStart(StartLoc) {
- unsigned Flags = 0;
- if (Inline)
- Flags |= F_Inline;
- if (Nested)
- Flags |= F_Nested;
- AnonOrFirstNamespaceAndFlags = {nullptr, Flags};
+ setInline(Inline);
+ setNested(Nested);
setPreviousDecl(PrevDecl);
-
- if (PrevDecl)
- AnonOrFirstNamespaceAndFlags.setPointer(PrevDecl->getOriginalNamespace());
}
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
@@ -2992,22 +2985,6 @@ NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C,
SourceLocation(), nullptr, nullptr, false);
}
-NamespaceDecl *NamespaceDecl::getOriginalNamespace() {
- if (isFirstDecl())
- return this;
-
- return AnonOrFirstNamespaceAndFlags.getPointer();
-}
-
-const NamespaceDecl *NamespaceDecl::getOriginalNamespace() const {
- if (isFirstDecl())
- return this;
-
- return AnonOrFirstNamespaceAndFlags.getPointer();
-}
-
-bool NamespaceDecl::isOriginalNamespace() const { return isFirstDecl(); }
-
NamespaceDecl *NamespaceDecl::getNextRedeclarationImpl() {
return getNextRedeclaration();
}
@@ -3043,7 +3020,7 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
NamedDecl *Namespace) {
// FIXME: Preserve the aliased namespace as written.
if (auto *NS = dyn_cast_or_null(Namespace))
- Namespace = NS->getOriginalNamespace();
+ Namespace = NS->getFirstDecl();
return new (C, DC) NamespaceAliasDecl(C, DC, UsingLoc, AliasLoc, Alias,
QualifierLoc, IdentLoc, Namespace);
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 9d2883a8debb72..8d2a1b5611ccc6 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1489,27 +1489,19 @@ SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const {
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc, ArrayRef UnqualifiedLookups,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue,
OK_Ordinary),
- Base(Base), BaseType(BaseType), MemberNameInfo(MemberNameInfo),
- OperatorLoc(OperatorLoc) {
+ Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc),
+ MemberNameInfo(MemberNameInfo) {
CXXDependentScopeMemberExprBits.IsArrow = IsArrow;
- CXXDependentScopeMemberExprBits.HasQualifier = QualifierLoc.hasQualifier();
- CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
- UnqualifiedLookups.size();
CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
(TemplateArgs != nullptr) || TemplateKWLoc.isValid();
-
- if (hasQualifier())
- new (getTrailingObjects())
- NestedNameSpecifierLoc(QualifierLoc);
-
- std::uninitialized_copy_n(UnqualifiedLookups.data(),
- UnqualifiedLookups.size(),
- getTrailingObjects());
+ CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
+ FirstQualifierFoundInScope != nullptr;
+ CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
@@ -1521,59 +1513,54 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
TemplateKWLoc);
}
+ if (hasFirstQualifierFoundInScope())
+ *getTrailingObjects() = FirstQualifierFoundInScope;
setDependence(computeDependence(this));
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
- EmptyShell Empty, bool HasQualifier, unsigned NumUnqualifiedLookups,
- bool HasTemplateKWAndArgsInfo)
+ EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
+ bool HasFirstQualifierFoundInScope)
: Expr(CXXDependentScopeMemberExprClass, Empty) {
- CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier;
- CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = NumUnqualifiedLookups;
CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
HasTemplateKWAndArgsInfo;
+ CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
+ HasFirstQualifierFoundInScope;
}
CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create(
const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc, ArrayRef UnqualifiedLookups,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
- bool HasQualifier = QualifierLoc.hasQualifier();
- unsigned NumUnqualifiedLookups = UnqualifiedLookups.size();
- assert(!NumUnqualifiedLookups || HasQualifier);
bool HasTemplateKWAndArgsInfo =
(TemplateArgs != nullptr) || TemplateKWLoc.isValid();
unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0;
- unsigned Size =
- totalSizeToAlloc(
- HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
- NumTemplateArgs);
+ bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr;
+
+ unsigned Size = totalSizeToAlloc(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
return new (Mem) CXXDependentScopeMemberExpr(
Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc,
- UnqualifiedLookups, MemberNameInfo, TemplateArgs);
+ FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs);
}
CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty(
- const ASTContext &Ctx, bool HasQualifier, unsigned NumUnqualifiedLookups,
- bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) {
- assert(!NumTemplateArgs || HasTemplateKWAndArgsInfo);
- assert(!NumUnqualifiedLookups || HasQualifier);
+ const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
+ unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) {
+ assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
- unsigned Size =
- totalSizeToAlloc(
- HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
- NumTemplateArgs);
+ unsigned Size = totalSizeToAlloc(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
- return new (Mem) CXXDependentScopeMemberExpr(EmptyShell(), HasQualifier,
- NumUnqualifiedLookups,
- HasTemplateKWAndArgsInfo);
+ return new (Mem) CXXDependentScopeMemberExpr(
+ EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope);
}
CXXThisExpr *CXXThisExpr::Create(const ASTContext &Ctx, SourceLocation L,
diff --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h
index 336f7941dfc479..1bfb26b1b669f9 100644
--- a/clang/lib/AST/Interp/Boolean.h
+++ b/clang/lib/AST/Interp/Boolean.h
@@ -45,15 +45,10 @@ class Boolean final {
Boolean operator-(const Boolean &Other) const { return Boolean(V - Other.V); }
Boolean operator~() const { return Boolean(true); }
- explicit operator int8_t() const { return V; }
- explicit operator uint8_t() const { return V; }
- explicit operator int16_t() const { return V; }
- explicit operator uint16_t() const { return V; }
- explicit operator int32_t() const { return V; }
- explicit operator uint32_t() const { return V; }
- explicit operator int64_t() const { return V; }
- explicit operator uint64_t() const { return V; }
- explicit operator bool() const { return V; }
+ template >>
+ explicit operator Ty() const {
+ return V;
+ }
APSInt toAPSInt() const {
return APSInt(APInt(1, static_cast(V), false), true);
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index ae777d555e9165..17da77bc63c9bb 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -93,6 +93,11 @@ Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
// Set up lambda capture to closure record field mapping.
if (isLambdaCallOperator(MD)) {
+ // The parent record needs to be complete, we need to know about all
+ // the lambda captures.
+ if (!MD->getParent()->isCompleteDefinition())
+ return nullptr;
+
const Record *R = P.getOrCreateRecord(MD->getParent());
llvm::DenseMap LC;
FieldDecl *LTC;
diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 48e7519f8f89d7..30dc7f5e4840be 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -3073,13 +3073,13 @@ bool Compiler::VisitStmtExpr(const StmtExpr *E) {
}
assert(S == Result);
- // This better produces a value (i.e. is an expression).
if (const Expr *ResultExpr = dyn_cast(S)) {
if (DiscardResult)
return this->discard(ResultExpr);
return this->delegate(ResultExpr);
}
- return false;
+
+ return this->visitStmt(S);
}
return BS.destroyLocals();
@@ -3583,7 +3583,19 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve
return checkDecl() && this->emitInitGlobal(*VarT, GlobalIndex, VD);
}
- return checkDecl() && this->visitGlobalInitializer(Init, GlobalIndex);
+ if (!checkDecl())
+ return false;
+
+ if (!this->emitGetPtrGlobal(GlobalIndex, Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+
+ if (!this->emitFinishInit(Init))
+ return false;
+
+ return this->emitPopPtr(Init);
};
// We've already seen and initialized this global.
@@ -3627,7 +3639,16 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve
if (!Init)
return true;
- return this->visitLocalInitializer(Init, *Offset);
+ if (!this->emitGetPtrLocal(*Offset, Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+
+ if (!this->emitFinishInit(Init))
+ return false;
+
+ return this->emitPopPtr(Init);
}
return false;
}
@@ -4685,6 +4706,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) {
case UO_PostInc: { // x++
if (!Ctx.getLangOpts().CPlusPlus14)
return this->emitInvalid(E);
+ if (!T)
+ return this->emitError(E);
if (!this->visit(SubExpr))
return false;
@@ -4706,6 +4729,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) {
case UO_PostDec: { // x--
if (!Ctx.getLangOpts().CPlusPlus14)
return this->emitInvalid(E);
+ if (!T)
+ return this->emitError(E);
if (!this->visit(SubExpr))
return false;
@@ -4727,6 +4752,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) {
case UO_PreInc: { // ++x
if (!Ctx.getLangOpts().CPlusPlus14)
return this->emitInvalid(E);
+ if (!T)
+ return this->emitError(E);
if (!this->visit(SubExpr))
return false;
@@ -4774,6 +4801,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) {
case UO_PreDec: { // --x
if (!Ctx.getLangOpts().CPlusPlus14)
return this->emitInvalid(E);
+ if (!T)
+ return this->emitError(E);
if (!this->visit(SubExpr))
return false;
@@ -4819,6 +4848,9 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) {
return E->isGLValue() || this->emitLoadPop(*T, E);
}
case UO_LNot: // !x
+ if (!T)
+ return this->emitError(E);
+
if (DiscardResult)
return this->discard(SubExpr);
@@ -4832,10 +4864,16 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) {
return this->emitCast(PT_Bool, ET, E);
return true;
case UO_Minus: // -x
+ if (!T)
+ return this->emitError(E);
+
if (!this->visit(SubExpr))
return false;
return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E);
case UO_Plus: // +x
+ if (!T)
+ return this->emitError(E);
+
if (!this->visit(SubExpr)) // noop
return false;
return DiscardResult ? this->emitPop(*T, E) : true;
@@ -4852,6 +4890,9 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) {
return this->discard(SubExpr);
return this->visit(SubExpr);
case UO_Not: // ~x
+ if (!T)
+ return this->emitError(E);
+
if (!this->visit(SubExpr))
return false;
return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
@@ -5094,9 +5135,10 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) {
if (E->getType()->isVoidType())
return true;
// Convert the dummy pointer to another pointer type if we have to.
- if (PrimType PT = classifyPrim(E); PT != PT_Ptr && isPtrType(PT)) {
- if (!this->emitDecayPtr(PT_Ptr, PT, E))
- return false;
+ if (PrimType PT = classifyPrim(E); PT != PT_Ptr) {
+ if (isPtrType(PT))
+ return this->emitDecayPtr(PT_Ptr, PT, E);
+ return false;
}
return true;
}
diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h
index de873c7e6825f9..23e7afd767e881 100644
--- a/clang/lib/AST/Interp/Compiler.h
+++ b/clang/lib/AST/Interp/Compiler.h
@@ -278,45 +278,6 @@ class Compiler : public ConstStmtVisitor, bool>,
/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
- /// Visits an initializer for a local.
- bool visitLocalInitializer(const Expr *Init, unsigned I) {
- if (!this->emitGetPtrLocal(I, Init))
- return false;
-
- if (!visitInitializer(Init))
- return false;
-
- if (!this->emitFinishInit(Init))
- return false;
-
- return this->emitPopPtr(Init);
- }
-
- /// Visits an initializer for a global.
- bool visitGlobalInitializer(const Expr *Init, unsigned I) {
- if (!this->emitGetPtrGlobal(I, Init))
- return false;
-
- if (!visitInitializer(Init))
- return false;
-
- if (!this->emitFinishInit(Init))
- return false;
-
- return this->emitPopPtr(Init);
- }
-
- /// Visits a delegated initializer.
- bool visitThisInitializer(const Expr *I) {
- if (!this->emitThis(I))
- return false;
-
- if (!visitInitializer(I))
- return false;
-
- return this->emitFinishInitPop(I);
- }
-
bool visitInitList(ArrayRef Inits, const Expr *ArrayFiller,
const Expr *E);
bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init);
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 913e8d514282ad..b5e992c5a9ac16 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -31,6 +31,9 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
if (!Func || !Func->hasBody())
Func = Compiler(*this, *P).compileFunc(FD);
+ if (!Func)
+ return false;
+
APValue DummyResult;
if (!Run(Parent, Func, DummyResult))
return false;
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index 9701796fb93039..74413baf6fc0c9 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -152,6 +152,8 @@ template <> bool EvalEmitter::emitRet(const SourceInfo &Info) {
// Implicitly convert lvalue to rvalue, if requested.
if (ConvertResultToRValue) {
+ if (!Ptr.isZero() && !Ptr.isDereferencable())
+ return false;
// Never allow reading from a non-const pointer, unless the memory
// has been created in this evaluation.
if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID())
diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h
index cc1cab8f39fb1e..db4cc9ae45b491 100644
--- a/clang/lib/AST/Interp/Integral.h
+++ b/clang/lib/AST/Interp/Integral.h
@@ -98,10 +98,10 @@ template class Integral final {
return Integral(V);
}
- explicit operator unsigned() const { return V; }
- explicit operator int64_t() const { return V; }
- explicit operator uint64_t() const { return V; }
- explicit operator int32_t() const { return V; }
+ template >>
+ explicit operator Ty() const {
+ return V;
+ }
APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast(V), Signed), !Signed);
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 0411fcad88ad0a..b673cc27aee21f 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -248,7 +248,8 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!Ptr.isExtern())
return true;
- if (Ptr.isInitialized())
+ if (Ptr.isInitialized() ||
+ (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))
return true;
if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
@@ -405,10 +406,16 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
// The This pointer is writable in constructors and destructors,
// even if isConst() returns true.
- if (const Function *Func = S.Current->getFunction();
- Func && (Func->isConstructor() || Func->isDestructor()) &&
- Ptr.block() == S.Current->getThis().block()) {
- return true;
+ // TODO(perf): We could be hitting this code path quite a lot in complex
+ // constructors. Is there a better way to do this?
+ if (S.Current->getFunction()) {
+ for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
+ if (const Function *Func = Frame->getFunction();
+ Func && (Func->isConstructor() || Func->isDestructor()) &&
+ Ptr.block() == Frame->getThis().block()) {
+ return true;
+ }
+ }
}
if (!Ptr.isBlockPointer())
@@ -438,6 +445,27 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return false;
}
+bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ assert(Ptr.isLive());
+
+ // FIXME: This check here might be kinda expensive. Maybe it would be better
+ // to have another field in InlineDescriptor for this?
+ if (!Ptr.isBlockPointer())
+ return true;
+
+ QualType PtrType = Ptr.getType();
+ if (!PtrType.isVolatileQualified())
+ return true;
+
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ if (S.getLangOpts().CPlusPlus)
+ S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;
+ else
+ S.FFDiag(Loc);
+ return false;
+}
+
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
assert(Ptr.isLive());
@@ -502,6 +530,8 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
+ if (!CheckVolatile(S, OpPC, Ptr, AK))
+ return false;
return true;
}
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 1df8d65c804454..c7d8604c7dc2ab 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -147,7 +147,7 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
const APSInt Val = RHS.toAPSInt();
QualType Ty = E->getType();
S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
- return true; // We will do the shift anyway but fix up the shift amount.
+ return !(S.getEvalStatus().Diag && !S.getEvalStatus().Diag->empty() && S.getLangOpts().CPlusPlus11);
}
if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
@@ -302,15 +302,16 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
auto Loc = E->getExprLoc();
S.report(Loc, diag::warn_integer_constant_overflow)
<< Trunc << Type << E->getSourceRange();
- return true;
- } else {
- S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
- if (!S.noteUndefinedBehavior()) {
- S.Stk.pop