2 changes: 1 addition & 1 deletion clang-tools-extra/clang-move/tool/ClangMove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ int main(int argc, const char **argv) {
Twine(EC.message()));

move::ClangMoveContext Context{Spec, Tool.getReplacements(),
std::string(InitialDirectory.str()), Style,
std::string(InitialDirectory), Style,
DumpDecls};
move::DeclarationReporter Reporter;
move::ClangMoveActionFactory Factory(&Context, &Reporter);
Expand Down
3 changes: 1 addition & 2 deletions clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
// appending the check name to the message in ClangTidyContext::diag and
// using getCustomDiagID.
std::string CheckNameInMessage = " [" + Error.DiagnosticName + "]";
if (Message.ends_with(CheckNameInMessage))
Message = Message.substr(0, Message.size() - CheckNameInMessage.size());
Message.consume_back(CheckNameInMessage);

auto TidyMessage =
Loc.isValid()
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace clang::tidy::utils {
static std::string cleanPath(StringRef Path) {
SmallString<256> Result = Path;
llvm::sys::path::remove_dots(Result, true);
return std::string(Result.str());
return std::string(Result);
}

namespace {
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) {
Parameters.drop_front(Head.size() + Pack.size());
SmallVector<const ParmVarDecl *> Result(Parameters.size());
// Fill in non-pack parameters
auto HeadIt = std::copy(Head.begin(), Head.end(), Result.begin());
auto *HeadIt = std::copy(Head.begin(), Head.end(), Result.begin());
auto TailIt = std::copy(Tail.rbegin(), Tail.rend(), Result.rbegin());
// Recurse on pack parameters
size_t Depth = 0;
Expand Down
6 changes: 5 additions & 1 deletion clang-tools-extra/clangd/SourceCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,11 @@ bool isSpelledInSource(SourceLocation Loc, const SourceManager &SM) {
if (Loc.isFileID())
return true;
auto Spelling = SM.getDecomposedSpellingLoc(Loc);
StringRef SpellingFile = SM.getSLocEntry(Spelling.first).getFile().getName();
bool InvalidSLocEntry = false;
const auto SLocEntry = SM.getSLocEntry(Spelling.first, &InvalidSLocEntry);
if (InvalidSLocEntry)
return false;
StringRef SpellingFile = SLocEntry.getFile().getName();
if (SpellingFile == "<scratch space>")
return false;
if (SpellingFile == "<built-in>")
Expand Down
19 changes: 19 additions & 0 deletions clang-tools-extra/clangd/unittests/SourceCodeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,25 @@ TEST(SourceCodeTests, isKeywords) {
EXPECT_FALSE(isKeyword("override", LangOpts));
}

TEST(SourceCodeTests, isSpelledInSource) {
Annotations Test("");
ParsedAST AST = TestTU::withCode(Test.code()).build();
const SourceManager &SM = AST.getSourceManager();

EXPECT_TRUE(
isSpelledInSource(SM.getLocForStartOfFile(SM.getMainFileID()), SM));

// Check that isSpelledInSource() handles various invalid source locations
// gracefully.
//
// Returning true for SourceLocation() is a behavior that falls out of the
// current implementation, which has an early exit for isFileID().
// FIXME: Should it return false on SourceLocation()? Does it matter?
EXPECT_TRUE(isSpelledInSource(SourceLocation(), SM));
EXPECT_FALSE(isSpelledInSource(
SourceLocation::getFromRawEncoding(SourceLocation::UIntTy(1 << 31)), SM));
}

struct IncrementalTestStep {
llvm::StringRef Src;
llvm::StringRef Contents;
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/modularize/ModularizeUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ std::string ModularizeUtilities::getDirectoryFromPath(StringRef Path) {
sys::path::remove_filename(Directory);
if (Directory.size() == 0)
return ".";
return std::string(Directory.str());
return std::string(Directory);
}

// Add unique problem file.
Expand Down
44 changes: 30 additions & 14 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -876,23 +876,38 @@ if (CLANG_ENABLE_BOOTSTRAP)
endforeach()
endif()

if (CLANG_BOLT_INSTRUMENT AND NOT LLVM_BUILD_INSTRUMENTED)
set(CLANG_BOLT OFF CACHE STRING "Apply BOLT optimization to Clang. \
May be specified as Instrument or Perf or LBR to use a particular profiling \
mechanism.")
string(TOUPPER "${CLANG_BOLT}" CLANG_BOLT)

if (CLANG_BOLT AND NOT LLVM_BUILD_INSTRUMENTED)
set(CLANG_PATH ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
set(CLANG_INSTRUMENTED ${CLANG_PATH}-bolt.inst)
set(CLANG_INSTRUMENTED ${LLVM_RUNTIME_OUTPUT_INTDIR}/${CLANG_BOLT_INSTRUMENTED})
set(BOLT_FDATA ${CMAKE_CURRENT_BINARY_DIR}/utils/perf-training/prof.fdata)

# Instrument clang with BOLT
add_custom_target(clang-instrumented
DEPENDS ${CLANG_INSTRUMENTED}
)
add_custom_command(OUTPUT ${CLANG_INSTRUMENTED}
DEPENDS clang llvm-bolt
COMMAND llvm-bolt ${CLANG_PATH} -o ${CLANG_INSTRUMENTED}
-instrument --instrumentation-file-append-pid
--instrumentation-file=${BOLT_FDATA}
COMMENT "Instrumenting clang binary with BOLT"
VERBATIM
)
# Pass extra flag in no-LBR mode
if (CLANG_BOLT STREQUAL "PERF")
set(BOLT_NO_LBR "-nl")
endif()

if (CLANG_BOLT STREQUAL "INSTRUMENT")
# Instrument clang with BOLT
add_custom_target(clang-instrumented
DEPENDS ${CLANG_INSTRUMENTED}
)
add_custom_command(OUTPUT ${CLANG_INSTRUMENTED}
DEPENDS clang llvm-bolt
COMMAND llvm-bolt ${CLANG_PATH} -o ${CLANG_INSTRUMENTED}
-instrument --instrumentation-file-append-pid
--instrumentation-file=${BOLT_FDATA}
COMMENT "Instrumenting clang binary with BOLT"
VERBATIM
)
add_custom_target(clang-bolt-training-deps DEPENDS clang-instrumented)
else() # perf or LBR
add_custom_target(clang-bolt-training-deps DEPENDS clang)
endif()

# Optimize original (pre-bolt) Clang using the collected profile
set(CLANG_OPTIMIZED ${CMAKE_CURRENT_BINARY_DIR}/clang.bolt)
Expand All @@ -906,6 +921,7 @@ if (CLANG_BOLT_INSTRUMENT AND NOT LLVM_BUILD_INSTRUMENTED)
-data ${BOLT_FDATA}
-reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions
-split-all-cold -split-eh -dyno-stats -icf=1 -use-gnu-stack
${BOLT_NO_LBR}
COMMAND ${CMAKE_COMMAND} -E rename ${CLANG_OPTIMIZED} $<TARGET_FILE:clang>
COMMENT "Optimizing Clang with BOLT"
VERBATIM
Expand Down
66 changes: 66 additions & 0 deletions clang/bindings/python/clang/cindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -3506,6 +3506,65 @@ def cursor(self):
return cursor


class Rewriter(ClangObject):
"""
The Rewriter is a wrapper class around clang::Rewriter
It enables rewriting buffers.
"""

@staticmethod
def create(tu):
"""
Creates a new Rewriter
Parameters:
tu -- The translation unit for the target AST.
"""
return Rewriter(conf.lib.clang_CXRewriter_create(tu))

def __init__(self, ptr):
ClangObject.__init__(self, ptr)

def __del__(self):
conf.lib.clang_CXRewriter_dispose(self)

def insert_text_before(self, loc, insert):
"""
Insert the specified string at the specified location in
the original buffer.
"""
conf.lib.clang_CXRewriter_insertTextBefore(self, loc, insert)

def replace_text(self, extent, replacement):
"""
This method replaces a range of characters in the input buffer with
a new string.
"""
conf.lib.clang_CXRewriter_replaceText(self, extent, replacement)

def remove_text(self, extent):
"""
Remove the specified text region.
"""
conf.lib.clang_CXRewriter_removeText(self, extent)

def overwrite_changed_files(self):
"""
Save all changed files to disk.
Returns 1 if any files were not saved successfully,
returns 0 otherwise.
"""
return conf.lib.clang_CXRewriter_overwriteChangedFiles(self)

def write_main_file_to_stdout(self):
"""
Writes the main file to stdout.
"""
sys.stdout.flush()
conf.lib.clang_CXRewriter_writeMainFileToStdOut(self)


# Now comes the plumbing to hook up the C library.

# Register callback types in common container.
Expand Down Expand Up @@ -3571,6 +3630,13 @@ def cursor(self):
("clang_codeCompleteGetNumDiagnostics", [CodeCompletionResults], c_int),
("clang_createIndex", [c_int, c_int], c_object_p),
("clang_createTranslationUnit", [Index, c_interop_string], c_object_p),
("clang_CXRewriter_create", [TranslationUnit], c_object_p),
("clang_CXRewriter_dispose", [Rewriter]),
("clang_CXRewriter_insertTextBefore", [Rewriter, SourceLocation, c_interop_string]),
("clang_CXRewriter_overwriteChangedFiles", [Rewriter], c_int),
("clang_CXRewriter_removeText", [Rewriter, SourceRange]),
("clang_CXRewriter_replaceText", [Rewriter, SourceRange, c_interop_string]),
("clang_CXRewriter_writeMainFileToStdOut", [Rewriter]),
("clang_CXXConstructor_isConvertingConstructor", [Cursor], bool),
("clang_CXXConstructor_isCopyConstructor", [Cursor], bool),
("clang_CXXConstructor_isDefaultConstructor", [Cursor], bool),
Expand Down
71 changes: 71 additions & 0 deletions clang/bindings/python/tests/cindex/test_rewrite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import unittest
import tempfile

from clang.cindex import (
Rewriter,
TranslationUnit,
File,
SourceLocation,
SourceRange,
)


class TestRewrite(unittest.TestCase):
code = """int main() { return 0; }"""

def setUp(self):
self.tmp = tempfile.NamedTemporaryFile(suffix=".cpp", buffering=0)
self.tmp.write(TestRewrite.code.encode("utf-8"))
self.tmp.flush()
self.tu = TranslationUnit.from_source(self.tmp.name)
self.rew = Rewriter.create(self.tu)
self.file = File.from_name(self.tu, self.tmp.name)

def tearDown(self):
self.tmp.close()

def get_content(self) -> str:
with open(self.tmp.name, "r", encoding="utf-8") as f:
return f.read()

def test_replace(self):
rng = SourceRange.from_locations(
SourceLocation.from_position(self.tu, self.file, 1, 5),
SourceLocation.from_position(self.tu, self.file, 1, 9),
)
self.rew.replace_text(rng, "MAIN")
self.rew.overwrite_changed_files()
self.assertEqual(self.get_content(), "int MAIN() { return 0; }")

def test_replace_shorter(self):
rng = SourceRange.from_locations(
SourceLocation.from_position(self.tu, self.file, 1, 5),
SourceLocation.from_position(self.tu, self.file, 1, 9),
)
self.rew.replace_text(rng, "foo")
self.rew.overwrite_changed_files()
self.assertEqual(self.get_content(), "int foo() { return 0; }")

def test_replace_longer(self):
rng = SourceRange.from_locations(
SourceLocation.from_position(self.tu, self.file, 1, 5),
SourceLocation.from_position(self.tu, self.file, 1, 9),
)
self.rew.replace_text(rng, "patatino")
self.rew.overwrite_changed_files()
self.assertEqual(self.get_content(), "int patatino() { return 0; }")

def test_insert(self):
pos = SourceLocation.from_position(self.tu, self.file, 1, 5)
self.rew.insert_text_before(pos, "ro")
self.rew.overwrite_changed_files()
self.assertEqual(self.get_content(), "int romain() { return 0; }")

def test_remove(self):
rng = SourceRange.from_locations(
SourceLocation.from_position(self.tu, self.file, 1, 5),
SourceLocation.from_position(self.tu, self.file, 1, 9),
)
self.rew.remove_text(rng)
self.rew.overwrite_changed_files()
self.assertEqual(self.get_content(), "int () { return 0; }")
2 changes: 1 addition & 1 deletion clang/cmake/caches/BOLT.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
set(CLANG_BOLT_INSTRUMENT ON CACHE BOOL "")
set(CLANG_BOLT "INSTRUMENT" CACHE STRING "")
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--emit-relocs,-znow" CACHE STRING "")

set(LLVM_ENABLE_PROJECTS "bolt;clang" CACHE STRING "")
Expand Down
63 changes: 63 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ ABI Changes in This Version
AST Dumping Potentially Breaking Changes
----------------------------------------

Clang Frontend Potentially Breaking Changes
-------------------------------------------

Target OS macros extension
^^^^^^^^^^^^^^^^^^^^^^^^^^
A new Clang extension (see :ref:`here <target_os_detail>`) is enabled for
Darwin (Apple platform) targets. Clang now defines ``TARGET_OS_*`` macros for
these targets, which could break existing code bases with improper checks for
the ``TARGET_OS_`` macros. For example, existing checks might fail to include
the ``TargetConditionals.h`` header from Apple SDKs and therefore leaving the
macros undefined and guarded code unexercised.

Affected code should be checked to see if it's still intended for the specific
target and fixed accordingly.

The extension can be turned off by the option ``-fno-define-target-os-macros``
as a workaround.

What's New in Clang |release|?
==============================
Some of the major new features and improvements to Clang are listed
Expand All @@ -62,14 +80,28 @@ C++ Language Changes
C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^

- Clang won't perform ODR checks for decls in the global module fragment any
more to ease the implementation and improve the user's using experience.
This follows the MSVC's behavior.
(`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^

- Implemented `P2718R0: Lifetime extension in range-based for loops <https://wg21.link/P2718R0>`_. Also
materialize temporary object which is a prvalue in discarded-value expression.

C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^

- Implemented `P2662R3 Pack Indexing <https://wg21.link/P2662R3>`_.


Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Substitute template parameter pack, when it is not explicitly specified
in the template parameters, but is deduced from a previous argument.
(`#78449: <https://github.com/llvm/llvm-project/issues/78449>`_).

C Language Changes
------------------
Expand All @@ -83,6 +115,17 @@ Non-comprehensive list of changes in this release
New Compiler Flags
------------------

.. _target_os_detail:

Target OS macros extension
^^^^^^^^^^^^^^^^^^^^^^^^^^
A pair of new flags ``-fdefine-target-os-macros`` and
``-fno-define-target-os-macros`` has been added to Clang to enable/disable the
extension to provide built-in definitions of a list of ``TARGET_OS_*`` macros
based on the target triple.

The extension is enabled by default for Darwin (Apple platform) targets.

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

Expand All @@ -97,12 +140,18 @@ Attribute Changes in Clang

Improvements to Clang's diagnostics
-----------------------------------
- Clang now applies syntax highlighting to the code snippets it
prints.

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

Bug Fixes in This Version
-------------------------
- Clang now accepts elaborated-type-specifiers that explicitly specialize
a member class template for an implicit instantiation of a class template.

- Fixed missing warnings when doing bool-like conversions in C23 (`#79435 <https://github.com/llvm/llvm-project/issues/79435>`_).

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -119,6 +168,18 @@ Bug Fixes to C++ Support
parameter where we did an incorrect specialization of the initialization of
the default parameter.
Fixes (`#68490 <https://github.com/llvm/llvm-project/issues/68490>`_)
- Fixed a bug where variables referenced by requires-clauses inside
nested generic lambdas were not properly injected into the constraint scope.
(`#73418 <https://github.com/llvm/llvm-project/issues/73418>`_)
- Fixed a crash where substituting into a requires-expression that refers to function
parameters during the equivalence determination of two constraint expressions.
(`#74447 <https://github.com/llvm/llvm-project/issues/74447>`_)
- Fixed deducing auto& from const int in template parameters of partial
specializations.
(`#77189 <https://github.com/llvm/llvm-project/issues/77189>`_)
- Fix for crash when using a erroneous type in a return statement.
Fixes (`#63244 <https://github.com/llvm/llvm-project/issues/63244>`_)
and (`#79745 <https://github.com/llvm/llvm-project/issues/79745>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -213,6 +274,8 @@ Sanitizers
Python Binding Changes
----------------------

- Exposed `CXRewriter` API as `class Rewriter`.

Additional Information
======================

Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,12 @@ enum CXCursorKind {
*/
CXCursor_CXXParenListInitExpr = 155,

CXCursor_LastExpr = CXCursor_CXXParenListInitExpr,
/**
* Represents a C++26 pack indexing expression.
*/
CXCursor_PackIndexingExpr = 156,

CXCursor_LastExpr = CXCursor_PackIndexingExpr,

/* Statements */
CXCursor_FirstStmt = 200,
Expand Down
22 changes: 18 additions & 4 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
DependentTypeOfExprTypes;
mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
DependentDecltypeTypes;

mutable llvm::FoldingSet<PackIndexingType> DependentPackIndexingTypes;

mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmType>
Expand Down Expand Up @@ -1713,6 +1716,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// C++11 decltype.
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;

QualType getPackIndexingType(QualType Pattern, Expr *IndexExpr,
bool FullySubstituted = false,
ArrayRef<QualType> Expansions = {},
int Index = -1) const;

/// Unary type transforms
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
UnaryTransformType::UTTKind UKind) const;
Expand Down Expand Up @@ -2405,12 +2413,18 @@ class ASTContext : public RefCountedBase<ASTContext> {
unsigned getTargetDefaultAlignForAttributeAligned() const;

/// Return the alignment in bits that should be given to a
/// global variable with type \p T.
unsigned getAlignOfGlobalVar(QualType T) const;
/// global variable with type \p T. If \p VD is non-null it will be
/// considered specifically for the query.
unsigned getAlignOfGlobalVar(QualType T, const VarDecl *VD) const;

/// Return the alignment in characters that should be given to a
/// global variable with type \p T.
CharUnits getAlignOfGlobalVarInChars(QualType T) const;
/// global variable with type \p T. If \p VD is non-null it will be
/// considered specifically for the query.
CharUnits getAlignOfGlobalVarInChars(QualType T, const VarDecl *VD) const;

/// Return the minimum alignement as specified by the target. If \p VD is
/// non-null it may be used to identify external or weak variables.
unsigned getMinGlobalAlignOfVar(uint64_t Size, const VarDecl *VD) const;

/// Return a conservative estimate of the alignment of the specified
/// decl \p D.
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/AST/ASTNodeTraverser.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,12 @@ class ASTNodeTraverser
void VisitDecltypeType(const DecltypeType *T) {
Visit(T->getUnderlyingExpr());
}

void VisitPackIndexingType(const PackIndexingType *T) {
Visit(T->getPattern());
Visit(T->getIndexExpr());
}

void VisitUnaryTransformType(const UnaryTransformType *T) {
Visit(T->getBaseType());
}
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/ComparisonCategories.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class ComparisonCategoryInfo {
friend class Sema;

public:
ComparisonCategoryInfo(const ASTContext &Ctx, CXXRecordDecl *RD,
ComparisonCategoryInfo(const ASTContext &Ctx, const CXXRecordDecl *RD,
ComparisonCategoryType Kind)
: Ctx(Ctx), Record(RD), Kind(Kind) {}

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/ComputeDependence.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class ArrayTypeTraitExpr;
class ExpressionTraitExpr;
class CXXNoexceptExpr;
class PackExpansionExpr;
class PackIndexingExpr;
class SubstNonTypeTemplateParmExpr;
class CoroutineSuspendExpr;
class DependentCoawaitExpr;
Expand Down Expand Up @@ -150,6 +151,7 @@ ExprDependence computeDependence(ArrayTypeTraitExpr *E);
ExprDependence computeDependence(ExpressionTraitExpr *E);
ExprDependence computeDependence(CXXNoexceptExpr *E, CanThrowResult CT);
ExprDependence computeDependence(PackExpansionExpr *E);
ExprDependence computeDependence(PackIndexingExpr *E);
ExprDependence computeDependence(SubstNonTypeTemplateParmExpr *E);
ExprDependence computeDependence(CoroutineSuspendExpr *E);
ExprDependence computeDependence(DependentCoawaitExpr *E);
Expand Down
5 changes: 2 additions & 3 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct SubobjectAdjustment {

union {
struct DTB DerivedToBase;
FieldDecl *Field;
const FieldDecl *Field;
struct P Ptr;
};

Expand All @@ -93,8 +93,7 @@ struct SubobjectAdjustment {
DerivedToBase.DerivedClass = DerivedClass;
}

SubobjectAdjustment(FieldDecl *Field)
: Kind(FieldAdjustment) {
SubobjectAdjustment(const FieldDecl *Field) : Kind(FieldAdjustment) {
this->Field = Field;
}

Expand Down
99 changes: 99 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -4331,6 +4331,105 @@ class SizeOfPackExpr final
}
};

class PackIndexingExpr final
: public Expr,
private llvm::TrailingObjects<PackIndexingExpr, Expr *> {
friend class ASTStmtReader;
friend class ASTStmtWriter;
friend TrailingObjects;

SourceLocation EllipsisLoc;

// The location of the closing bracket
SourceLocation RSquareLoc;

// The pack being indexed, followed by the index
Stmt *SubExprs[2];

size_t TransformedExpressions;

PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
ArrayRef<Expr *> SubstitutedExprs = {})
: Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
SubExprs{PackIdExpr, IndexExpr},
TransformedExpressions(SubstitutedExprs.size()) {

auto *Exprs = getTrailingObjects<Expr *>();
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
Exprs);

setDependence(computeDependence(this));
if (!isInstantiationDependent())
setValueKind(getSelectedExpr()->getValueKind());
}

/// Create an empty expression.
PackIndexingExpr(EmptyShell Empty) : Expr(PackIndexingExprClass, Empty) {}

unsigned numTrailingObjects(OverloadToken<Expr *>) const {
return TransformedExpressions;
}

public:
static PackIndexingExpr *Create(ASTContext &Context,
SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr,
Expr *IndexExpr, std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs = {});
static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
unsigned NumTransformedExprs);

/// Determine the location of the 'sizeof' keyword.
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }

/// Determine the location of the parameter pack.
SourceLocation getPackLoc() const { return SubExprs[0]->getBeginLoc(); }

/// Determine the location of the right parenthesis.
SourceLocation getRSquareLoc() const { return RSquareLoc; }

SourceLocation getBeginLoc() const LLVM_READONLY { return getPackLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY { return RSquareLoc; }

Expr *getPackIdExpression() const { return cast<Expr>(SubExprs[0]); }

NamedDecl *getPackDecl() const;

Expr *getIndexExpr() const { return cast<Expr>(SubExprs[1]); }

std::optional<unsigned> getSelectedIndex() const {
if (isInstantiationDependent())
return std::nullopt;
ConstantExpr *CE = cast<ConstantExpr>(getIndexExpr());
auto Index = CE->getResultAsAPSInt();
assert(Index.isNonNegative() && "Invalid index");
return static_cast<unsigned>(Index.getExtValue());
}

Expr *getSelectedExpr() const {
std::optional<unsigned> Index = getSelectedIndex();
assert(Index && "extracting the indexed expression of a dependant pack");
return getTrailingObjects<Expr *>()[*Index];
}

ArrayRef<Expr *> getExpressions() const {
return {getTrailingObjects<Expr *>(), TransformedExpressions};
}

static bool classof(const Stmt *T) {
return T->getStmtClass() == PackIndexingExprClass;
}

// Iterators
child_range children() { return child_range(SubExprs, SubExprs + 2); }

const_child_range children() const {
return const_child_range(SubExprs, SubExprs + 2);
}
};

/// Represents a reference to a non-type template parameter
/// that has been substituted with a template argument.
class SubstNonTypeTemplateParmExpr : public Expr {
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,11 @@ DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnmodifiedType())); })
DEF_TRAVERSE_TYPE(DecltypeType,
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })

DEF_TRAVERSE_TYPE(PackIndexingType, {
TRY_TO(TraverseType(T->getPattern()));
TRY_TO(TraverseStmt(T->getIndexExpr()));
})

DEF_TRAVERSE_TYPE(UnaryTransformType, {
TRY_TO(TraverseType(T->getBaseType()));
TRY_TO(TraverseType(T->getUnderlyingType()));
Expand Down Expand Up @@ -1343,6 +1348,11 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
})

DEF_TRAVERSE_TYPELOC(PackIndexingType, {
TRY_TO(TraverseType(TL.getPattern()));
TRY_TO(TraverseStmt(TL.getTypePtr()->getIndexExpr()));
})

DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
})
Expand Down Expand Up @@ -2854,6 +2864,7 @@ DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
DEF_TRAVERSE_STMT(PackExpansionExpr, {})
DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
DEF_TRAVERSE_STMT(PackIndexingExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
Expand Down
67 changes: 67 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -4934,6 +4934,73 @@ class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
Expr *E);
};

class PackIndexingType final
: public Type,
public llvm::FoldingSetNode,
private llvm::TrailingObjects<PackIndexingType, QualType> {
friend TrailingObjects;

const ASTContext &Context;
QualType Pattern;
Expr *IndexExpr;

unsigned Size;

protected:
friend class ASTContext; // ASTContext creates these.
PackIndexingType(const ASTContext &Context, QualType Canonical,
QualType Pattern, Expr *IndexExpr,
ArrayRef<QualType> Expansions = {});

public:
Expr *getIndexExpr() const { return IndexExpr; }
QualType getPattern() const { return Pattern; }

bool isSugared() const { return hasSelectedType(); }

QualType desugar() const {
if (hasSelectedType())
return getSelectedType();
return QualType(this, 0);
}

QualType getSelectedType() const {
assert(hasSelectedType() && "Type is dependant");
return *(getExpansionsPtr() + *getSelectedIndex());
}

std::optional<unsigned> getSelectedIndex() const;

bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; }

ArrayRef<QualType> getExpansions() const {
return {getExpansionsPtr(), Size};
}

static bool classof(const Type *T) {
return T->getTypeClass() == PackIndexing;
}

void Profile(llvm::FoldingSetNodeID &ID) {
if (hasSelectedType())
getSelectedType().Profile(ID);
else
Profile(ID, Context, getPattern(), getIndexExpr());
}
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
QualType Pattern, Expr *E);

private:
const QualType *getExpansionsPtr() const {
return getTrailingObjects<QualType>();
}

static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr,
ArrayRef<QualType> Expansions = {});

unsigned numTrailingObjects(OverloadToken<QualType>) const { return Size; }
};

/// A unary type transform, which is a type constructed from another.
class UnaryTransformType : public Type {
public:
Expand Down
28 changes: 28 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,34 @@ class DecltypeTypeLoc
}
};

struct PackIndexingTypeLocInfo {
SourceLocation EllipsisLoc;
};

class PackIndexingTypeLoc
: public ConcreteTypeLoc<UnqualTypeLoc, PackIndexingTypeLoc,
PackIndexingType, PackIndexingTypeLocInfo> {

public:
Expr *getIndexExpr() const { return getTypePtr()->getIndexExpr(); }
QualType getPattern() const { return getTypePtr()->getPattern(); }

SourceLocation getEllipsisLoc() const { return getLocalData()->EllipsisLoc; }
void setEllipsisLoc(SourceLocation Loc) { getLocalData()->EllipsisLoc = Loc; }

void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setEllipsisLoc(Loc);
}

TypeLoc getPatternLoc() const { return getInnerTypeLoc(); }

QualType getInnerType() const { return this->getTypePtr()->getPattern(); }

SourceRange getLocalSourceRange() const {
return SourceRange(getEllipsisLoc(), getEllipsisLoc());
}
};

struct UnaryTransformTypeLocInfo {
// FIXME: While there's only one unary transform right now, future ones may
// need different representations
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,20 @@ let Class = DecltypeType in {
}]>;
}

let Class = PackIndexingType in {
def : Property<"pattern", QualType> {
let Read = [{ node->getPattern() }];
}
def : Property<"indexExpression", ExprRef> {
let Read = [{ node->getIndexExpr() }];
}

def : Creator<[{
return ctx.getPackIndexingType(pattern, indexExpression);
}]>;
}


let Class = UnaryTransformType in {
def : Property<"baseType", QualType> {
let Read = [{ node->getBaseType() }];
Expand Down
8 changes: 7 additions & 1 deletion clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Debug.h"

namespace clang {
Expand Down Expand Up @@ -98,9 +99,14 @@ class UnsafeBufferUsageHandler {
#endif

public:
/// Returns a reference to the `Preprocessor`:
/// \return true iff buffer safety is opt-out at `Loc`; false otherwise.
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0;

/// \return true iff unsafe uses in containers should NOT be reported at
/// `Loc`; false otherwise.
virtual bool
ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const = 0;

virtual std::string
getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
StringRef WSSuffix = "") const = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
#define WARNING_GADGET(name) GADGET(name)
#endif

/// A `WARNING_GADGET` subset, where the code pattern of each gadget
/// corresponds uses of a (possibly hardened) contatiner (e.g., `std::span`).
#ifndef WARNING_CONTAINER_GADGET
#define WARNING_CONTAINER_GADGET(name) WARNING_GADGET(name)
#endif

/// Safe gadgets correspond to code patterns that aren't unsafe but need to be
/// properly recognized in order to emit correct warnings and fixes over unsafe
/// gadgets.
Expand All @@ -31,6 +37,7 @@ WARNING_GADGET(ArraySubscript)
WARNING_GADGET(PointerArithmetic)
WARNING_GADGET(UnsafeBufferUsageAttr)
WARNING_GADGET(DataInvocation)
WARNING_CONTAINER_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context
FIXABLE_GADGET(DerefSimplePtrArithFixable)
FIXABLE_GADGET(PointerDereference)
Expand All @@ -43,4 +50,5 @@ FIXABLE_GADGET(PointerInit)

#undef FIXABLE_GADGET
#undef WARNING_GADGET
#undef WARNING_CONTAINER_GADGET
#undef GADGET
11 changes: 10 additions & 1 deletion clang/include/clang/Basic/BuiltinsNVPTX.def
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#pragma push_macro("PTX42")
#pragma push_macro("PTX60")
#pragma push_macro("PTX61")
#pragma push_macro("PTX62")
#pragma push_macro("PTX63")
#pragma push_macro("PTX64")
#pragma push_macro("PTX65")
Expand Down Expand Up @@ -76,7 +77,8 @@
#define PTX65 "ptx65|" PTX70
#define PTX64 "ptx64|" PTX65
#define PTX63 "ptx63|" PTX64
#define PTX61 "ptx61|" PTX63
#define PTX62 "ptx62|" PTX63
#define PTX61 "ptx61|" PTX62
#define PTX60 "ptx60|" PTX61
#define PTX42 "ptx42|" PTX60

Expand Down Expand Up @@ -146,6 +148,7 @@ BUILTIN(__nvvm_read_ptx_sreg_lanemask_gt, "i", "nc")

BUILTIN(__nvvm_read_ptx_sreg_clock, "i", "n")
BUILTIN(__nvvm_read_ptx_sreg_clock64, "LLi", "n")
BUILTIN(__nvvm_read_ptx_sreg_globaltimer, "LLi", "n")

BUILTIN(__nvvm_read_ptx_sreg_pm0, "i", "n")
BUILTIN(__nvvm_read_ptx_sreg_pm1, "i", "n")
Expand All @@ -155,6 +158,8 @@ BUILTIN(__nvvm_read_ptx_sreg_pm3, "i", "n")
// MISC

BUILTIN(__nvvm_prmt, "UiUiUiUi", "")
BUILTIN(__nvvm_exit, "v", "r")
TARGET_BUILTIN(__nvvm_nanosleep, "vUi", "n", AND(SM_70, PTX63))

// Min Max

Expand Down Expand Up @@ -632,6 +637,9 @@ TARGET_BUILTIN(__nvvm_vote_any_sync, "bUib", "", PTX60)
TARGET_BUILTIN(__nvvm_vote_uni_sync, "bUib", "", PTX60)
TARGET_BUILTIN(__nvvm_vote_ballot_sync, "UiUib", "", PTX60)

// Mask
TARGET_BUILTIN(__nvvm_activemask, "Ui", "n", PTX62)

// Match
TARGET_BUILTIN(__nvvm_match_any_sync_i32, "UiUiUi", "", AND(SM_70,PTX60))
TARGET_BUILTIN(__nvvm_match_any_sync_i64, "UiUiWi", "", AND(SM_70,PTX60))
Expand Down Expand Up @@ -1065,6 +1073,7 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
#pragma pop_macro("PTX42")
#pragma pop_macro("PTX60")
#pragma pop_macro("PTX61")
#pragma pop_macro("PTX62")
#pragma pop_macro("PTX63")
#pragma pop_macro("PTX64")
#pragma pop_macro("PTX65")
Expand Down
17 changes: 14 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5721,9 +5721,18 @@ def err_function_parameter_pack_without_parameter_packs : Error<
def err_ellipsis_in_declarator_not_parameter : Error<
"only function and template parameters can be parameter packs">;

def err_sizeof_pack_no_pack_name : Error<
def err_expected_name_of_pack : Error<
"%0 does not refer to the name of a parameter pack">;

def err_pack_index_out_of_bound : Error<
"invalid index %0 for pack %1 of size %2">;

def ext_pack_indexing : ExtWarn<
"pack indexing is a C++2c extension">, InGroup<CXX26>;
def warn_cxx23_pack_indexing : Warning<
"pack indexing is incompatible with C++ standards before C++2c">,
DefaultIgnore, InGroup<CXXPre26Compat>;

def err_fold_expression_packs_both_sides : Error<
"binary fold expression has unexpanded parameter packs in both operands">;
def err_fold_expression_empty : Error<
Expand Down Expand Up @@ -7139,8 +7148,7 @@ def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">,
def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration "
"of a type">, InGroup<MissingDeclarations>;
def err_standalone_class_nested_name_specifier : Error<
"forward declaration of %select{class|struct|interface|union|enum|enum class|enum struct}0 cannot "
"have a nested name specifier">;
"forward declaration of %0 cannot have a nested name specifier">;
def err_typecheck_sclass_func : Error<"illegal storage class on function">;
def err_static_block_func : Error<
"function declared in block scope cannot have 'static' storage class">;
Expand Down Expand Up @@ -12111,6 +12119,9 @@ def note_unsafe_buffer_variable_fixit_together : Note<
"%select{|, and change %2 to safe types to make function %4 bounds-safe}3">;
def note_safe_buffer_usage_suggestions_disabled : Note<
"pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions">;
def warn_unsafe_buffer_usage_in_container : Warning<
"the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information">,
InGroup<UnsafeBufferUsageInContainer>, DefaultIgnore;
#ifndef NDEBUG
// Not a user-facing diagnostic. Useful for debugging false negatives in
// -fsafe-buffer-usage-suggestions (i.e. lack of -Wunsafe-buffer-usage fixits).
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ enum class OpenACCClauseKind {
Async,
/// 'tile' clause, allowed on 'loop' and Combined constructs.
Tile,
/// 'gang' clause, allowed on 'loop' and Combined constructs.
Gang,

/// Represents an invalid clause, for the purposes of parsing.
Invalid,
Expand Down Expand Up @@ -371,6 +373,9 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
case OpenACCClauseKind::Tile:
return Out << "tile";

case OpenACCClauseKind::Gang:
return Out << "gang";

case OpenACCClauseKind::Invalid:
return Out << "<invalid>";
}
Expand Down
12 changes: 7 additions & 5 deletions clang/include/clang/Basic/Specifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,24 @@ namespace clang {
TST_enum,
TST_union,
TST_struct,
TST_class, // C++ class type
TST_interface, // C++ (Microsoft-specific) __interface type
TST_typename, // Typedef, C++ class-name or enum name, etc.
TST_class, // C++ class type
TST_interface, // C++ (Microsoft-specific) __interface type
TST_typename, // Typedef, C++ class-name or enum name, etc.
TST_typeofType, // C23 (and GNU extension) typeof(type-name)
TST_typeofExpr, // C23 (and GNU extension) typeof(expression)
TST_typeof_unqualType, // C23 typeof_unqual(type-name)
TST_typeof_unqualExpr, // C23 typeof_unqual(expression)
TST_decltype, // C++11 decltype
TST_decltype, // C++11 decltype
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait,
#include "clang/Basic/TransformTypeTraits.def"
TST_auto, // C++11 auto
TST_decltype_auto, // C++1y decltype(auto)
TST_auto_type, // __auto_type extension
TST_unknown_anytype, // __unknown_anytype extension
TST_atomic, // C11 _Atomic
#define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
TST_typename_pack_indexing,
#define GENERIC_IMAGE_TYPE(ImgType, Id) \
TST_##ImgType##_t, // OpenCL image types
#include "clang/Basic/OpenCLImageTypes.def"
TST_error // erroneous type
};
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ def UnresolvedMemberExpr : StmtNode<OverloadExpr>;
def CXXNoexceptExpr : StmtNode<Expr>;
def PackExpansionExpr : StmtNode<Expr>;
def SizeOfPackExpr : StmtNode<Expr>;
def PackIndexingExpr : StmtNode<Expr>;
def SubstNonTypeTemplateParmExpr : StmtNode<Expr>;
def SubstNonTypeTemplateParmPackExpr : StmtNode<Expr>;
def FunctionParmPackExpr : StmtNode<Expr>;
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,10 @@ class TargetInfo : public TransferrableTargetInfo,
}

/// getMinGlobalAlign - Return the minimum alignment of a global variable,
/// unless its alignment is explicitly reduced via attributes.
virtual unsigned getMinGlobalAlign (uint64_t) const {
/// unless its alignment is explicitly reduced via attributes. If \param
/// HasNonWeakDef is true, this concerns a VarDecl which has a definition
/// in current translation unit and that is not weak.
virtual unsigned getMinGlobalAlign(uint64_t Size, bool HasNonWeakDef) const {
return MinGlobalAlign;
}

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,8 @@ ANNOTATION(primary_expr) // annotation for a primary expression, used when
// message send
ANNOTATION(decltype) // annotation for a decltype expression,
// e.g., "decltype(foo.bar())"
ANNOTATION(pack_indexing_type) // annotation for an indexed pack of type,
// e.g., "T...[expr]"

// Annotation for #pragma unused(...)
// For each argument inside the parentheses the pragma handler will produce
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TypeNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def InjectedClassNameType : TypeNode<Type>, AlwaysDependent, LeafType;
def DependentNameType : TypeNode<Type>, AlwaysDependent;
def DependentTemplateSpecializationType : TypeNode<Type>, AlwaysDependent;
def PackExpansionType : TypeNode<Type>, AlwaysDependent;
def PackIndexingType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def ObjCTypeParamType : TypeNode<Type>, NeverCanonical;
def ObjCObjectType : TypeNode<Type>;
def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType;
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4619,6 +4619,10 @@ def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64/LoongArch/RISC-V only)">;
def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_Group>,
HelpText<"Force all memory accesses to be aligned (AArch32/AArch64/LoongArch/RISC-V only)">;
def munaligned_symbols : Flag<["-"], "munaligned-symbols">, Group<m_Group>,
HelpText<"Expect external char-aligned symbols to be without ABI alignment (SystemZ only)">;
def mno_unaligned_symbols : Flag<["-"], "mno-unaligned-symbols">, Group<m_Group>,
HelpText<"Expect external char-aligned symbols to be without ABI alignment (SystemZ only)">;
} // let Flags = [TargetSpecific]
def mstrict_align : Flag<["-"], "mstrict-align">, Alias<mno_unaligned_access>,
Flags<[HelpHidden]>, Visibility<[ClangOption, CC1Option]>,
Expand Down
3 changes: 1 addition & 2 deletions clang/include/clang/ExtractAPI/DeclarationFragments.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,7 @@ DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
Function->getASTContext(), After);
if (isa<FunctionDecl>(Function) &&
dyn_cast<FunctionDecl>(Function)->getDescribedFunctionTemplate() &&
ReturnType.begin()->Spelling.substr(0, 14).compare("type-parameter") ==
0) {
StringRef(ReturnType.begin()->Spelling).starts_with("type-parameter")) {
std::string ProperArgName =
getNameForTemplateArgument(dyn_cast<FunctionDecl>(Function)
->getDescribedFunctionTemplate()
Expand Down
18 changes: 14 additions & 4 deletions clang/include/clang/Frontend/TextDiagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define LLVM_CLANG_FRONTEND_TEXTDIAGNOSTIC_H

#include "clang/Frontend/DiagnosticRenderer.h"
#include "llvm/Support/raw_ostream.h"

namespace clang {

Expand All @@ -33,14 +34,22 @@ namespace clang {
/// printing coming out of libclang.
class TextDiagnostic : public DiagnosticRenderer {
raw_ostream &OS;
const Preprocessor *PP;

public:
TextDiagnostic(raw_ostream &OS,
const LangOptions &LangOpts,
DiagnosticOptions *DiagOpts);
TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
DiagnosticOptions *DiagOpts, const Preprocessor *PP = nullptr);

~TextDiagnostic() override;

struct StyleRange {
unsigned Start;
unsigned End;
enum llvm::raw_ostream::Colors Color;
StyleRange(unsigned S, unsigned E, enum llvm::raw_ostream::Colors C)
: Start(S), End(E), Color(C){};
};

/// Print the diagonstic level to a raw_ostream.
///
/// This is a static helper that handles colorizing the level and formatting
Expand Down Expand Up @@ -104,7 +113,8 @@ class TextDiagnostic : public DiagnosticRenderer {
ArrayRef<FixItHint> Hints);

void emitSnippet(StringRef SourceLine, unsigned MaxLineNoDisplayWidth,
unsigned LineNo);
unsigned LineNo, unsigned DisplayLineNo,
ArrayRef<StyleRange> Styles);

void emitParseableFixits(ArrayRef<FixItHint> Hints, const SourceManager &SM);
};
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,13 @@ class Preprocessor {
/// The kind of translation unit we are processing.
const TranslationUnitKind TUKind;

/// Returns a pointer into the given file's buffer that's guaranteed
/// to be between tokens. The returned pointer is always before \p Start.
/// The maximum distance betweenthe returned pointer and \p Start is
/// limited by a constant value, but also an implementation detail.
/// If no such check point exists, \c nullptr is returned.
const char *getCheckPoint(FileID FID, const char *Start) const;

private:
/// The code-completion handler.
CodeCompletionHandler *CodeComplete = nullptr;
Expand Down Expand Up @@ -311,6 +318,9 @@ class Preprocessor {
/// The import path for named module that we're currently processing.
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> NamedModuleImportPath;

llvm::DenseMap<FileID, SmallVector<const char *>> CheckPoints;
unsigned CheckPointCounter = 0;

/// Whether the import is an `@import` or a standard c++ modules import.
bool IsAtImport = false;

Expand Down
15 changes: 14 additions & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,10 @@ class Parser : public CodeCompletionHandler {
// C++ Expressions
ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
Token &Replacement);

ExprResult tryParseCXXPackIndexingExpression(ExprResult PackIdExpression);
ExprResult ParseCXXPackIndexingExpression(ExprResult PackIdExpression);

ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);

bool areTokensAdjacent(const Token &A, const Token &B);
Expand Down Expand Up @@ -2398,7 +2402,7 @@ class Parser : public CodeCompletionHandler {
struct ForRangeInit {
SourceLocation ColonLoc;
ExprResult RangeExpr;

SmallVector<MaterializeTemporaryExpr *, 8> LifetimeExtendTemps;
bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); }
};
struct ForRangeInfo : ForRangeInit {
Expand Down Expand Up @@ -2457,6 +2461,11 @@ class Parser : public CodeCompletionHandler {
DeclSpecContext DSC, LateParsedAttrList *LateAttrs,
ImplicitTypenameContext AllowImplicitTypename);

SourceLocation ParsePackIndexingType(DeclSpec &DS);
void AnnotateExistingIndexedTypeNamePack(ParsedType T,
SourceLocation StartLoc,
SourceLocation EndLoc);

bool DiagnoseMissingSemiAfterTagDefinition(
DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext,
LateParsedAttrList *LateAttrs = nullptr);
Expand Down Expand Up @@ -3596,6 +3605,10 @@ class Parser : public CodeCompletionHandler {
bool ParseOpenACCSizeExpr();
/// Parses a comma delimited list of 'size-expr's.
bool ParseOpenACCSizeExprList();
/// Parses a 'gang-arg-list', used for the 'gang' clause.
bool ParseOpenACCGangArgList();
/// Parses a 'gang-arg', used for the 'gang' clause.
bool ParseOpenACCGangArg();

private:
//===--------------------------------------------------------------------===//
Expand Down
26 changes: 24 additions & 2 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ class DeclSpec {
static const TST TST_typeof_unqualExpr = clang::TST_typeof_unqualExpr;
static const TST TST_decltype = clang::TST_decltype;
static const TST TST_decltype_auto = clang::TST_decltype_auto;
static const TST TST_typename_pack_indexing =
clang::TST_typename_pack_indexing;
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
static const TST TST_##Trait = clang::TST_##Trait;
#include "clang/Basic/TransformTypeTraits.def"
Expand Down Expand Up @@ -389,6 +391,7 @@ class DeclSpec {
Expr *ExprRep;
TemplateIdAnnotation *TemplateIdRep;
};
Expr *PackIndexingExpr = nullptr;

/// ExplicitSpecifier - Store information about explicit spicifer.
ExplicitSpecifier FS_explicit_specifier;
Expand All @@ -405,7 +408,7 @@ class DeclSpec {

SourceLocation StorageClassSpecLoc, ThreadStorageClassSpecLoc;
SourceRange TSWRange;
SourceLocation TSCLoc, TSSLoc, TSTLoc, AltiVecLoc, TSSatLoc;
SourceLocation TSCLoc, TSSLoc, TSTLoc, AltiVecLoc, TSSatLoc, EllipsisLoc;
/// TSTNameLoc - If TypeSpecType is any of class, enum, struct, union,
/// typename, then this is the location of the named type (if present);
/// otherwise, it is the same as TSTLoc. Hence, the pair TSTLoc and
Expand All @@ -427,7 +430,8 @@ class DeclSpec {

static bool isTypeRep(TST T) {
return T == TST_atomic || T == TST_typename || T == TST_typeofType ||
T == TST_typeof_unqualType || isTransformTypeTrait(T);
T == TST_typeof_unqualType || isTransformTypeTrait(T) ||
T == TST_typename_pack_indexing;
}
static bool isExprRep(TST T) {
return T == TST_typeofExpr || T == TST_typeof_unqualExpr ||
Expand Down Expand Up @@ -530,6 +534,13 @@ class DeclSpec {
assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
return ExprRep;
}

Expr *getPackIndexingExpr() const {
assert(TypeSpecType == TST_typename_pack_indexing &&
"DeclSpec is not a pack indexing expr");
return PackIndexingExpr;
}

TemplateIdAnnotation *getRepAsTemplateId() const {
assert(isTemplateIdRep((TST) TypeSpecType) &&
"DeclSpec does not store a template id");
Expand Down Expand Up @@ -587,6 +598,7 @@ class DeclSpec {
SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; }
SourceLocation getUnalignedSpecLoc() const { return TQ_unalignedLoc; }
SourceLocation getPipeLoc() const { return TQ_pipeLoc; }
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }

/// Clear out all of the type qualifiers.
void ClearTypeQualifiers() {
Expand Down Expand Up @@ -743,6 +755,9 @@ class DeclSpec {
const PrintingPolicy &Policy);
bool SetTypeSpecSat(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);

void SetPackIndexingExpr(SourceLocation EllipsisLoc, Expr *Pack);

bool SetTypeSpecError();
void UpdateDeclRep(Decl *Rep) {
assert(isDeclRep((TST) TypeSpecType));
Expand Down Expand Up @@ -1939,6 +1954,8 @@ class Declarator {
/// this declarator as a parameter pack.
SourceLocation EllipsisLoc;

Expr *PackIndexingExpr;

friend struct DeclaratorChunk;

public:
Expand Down Expand Up @@ -2063,6 +2080,7 @@ class Declarator {
ObjCWeakProperty = false;
CommaLoc = SourceLocation();
EllipsisLoc = SourceLocation();
PackIndexingExpr = nullptr;
}

/// mayOmitIdentifier - Return true if the identifier is either optional or
Expand Down Expand Up @@ -2648,6 +2666,10 @@ class Declarator {
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; }

bool hasPackIndexing() const { return PackIndexingExpr != nullptr; }
Expr *getPackIndexingExpr() const { return PackIndexingExpr; }
void setPackIndexingExpr(Expr *PI) { PackIndexingExpr = PI; }

void setFunctionDefinitionKind(FunctionDefinitionKind Val) {
FunctionDefinition = static_cast<unsigned>(Val);
}
Expand Down
129 changes: 113 additions & 16 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,12 @@ class Sema final {
/// context not already known to be immediately invoked.
llvm::SmallPtrSet<DeclRefExpr *, 4> ReferenceToConsteval;

/// P2718R0 - Lifetime extension in range-based for loops.
/// MaterializeTemporaryExprs in for-range-init expressions which need to
/// extend lifetime. Add MaterializeTemporaryExpr* if the value of
/// InLifetimeExtendingContext is true.
SmallVector<MaterializeTemporaryExpr *, 8> ForRangeLifetimeExtendTemps;

/// \brief Describes whether we are in an expression constext which we have
/// to handle differently.
enum ExpressionKind {
Expand All @@ -1361,6 +1367,39 @@ class Sema final {
// VLAs).
bool InConditionallyConstantEvaluateContext = false;

/// Whether we are currently in a context in which all temporaries must be
/// lifetime-extended, even if they're not bound to a reference (for
/// example, in a for-range initializer).
bool InLifetimeExtendingContext = false;

/// Whether we are currently in a context in which all temporaries must be
/// materialized.
///
/// [class.temporary]/p2:
/// The materialization of a temporary object is generally delayed as long
/// as possible in order to avoid creating unnecessary temporary objects.
///
/// Temporary objects are materialized:
/// (2.1) when binding a reference to a prvalue ([dcl.init.ref],
/// [expr.type.conv], [expr.dynamic.cast], [expr.static.cast],
/// [expr.const.cast], [expr.cast]),
///
/// (2.2) when performing member access on a class prvalue ([expr.ref],
/// [expr.mptr.oper]),
///
/// (2.3) when performing an array-to-pointer conversion or subscripting
/// on an array prvalue ([conv.array], [expr.sub]),
///
/// (2.4) when initializing an object of type
/// std​::​initializer_list<T> from a braced-init-list
/// ([dcl.init.list]),
///
/// (2.5) for certain unevaluated operands ([expr.typeid], [expr.sizeof])
///
/// (2.6) when a prvalue that has type other than cv void appears as a
/// discarded-value expression ([expr.context]).
bool InMaterializeTemporaryObjectContext = false;

// When evaluating immediate functions in the initializer of a default
// argument or default member initializer, this is the declaration whose
// default initializer is being evaluated and the location of the call
Expand Down Expand Up @@ -2602,6 +2641,14 @@ class Sema final {
/// context, such as when building a type for decltype(auto).
QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true);

QualType ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
SourceLocation Loc,
SourceLocation EllipsisLoc);
QualType BuildPackIndexingType(QualType Pattern, Expr *IndexExpr,
SourceLocation Loc, SourceLocation EllipsisLoc,
bool FullySubstituted = false,
ArrayRef<QualType> Expansions = {});

using UTTKind = UnaryTransformType::UTTKind;
QualType BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
Expand Down Expand Up @@ -5245,22 +5292,17 @@ class Sema final {
BFRK_Check
};

StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
SourceLocation CoawaitLoc,
Stmt *InitStmt,
Stmt *LoopVar,
SourceLocation ColonLoc, Expr *Collection,
SourceLocation RParenLoc,
BuildForRangeKind Kind);
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation CoawaitLoc,
Stmt *InitStmt,
SourceLocation ColonLoc,
Stmt *RangeDecl, Stmt *Begin, Stmt *End,
Expr *Cond, Expr *Inc,
Stmt *LoopVarDecl,
SourceLocation RParenLoc,
BuildForRangeKind Kind);
StmtResult ActOnCXXForRangeStmt(
Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc,
Stmt *InitStmt, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection,
SourceLocation RParenLoc, BuildForRangeKind Kind,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps = {});
StmtResult BuildCXXForRangeStmt(
SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt,
SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *Begin, Stmt *End,
Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc,
BuildForRangeKind Kind,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps = {});
StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body);

StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
Expand Down Expand Up @@ -5873,6 +5915,18 @@ class Sema final {
IdentifierInfo &Name,
SourceLocation NameLoc,
SourceLocation RParenLoc);

ExprResult ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
SourceLocation EllipsisLoc,
SourceLocation LSquareLoc, Expr *IndexExpr,
SourceLocation RSquareLoc);

ExprResult BuildPackIndexingExpr(Expr *PackExpression,
SourceLocation EllipsisLoc, Expr *IndexExpr,
SourceLocation RSquareLoc,
ArrayRef<Expr *> ExpandedExprs = {},
bool EmptyPack = false);

ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, Expr *Input);

Expand Down Expand Up @@ -7140,6 +7194,11 @@ class Sema final {
const DeclSpec &DS,
SourceLocation ColonColonLoc);

bool ActOnCXXNestedNameSpecifierIndexedPack(CXXScopeSpec &SS,
const DeclSpec &DS,
SourceLocation ColonColonLoc,
QualType Type);

bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
NestedNameSpecInfo &IdInfo,
bool EnteringContext);
Expand Down Expand Up @@ -9985,6 +10044,18 @@ class Sema final {
return currentEvaluationContext().isImmediateFunctionContext();
}

bool isInLifetimeExtendingContext() const {
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
return ExprEvalContexts.back().InLifetimeExtendingContext;
}

bool isInMaterializeTemporaryObjectContext() const {
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
return ExprEvalContexts.back().InMaterializeTemporaryObjectContext;
}

bool isCheckingDefaultArgumentOrInitializer() const {
const ExpressionEvaluationContextRecord &Ctx = currentEvaluationContext();
return (Ctx.Context ==
Expand Down Expand Up @@ -10024,6 +10095,32 @@ class Sema final {
return Res;
}

/// keepInLifetimeExtendingContext - Pull down InLifetimeExtendingContext
/// flag from previous context.
void keepInLifetimeExtendingContext() {
if (ExprEvalContexts.size() > 2 &&
ExprEvalContexts[ExprEvalContexts.size() - 2]
.InLifetimeExtendingContext) {
auto &LastRecord = ExprEvalContexts.back();
auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2];
LastRecord.InLifetimeExtendingContext =
PrevRecord.InLifetimeExtendingContext;
}
}

/// keepInMaterializeTemporaryObjectContext - Pull down
/// InMaterializeTemporaryObjectContext flag from previous context.
void keepInMaterializeTemporaryObjectContext() {
if (ExprEvalContexts.size() > 2 &&
ExprEvalContexts[ExprEvalContexts.size() - 2]
.InMaterializeTemporaryObjectContext) {
auto &LastRecord = ExprEvalContexts.back();
auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2];
LastRecord.InMaterializeTemporaryObjectContext =
PrevRecord.InMaterializeTemporaryObjectContext;
}
}

/// RAII class used to determine whether SFINAE has
/// trapped any errors that occur during template argument
/// deduction.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,7 @@ enum StmtCode {
EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr

EXPR_PACK_EXPANSION, // PackExpansionExpr
EXPR_PACK_INDEXING, // PackIndexingExpr
EXPR_SIZEOF_PACK, // SizeOfPackExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -2452,6 +2452,10 @@ class BitsUnpacker {
uint32_t CurrentBitsIndex = ~0;
};

inline bool isFromExplicitGMF(const Decl *D) {
return D->getOwningModule() && D->getOwningModule()->isExplicitGlobalModule();
}

} // namespace clang

#endif // LLVM_CLANG_SERIALIZATION_ASTREADER_H
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/TypeBitCodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,7 @@ TYPE_BIT_CODE(ConstantMatrix, CONSTANT_MATRIX, 52)
TYPE_BIT_CODE(DependentSizedMatrix, DEPENDENT_SIZE_MATRIX, 53)
TYPE_BIT_CODE(Using, USING, 54)
TYPE_BIT_CODE(BTFTagAttributed, BTFTAG_ATTRIBUTED, 55)
TYPE_BIT_CODE(PackIndexing, PACK_INDEXING, 56)


#undef TYPE_BIT_CODE
68 changes: 62 additions & 6 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,11 @@ void ASTContext::attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls,
return;

FileID File;
for (Decl *D : Decls) {
for (const Decl *D : Decls) {
if (D->isInvalidDecl())
continue;

D = &adjustDeclToTemplate(*D);
SourceLocation Loc = D->getLocation();
if (Loc.isValid()) {
// See if there are any new comments that are not attached to a decl.
Expand Down Expand Up @@ -1688,7 +1692,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
if (VD->hasGlobalStorage() && !ForAlignof) {
uint64_t TypeSize =
!BaseT->isIncompleteType() ? getTypeSize(T.getTypePtr()) : 0;
Align = std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize));
Align = std::max(Align, getMinGlobalAlignOfVar(TypeSize, VD));
}

// Fields can be subject to extra alignment constraints, like if
Expand Down Expand Up @@ -2511,16 +2515,25 @@ unsigned ASTContext::getTargetDefaultAlignForAttributeAligned() const {

/// getAlignOfGlobalVar - Return the alignment in bits that should be given
/// to a global variable of the specified type.
unsigned ASTContext::getAlignOfGlobalVar(QualType T) const {
unsigned ASTContext::getAlignOfGlobalVar(QualType T, const VarDecl *VD) const {
uint64_t TypeSize = getTypeSize(T.getTypePtr());
return std::max(getPreferredTypeAlign(T),
getTargetInfo().getMinGlobalAlign(TypeSize));
getMinGlobalAlignOfVar(TypeSize, VD));
}

/// getAlignOfGlobalVarInChars - Return the alignment in characters that
/// should be given to a global variable of the specified type.
CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T) const {
return toCharUnitsFromBits(getAlignOfGlobalVar(T));
CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T,
const VarDecl *VD) const {
return toCharUnitsFromBits(getAlignOfGlobalVar(T, VD));
}

unsigned ASTContext::getMinGlobalAlignOfVar(uint64_t Size,
const VarDecl *VD) const {
// Make the default handling as that of a non-weak definition in the
// current translation unit.
bool HasNonWeakDef = !VD || (VD->hasDefinition() && !VD->isWeak());
return getTargetInfo().getMinGlobalAlign(Size, HasNonWeakDef);
}

CharUnits ASTContext::getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const {
Expand Down Expand Up @@ -3598,6 +3611,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::Auto:
case Type::DeducedTemplateSpecialization:
case Type::PackExpansion:
case Type::PackIndexing:
case Type::BitInt:
case Type::DependentBitInt:
llvm_unreachable("type should never be variably-modified");
Expand Down Expand Up @@ -5701,6 +5715,39 @@ QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
return QualType(dt, 0);
}

QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
bool FullySubstituted,
ArrayRef<QualType> Expansions,
int Index) const {
QualType Canonical;
if (FullySubstituted && Index != -1) {
Canonical = getCanonicalType(Expansions[Index]);
} else {
llvm::FoldingSetNodeID ID;
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr);
void *InsertPos = nullptr;
PackIndexingType *Canon =
DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!Canon) {
void *Mem = Allocate(
PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
Canon = new (Mem)
PackIndexingType(*this, QualType(), Pattern, IndexExpr, Expansions);
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
}
Canonical = QualType(Canon, 0);
}

void *Mem =
Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
auto *T = new (Mem)
PackIndexingType(*this, Canonical, Pattern, IndexExpr, Expansions);
Types.push_back(T);
return QualType(T, 0);
}

/// getUnaryTransformationType - We don't unique these, since the memory
/// savings are minimal and these are rare.
QualType ASTContext::getUnaryTransformType(QualType BaseType,
Expand Down Expand Up @@ -12917,6 +12964,14 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
// As Decltype is not uniqued, building a common type would be wasteful.
return QualType(DX, 0);
}
case Type::PackIndexing: {
const auto *DX = cast<PackIndexingType>(X);
[[maybe_unused]] const auto *DY = cast<PackIndexingType>(Y);
assert(DX->isDependentType());
assert(DY->isDependentType());
assert(Ctx.hasSameExpr(DX->getIndexExpr(), DY->getIndexExpr()));
return QualType(DX, 0);
}
case Type::DependentName: {
const auto *NX = cast<DependentNameType>(X),
*NY = cast<DependentNameType>(Y);
Expand Down Expand Up @@ -13077,6 +13132,7 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
return Ctx.getAutoType(Ctx.getQualifiedType(Underlying), AX->getKeyword(),
/*IsDependent=*/false, /*IsPack=*/false, CD, As);
}
case Type::PackIndexing:
case Type::Decltype:
return QualType();
case Type::DeducedTemplateSpecialization:
Expand Down
229 changes: 130 additions & 99 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,18 @@ ExpectedType ASTNodeImporter::VisitParenType(const ParenType *T) {
return Importer.getToContext().getParenType(*ToInnerTypeOrErr);
}

ExpectedType
ASTNodeImporter::VisitPackIndexingType(clang::PackIndexingType const *T) {

ExpectedType Pattern = import(T->getPattern());
if (!Pattern)
return Pattern.takeError();
ExpectedExpr Index = import(T->getIndexExpr());
if (!Index)
return Index.takeError();
return Importer.getToContext().getPackIndexingType(*Pattern, *Index);
}

ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
Expected<TypedefNameDecl *> ToDeclOrErr = import(T->getDecl());
if (!ToDeclOrErr)
Expand Down Expand Up @@ -6373,16 +6385,19 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {

ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D) {
// If this record has a definition in the translation unit we're coming from,
// but this particular declaration is not that definition, import the
// definition and map to that.
VarDecl *Definition = D->getDefinition();
if (Definition && Definition != D) {
if (ExpectedDecl ImportedDefOrErr = import(Definition))
return Importer.MapImported(D, *ImportedDefOrErr);
else
return ImportedDefOrErr.takeError();
// A VarTemplateSpecializationDecl inherits from VarDecl, the import is done
// in an analog way (but specialized for this case).

SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D);
auto RedeclIt = Redecls.begin();
// Import the first part of the decl chain. I.e. import all previous
// declarations starting from the canonical decl.
for (; RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt) {
ExpectedDecl RedeclOrErr = import(*RedeclIt);
if (!RedeclOrErr)
return RedeclOrErr.takeError();
}
assert(*RedeclIt == D);

VarTemplateDecl *VarTemplate = nullptr;
if (Error Err = importInto(VarTemplate, D->getSpecializedTemplate()))
Expand Down Expand Up @@ -6410,116 +6425,132 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(

// Try to find an existing specialization with these template arguments.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization(
TemplateArgs, InsertPos);
if (D2) {
// We already have a variable template specialization with these template
// arguments.

// FIXME: Check for specialization vs. instantiation errors.

if (VarDecl *FoundDef = D2->getDefinition()) {
if (!D->isThisDeclarationADefinition() ||
IsStructuralMatch(D, FoundDef)) {
// The record types structurally match, or the "from" translation
// unit only had a forward declaration anyway; call it the same
// variable.
return Importer.MapImported(D, FoundDef);
VarTemplateSpecializationDecl *FoundSpecialization =
VarTemplate->findSpecialization(TemplateArgs, InsertPos);
if (FoundSpecialization) {
if (IsStructuralMatch(D, FoundSpecialization)) {
VarDecl *FoundDef = FoundSpecialization->getDefinition();
if (D->getDeclContext()->isRecord()) {
// In a record, it is allowed only to have one optional declaration and
// one definition of the (static or constexpr) variable template.
assert(
FoundSpecialization->getDeclContext()->isRecord() &&
"Member variable template specialization imported as non-member, "
"inconsistent imported AST?");
if (FoundDef)
return Importer.MapImported(D, FoundDef);
if (!D->isThisDeclarationADefinition())
return Importer.MapImported(D, FoundSpecialization);
} else {
// If definition is imported and there is already one, map to it.
// Otherwise create a new variable and link it to the existing.
if (FoundDef && D->isThisDeclarationADefinition())
return Importer.MapImported(D, FoundDef);
}
} else {
return make_error<ASTImportError>(ASTImportError::NameConflict);
}
} else {
TemplateArgumentListInfo ToTAInfo;
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) {
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
return std::move(Err);
}
}

using PartVarSpecDecl = VarTemplatePartialSpecializationDecl;
// Create a new specialization.
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) {
// Import TemplateArgumentListInfo
TemplateArgumentListInfo ArgInfos;
const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten();
// NOTE: FromTAArgsAsWritten and template parameter list are non-null.
if (Error Err = ImportTemplateArgumentListInfo(
*FromTAArgsAsWritten, ArgInfos))
return std::move(Err);
VarTemplateSpecializationDecl *D2 = nullptr;

auto ToTPListOrErr = import(FromPartial->getTemplateParameters());
if (!ToTPListOrErr)
return ToTPListOrErr.takeError();
TemplateArgumentListInfo ToTAInfo;
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) {
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
return std::move(Err);
}

PartVarSpecDecl *ToPartial;
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs, ArgInfos))
return ToPartial;
using PartVarSpecDecl = VarTemplatePartialSpecializationDecl;
// Create a new specialization.
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) {
// Import TemplateArgumentListInfo
TemplateArgumentListInfo ArgInfos;
const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten();
// NOTE: FromTAArgsAsWritten and template parameter list are non-null.
if (Error Err =
ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ArgInfos))
return std::move(Err);

if (Expected<PartVarSpecDecl *> ToInstOrErr = import(
FromPartial->getInstantiatedFromMember()))
ToPartial->setInstantiatedFromMember(*ToInstOrErr);
else
return ToInstOrErr.takeError();

if (FromPartial->isMemberSpecialization())
ToPartial->setMemberSpecialization();

D2 = ToPartial;

// FIXME: Use this update if VarTemplatePartialSpecializationDecl is fixed
// to adopt template parameters.
// updateLookupTableForTemplateParameters(**ToTPListOrErr);
} else { // Full specialization
if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, VarTemplate,
QualType(), nullptr, D->getStorageClass(),
TemplateArgs))
return D2;
}
auto ToTPListOrErr = import(FromPartial->getTemplateParameters());
if (!ToTPListOrErr)
return ToTPListOrErr.takeError();

QualType T;
if (Error Err = importInto(T, D->getType()))
return std::move(Err);
D2->setType(T);
PartVarSpecDecl *ToPartial;
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs, ArgInfos))
return ToPartial;

auto TInfoOrErr = import(D->getTypeSourceInfo());
if (!TInfoOrErr)
return TInfoOrErr.takeError();
D2->setTypeSourceInfo(*TInfoOrErr);
if (Expected<PartVarSpecDecl *> ToInstOrErr =
import(FromPartial->getInstantiatedFromMember()))
ToPartial->setInstantiatedFromMember(*ToInstOrErr);
else
return ToInstOrErr.takeError();

if (D->getPointOfInstantiation().isValid()) {
if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation()))
D2->setPointOfInstantiation(*POIOrErr);
else
return POIOrErr.takeError();
}
if (FromPartial->isMemberSpecialization())
ToPartial->setMemberSpecialization();

D2 = ToPartial;

// FIXME: Use this update if VarTemplatePartialSpecializationDecl is fixed
// to adopt template parameters.
// updateLookupTableForTemplateParameters(**ToTPListOrErr);
} else { // Full specialization
if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, VarTemplate,
QualType(), nullptr, D->getStorageClass(),
TemplateArgs))
return D2;
}

D2->setSpecializationKind(D->getSpecializationKind());
D2->setTemplateArgsInfo(ToTAInfo);
QualType T;
if (Error Err = importInto(T, D->getType()))
return std::move(Err);
D2->setType(T);

// Add this specialization to the class template.
VarTemplate->AddSpecialization(D2, InsertPos);
auto TInfoOrErr = import(D->getTypeSourceInfo());
if (!TInfoOrErr)
return TInfoOrErr.takeError();
D2->setTypeSourceInfo(*TInfoOrErr);

// Import the qualifier, if any.
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
if (D->getPointOfInstantiation().isValid()) {
if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation()))
D2->setPointOfInstantiation(*POIOrErr);
else
return LocOrErr.takeError();
return POIOrErr.takeError();
}

if (D->isConstexpr())
D2->setConstexpr(true);
D2->setSpecializationKind(D->getSpecializationKind());
D2->setTemplateArgsInfo(ToTAInfo);

// Add the specialization to this context.
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(D2);
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
else
return LocOrErr.takeError();

D2->setAccess(D->getAccess());
}
if (D->isConstexpr())
D2->setConstexpr(true);

D2->setAccess(D->getAccess());

if (Error Err = ImportInitializer(D, D2))
return std::move(Err);

if (FoundSpecialization)
D2->setPreviousDecl(FoundSpecialization->getMostRecentDecl());

VarTemplate->AddSpecialization(D2, InsertPos);

addDeclToContexts(D, D2);

// Import the rest of the chain. I.e. import all subsequent declarations.
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) {
ExpectedDecl RedeclOrErr = import(*RedeclIt);
if (!RedeclOrErr)
return RedeclOrErr.takeError();
}

return D2;
}

Expand Down
22 changes: 19 additions & 3 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;

case Type::PackIndexing:
if (!IsStructurallyEquivalent(Context,
cast<PackIndexingType>(T1)->getPattern(),
cast<PackIndexingType>(T2)->getPattern()))
if (!IsStructurallyEquivalent(Context,
cast<PackIndexingType>(T1)->getIndexExpr(),
cast<PackIndexingType>(T2)->getIndexExpr()))
return false;
break;

case Type::ObjCInterface: {
const auto *Iface1 = cast<ObjCInterfaceType>(T1);
const auto *Iface2 = cast<ObjCInterfaceType>(T2);
Expand Down Expand Up @@ -1379,9 +1389,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,

static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
VarDecl *D1, VarDecl *D2) {
if (D1->getStorageClass() != D2->getStorageClass())
return false;

IdentifierInfo *Name1 = D1->getIdentifier();
IdentifierInfo *Name2 = D2->getIdentifier();
if (!::IsStructurallyEquivalent(Name1, Name2))
Expand All @@ -1390,6 +1397,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
return false;

// Compare storage class and initializer only if none or both are a
// definition. Like a forward-declaration matches a class definition, variable
// declarations that are not definitions should match with the definitions.
if (D1->isThisDeclarationADefinition() != D2->isThisDeclarationADefinition())
return true;

if (D1->getStorageClass() != D2->getStorageClass())
return false;

return IsStructurallyEquivalent(Context, D1->getInit(), D2->getInit());
}

Expand Down
16 changes: 8 additions & 8 deletions clang/lib/AST/ComparisonCategories.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {

// Before we attempt to get the value of the first field, ensure that we
// actually have one (and only one) field.
auto *Record = VD->getType()->getAsCXXRecordDecl();
const auto *Record = VD->getType()->getAsCXXRecordDecl();
if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
!Record->field_begin()->getType()->isIntegralOrEnumerationType())
return false;
Expand Down Expand Up @@ -98,13 +98,13 @@ static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
return StdNS;
}

static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
const NamespaceDecl *StdNS,
ComparisonCategoryType Kind) {
static const CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
const NamespaceDecl *StdNS,
ComparisonCategoryType Kind) {
StringRef Name = ComparisonCategories::getCategoryString(Kind);
DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
if (!Lookup.empty())
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
return RD;
return nullptr;
}
Expand All @@ -116,7 +116,7 @@ ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
return &It->second;

if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
if (const CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;

return nullptr;
Expand All @@ -126,13 +126,13 @@ const ComparisonCategoryInfo *
ComparisonCategories::lookupInfoForType(QualType Ty) const {
assert(!Ty.isNull() && "type must be non-null");
using CCT = ComparisonCategoryType;
auto *RD = Ty->getAsCXXRecordDecl();
const auto *RD = Ty->getAsCXXRecordDecl();
if (!RD)
return nullptr;

// Check to see if we have information for the specified type cached.
const auto *CanonRD = RD->getCanonicalDecl();
for (auto &KV : Data) {
for (const auto &KV : Data) {
const ComparisonCategoryInfo &Info = KV.second;
if (CanonRD == Info.Record->getCanonicalDecl())
return &Info;
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,21 @@ ExprDependence clang::computeDependence(PackExpansionExpr *E) {
ExprDependence::TypeValueInstantiation;
}

ExprDependence clang::computeDependence(PackIndexingExpr *E) {
ExprDependence D = E->getIndexExpr()->getDependence();
ArrayRef<Expr *> Exprs = E->getExpressions();
if (Exprs.empty())
D |= (E->getPackIdExpression()->getDependence() |
ExprDependence::TypeValueInstantiation) &
~ExprDependence::UnexpandedPack;
else if (!E->getIndexExpr()->isInstantiationDependent()) {
std::optional<unsigned> Index = E->getSelectedIndex();
assert(Index && *Index < Exprs.size() && "pack index out of bound");
D |= Exprs[*Index]->getDependence();
}
return D;
}

ExprDependence clang::computeDependence(SubstNonTypeTemplateParmExpr *E) {
return E->getReplacement()->getDependence();
}
Expand Down
21 changes: 14 additions & 7 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
while (true) {
E = E->IgnoreParens();

if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
if (const auto *CE = dyn_cast<CastExpr>(E)) {
if ((CE->getCastKind() == CK_DerivedToBase ||
CE->getCastKind() == CK_UncheckedDerivedToBase) &&
E->getType()->isRecordType()) {
E = CE->getSubExpr();
auto *Derived =
const auto *Derived =
cast<CXXRecordDecl>(E->getType()->castAs<RecordType>()->getDecl());
Adjustments.push_back(SubobjectAdjustment(CE, Derived));
continue;
Expand All @@ -101,23 +101,22 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
E = CE->getSubExpr();
continue;
}
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
} else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
if (!ME->isArrow()) {
assert(ME->getBase()->getType()->isRecordType());
if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
E = ME->getBase();
Adjustments.push_back(SubobjectAdjustment(Field));
continue;
}
}
}
} else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
} else if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
if (BO->getOpcode() == BO_PtrMemD) {
assert(BO->getRHS()->isPRValue());
E = BO->getLHS();
const MemberPointerType *MPT =
BO->getRHS()->getType()->getAs<MemberPointerType>();
const auto *MPT = BO->getRHS()->getType()->getAs<MemberPointerType>();
Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
continue;
}
Expand Down Expand Up @@ -3397,6 +3396,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
return Exp->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
break;
}
case PackIndexingExprClass: {
return cast<PackIndexingExpr>(this)
->getSelectedExpr()
->isConstantInitializer(Ctx, false, Culprit);
}
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
case ImplicitCastExprClass:
Expand Down Expand Up @@ -3572,6 +3576,9 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
// These never have a side-effect.
return false;

case PackIndexingExprClass:
return cast<PackIndexingExpr>(this)->getSelectedExpr()->HasSideEffects(
Ctx, IncludePossibleEffects);
case ConstantExprClass:
// FIXME: Move this into the "return false;" block above.
return cast<ConstantExpr>(this)->getSubExpr()->HasSideEffects(
Expand Down
36 changes: 36 additions & 0 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1665,6 +1665,42 @@ NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
}

PackIndexingExpr *PackIndexingExpr::Create(ASTContext &Context,
SourceLocation EllipsisLoc,
SourceLocation RSquareLoc,
Expr *PackIdExpr, Expr *IndexExpr,
std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs) {
QualType Type;
if (Index && !SubstitutedExprs.empty())
Type = SubstitutedExprs[*Index]->getType();
else
Type = Context.DependentTy;

void *Storage =
Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size()));
return new (Storage) PackIndexingExpr(
Type, EllipsisLoc, RSquareLoc, PackIdExpr, IndexExpr, SubstitutedExprs);
}

NamedDecl *PackIndexingExpr::getPackDecl() const {
if (auto *D = dyn_cast<DeclRefExpr>(getPackIdExpression()); D) {
NamedDecl *ND = dyn_cast<NamedDecl>(D->getDecl());
assert(ND && "exected a named decl");
return ND;
}
assert(false && "invalid declaration kind in pack indexing expression");
return nullptr;
}

PackIndexingExpr *
PackIndexingExpr::CreateDeserialized(ASTContext &Context,
unsigned NumTransformedExprs) {
void *Storage =
Context.Allocate(totalSizeToAlloc<Expr *>(NumTransformedExprs));
return new (Storage) PackIndexingExpr(EmptyShell{});
}

QualType SubstNonTypeTemplateParmExpr::getParameterType(
const ASTContext &Context) const {
// Note that, for a class type NTTP, we will have an lvalue of type 'const
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ExprClassification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return ClassifyInternal(Ctx,
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());

case Expr::PackIndexingExprClass:
return ClassifyInternal(Ctx, cast<PackIndexingExpr>(E)->getSelectedExpr());

// C, C++98 [expr.sub]p1: The result is an lvalue of type "T".
// C++11 (DR1213): in the case of an array operand, the result is an lvalue
// if that operand is an lvalue and an xvalue otherwise.
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8254,6 +8254,10 @@ class ExprEvaluatorBase
llvm_unreachable("Return from function from the loop above.");
}

bool VisitPackIndexingExpr(const PackIndexingExpr *E) {
return StmtVisitorTy::Visit(E->getSelectedExpr());
}

/// Visit a value which is evaluated, but whose value is ignored.
void VisitIgnoredValue(const Expr *E) {
EvaluateIgnoredValue(Info, E);
Expand Down Expand Up @@ -16062,6 +16066,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::SourceLocExprClass:
return NoDiag();

case Expr::PackIndexingExprClass:
return CheckICE(cast<PackIndexingExpr>(E)->getSelectedExpr(), Ctx);

case Expr::SubstNonTypeTemplateParmExprClass:
return
CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
Expand Down
17 changes: 7 additions & 10 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {

case CK_IntegralComplexToBoolean:
case CK_FloatingComplexToBoolean: {
std::optional<PrimType> ElemT =
classifyComplexElementType(SubExpr->getType());
if (!ElemT)
return false;
PrimType ElemT = classifyComplexElementType(SubExpr->getType());
// We emit the expression (__real(E) != 0 || __imag(E) != 0)
// for us, that means (bool)E[0] || (bool)E[1]
if (!this->visit(SubExpr))
Expand All @@ -243,13 +240,13 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return false;
if (!this->emitArrayElemPtrUint8(CE))
return false;
if (!this->emitLoadPop(*ElemT, CE))
if (!this->emitLoadPop(ElemT, CE))
return false;
if (*ElemT == PT_Float) {
if (ElemT == PT_Float) {
if (!this->emitCastFloatingIntegral(PT_Bool, CE))
return false;
} else {
if (!this->emitCast(*ElemT, PT_Bool, CE))
if (!this->emitCast(ElemT, PT_Bool, CE))
return false;
}

Expand All @@ -262,13 +259,13 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return false;
if (!this->emitArrayElemPtrPopUint8(CE))
return false;
if (!this->emitLoadPop(*ElemT, CE))
if (!this->emitLoadPop(ElemT, CE))
return false;
if (*ElemT == PT_Float) {
if (ElemT == PT_Float) {
if (!this->emitCastFloatingIntegral(PT_Bool, CE))
return false;
} else {
if (!this->emitCast(*ElemT, PT_Bool, CE))
if (!this->emitCast(ElemT, PT_Bool, CE))
return false;
}
// Leave the boolean value of E[1] on the stack.
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);
template <typename T> bool emitConst(T Value, const Expr *E);

/// Returns the CXXRecordDecl for the type of the given expression,
/// or nullptr if no such decl exists.
const CXXRecordDecl *getRecordDecl(const Expr *E) const {
QualType T = E->getType();
if (const auto *RD = T->getPointeeCXXRecordDecl())
return RD;
return T->getAsCXXRecordDecl();
}

llvm::RoundingMode getRoundingMode(const Expr *E) const {
FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts());

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
Func = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD);

APValue DummyResult;
if (!Run(Parent, Func, DummyResult)) {
if (!Run(Parent, Func, DummyResult))
return false;
}

return Func->isConstexpr();
}
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2448,6 +2448,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
case Type::PackIndexing:
case Type::TemplateTypeParm:
case Type::UnaryTransform:
case Type::SubstTemplateTypeParm:
Expand Down Expand Up @@ -4202,6 +4203,13 @@ void CXXNameMangler::mangleType(const PackExpansionType *T) {
mangleType(T->getPattern());
}

void CXXNameMangler::mangleType(const PackIndexingType *T) {
if (!T->hasSelectedType())
mangleType(T->getPattern());
else
mangleType(T->getSelectedType());
}

void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
mangleSourceName(T->getDecl()->getIdentifier());
}
Expand Down Expand Up @@ -4704,6 +4712,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
case Expr::OMPIteratorExprClass:
case Expr::CXXInheritedCtorInitExprClass:
case Expr::CXXParenListInitExprClass:
case Expr::PackIndexingExprClass:
llvm_unreachable("unexpected statement kind");

case Expr::ConstantExprClass:
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3408,6 +3408,12 @@ void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, Qualifiers,
<< Range;
}

void MicrosoftCXXNameMangler::mangleType(const PackIndexingType *T,
Qualifiers Quals, SourceRange Range) {
manglePointerCVQualifiers(Quals);
mangleType(T->getSelectedType(), Range);
}

void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
Expand Down
49 changes: 1 addition & 48 deletions clang/lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,55 +745,8 @@ void ODRHash::AddEnumDecl(const EnumDecl *Enum) {
if (Enum->isScoped())
AddBoolean(Enum->isScopedUsingClassTag());

if (Enum->getIntegerTypeSourceInfo()) {
// FIMXE: This allows two enums with different spellings to have the same
// hash.
//
// // mod1.cppm
// module;
// extern "C" {
// typedef unsigned __int64 size_t;
// }
// namespace std {
// using :: size_t;
// }
//
// extern "C++" {
// namespace std {
// enum class align_val_t : std::size_t {};
// }
// }
//
// export module mod1;
// export using std::align_val_t;
//
// // mod2.cppm
// module;
// extern "C" {
// typedef unsigned __int64 size_t;
// }
//
// extern "C++" {
// namespace std {
// enum class align_val_t : size_t {};
// }
// }
//
// export module mod2;
// import mod1;
// export using std::align_val_t;
//
// The above example should be disallowed since it violates
// [basic.def.odr]p14:
//
// Each such definition shall consist of the same sequence of tokens
//
// The definitions of `std::align_val_t` in two module units have different
// spellings but we failed to give an error here.
//
// See https://github.com/llvm/llvm-project/issues/76638 for details.
if (Enum->getIntegerTypeSourceInfo())
AddQualType(Enum->getIntegerType().getCanonicalType());
}

// Filter out sub-Decls which will not be processed in order to get an
// accurate count of Decl's.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,10 @@ void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
OS << "sizeof...(" << *E->getPack() << ")";
}

void StmtPrinter::VisitPackIndexingExpr(PackIndexingExpr *E) {
OS << E->getPackIdExpression() << "...[" << E->getIndexExpr() << "]";
}

void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *Node) {
OS << *Node->getParameterPack();
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2219,6 +2219,12 @@ void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
}
}

void StmtProfiler::VisitPackIndexingExpr(const PackIndexingExpr *E) {
VisitExpr(E);
VisitExpr(E->getPackIdExpression());
VisitExpr(E->getIndexExpr());
}

void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
const SubstNonTypeTemplateParmPackExpr *S) {
VisitExpr(S);
Expand Down
52 changes: 52 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3813,6 +3813,57 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
E->Profile(ID, Context, true);
}

PackIndexingType::PackIndexingType(const ASTContext &Context,
QualType Canonical, QualType Pattern,
Expr *IndexExpr,
ArrayRef<QualType> Expansions)
: Type(PackIndexing, Canonical,
computeDependence(Pattern, IndexExpr, Expansions)),
Context(Context), Pattern(Pattern), IndexExpr(IndexExpr),
Size(Expansions.size()) {

std::uninitialized_copy(Expansions.begin(), Expansions.end(),
getTrailingObjects<QualType>());
}

std::optional<unsigned> PackIndexingType::getSelectedIndex() const {
if (isInstantiationDependentType())
return std::nullopt;
// Should only be not a constant for error recovery.
ConstantExpr *CE = dyn_cast<ConstantExpr>(getIndexExpr());
if (!CE)
return std::nullopt;
auto Index = CE->getResultAsAPSInt();
assert(Index.isNonNegative() && "Invalid index");
return static_cast<unsigned>(Index.getExtValue());
}

TypeDependence
PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,
ArrayRef<QualType> Expansions) {
TypeDependence IndexD = toTypeDependence(IndexExpr->getDependence());

TypeDependence TD = IndexD | (IndexExpr->isInstantiationDependent()
? TypeDependence::DependentInstantiation
: TypeDependence::None);
if (Expansions.empty())
TD |= Pattern->getDependence() & TypeDependence::DependentInstantiation;
else
for (const QualType &T : Expansions)
TD |= T->getDependence();

if (!(IndexD & TypeDependence::UnexpandedPack))
TD &= ~TypeDependence::UnexpandedPack;
return TD;
}

void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context, QualType Pattern,
Expr *E) {
Pattern.Profile(ID);
E->Profile(ID, Context, true);
}

UnaryTransformType::UnaryTransformType(QualType BaseType,
QualType UnderlyingType, UTTKind UKind,
QualType CanonicalType)
Expand Down Expand Up @@ -4488,6 +4539,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
case Type::PackIndexing:
case Type::UnaryTransform:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace;
break;
}
case Type::PackIndexing: {
return canPrefixQualifiers(
cast<PackIndexingType>(UnderlyingType)->getPattern().getTypePtr(),
NeedARCStrongQualifier);
}
}

return CanPrefixQualifiers;
Expand Down Expand Up @@ -1188,6 +1193,18 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {
spaceBeforePlaceHolder(OS);
}

void TypePrinter::printPackIndexingBefore(const PackIndexingType *T,
raw_ostream &OS) {
if (T->isInstantiationDependentType())
OS << T->getPattern() << "...[" << T->getIndexExpr() << "]";
else
OS << T->getSelectedType();
spaceBeforePlaceHolder(OS);
}

void TypePrinter::printPackIndexingAfter(const PackIndexingType *T,
raw_ostream &OS) {}

void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) {}

void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
Expand Down
5 changes: 1 addition & 4 deletions clang/lib/Analysis/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1788,10 +1788,7 @@ static QualType getReferenceInitTemporaryType(const Expr *Init,
}

// Skip sub-object accesses into rvalues.
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
const Expr *SkippedInit = Init->skipRValueSubobjectAdjustments();
if (SkippedInit != Init) {
Init = SkippedInit;
continue;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Analysis/CalledOnceCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class ParameterStatus {
NotVisited = 0x8, /* 1000 */
// We already reported a violation and stopped tracking calls for this
// parameter.
Reported = 0x15, /* 1111 */
Reported = 0xF, /* 1111 */
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Reported)
};

Expand Down Expand Up @@ -932,7 +932,8 @@ class CalledOnceChecker : public ConstStmtVisitor<CalledOnceChecker> {
ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index);

// Escape overrides whatever error we think happened.
if (CurrentParamStatus.isErrorStatus()) {
if (CurrentParamStatus.isErrorStatus() &&
CurrentParamStatus.getKind() != ParameterStatus::Kind::Reported) {
CurrentParamStatus = ParameterStatus::Escaped;
}
}
Expand Down
Loading