aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/ASTConcept.h16
-rw-r--r--clang/include/clang/AST/ASTContext.h11
-rw-r--r--clang/include/clang/AST/DeclTemplate.h46
-rw-r--r--clang/include/clang/AST/ExprCXX.h47
-rw-r--r--clang/include/clang/AST/ExprConcepts.h4
-rw-r--r--clang/include/clang/AST/TemplateBase.h2
-rw-r--r--clang/include/clang/AST/Type.h8
-rw-r--r--clang/include/clang/AST/TypeLoc.h2
-rw-r--r--clang/include/clang/AST/TypeProperties.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td19
-rw-r--r--clang/include/clang/Sema/Initialization.h9
-rw-r--r--clang/include/clang/Sema/Ownership.h1
-rw-r--r--clang/include/clang/Sema/Sema.h20
-rw-r--r--clang/include/clang/Sema/SemaInternal.h1
-rw-r--r--clang/lib/AST/ASTConcept.cpp2
-rw-r--r--clang/lib/AST/ASTContext.cpp27
-rw-r--r--clang/lib/AST/ASTImporter.cpp4
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp3
-rw-r--r--clang/lib/AST/ComputeDependence.cpp2
-rw-r--r--clang/lib/AST/Decl.cpp3
-rw-r--r--clang/lib/AST/DeclTemplate.cpp39
-rw-r--r--clang/lib/AST/ExprCXX.cpp36
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp4
-rw-r--r--clang/lib/AST/TemplateBase.cpp11
-rw-r--r--clang/lib/AST/Type.cpp7
-rw-r--r--clang/lib/Frontend/FrontendAction.cpp83
-rw-r--r--clang/lib/Parse/ParseDecl.cpp2
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp85
-rw-r--r--clang/lib/Parse/ParseTentative.cpp2
-rw-r--r--clang/lib/Parse/Parser.cpp7
-rw-r--r--clang/lib/Sema/SemaChecking.cpp3
-rw-r--r--clang/lib/Sema/SemaExpr.cpp5
-rw-r--r--clang/lib/Sema/SemaInit.cpp2
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp391
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp210
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp32
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp10
-rw-r--r--clang/lib/Sema/SemaType.cpp10
-rw-r--r--clang/lib/Sema/TreeTransform.h36
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp8
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp1
-rw-r--r--clang/test/CodeGenCXX/mangle-concept.cpp3
-rw-r--r--clang/test/Frontend/dump-minimization-hints-cpp20-modules.cpp117
-rw-r--r--clang/test/Parser/cxx-template-template-recovery.cpp12
-rw-r--r--clang/test/Parser/cxx2a-concept-declaration.cpp5
-rw-r--r--clang/test/Parser/cxx2c-template-template-param.cpp79
-rw-r--r--clang/test/SemaCXX/cxx2c-template-template-param.cpp352
-rw-r--r--clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp3
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h10
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp85
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h4
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp11
-rw-r--r--lldb/source/Symbol/Type.cpp6
-rw-r--r--lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test135
-rw-r--r--llvm/docs/LangRef.rst20
-rw-r--r--llvm/include/llvm/IR/RuntimeLibcalls.td18
-rw-r--r--llvm/include/llvm/MC/MCAssembler.h1
-rw-r--r--llvm/include/llvm/MC/MCObjectStreamer.h20
-rw-r--r--llvm/include/llvm/MC/MCSection.h50
-rw-r--r--llvm/include/llvm/MC/MCSymbol.h13
-rw-r--r--llvm/lib/Analysis/StackLifetime.cpp5
-rw-r--r--llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp4
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp4
-rw-r--r--llvm/lib/IR/RuntimeLibcalls.cpp9
-rw-r--r--llvm/lib/IR/Verifier.cpp9
-rw-r--r--llvm/lib/MC/MCAssembler.cpp10
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp117
-rw-r--r--llvm/lib/MC/MCParser/AsmParser.cpp3
-rw-r--r--llvm/lib/MC/MCWin64EH.cpp3
-rw-r--r--llvm/lib/MC/MCWinCOFFStreamer.cpp5
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp6
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td17
-rw-r--r--llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.cpp93
-rw-r--r--llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.h6
-rw-r--r--llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp4
-rw-r--r--llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp5
-rw-r--r--llvm/lib/Transforms/Utils/Local.cpp3
-rw-r--r--llvm/lib/Transforms/Utils/MemoryTaggingSupport.cpp5
-rw-r--r--llvm/test/CodeGen/AArch64/arm64-ext.ll65
-rw-r--r--llvm/test/CodeGen/AArch64/arm64-neon-copy.ll20
-rw-r--r--llvm/test/CodeGen/AArch64/arm64-vext.ll250
-rw-r--r--llvm/test/CodeGen/AArch64/arm64-vext_reverse.ll131
-rw-r--r--llvm/test/CodeGen/AArch64/extend_inreg_of_concat_subvectors.ll159
-rw-r--r--llvm/test/CodeGen/AArch64/lifetime-poison.ll14
-rw-r--r--llvm/test/CodeGen/RISCV/xqcilsm-memset.ll900
-rw-r--r--llvm/test/Instrumentation/AddressSanitizer/lifetime.ll15
-rw-r--r--llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll19
-rw-r--r--llvm/test/MC/ELF/many-instructions.s10
-rw-r--r--llvm/test/MC/ELF/mc-dump.s2
-rw-r--r--llvm/test/Transforms/InstCombine/pr150338.ll16
-rw-r--r--llvm/test/Transforms/InstCombine/unreachable-alloca-lifetime-markers.ll51
-rw-r--r--llvm/test/tools/llvm-reduce/reduce-operands-alloca.ll12
-rw-r--r--llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp3
96 files changed, 3407 insertions, 738 deletions
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index c8f6330..7ccac44 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -27,6 +27,7 @@
namespace clang {
class ConceptDecl;
+class TemplateDecl;
class Expr;
class NamedDecl;
struct PrintingPolicy;
@@ -123,6 +124,7 @@ struct ASTConstraintSatisfaction final :
/// template <std::derives_from<Expr> T> void dump();
/// ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl)
class ConceptReference {
+protected:
// \brief The optional nested name specifier used when naming the concept.
NestedNameSpecifierLoc NestedNameSpec;
@@ -140,7 +142,7 @@ class ConceptReference {
NamedDecl *FoundDecl;
/// \brief The concept named.
- ConceptDecl *NamedConcept;
+ TemplateDecl *NamedConcept;
/// \brief The template argument list source info used to specialize the
/// concept.
@@ -148,7 +150,7 @@ class ConceptReference {
ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
- ConceptDecl *NamedConcept,
+ TemplateDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten)
: NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
@@ -158,7 +160,7 @@ public:
static ConceptReference *
Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ NamedDecl *FoundDecl, TemplateDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten);
const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
@@ -197,9 +199,7 @@ public:
return FoundDecl;
}
- ConceptDecl *getNamedConcept() const {
- return NamedConcept;
- }
+ TemplateDecl *getNamedConcept() const { return NamedConcept; }
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
@@ -252,7 +252,9 @@ public:
// FIXME: Instead of using these concept related functions the callers should
// directly work with the corresponding ConceptReference.
- ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
+ TemplateDecl *getNamedConcept() const {
+ return ConceptRef->getNamedConcept();
+ }
SourceLocation getConceptNameLoc() const {
return ConceptRef->getConceptNameLoc();
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index db86963..a73e594 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1759,7 +1759,7 @@ private:
QualType
getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword,
bool IsDependent, bool IsPack = false,
- ConceptDecl *TypeConstraintConcept = nullptr,
+ TemplateDecl *TypeConstraintConcept = nullptr,
ArrayRef<TemplateArgument> TypeConstraintArgs = {},
bool IsCanon = false) const;
@@ -1979,10 +1979,11 @@ public:
UnaryTransformType::UTTKind UKind) const;
/// C++11 deduced auto type.
- QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
- bool IsDependent, bool IsPack = false,
- ConceptDecl *TypeConstraintConcept = nullptr,
- ArrayRef<TemplateArgument> TypeConstraintArgs ={}) const;
+ QualType
+ getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent,
+ bool IsPack = false,
+ TemplateDecl *TypeConstraintConcept = nullptr,
+ ArrayRef<TemplateArgument> TypeConstraintArgs = {}) const;
/// C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 1ff6cc6..32de203 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -26,6 +26,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TemplateKinds.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -1585,6 +1586,9 @@ class TemplateTemplateParmDecl final
DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *>;
DefArgStorage DefaultArgument;
+ LLVM_PREFERRED_TYPE(TemplateNameKind)
+ unsigned ParameterKind : 3;
+
/// Whether this template template parameter was declaration with
/// the 'typename' keyword.
///
@@ -1607,13 +1611,16 @@ class TemplateTemplateParmDecl final
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
unsigned P, bool ParameterPack, IdentifierInfo *Id,
- bool Typename, TemplateParameterList *Params)
+ TemplateNameKind ParameterKind, bool Typename,
+ TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
- TemplateParmPosition(D, P), Typename(Typename),
- ParameterPack(ParameterPack), ExpandedParameterPack(false) {}
+ TemplateParmPosition(D, P), ParameterKind(ParameterKind),
+ Typename(Typename), ParameterPack(ParameterPack),
+ ExpandedParameterPack(false) {}
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id, bool Typename,
+ unsigned P, IdentifierInfo *Id,
+ TemplateNameKind ParameterKind, bool Typename,
TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions);
@@ -1624,15 +1631,16 @@ public:
friend class ASTDeclWriter;
friend TrailingObjects;
- static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D,
- unsigned P, bool ParameterPack,
- IdentifierInfo *Id, bool Typename,
- TemplateParameterList *Params);
static TemplateTemplateParmDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id, bool Typename,
- TemplateParameterList *Params,
+ unsigned P, bool ParameterPack, IdentifierInfo *Id,
+ TemplateNameKind ParameterKind, bool Typename,
+ TemplateParameterList *Params);
+
+ static TemplateTemplateParmDecl *
+ Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
+ unsigned P, IdentifierInfo *Id, TemplateNameKind ParameterKind,
+ bool Typename, TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
@@ -1746,6 +1754,16 @@ public:
return SourceRange(getTemplateParameters()->getTemplateLoc(), End);
}
+ TemplateNameKind templateParameterKind() const {
+ return static_cast<TemplateNameKind>(ParameterKind);
+ }
+
+ bool isTypeConceptTemplateParam() const {
+ return templateParameterKind() == TemplateNameKind::TNK_Concept_template &&
+ getTemplateParameters()->size() > 0 &&
+ isa<TemplateTypeParmDecl>(getTemplateParameters()->getParam(0));
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == TemplateTemplateParm; }
@@ -3341,7 +3359,11 @@ inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
return TD && (isa<ClassTemplateDecl>(TD) ||
isa<ClassTemplatePartialSpecializationDecl>(TD) ||
isa<TypeAliasTemplateDecl>(TD) ||
- isa<TemplateTemplateParmDecl>(TD))
+ [&]() {
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD))
+ return TTP->templateParameterKind() == TNK_Type_template;
+ return false;
+ }())
? TD
: nullptr;
}
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index a22c322..7a26934 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -38,6 +38,7 @@
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerUnion.h"
@@ -3257,7 +3258,49 @@ public:
bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
/// Determines whether this expression had explicit template arguments.
- bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
+ bool hasExplicitTemplateArgs() const {
+ if (!hasTemplateKWAndArgsInfo())
+ return false;
+ // FIXME: deduced function types can have "hidden" args and no <
+ // investigate that further, but ultimately maybe we want to model concepts
+ // reference with another kind of expression.
+ return (isConceptReference() || isVarDeclReference())
+ ? getTrailingASTTemplateKWAndArgsInfo()->NumTemplateArgs
+ : getLAngleLoc().isValid();
+ }
+
+ bool isConceptReference() const {
+ return getNumDecls() == 1 && [&]() {
+ if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ getTrailingResults()->getDecl()))
+ return TTP->templateParameterKind() == TNK_Concept_template;
+ if (isa<ConceptDecl>(getTrailingResults()->getDecl()))
+ return true;
+ return false;
+ }();
+ }
+
+ bool isVarDeclReference() const {
+ return getNumDecls() == 1 && [&]() {
+ if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ getTrailingResults()->getDecl()))
+ return TTP->templateParameterKind() == TNK_Var_template;
+ if (isa<VarTemplateDecl>(getTrailingResults()->getDecl()))
+ return true;
+ return false;
+ }();
+ }
+
+ TemplateDecl *getTemplateDecl() const {
+ assert(getNumDecls() == 1);
+ return dyn_cast_or_null<TemplateDecl>(getTrailingResults()->getDecl());
+ }
+
+ TemplateTemplateParmDecl *getTemplateTemplateDecl() const {
+ assert(getNumDecls() == 1);
+ return dyn_cast_or_null<TemplateTemplateParmDecl>(
+ getTrailingResults()->getDecl());
+ }
TemplateArgumentLoc const *getTemplateArgs() const {
if (!hasExplicitTemplateArgs())
@@ -4658,7 +4701,7 @@ public:
// sugared: it doesn't need to be resugared later.
bool getFinal() const { return Final; }
- NonTypeTemplateParmDecl *getParameter() const;
+ NamedDecl *getParameter() const;
bool isReferenceParameter() const { return AssociatedDeclAndRef.getInt(); }
diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h
index 7ab0c3e..4f162b6 100644
--- a/clang/include/clang/AST/ExprConcepts.h
+++ b/clang/include/clang/AST/ExprConcepts.h
@@ -84,7 +84,9 @@ public:
ConceptReference *getConceptReference() const { return ConceptRef; }
- ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
+ ConceptDecl *getNamedConcept() const {
+ return cast<ConceptDecl>(ConceptRef->getNamedConcept());
+ }
// FIXME: Several of the following functions can be removed. Instead the
// caller can directly work with the ConceptReference.
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index b67036c..eb384ea 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -316,6 +316,8 @@ public:
/// Determine whether this template argument is a pack expansion.
bool isPackExpansion() const;
+ bool isConceptOrConceptTemplateParameter() const;
+
/// Retrieve the type for a type template argument.
QualType getAsType() const {
assert(getKind() == Type && "Unexpected kind");
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 98810fb..12dce30 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -6762,10 +6762,10 @@ public:
class AutoType : public DeducedType {
friend class ASTContext; // ASTContext creates these
- ConceptDecl *TypeConstraintConcept;
+ TemplateDecl *TypeConstraintConcept;
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
- TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD,
+ TypeDependence ExtraDependence, QualType Canon, TemplateDecl *CD,
ArrayRef<TemplateArgument> TypeConstraintArgs);
public:
@@ -6774,7 +6774,7 @@ public:
AutoTypeBits.NumArgs};
}
- ConceptDecl *getTypeConstraintConcept() const {
+ TemplateDecl *getTypeConstraintConcept() const {
return TypeConstraintConcept;
}
@@ -6797,7 +6797,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
QualType Deduced, AutoTypeKeyword Keyword,
- bool IsDependent, ConceptDecl *CD,
+ bool IsDependent, TemplateDecl *CD,
ArrayRef<TemplateArgument> Arguments);
static bool classof(const Type *T) {
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index be0bc89..52ef7ac 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -2284,7 +2284,7 @@ public:
return nullptr;
}
- ConceptDecl *getNamedConcept() const {
+ TemplateDecl *getNamedConcept() const {
if (const auto *CR = getConceptReference())
return CR->getNamedConcept();
return nullptr;
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 3114d11..3373e96 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -495,9 +495,9 @@ let Class = AutoType in {
def : Property<"keyword", AutoTypeKeyword> {
let Read = [{ node->getKeyword() }];
}
- def : Property<"typeConstraintConcept", Optional<ConceptDeclRef>> {
+ def : Property<"typeConstraintConcept", Optional<TemplateDeclRef>> {
let Read = [{ makeOptionalFromPointer(
- const_cast<const ConceptDecl*>(node->getTypeConstraintConcept())) }];
+ node->getTypeConstraintConcept()) }];
}
def : Property<"typeConstraintArguments", Array<TemplateArgument>> {
let Read = [{ node->getTypeConstraintArguments() }];
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 165f015..0042afc 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -931,6 +931,10 @@ def err_missing_dependent_template_keyword : Error<
def warn_missing_dependent_template_keyword : ExtWarn<
"use 'template' keyword to treat '%0' as a dependent template name">;
+def err_cxx26_template_template_params
+ : Error<"%select{variable template|concept}0 template parameter is a C++2c "
+ "extension">;
+
def ext_extern_template : Extension<
"extern templates are a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_extern_template : Warning<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 94b174c..0ba06d6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5438,8 +5438,10 @@ def err_template_arg_must_be_expr : Error<
"template argument for non-type template parameter must be an expression">;
def err_template_arg_nontype_ambig : Error<
"template argument for non-type template parameter is treated as function type %0">;
-def err_template_arg_must_be_template : Error<
- "template argument for template template parameter must be a class template%select{| or type alias template}0">;
+def err_template_arg_must_be_template
+ : Error<"template argument for template template parameter must be a "
+ "%select{class template%select{| or type alias template}1|variable "
+ "template|concept}0">;
def ext_template_arg_local_type : ExtWarn<
"template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>;
def ext_template_arg_unnamed_type : ExtWarn<
@@ -5454,11 +5456,14 @@ def note_template_unnamed_type_here : Note<
"unnamed type used in template argument was declared here">;
def err_template_arg_overload_type : Error<
"template argument is the type of an unresolved overloaded function">;
-def err_template_arg_not_valid_template : Error<
- "template argument does not refer to a class or alias template, or template "
- "template parameter">;
-def note_template_arg_refers_here_func : Note<
- "template argument refers to function template %0, here">;
+def err_template_arg_not_valid_template
+ : Error<"template argument does not refer to a %select{class or alias "
+ "template|variable template|concept}0, or template "
+ "template parameter">;
+
+def note_template_arg_refers_to_template_here
+ : Note<"template argument refers to a %select{function template|class "
+ "template|variable template|concept}0 %1, here">;
def err_template_arg_template_params_mismatch : Error<
"template template argument has different template parameters than its "
"corresponding template template parameter">;
diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h
index a1c156e..d7675ea 100644
--- a/clang/include/clang/Sema/Initialization.h
+++ b/clang/include/clang/Sema/Initialization.h
@@ -159,8 +159,9 @@ private:
};
struct VD {
- /// The VarDecl, FieldDecl, or BindingDecl being initialized.
- ValueDecl *VariableOrMember;
+ /// The VarDecl, FieldDecl, TemplateParmDecl, or BindingDecl being
+ /// initialized.
+ NamedDecl *VariableOrMember;
/// When Kind == EK_Member, whether this is an implicit member
/// initialization in a copy or move constructor. These can perform array
@@ -291,8 +292,8 @@ public:
}
/// Create the initialization entity for a template parameter.
- static InitializedEntity
- InitializeTemplateParameter(QualType T, NonTypeTemplateParmDecl *Param) {
+ static InitializedEntity InitializeTemplateParameter(QualType T,
+ NamedDecl *Param) {
InitializedEntity Entity;
Entity.Kind = EK_TemplateParameter;
Entity.Type = T;
diff --git a/clang/include/clang/Sema/Ownership.h b/clang/include/clang/Sema/Ownership.h
index 0752f5d..b152083 100644
--- a/clang/include/clang/Sema/Ownership.h
+++ b/clang/include/clang/Sema/Ownership.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_SEMA_OWNERSHIP_H
#define LLVM_CLANG_SEMA_OWNERSHIP_H
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0b2c027..5211373 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11458,7 +11458,7 @@ public:
/// of arguments for the named concept).
bool AttachTypeConstraint(NestedNameSpecifierLoc NS,
DeclarationNameInfo NameInfo,
- ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
+ TemplateDecl *NamedConcept, NamedDecl *FoundDecl,
const TemplateArgumentListInfo *TemplateArgs,
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc);
@@ -11491,8 +11491,9 @@ public:
/// parameter (e.g. T in template <template \<typename> class T> class array)
/// has been parsed. S is the current scope.
NamedDecl *ActOnTemplateTemplateParameter(
- Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params,
- bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *ParamName,
+ Scope *S, SourceLocation TmpLoc, TemplateNameKind Kind,
+ bool TypenameKeyword, TemplateParameterList *Params,
+ SourceLocation EllipsisLoc, IdentifierInfo *ParamName,
SourceLocation ParamNameLoc, unsigned Depth, unsigned Position,
SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg);
@@ -11660,6 +11661,11 @@ public:
SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs);
+ ExprResult CheckVarOrConceptTemplateTemplateId(
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
+ TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs);
+
ExprResult
CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &ConceptNameInfo,
@@ -11996,7 +12002,7 @@ public:
/// If an error occurred, it returns ExprError(); otherwise, it
/// returns the converted template argument. \p ParamType is the
/// type of the non-type template parameter after it has been instantiated.
- ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ ExprResult CheckTemplateArgument(NamedDecl *Param,
QualType InstantiatedParamType, Expr *Arg,
TemplateArgument &SugaredConverted,
TemplateArgument &CanonicalConverted,
@@ -12014,6 +12020,10 @@ public:
bool PartialOrdering,
bool *StrictPackMatch);
+ bool CheckDeclCompatibleWithTemplateTemplate(TemplateDecl *Template,
+ TemplateTemplateParmDecl *Param,
+ const TemplateArgumentLoc &Arg);
+
void NoteTemplateLocation(const NamedDecl &Decl,
std::optional<SourceRange> ParamRange = {});
void NoteTemplateParameterLocation(const NamedDecl &Decl);
@@ -12290,7 +12300,7 @@ public:
void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous,
bool &AddToScope);
- bool CheckConceptUseInDefinition(ConceptDecl *Concept, SourceLocation Loc);
+ bool CheckConceptUseInDefinition(NamedDecl *Concept, SourceLocation Loc);
TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
const CXXScopeSpec &SS,
diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h
index 4d0da11..42c9469 100644
--- a/clang/include/clang/Sema/SemaInternal.h
+++ b/clang/include/clang/Sema/SemaInternal.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_SEMA_SEMAINTERNAL_H
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index 91ab66f..2243ac0 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -86,7 +86,7 @@ ConceptReference *
ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
SourceLocation TemplateKWLoc,
DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ NamedDecl *FoundDecl, TemplateDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten) {
return new (C) ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo,
FoundDecl, NamedConcept, ArgsAsWritten);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 16cf114..3a16111 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -80,6 +80,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/Support/Capacity.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
@@ -717,13 +718,13 @@ comments::FullComment *ASTContext::getCommentForDecl(
return FC;
}
-void
-ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
- const ASTContext &C,
- TemplateTemplateParmDecl *Parm) {
+void ASTContext::CanonicalTemplateTemplateParm::Profile(
+ llvm::FoldingSetNodeID &ID, const ASTContext &C,
+ TemplateTemplateParmDecl *Parm) {
ID.AddInteger(Parm->getDepth());
ID.AddInteger(Parm->getPosition());
ID.AddBoolean(Parm->isParameterPack());
+ ID.AddInteger(Parm->templateParameterKind());
TemplateParameterList *Params = Parm->getTemplateParameters();
ID.AddInteger(Params->size());
@@ -829,7 +830,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create(
*this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(),
- TTP->getPosition(), TTP->isParameterPack(), nullptr, /*Typename=*/false,
+ TTP->getPosition(), TTP->isParameterPack(), nullptr,
+ TTP->templateParameterKind(),
+ /*Typename=*/false,
TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(),
CanonParams, SourceLocation(),
/*RequiresClause=*/nullptr));
@@ -6643,7 +6646,7 @@ ASTContext::getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
QualType ASTContext::getAutoTypeInternal(
QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent,
- bool IsPack, ConceptDecl *TypeConstraintConcept,
+ bool IsPack, TemplateDecl *TypeConstraintConcept,
ArrayRef<TemplateArgument> TypeConstraintArgs, bool IsCanon) const {
if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
!TypeConstraintConcept && !IsDependent)
@@ -6652,7 +6655,8 @@ QualType ASTContext::getAutoTypeInternal(
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
bool IsDeducedDependent =
- !DeducedType.isNull() && DeducedType->isDependentType();
+ isa_and_nonnull<TemplateTemplateParmDecl>(TypeConstraintConcept) ||
+ (!DeducedType.isNull() && DeducedType->isDependentType());
AutoType::Profile(ID, *this, DeducedType, Keyword,
IsDependent || IsDeducedDependent, TypeConstraintConcept,
TypeConstraintArgs);
@@ -6665,7 +6669,8 @@ QualType ASTContext::getAutoTypeInternal(
Canon = DeducedType.getCanonicalType();
} else if (TypeConstraintConcept) {
bool AnyNonCanonArgs = false;
- ConceptDecl *CanonicalConcept = TypeConstraintConcept->getCanonicalDecl();
+ auto *CanonicalConcept =
+ cast<TemplateDecl>(TypeConstraintConcept->getCanonicalDecl());
auto CanonicalConceptArgs = ::getCanonicalTemplateArguments(
*this, TypeConstraintArgs, AnyNonCanonArgs);
if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) {
@@ -6701,7 +6706,7 @@ QualType ASTContext::getAutoTypeInternal(
QualType
ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
bool IsDependent, bool IsPack,
- ConceptDecl *TypeConstraintConcept,
+ TemplateDecl *TypeConstraintConcept,
ArrayRef<TemplateArgument> TypeConstraintArgs) const {
assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
assert((!IsDependent || DeducedType.isNull()) &&
@@ -14387,8 +14392,8 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
if (KW != AY->getKeyword())
return QualType();
- ConceptDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(),
- AY->getTypeConstraintConcept());
+ TemplateDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(),
+ AY->getTypeConstraintConcept());
SmallVector<TemplateArgument, 8> As;
if (CD &&
getCommonTemplateArguments(Ctx, As, AX->getTypeConstraintArguments(),
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index b9bdabe0b..8e2927b 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -6268,8 +6268,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
ToD, D, Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(), *LocationOrErr,
D->getDepth(), D->getPosition(), D->isParameterPack(),
- (*NameOrErr).getAsIdentifierInfo(), D->wasDeclaredWithTypename(),
- *TemplateParamsOrErr))
+ (*NameOrErr).getAsIdentifierInfo(), D->templateParameterKind(),
+ D->wasDeclaredWithTypename(), *TemplateParamsOrErr))
return ToD;
if (Error Err = importTemplateParameterDefaultArgument(D, ToD))
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 22bb4cb..0e2023f 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -2313,7 +2313,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
// Check template parameter lists.
- return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
+ return D1->templateParameterKind() == D2->templateParameterKind() &&
+ IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
D2->getTemplateParameters());
}
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 14ec93e..87334d9 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -806,7 +806,7 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent,
~NestedNameSpecifierDependence::Dependent);
for (auto *D : E->decls()) {
if (D->getDeclContext()->isDependentContext() ||
- isa<UnresolvedUsingValueDecl>(D))
+ isa<UnresolvedUsingValueDecl>(D) || isa<TemplateTemplateParmDecl>(D))
Deps |= ExprDependence::TypeValueInstantiation;
}
// If we have explicit template arguments, check for dependent
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 1588be4..5471f31 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1233,6 +1233,9 @@ getExplicitVisibilityAux(const NamedDecl *ND,
bool IsMostRecent) {
assert(!IsMostRecent || ND == ND->getMostRecentDecl());
+ if (isa<ConceptDecl>(ND))
+ return {};
+
// Check the declaration itself first.
if (std::optional<Visibility> V = getVisibilityOf(ND, kind))
return V;
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 5035f2d..bc4a299 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -162,6 +162,7 @@ void TemplateParameterList::Profile(llvm::FoldingSetNodeID &ID,
}
const auto *TTP = cast<TemplateTemplateParmDecl>(D);
ID.AddInteger(2);
+ ID.AddInteger(TTP->templateParameterKind());
ID.AddBoolean(TTP->isParameterPack());
TTP->getTemplateParameters()->Profile(ID, C);
}
@@ -184,7 +185,8 @@ unsigned TemplateParameterList::getMinRequiredArguments() const {
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
if (NTTP->hasDefaultArgument())
break;
- } else if (cast<TemplateTemplateParmDecl>(P)->hasDefaultArgument())
+ } else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P);
+ TTP && TTP->hasDefaultArgument())
break;
++NumRequiredArgs;
@@ -873,38 +875,40 @@ void TemplateTemplateParmDecl::anchor() {}
TemplateTemplateParmDecl::TemplateTemplateParmDecl(
DeclContext *DC, SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id, bool Typename, TemplateParameterList *Params,
- ArrayRef<TemplateParameterList *> Expansions)
+ IdentifierInfo *Id, TemplateNameKind Kind, bool Typename,
+ TemplateParameterList *Params, ArrayRef<TemplateParameterList *> Expansions)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
- TemplateParmPosition(D, P), Typename(Typename), ParameterPack(true),
- ExpandedParameterPack(true), NumExpandedParams(Expansions.size()) {
+ TemplateParmPosition(D, P), ParameterKind(Kind), Typename(Typename),
+ ParameterPack(true), ExpandedParameterPack(true),
+ NumExpandedParams(Expansions.size()) {
llvm::uninitialized_copy(Expansions, getTrailingObjects());
}
-TemplateTemplateParmDecl *
-TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
- bool ParameterPack, IdentifierInfo *Id,
- bool Typename, TemplateParameterList *Params) {
+TemplateTemplateParmDecl *TemplateTemplateParmDecl::Create(
+ const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
+ unsigned P, bool ParameterPack, IdentifierInfo *Id, TemplateNameKind Kind,
+ bool Typename, TemplateParameterList *Params) {
return new (C, DC) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id,
- Typename, Params);
+ Kind, Typename, Params);
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id, bool Typename,
- TemplateParameterList *Params,
+ IdentifierInfo *Id, TemplateNameKind Kind,
+ bool Typename, TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions) {
return new (C, DC,
additionalSizeToAlloc<TemplateParameterList *>(Expansions.size()))
- TemplateTemplateParmDecl(DC, L, D, P, Id, Typename, Params, Expansions);
+ TemplateTemplateParmDecl(DC, L, D, P, Id, Kind, Typename, Params,
+ Expansions);
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
- return new (C, ID) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0,
- false, nullptr, false, nullptr);
+ return new (C, ID) TemplateTemplateParmDecl(
+ nullptr, SourceLocation(), 0, 0, false, nullptr,
+ TemplateNameKind::TNK_Type_template, false, nullptr);
}
TemplateTemplateParmDecl *
@@ -913,7 +917,8 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
auto *TTP =
new (C, ID, additionalSizeToAlloc<TemplateParameterList *>(NumExpansions))
TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr,
- false, nullptr, {});
+ TemplateNameKind::TNK_Type_template, false,
+ nullptr, {});
TTP->NumExpandedParams = NumExpansions;
return TTP;
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 5833a64..a099e97 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -396,6 +396,16 @@ SourceLocation CXXPseudoDestructorExpr::getEndLoc() const {
return End;
}
+static bool UnresolvedLookupExprIsVariableOrConceptParameterPack(
+ UnresolvedSetIterator Begin, UnresolvedSetIterator End) {
+ if (std::distance(Begin, End) != 1)
+ return false;
+ NamedDecl *ND = *Begin;
+ if (const auto *TTP = llvm::dyn_cast<TemplateTemplateParmDecl>(ND))
+ return TTP->isParameterPack();
+ return false;
+}
+
// UnresolvedLookupExpr
UnresolvedLookupExpr::UnresolvedLookupExpr(
const ASTContext &Context, CXXRecordDecl *NamingClass,
@@ -404,9 +414,11 @@ UnresolvedLookupExpr::UnresolvedLookupExpr(
const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin,
UnresolvedSetIterator End, bool KnownDependent,
bool KnownInstantiationDependent)
- : OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc,
- TemplateKWLoc, NameInfo, TemplateArgs, Begin, End,
- KnownDependent, KnownInstantiationDependent, false),
+ : OverloadExpr(
+ UnresolvedLookupExprClass, Context, QualifierLoc, TemplateKWLoc,
+ NameInfo, TemplateArgs, Begin, End, KnownDependent,
+ KnownInstantiationDependent,
+ UnresolvedLookupExprIsVariableOrConceptParameterPack(Begin, End)),
NamingClass(NamingClass) {
UnresolvedLookupExprBits.RequiresADL = RequiresADL;
}
@@ -1714,8 +1726,8 @@ SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context,
return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs);
}
-NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
- return cast<NonTypeTemplateParmDecl>(
+NamedDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
+ return cast<NamedDecl>(
getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
}
@@ -1758,9 +1770,12 @@ QualType SubstNonTypeTemplateParmExpr::getParameterType(
const ASTContext &Context) const {
// Note that, for a class type NTTP, we will have an lvalue of type 'const
// T', so we can't just compute this from the type and value category.
+
+ QualType Type = getType();
+
if (isReferenceParameter())
- return Context.getLValueReferenceType(getType());
- return getType().getUnqualifiedType();
+ return Context.getLValueReferenceType(Type);
+ return Type.getUnqualifiedType();
}
SubstNonTypeTemplateParmPackExpr::SubstNonTypeTemplateParmPackExpr(
@@ -1997,9 +2012,10 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee,
NumExpansions(NumExpansions) {
CXXFoldExprBits.Opcode = Opcode;
// We rely on asserted invariant to distinguish left and right folds.
- assert(((LHS && LHS->containsUnexpandedParameterPack()) !=
- (RHS && RHS->containsUnexpandedParameterPack())) &&
- "Exactly one of LHS or RHS should contain an unexpanded pack");
+ if (LHS && RHS)
+ assert(LHS->containsUnexpandedParameterPack() !=
+ RHS->containsUnexpandedParameterPack() &&
+ "Exactly one of LHS or RHS should contain an unexpanded pack");
SubExprs[SubExpr::Callee] = Callee;
SubExprs[SubExpr::LHS] = LHS;
SubExprs[SubExpr::RHS] = RHS;
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 2a66793..5233648 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -529,7 +529,7 @@ private:
void mangleUnqualifiedBlock(const BlockDecl *Block);
void mangleTemplateParamDecl(const NamedDecl *Decl);
void mangleTemplateParameterList(const TemplateParameterList *Params);
- void mangleTypeConstraint(const ConceptDecl *Concept,
+ void mangleTypeConstraint(const TemplateDecl *Concept,
ArrayRef<TemplateArgument> Arguments);
void mangleTypeConstraint(const TypeConstraint *Constraint);
void mangleRequiresClause(const Expr *RequiresClause);
@@ -2080,7 +2080,7 @@ void CXXNameMangler::mangleTemplateParameterList(
}
void CXXNameMangler::mangleTypeConstraint(
- const ConceptDecl *Concept, ArrayRef<TemplateArgument> Arguments) {
+ const TemplateDecl *Concept, ArrayRef<TemplateArgument> Arguments) {
const DeclContext *DC = Context.getEffectiveDeclContext(Concept);
if (!Arguments.empty())
mangleTemplateName(Concept, Arguments);
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 7c89dea..7a0f740 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -339,6 +339,17 @@ bool TemplateArgument::isPackExpansion() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
+bool TemplateArgument::isConceptOrConceptTemplateParameter() const {
+ if (getKind() == TemplateArgument::Template) {
+ if (isa<ConceptDecl>(getAsTemplate().getAsTemplateDecl()))
+ return true;
+ else if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>(
+ getAsTemplate().getAsTemplateDecl()))
+ return TTP->templateParameterKind() == TNK_Concept_template;
+ }
+ return false;
+}
+
bool TemplateArgument::containsUnexpandedParameterPack() const {
return getDependence() & TemplateArgumentDependence::UnexpandedPack;
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 7444a2f..141edc8 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5338,7 +5338,7 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
TypeDependence ExtraDependence, QualType Canon,
- ConceptDecl *TypeConstraintConcept,
+ TemplateDecl *TypeConstraintConcept,
ArrayRef<TemplateArgument> TypeConstraintArgs)
: DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) {
AutoTypeBits.Keyword = llvm::to_underlying(Keyword);
@@ -5346,6 +5346,9 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
this->TypeConstraintConcept = TypeConstraintConcept;
assert(TypeConstraintConcept || AutoTypeBits.NumArgs == 0);
if (TypeConstraintConcept) {
+ if (isa<TemplateTemplateParmDecl>(TypeConstraintConcept))
+ addDependence(TypeDependence::DependentInstantiation);
+
auto *ArgBuffer =
const_cast<TemplateArgument *>(getTypeConstraintArguments().data());
for (const TemplateArgument &Arg : TypeConstraintArgs) {
@@ -5361,7 +5364,7 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
QualType Deduced, AutoTypeKeyword Keyword,
- bool IsDependent, ConceptDecl *CD,
+ bool IsDependent, TemplateDecl *CD,
ArrayRef<TemplateArgument> Arguments) {
ID.AddPointer(Deduced.getAsOpaquePtr());
ID.AddInteger((unsigned)Keyword);
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 2d69f8c..a7d6a068 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -84,29 +84,28 @@ public:
if (!IsCollectingDecls)
return;
if (!D || isa<TranslationUnitDecl>(D) || isa<LinkageSpecDecl>(D) ||
- isa<NamespaceDecl>(D)) {
+ isa<NamespaceDecl>(D) || isa<ExportDecl>(D)) {
// These decls cover a lot of nested declarations that might not be used,
// reducing the granularity and making the output less useful.
return;
}
- auto *DC = D->getLexicalDeclContext();
- if (!DC || !DC->isFileContext()) {
- // We choose to work at namespace level to reduce complexity and the
- // number of cases we care about.
+ if (isa<ParmVarDecl>(D)) {
+ // Parameters are covered by their functions.
return;
}
+ auto *DC = D->getLexicalDeclContext();
+ if (!DC || !shouldIncludeDeclsIn(DC))
+ return;
PendingDecls.push_back(D);
- if (auto *NS = dyn_cast<NamespaceDecl>(DC)) {
- // Add any namespaces we have not seen before.
- // Note that we filter out namespaces from DeclRead as it includes too
- // all redeclarations and we only want the ones that had other used
- // declarations.
- while (NS && ProcessedNamespaces.insert(NS).second) {
- PendingDecls.push_back(NS);
-
- NS = dyn_cast<NamespaceDecl>(NS->getLexicalParent());
- }
+ for (; (isa<ExportDecl>(DC) || isa<NamespaceDecl>(DC)) &&
+ ProcessedDeclContexts.insert(DC).second;
+ DC = DC->getLexicalParent()) {
+ // Add any interesting decl contexts that we have not seen before.
+ // Note that we filter them out from DeclRead as that would include all
+ // redeclarations of namespaces, potentially those that do not have any
+ // imported declarations.
+ PendingDecls.push_back(cast<Decl>(DC));
}
}
@@ -205,12 +204,38 @@ public:
private:
std::vector<const Decl *> PendingDecls;
- llvm::SmallPtrSet<const NamespaceDecl *, 0> ProcessedNamespaces;
+ llvm::SmallPtrSet<const DeclContext *, 0> ProcessedDeclContexts;
bool IsCollectingDecls = true;
const SourceManager &SM;
std::unique_ptr<llvm::raw_ostream> OS;
+ static bool shouldIncludeDeclsIn(const DeclContext *DC) {
+ assert(DC && "DC is null");
+ // We choose to work at namespace level to reduce complexity and the number
+ // of cases we care about.
+ // We still need to carefully handle composite declarations like
+ // `ExportDecl`.
+ for (; DC; DC = DC->getLexicalParent()) {
+ if (DC->isFileContext())
+ return true;
+ if (isa<ExportDecl>(DC))
+ continue; // Depends on the parent.
+ return false;
+ }
+ llvm_unreachable("DeclContext chain must end with a translation unit");
+ }
+
llvm::SmallVector<CharSourceRange, 2> getRangesToMark(const Decl *D) {
+ if (auto *ED = dyn_cast<ExportDecl>(D)) {
+ if (!ED->hasBraces())
+ return {SM.getExpansionRange(ED->getExportLoc())};
+
+ return {SM.getExpansionRange(SourceRange(
+ ED->getExportLoc(),
+ lexForLBrace(ED->getExportLoc(), D->getLangOpts()))),
+ SM.getExpansionRange(ED->getRBraceLoc())};
+ }
+
auto *NS = dyn_cast<NamespaceDecl>(D);
if (!NS)
return {SM.getExpansionRange(D->getSourceRange())};
@@ -232,17 +257,7 @@ private:
}
}
}
- auto &LangOpts = D->getLangOpts();
- // Now skip one token, the next should be the lbrace.
- Token Tok;
- if (Lexer::getRawToken(TokenBeforeLBrace, Tok, SM, LangOpts, true) ||
- Lexer::getRawToken(Tok.getEndLoc(), Tok, SM, LangOpts, true) ||
- Tok.getKind() != tok::l_brace) {
- // On error or if we did not find the token we expected, avoid marking
- // everything inside the namespace as used.
- return {};
- }
- LBraceLoc = Tok.getLocation();
+ LBraceLoc = lexForLBrace(TokenBeforeLBrace, D->getLangOpts());
}
return {SM.getExpansionRange(SourceRange(NS->getBeginLoc(), LBraceLoc)),
SM.getExpansionRange(NS->getRBraceLoc())};
@@ -285,6 +300,20 @@ private:
OS->flush();
}
+
+ SourceLocation lexForLBrace(SourceLocation TokenBeforeLBrace,
+ const LangOptions &LangOpts) {
+ // Now skip one token, the next should be the lbrace.
+ Token Tok;
+ if (Lexer::getRawToken(TokenBeforeLBrace, Tok, SM, LangOpts, true) ||
+ Lexer::getRawToken(Tok.getEndLoc(), Tok, SM, LangOpts, true) ||
+ Tok.getKind() != tok::l_brace) {
+ // On error or if we did not find the token we expected, avoid marking
+ // everything inside the namespace as used.
+ return SourceLocation();
+ }
+ return Tok.getLocation();
+ }
};
/// Dumps deserialized declarations.
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index e47caeb..5fb3f92 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3310,6 +3310,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
case NameClassificationKind::TypeTemplate:
case NameClassificationKind::UndeclaredNonType:
case NameClassificationKind::UndeclaredTemplate:
+ case NameClassificationKind::Concept:
// Not a previously-declared non-type entity.
MightBeDeclarator = false;
break;
@@ -3320,7 +3321,6 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
case NameClassificationKind::OverloadSet:
case NameClassificationKind::VarTemplate:
case NameClassificationKind::FunctionTemplate:
- case NameClassificationKind::Concept:
// Might be a redeclaration of a prior entity.
break;
}
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 9a04bf2..0277dfb 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -711,41 +711,61 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
}
}
- // Provide an ExtWarn if the C++1z feature of using 'typename' here is used.
- // Generate a meaningful error if the user forgot to put class before the
- // identifier, comma, or greater. Provide a fixit if the identifier, comma,
- // or greater appear immediately or after 'struct'. In the latter case,
- // replace the keyword with 'class'.
+ TemplateNameKind Kind = TemplateNameKind::TNK_Non_template;
+ SourceLocation NameLoc;
+ IdentifierInfo *ParamName = nullptr;
+ SourceLocation EllipsisLoc;
bool TypenameKeyword = false;
- if (!TryConsumeToken(tok::kw_class)) {
+
+ if (TryConsumeToken(tok::kw_class)) {
+ Kind = TemplateNameKind::TNK_Type_template;
+ } else {
+
+ // Provide an ExtWarn if the C++1z feature of using 'typename' here is used.
+ // Generate a meaningful error if the user forgot to put class before the
+ // identifier, comma, or greater. Provide a fixit if the identifier, comma,
+ // or greater appear immediately or after 'struct'. In the latter case,
+ // replace the keyword with 'class'.
bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct);
const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok;
if (Tok.is(tok::kw_typename)) {
TypenameKeyword = true;
+ Kind = TemplateNameKind::TNK_Type_template;
Diag(Tok.getLocation(),
getLangOpts().CPlusPlus17
? diag::warn_cxx14_compat_template_template_param_typename
: diag::ext_template_template_param_typename)
- << (!getLangOpts().CPlusPlus17
- ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
- : FixItHint());
+ << (!getLangOpts().CPlusPlus17
+ ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
+ : FixItHint());
+ Kind = TemplateNameKind::TNK_Type_template;
+ } else if (TryConsumeToken(tok::kw_concept)) {
+ Kind = TemplateNameKind::TNK_Concept_template;
+ } else if (TryConsumeToken(tok::kw_auto)) {
+ Kind = TemplateNameKind::TNK_Var_template;
} else if (Next.isOneOf(tok::identifier, tok::comma, tok::greater,
tok::greatergreater, tok::ellipsis)) {
+ // Provide a fixit if the identifier, comma,
+ // or greater appear immediately or after 'struct'. In the latter case,
+ // replace the keyword with 'class'.
Diag(Tok.getLocation(), diag::err_class_on_template_template_param)
<< getLangOpts().CPlusPlus17
<< (Replace
? FixItHint::CreateReplacement(Tok.getLocation(), "class")
: FixItHint::CreateInsertion(Tok.getLocation(), "class "));
- } else
- Diag(Tok.getLocation(), diag::err_class_on_template_template_param)
- << getLangOpts().CPlusPlus17;
-
+ }
if (Replace)
ConsumeToken();
}
+ if (!getLangOpts().CPlusPlus26 &&
+ (Kind == TemplateNameKind::TNK_Concept_template ||
+ Kind == TemplateNameKind::TNK_Var_template)) {
+ Diag(PrevTokLocation, diag::err_cxx26_template_template_params)
+ << (Kind == TemplateNameKind::TNK_Concept_template);
+ }
+
// Parse the ellipsis, if given.
- SourceLocation EllipsisLoc;
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
Diag(EllipsisLoc,
getLangOpts().CPlusPlus11
@@ -753,8 +773,7 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
: diag::ext_variadic_templates);
// Get the identifier, if given.
- SourceLocation NameLoc = Tok.getLocation();
- IdentifierInfo *ParamName = nullptr;
+ NameLoc = Tok.getLocation();
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
ConsumeToken();
@@ -792,7 +811,7 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
}
return Actions.ActOnTemplateTemplateParameter(
- getCurScope(), TemplateLoc, ParamList, TypenameKeyword, EllipsisLoc,
+ getCurScope(), TemplateLoc, Kind, TypenameKeyword, ParamList, EllipsisLoc,
ParamName, NameLoc, Depth, Position, EqualLoc, DefaultArg);
}
@@ -1201,7 +1220,8 @@ static bool isEndOfTemplateArgument(Token Tok) {
ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) &&
- !Tok.is(tok::annot_cxxscope))
+ !Tok.is(tok::annot_cxxscope) && !Tok.is(tok::annot_template_id) &&
+ !Tok.is(tok::annot_non_type))
return ParsedTemplateArgument();
// C++0x [temp.arg.template]p1:
@@ -1245,12 +1265,27 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
/*EnteringContext=*/false, Template))
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
- } else if (Tok.is(tok::identifier)) {
+ } else if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) ||
+ Tok.is(tok::annot_non_type)) {
// We may have a (non-dependent) template name.
TemplateTy Template;
UnqualifiedId Name;
- Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
- ConsumeToken(); // the identifier
+ if (Tok.is(tok::annot_non_type)) {
+ NamedDecl *ND = getNonTypeAnnotation(Tok);
+ if (!isa<VarTemplateDecl>(ND))
+ return Result;
+ Name.setIdentifier(ND->getIdentifier(), Tok.getLocation());
+ ConsumeAnnotationToken();
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ if (TemplateId->LAngleLoc.isValid())
+ return Result;
+ Name.setIdentifier(TemplateId->Name, Tok.getLocation());
+ ConsumeAnnotationToken();
+ } else {
+ Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeToken(); // the identifier
+ }
TryConsumeToken(tok::ellipsis, EllipsisLoc);
@@ -1261,7 +1296,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
/*hasTemplateKeyword=*/false, Name,
/*ObjectType=*/nullptr,
/*EnteringContext=*/false, Template, MemberOfUnknownSpecialization);
- if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
+ if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template ||
+ TNK == TNK_Var_template || TNK == TNK_Concept_template) {
// We have an id-expression that refers to a class template or
// (C++0x) alias template.
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
@@ -1301,13 +1337,12 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
{
TentativeParsingAction TPA(*this);
- ParsedTemplateArgument TemplateTemplateArgument
- = ParseTemplateTemplateArgument();
+ ParsedTemplateArgument TemplateTemplateArgument =
+ ParseTemplateTemplateArgument();
if (!TemplateTemplateArgument.isInvalid()) {
TPA.Commit();
return TemplateTemplateArgument;
}
-
// Revert this tentative parse to parse a non-type template argument.
TPA.Revert();
}
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index b58100c..2a731a1 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1376,7 +1376,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
// If we annotated then the current token should not still be ::
// FIXME we may want to also check for tok::annot_typename but
// currently don't have a test case.
- if (Tok.isNot(tok::annot_cxxscope))
+ if (Tok.isNot(tok::annot_cxxscope) && Tok.isNot(tok::identifier))
break;
}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index ff50b3f..a8cfe20 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1838,7 +1838,8 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC,
case NameClassificationKind::TypeTemplate:
if (Next.isNot(tok::less)) {
- // This may be a type template being used as a template template argument.
+ // This may be a type or variable template being used as a template
+ // template argument.
if (SS.isNotEmpty())
AnnotateScopeToken(SS, !WasScopeAnnotation);
return AnnotatedNameKind::TemplateName;
@@ -1852,10 +1853,10 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC,
Classification.getKind() == NameClassificationKind::Concept;
// We have a template name followed by '<'. Consume the identifier token so
// we reach the '<' and annotate it.
- if (Next.is(tok::less))
- ConsumeToken();
UnqualifiedId Id;
Id.setIdentifier(Name, NameLoc);
+ if (Next.is(tok::less))
+ ConsumeToken();
if (AnnotateTemplateIdToken(
TemplateTy::make(Classification.getTemplateName()),
Classification.getTemplateNameKind(), SS, SourceLocation(), Id,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bc87611..3c4511b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -35,6 +35,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
@@ -3716,7 +3717,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
}
void Sema::CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc) {
- if (ConceptDecl *Decl = AutoT->getTypeConstraintConcept()) {
+ if (TemplateDecl *Decl = AutoT->getTypeConstraintConcept()) {
DiagnoseUseOfDecl(Decl, Loc);
}
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e4c2543..6793d6d 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2903,8 +2903,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// in BuildTemplateIdExpr().
// The single lookup result must be a variable template declaration.
if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId && Id.TemplateId &&
- Id.TemplateId->Kind == TNK_Var_template) {
- assert(R.getAsSingle<VarTemplateDecl>() &&
+ (Id.TemplateId->Kind == TNK_Var_template ||
+ Id.TemplateId->Kind == TNK_Concept_template)) {
+ assert(R.getAsSingle<TemplateDecl>() &&
"There should only be one declaration found.");
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 7b9c638..1dd38c0 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3713,7 +3713,7 @@ ValueDecl *InitializedEntity::getDecl() const {
case EK_ParenAggInitMember:
case EK_Binding:
case EK_TemplateParameter:
- return Variable.VariableOrMember;
+ return cast<ValueDecl>(Variable.VariableOrMember);
case EK_Parameter:
case EK_Parameter_CF_Audited:
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 21fed2e..b6b8932 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
@@ -38,6 +39,7 @@
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/SaveAndRestore.h"
#include <optional>
@@ -306,9 +308,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD));
TemplateKind =
- isa<VarTemplateDecl>(TD) ? TNK_Var_template :
- isa<ConceptDecl>(TD) ? TNK_Concept_template :
- TNK_Type_template;
+ isa<TemplateTemplateParmDecl>(TD)
+ ? dyn_cast<TemplateTemplateParmDecl>(TD)->templateParameterKind()
+ : isa<VarTemplateDecl>(TD) ? TNK_Var_template
+ : isa<ConceptDecl>(TD) ? TNK_Concept_template
+ : TNK_Type_template;
}
}
@@ -1071,12 +1075,26 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) {
TemplateName TN = TypeConstr->Template.get();
- ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl());
+ NamedDecl *CD = nullptr;
+ bool IsTypeConcept = false;
+ bool RequiresArguments = false;
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TN.getAsTemplateDecl())) {
+ IsTypeConcept = TTP->isTypeConceptTemplateParam();
+ RequiresArguments =
+ TTP->getTemplateParameters()->getMinRequiredArguments() > 1;
+ CD = TTP;
+ } else {
+ CD = TN.getAsTemplateDecl();
+ IsTypeConcept = cast<ConceptDecl>(CD)->isTypeConcept();
+ RequiresArguments = cast<ConceptDecl>(CD)
+ ->getTemplateParameters()
+ ->getMinRequiredArguments() > 1;
+ }
// C++2a [temp.param]p4:
// [...] The concept designated by a type-constraint shall be a type
// concept ([temp.concept]).
- if (!CD->isTypeConcept()) {
+ if (!IsTypeConcept) {
Diag(TypeConstr->TemplateNameLoc,
diag::err_type_constraint_non_type_concept);
return true;
@@ -1087,8 +1105,7 @@ bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) {
bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid();
- if (!WereArgsSpecified &&
- CD->getTemplateParameters()->getMinRequiredArguments() > 1) {
+ if (!WereArgsSpecified && RequiresArguments) {
Diag(TypeConstr->TemplateNameLoc,
diag::err_type_constraint_missing_arguments)
<< CD;
@@ -1115,7 +1132,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS,
return true;
TemplateName TN = TypeConstr->Template.get();
- ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl());
+ TemplateDecl *CD = cast<TemplateDecl>(TN.getAsTemplateDecl());
UsingShadowDecl *USD = TN.getAsUsingShadowDecl();
DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name),
@@ -1143,7 +1160,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS,
template <typename ArgumentLocAppender>
static ExprResult formImmediatelyDeclaredConstraint(
Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo,
- ConceptDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc,
+ NamedDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc,
SourceLocation RAngleLoc, QualType ConstrainedType,
SourceLocation ParamNameLoc, ArgumentLocAppender Appender,
SourceLocation EllipsisLoc) {
@@ -1162,10 +1179,19 @@ static ExprResult formImmediatelyDeclaredConstraint(
// constraint of T. [...]
CXXScopeSpec SS;
SS.Adopt(NS);
- ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
- SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
- /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, NamedConcept,
- &ConstraintArgs);
+ ExprResult ImmediatelyDeclaredConstraint;
+ if (auto *CD = dyn_cast<ConceptDecl>(NamedConcept)) {
+ ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
+ SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+ /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, CD,
+ &ConstraintArgs);
+ }
+ // We have a template template parameter
+ else {
+ auto *CDT = dyn_cast<TemplateTemplateParmDecl>(NamedConcept);
+ ImmediatelyDeclaredConstraint = S.CheckVarOrConceptTemplateTemplateId(
+ SS, NameInfo, CDT, SourceLocation(), &ConstraintArgs);
+ }
if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
return ImmediatelyDeclaredConstraint;
@@ -1191,7 +1217,8 @@ static ExprResult formImmediatelyDeclaredConstraint(
bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
DeclarationNameInfo NameInfo,
- ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
+ TemplateDecl *NamedConcept,
+ NamedDecl *FoundDecl,
const TemplateArgumentListInfo *TemplateArgs,
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc) {
@@ -1588,11 +1615,15 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
return Param;
}
+/// ActOnTemplateTemplateParameter - Called when a C++ template template
+/// parameter (e.g. T in template <template \<typename> class T> class array)
+/// has been parsed. S is the current scope.
NamedDecl *Sema::ActOnTemplateTemplateParameter(
- Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params,
- bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *Name,
- SourceLocation NameLoc, unsigned Depth, unsigned Position,
- SourceLocation EqualLoc, ParsedTemplateArgument Default) {
+ Scope *S, SourceLocation TmpLoc, TemplateNameKind Kind, bool Typename,
+ TemplateParameterList *Params, SourceLocation EllipsisLoc,
+ IdentifierInfo *Name, SourceLocation NameLoc, unsigned Depth,
+ unsigned Position, SourceLocation EqualLoc,
+ ParsedTemplateArgument Default) {
assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!");
@@ -1609,7 +1640,7 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(
Context, Context.getTranslationUnitDecl(),
NameLoc.isInvalid() ? TmpLoc : NameLoc, Depth, Position, IsParameterPack,
- Name, Typename, Params);
+ Name, Kind, Typename, Params);
Param->setAccess(AS_public);
if (Param->isParameterPack())
@@ -1658,6 +1689,14 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
return Param;
}
+ TemplateName Name =
+ DefaultArg.getArgument().getAsTemplateOrTemplatePattern();
+ TemplateDecl *Template = Name.getAsTemplateDecl();
+ if (Template &&
+ !CheckDeclCompatibleWithTemplateTemplate(Template, Param, DefaultArg)) {
+ return Param;
+ }
+
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(DefaultArg.getLocation(),
DefaultArg.getArgument().getAsTemplate(),
@@ -2667,6 +2706,18 @@ struct DependencyChecker : DynamicRecursiveASTVisitor {
return DynamicRecursiveASTVisitor::VisitDeclRefExpr(E);
}
+ bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override {
+ if (ULE->isConceptReference() || ULE->isVarDeclReference()) {
+ if (auto *TTP = ULE->getTemplateTemplateDecl()) {
+ if (Matches(TTP->getDepth(), ULE->getExprLoc()))
+ return false;
+ }
+ for (auto &TLoc : ULE->template_arguments())
+ DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc);
+ }
+ return DynamicRecursiveASTVisitor::VisitUnresolvedLookupExpr(ULE);
+ }
+
bool VisitSubstTemplateTypeParmType(SubstTemplateTypeParmType *T) override {
return TraverseType(T->getReplacementType());
}
@@ -4047,8 +4098,10 @@ static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
-static bool isTemplateArgumentTemplateParameter(
- const TemplateArgument &Arg, unsigned Depth, unsigned Index) {
+static bool isTemplateArgumentTemplateParameter(const TemplateArgument &Arg,
+ NamedDecl *Param,
+ unsigned Depth,
+ unsigned Index) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::NullPtr:
@@ -4104,7 +4157,8 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
Arg = Arg.pack_begin()->getPackExpansionPattern();
}
- if (!isTemplateArgumentTemplateParameter(Arg, Depth, I))
+ if (!isTemplateArgumentTemplateParameter(Arg, Params->getParam(I), Depth,
+ I))
return false;
}
@@ -4694,6 +4748,43 @@ ExprResult Sema::CheckVarTemplateId(
return BuildDeclarationNameExpr(SS, NameInfo, Var, FoundD, TemplateArgs);
}
+ExprResult Sema::CheckVarOrConceptTemplateTemplateId(
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
+ TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert(Template && "A variable template id without template?");
+
+ if (Template->templateParameterKind() != TemplateNameKind::TNK_Var_template &&
+ Template->templateParameterKind() !=
+ TemplateNameKind::TNK_Concept_template)
+ return ExprResult();
+
+ // Check that the template argument list is well-formed for this template.
+ CheckTemplateArgumentInfo CTAI;
+ if (CheckTemplateArgumentList(
+ Template, TemplateLoc,
+ // FIXME: TemplateArgs will not be modified because
+ // UpdateArgsWithConversions is false, however, we should
+ // CheckTemplateArgumentList to be const-correct.
+ const_cast<TemplateArgumentListInfo &>(*TemplateArgs),
+ /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, CTAI,
+ /*UpdateArgsWithConversions=*/false))
+ return true;
+
+ UnresolvedSet<1> R;
+ R.addDecl(Template);
+
+ // FIXME: We model references to variable template and concept parameters
+ // as an UnresolvedLookupExpr. This is because they encapsulate the same
+ // data, can generally be used in the same places and work the same way.
+ // However, it might be cleaner to use a dedicated AST node in the long run.
+ return UnresolvedLookupExpr::Create(
+ getASTContext(), nullptr, SS.getWithLocInContext(getASTContext()),
+ SourceLocation(), NameInfo, false, TemplateArgs, R.begin(), R.end(),
+ /*KnownDependent=*/false,
+ /*KnownInstantiationDependent=*/false);
+}
+
void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
SourceLocation Loc) {
Diag(Loc, diag::err_template_missing_args)
@@ -4804,21 +4895,29 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
KnownDependent = true;
}
+ // We don't want lookup warnings at this point.
+ R.suppressDiagnostics();
+
if (R.getAsSingle<ConceptDecl>()) {
return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(),
R.getRepresentativeDecl(),
R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
- // We don't want lookup warnings at this point.
- R.suppressDiagnostics();
+ // Check variable template ids (C++17) and concept template parameters
+ // (C++26).
+ UnresolvedLookupExpr *ULE;
+ if (R.getAsSingle<TemplateTemplateParmDecl>())
+ return CheckVarOrConceptTemplateTemplateId(
+ SS, R.getLookupNameInfo(), R.getAsSingle<TemplateTemplateParmDecl>(),
+ TemplateKWLoc, TemplateArgs);
- UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
+ // Function templates
+ ULE = UnresolvedLookupExpr::Create(
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
TemplateKWLoc, R.getLookupNameInfo(), RequiresADL, TemplateArgs,
R.begin(), R.end(), KnownDependent,
/*KnownInstantiationDependent=*/false);
-
// Model the templates with UnresolvedTemplateTy. The expression should then
// either be transformed in an instantiation or be diagnosed in
// CheckPlaceholderExpr.
@@ -5609,12 +5708,25 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
break;
case TemplateArgument::Expression:
- case TemplateArgument::Type:
+ case TemplateArgument::Type: {
+ auto Kind = 0;
+ switch (TempParm->templateParameterKind()) {
+ case TemplateNameKind::TNK_Var_template:
+ Kind = 1;
+ break;
+ case TemplateNameKind::TNK_Concept_template:
+ Kind = 2;
+ break;
+ default:
+ break;
+ }
+
// We have a template template parameter but the template
// argument does not refer to a template.
Diag(ArgLoc.getLocation(), diag::err_template_arg_must_be_template)
- << getLangOpts().CPlusPlus11;
+ << Kind << getLangOpts().CPlusPlus11;
return true;
+ }
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
@@ -6359,7 +6471,7 @@ enum NullPointerValueKind {
/// Determine whether the given template argument is a null pointer
/// value of the appropriate type.
static NullPointerValueKind
-isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
+isNullPointerValueTemplateArgument(Sema &S, NamedDecl *Param,
QualType ParamType, Expr *Arg,
Decl *Entity = nullptr) {
if (Arg->isValueDependent() || Arg->isTypeDependent())
@@ -6464,9 +6576,10 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
/// Checks whether the given template argument is compatible with its
/// template parameter.
-static bool CheckTemplateArgumentIsCompatibleWithParameter(
- Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
- Expr *Arg, QualType ArgType) {
+static bool
+CheckTemplateArgumentIsCompatibleWithParameter(Sema &S, NamedDecl *Param,
+ QualType ParamType, Expr *ArgIn,
+ Expr *Arg, QualType ArgType) {
bool ObjCLifetimeConversion;
if (ParamType->isPointerType() &&
!ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() &&
@@ -6522,7 +6635,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
/// Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
static bool CheckTemplateArgumentAddressOfObjectOrFunction(
- Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
+ Sema &S, NamedDecl *Param, QualType ParamType, Expr *ArgIn,
TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ArgIn;
@@ -6784,11 +6897,9 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
/// Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-static bool
-CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
- QualType ParamType, Expr *&ResultArg,
- TemplateArgument &SugaredConverted,
- TemplateArgument &CanonicalConverted) {
+static bool CheckTemplateArgumentPointerToMember(
+ Sema &S, NamedDecl *Param, QualType ParamType, Expr *&ResultArg,
+ TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ResultArg;
@@ -6919,8 +7030,15 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
return true;
}
-ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- QualType ParamType, Expr *Arg,
+/// Check a template argument against its corresponding
+/// non-type template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.nontype].
+/// If an error occurred, it returns ExprError(); otherwise, it
+/// returns the converted template argument. \p ParamType is the
+/// type of the non-type template parameter after it has been instantiated.
+ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
+ Expr *Arg,
TemplateArgument &SugaredConverted,
TemplateArgument &CanonicalConverted,
bool StrictCheck,
@@ -6974,7 +7092,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
} else {
TemplateDeductionInfo Info(DeductionArg->getExprLoc(),
- Param->getDepth() + 1);
+ Param->getTemplateDepth() + 1);
ParamType = QualType();
TemplateDeductionResult Result =
DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info,
@@ -6986,13 +7104,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// checking the template argument list.
/*IgnoreConstraints=*/true);
if (Result == TemplateDeductionResult::AlreadyDiagnosed) {
- if (ParamType.isNull())
- return ExprError();
+ return ExprError();
} else if (Result != TemplateDeductionResult::Success) {
- Diag(Arg->getExprLoc(),
- diag::err_non_type_template_parm_type_deduction_failure)
- << Param->getDeclName() << Param->getType() << Arg->getType()
- << Arg->getSourceRange();
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << NTTP->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ }
NoteTemplateParameterLocation(*Param);
return ExprError();
}
@@ -7387,7 +7506,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (IntegerType->isUnsignedIntegerOrEnumerationType() &&
(OldValue.isSigned() && OldValue.isNegative())) {
Diag(Arg->getBeginLoc(), diag::warn_template_arg_negative)
- << toString(OldValue, 10) << toString(Value, 10) << Param->getType()
+ << toString(OldValue, 10) << toString(Value, 10) << ParamType
<< Arg->getSourceRange();
NoteTemplateParameterLocation(*Param);
}
@@ -7402,7 +7521,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
RequiredBits = OldValue.getSignificantBits();
if (RequiredBits > AllowedBits) {
Diag(Arg->getBeginLoc(), diag::warn_template_arg_too_large)
- << toString(OldValue, 10) << toString(Value, 10) << Param->getType()
+ << toString(OldValue, 10) << toString(Value, 10) << ParamType
<< Arg->getSourceRange();
NoteTemplateParameterLocation(*Param);
}
@@ -7581,6 +7700,81 @@ static void DiagnoseTemplateParameterListArityMismatch(
Sema &S, TemplateParameterList *New, TemplateParameterList *Old,
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc);
+bool Sema::CheckDeclCompatibleWithTemplateTemplate(
+ TemplateDecl *Template, TemplateTemplateParmDecl *Param,
+ const TemplateArgumentLoc &Arg) {
+ // C++0x [temp.arg.template]p1:
+ // A template-argument for a template template-parameter shall be
+ // the name of a class template or an alias template, expressed as an
+ // id-expression. When the template-argument names a class template, only
+ // primary class templates are considered when matching the
+ // template template argument with the corresponding parameter;
+ // partial specializations are not considered even if their
+ // parameter lists match that of the template template parameter.
+ //
+
+ TemplateNameKind Kind = TNK_Non_template;
+ unsigned DiagFoundKind = 0;
+
+ if (auto *TTP = llvm::dyn_cast<TemplateTemplateParmDecl>(Template)) {
+ switch (TTP->templateParameterKind()) {
+ case TemplateNameKind::TNK_Concept_template:
+ DiagFoundKind = 3;
+ break;
+ case TemplateNameKind::TNK_Var_template:
+ DiagFoundKind = 2;
+ break;
+ default:
+ DiagFoundKind = 1;
+ break;
+ }
+ Kind = TTP->templateParameterKind();
+ } else if (isa<ConceptDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Concept_template;
+ DiagFoundKind = 3;
+ } else if (isa<FunctionTemplateDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Function_template;
+ DiagFoundKind = 0;
+ } else if (isa<VarTemplateDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Var_template;
+ DiagFoundKind = 2;
+ } else if (isa<ClassTemplateDecl>(Template) ||
+ isa<TypeAliasTemplateDecl>(Template) ||
+ isa<BuiltinTemplateDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Type_template;
+ DiagFoundKind = 1;
+ } else {
+ assert(false && "Unexpected Decl");
+ }
+
+ if (Kind == Param->templateParameterKind()) {
+ return true;
+ }
+
+ unsigned DiagKind = 0;
+ switch (Param->templateParameterKind()) {
+ case TemplateNameKind::TNK_Concept_template:
+ DiagKind = 2;
+ break;
+ case TemplateNameKind::TNK_Var_template:
+ DiagKind = 1;
+ break;
+ default:
+ DiagKind = 0;
+ break;
+ }
+ Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template)
+ << DiagKind;
+ Diag(Template->getLocation(), diag::note_template_arg_refers_to_template_here)
+ << DiagFoundKind << Template;
+ return false;
+}
+
+/// Check a template argument against its corresponding
+/// template template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.template].
+/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
TemplateArgumentLoc &Arg,
@@ -7597,27 +7791,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
if (Template->isInvalidDecl())
return true;
- // C++0x [temp.arg.template]p1:
- // A template-argument for a template template-parameter shall be
- // the name of a class template or an alias template, expressed as an
- // id-expression. When the template-argument names a class template, only
- // primary class templates are considered when matching the
- // template template argument with the corresponding parameter;
- // partial specializations are not considered even if their
- // parameter lists match that of the template template parameter.
- //
- // Note that we also allow template template parameters here, which
- // will happen when we are dealing with, e.g., class template
- // partial specializations.
- if (!isa<ClassTemplateDecl>(Template) &&
- !isa<TemplateTemplateParmDecl>(Template) &&
- !isa<TypeAliasTemplateDecl>(Template) &&
- !isa<BuiltinTemplateDecl>(Template)) {
- assert(isa<FunctionTemplateDecl>(Template) &&
- "Only function templates are possible here");
- Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template);
- Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
- << Template;
+ if (!CheckDeclCompatibleWithTemplateTemplate(Template, Param, Arg)) {
+ return true;
}
// C++1z [temp.arg.template]p3: (DR 150)
@@ -7689,6 +7864,10 @@ void Sema::NoteTemplateParameterLocation(const NamedDecl &Decl) {
diag::note_template_param_external);
}
+/// Given a non-type template argument that refers to a
+/// declaration and the type of its corresponding non-type template
+/// parameter, produce an expression that properly refers to that
+/// declaration.
ExprResult Sema::BuildExpressionFromDeclTemplateArgument(
const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc,
NamedDecl *TemplateParam) {
@@ -8009,34 +8188,40 @@ static bool MatchTemplateParameterKind(
return false;
}
-
// For non-type template parameters, check the type of the parameter.
- if (NonTypeTemplateParmDecl *OldNTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Old)) {
+ if (NonTypeTemplateParmDecl *OldNTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(Old)) {
NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New);
- // C++20 [temp.over.link]p6:
- // Two [non-type] template-parameters are equivalent [if] they have
- // equivalent types ignoring the use of type-constraints for
- // placeholder types
- QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType());
- QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType());
- if (!S.Context.hasSameType(OldType, NewType)) {
- if (Complain) {
- unsigned NextDiag = diag::err_template_nontype_parm_different_type;
- if (TemplateArgLoc.isValid()) {
- S.Diag(TemplateArgLoc,
- diag::err_template_arg_template_params_mismatch);
- NextDiag = diag::note_template_nontype_parm_different_type;
+ // If we are matching a template template argument to a template
+ // template parameter and one of the non-type template parameter types
+ // is dependent, then we must wait until template instantiation time
+ // to actually compare the arguments.
+ if (Kind != Sema::TPL_TemplateTemplateParmMatch ||
+ (!OldNTTP->getType()->isDependentType() &&
+ !NewNTTP->getType()->isDependentType())) {
+ // C++20 [temp.over.link]p6:
+ // Two [non-type] template-parameters are equivalent [if] they have
+ // equivalent types ignoring the use of type-constraints for
+ // placeholder types
+ QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType());
+ QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType());
+ if (!S.Context.hasSameType(OldType, NewType)) {
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+ if (TemplateArgLoc.isValid()) {
+ S.Diag(TemplateArgLoc,
+ diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_nontype_parm_different_type;
+ }
+ S.Diag(NewNTTP->getLocation(), NextDiag)
+ << NewNTTP->getType() << (Kind != Sema::TPL_TemplateMatch);
+ S.Diag(OldNTTP->getLocation(),
+ diag::note_template_nontype_parm_prev_declaration)
+ << OldNTTP->getType();
}
- S.Diag(NewNTTP->getLocation(), NextDiag)
- << NewNTTP->getType() << (Kind != Sema::TPL_TemplateMatch);
- S.Diag(OldNTTP->getLocation(),
- diag::note_template_nontype_parm_prev_declaration)
- << OldNTTP->getType();
+ return false;
}
-
- return false;
}
}
// For template template parameters, check the template parameter types.
@@ -8045,6 +8230,8 @@ static bool MatchTemplateParameterKind(
else if (TemplateTemplateParmDecl *OldTTP =
dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
+ if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind())
+ return false;
if (!S.TemplateParameterListsAreEqual(
NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
OldTTP->getTemplateParameters(), Complain,
@@ -8056,6 +8243,7 @@ static bool MatchTemplateParameterKind(
}
if (Kind != Sema::TPL_TemplateParamsEquivalent &&
+ Kind != Sema::TPL_TemplateTemplateParmMatch &&
!isa<TemplateTemplateParmDecl>(Old)) {
const Expr *NewC = nullptr, *OldC = nullptr;
@@ -8421,6 +8609,11 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
if (isa<NonTypeTemplateParmDecl>(DRE->getDecl()))
continue;
+ if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(ArgExpr);
+ ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) {
+ continue;
+ }
+
// C++ [temp.class.spec]p9:
// Within the argument list of a class template partial
// specialization, the following restrictions apply:
@@ -9032,13 +9225,15 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl());
}
-bool Sema::CheckConceptUseInDefinition(ConceptDecl *Concept,
- SourceLocation Loc) {
- if (!Concept->isInvalidDecl() && !Concept->hasDefinition()) {
- Diag(Loc, diag::err_recursive_concept) << Concept;
- Diag(Concept->getLocation(), diag::note_declared_at);
+bool Sema::CheckConceptUseInDefinition(NamedDecl *Concept, SourceLocation Loc) {
+ if (auto *CE = llvm::dyn_cast<ConceptDecl>(Concept);
+ CE && !CE->isInvalidDecl() && !CE->hasDefinition()) {
+ Diag(Loc, diag::err_recursive_concept) << CE;
+ Diag(CE->getLocation(), diag::note_declared_at);
return true;
}
+ // Concept template parameters don't have a definition and can't
+ // be defined recursively.
return false;
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 9e56e697..0d70321 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -37,6 +37,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TemplateKinds.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Sema.h"
@@ -146,11 +147,7 @@ static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced, unsigned Level,
llvm::SmallBitVector &Deduced);
-/// If the given expression is of a form that permits the deduction
-/// of a non-type template parameter, return the declaration of that
-/// non-type template parameter.
-static const NonTypeTemplateParmDecl *
-getDeducedParameterFromExpr(const Expr *E, unsigned Depth) {
+static const Expr *unwrapExpressionForDeduction(const Expr *E) {
// If we are within an alias template, the expression may have undergone
// any number of parameter substitutions already.
while (true) {
@@ -170,18 +167,100 @@ getDeducedParameterFromExpr(const Expr *E, unsigned Depth) {
} else
break;
}
+ return E;
+}
+
+class NonTypeOrVarTemplateParmDecl {
+public:
+ NonTypeOrVarTemplateParmDecl(const NamedDecl *Template) : Template(Template) {
+ assert(
+ !Template || isa<NonTypeTemplateParmDecl>(Template) ||
+ (isa<TemplateTemplateParmDecl>(Template) &&
+ (cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() ==
+ TNK_Var_template ||
+ cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() ==
+ TNK_Concept_template)));
+ }
+
+ QualType getType() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getType();
+ return getTemplate()->templateParameterKind() == TNK_Concept_template
+ ? getTemplate()->getASTContext().BoolTy
+ : getTemplate()->getASTContext().DependentTy;
+ }
+
+ unsigned getDepth() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getDepth();
+ return getTemplate()->getDepth();
+ }
+
+ unsigned getIndex() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getIndex();
+ return getTemplate()->getIndex();
+ }
+
+ const TemplateTemplateParmDecl *getTemplate() const {
+ return cast<TemplateTemplateParmDecl>(Template);
+ }
+
+ const NonTypeTemplateParmDecl *getNTTP() const {
+ return cast<NonTypeTemplateParmDecl>(Template);
+ }
+
+ TemplateParameter asTemplateParam() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return const_cast<NonTypeTemplateParmDecl *>(NTTP);
+ return const_cast<TemplateTemplateParmDecl *>(getTemplate());
+ }
+
+ bool isExpandedParameterPack() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->isExpandedParameterPack();
+ return getTemplate()->isExpandedParameterPack();
+ }
+
+ SourceLocation getLocation() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getLocation();
+ return getTemplate()->getLocation();
+ }
+
+ operator bool() const { return Template; }
+private:
+ const NamedDecl *Template;
+};
+
+/// If the given expression is of a form that permits the deduction
+/// of a non-type template parameter, return the declaration of that
+/// non-type template parameter.
+static NonTypeOrVarTemplateParmDecl
+getDeducedNTTParameterFromExpr(const Expr *E, unsigned Depth) {
+ // If we are within an alias template, the expression may have undergone
+ // any number of parameter substitutions already.
+ E = unwrapExpressionForDeduction(E);
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()))
if (NTTP->getDepth() == Depth)
return NTTP;
+ if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E);
+ ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) {
+ if (auto *TTP = ULE->getTemplateTemplateDecl()) {
+
+ if (TTP->getDepth() == Depth)
+ return TTP;
+ }
+ }
return nullptr;
}
-static const NonTypeTemplateParmDecl *
-getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) {
- return getDeducedParameterFromExpr(E, Info.getDeducedDepth());
+static const NonTypeOrVarTemplateParmDecl
+getDeducedNTTParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) {
+ return getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth());
}
/// Determine whether two declaration pointers refer to the same
@@ -386,29 +465,28 @@ checkDeducedTemplateArguments(ASTContext &Context,
/// deduction is funneled through here.
static TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP,
+ const NonTypeOrVarTemplateParmDecl NTTP,
const DeducedTemplateArgument &NewDeduced,
QualType ValueType, TemplateDeductionInfo &Info,
bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
- assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ assert(NTTP.getDepth() == Info.getDeducedDepth() &&
"deducing non-type template argument with wrong depth");
DeducedTemplateArgument Result = checkDeducedTemplateArguments(
- S.Context, Deduced[NTTP->getIndex()], NewDeduced);
+ S.Context, Deduced[NTTP.getIndex()], NewDeduced);
if (Result.isNull()) {
- Info.Param = const_cast<NonTypeTemplateParmDecl*>(NTTP);
- Info.FirstArg = Deduced[NTTP->getIndex()];
+ Info.Param = NTTP.asTemplateParam();
+ Info.FirstArg = Deduced[NTTP.getIndex()];
Info.SecondArg = NewDeduced;
return TemplateDeductionResult::Inconsistent;
}
-
- Deduced[NTTP->getIndex()] = Result;
+ Deduced[NTTP.getIndex()] = Result;
if (!S.getLangOpts().CPlusPlus17)
return TemplateDeductionResult::Success;
- if (NTTP->isExpandedParameterPack())
+ if (NTTP.isExpandedParameterPack())
// FIXME: We may still need to deduce parts of the type here! But we
// don't have any way to find which slice of the type to use, and the
// type stored on the NTTP itself is nonsense. Perhaps the type of an
@@ -417,7 +495,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
// Get the type of the parameter for deduction. If it's a (dependent) array
// or function type, we will not have decayed it yet, so do that now.
- QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType());
+ QualType ParamType = S.Context.getAdjustedParameterType(NTTP.getType());
if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
ParamType = Expansion->getPattern();
@@ -444,7 +522,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
/// from the given integral constant.
static TemplateDeductionResult DeduceNonTypeTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
+ NonTypeOrVarTemplateParmDecl NTTP, const llvm::APSInt &Value,
QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info,
bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
@@ -459,14 +537,14 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(
/// from the given null pointer template argument type.
static TemplateDeductionResult
DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP,
+ NonTypeOrVarTemplateParmDecl NTTP,
QualType NullPtrType, TemplateDeductionInfo &Info,
bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
Expr *Value = S.ImpCastExprToType(
new (S.Context) CXXNullPtrLiteralExpr(S.Context.NullPtrTy,
- NTTP->getLocation()),
+ NTTP.getLocation()),
NullPtrType,
NullPtrType->isMemberPointerType() ? CK_NullToMemberPointer
: CK_NullToPointer)
@@ -482,7 +560,7 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
/// \returns true if deduction succeeded, false otherwise.
static TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, Expr *Value,
+ NonTypeOrVarTemplateParmDecl NTTP, Expr *Value,
TemplateDeductionInfo &Info, bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
@@ -497,7 +575,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
/// \returns true if deduction succeeded, false otherwise.
static TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, ValueDecl *D,
+ NonTypeOrVarTemplateParmDecl NTTP, ValueDecl *D,
QualType T, TemplateDeductionInfo &Info,
bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
@@ -1930,14 +2008,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Determine the array bound is something we can deduce.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, DAP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, DAP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
// We can perform template argument deduction for the given non-type
// template parameter.
- assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ assert(NTTP.getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
if (const auto *CAA = dyn_cast<ConstantArrayType>(AA)) {
llvm::APSInt Size(CAA->getSize());
@@ -1994,10 +2072,10 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// deducing through the noexcept-specifier if it's part of the canonical
// type. libstdc++ relies on this.
Expr *NoexceptExpr = FPP->getNoexceptExpr();
- if (const NonTypeTemplateParmDecl *NTTP =
- NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
+ if (NonTypeOrVarTemplateParmDecl NTTP =
+ NoexceptExpr ? getDeducedNTTParameterFromExpr(Info, NoexceptExpr)
: nullptr) {
- assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ assert(NTTP.getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
llvm::APSInt Noexcept(1);
@@ -2191,8 +2269,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2217,8 +2295,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2246,8 +2324,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2271,8 +2349,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2348,8 +2426,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return TemplateDeductionResult::NonDeducedMismatch;
}
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, ParamExpr);
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, ParamExpr);
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2395,8 +2473,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the address space, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2420,8 +2498,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the address space, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2440,8 +2518,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (IP->isUnsigned() != IA->isUnsigned())
return TemplateDeductionResult::NonDeducedMismatch;
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, IP->getNumBitsExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, IP->getNumBitsExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2573,8 +2651,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
return TemplateDeductionResult::NonDeducedMismatch;
case TemplateArgument::Expression:
- if (const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, P.getAsExpr())) {
+ if (NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, P.getAsExpr())) {
switch (A.getKind()) {
case TemplateArgument::Expression: {
const Expr *E = A.getAsExpr();
@@ -2628,7 +2706,6 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
}
llvm_unreachable("Unknown template argument kind");
}
-
// Can't deduce anything, but that's okay.
return TemplateDeductionResult::Success;
case TemplateArgument::Pack:
@@ -4392,8 +4469,8 @@ static TemplateDeductionResult DeduceFromInitializerList(
// from the length of the initializer list.
if (auto *DependentArrTy = dyn_cast_or_null<DependentSizedArrayType>(ArrTy)) {
// Determine the array bound is something we can deduce.
- if (const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, DependentArrTy->getSizeExpr())) {
+ if (NonTypeOrVarTemplateParmDecl NTTP = getDeducedNTTParameterFromExpr(
+ Info, DependentArrTy->getSizeExpr())) {
// We can perform template argument deduction for the given non-type
// template parameter.
// C++ [temp.deduct.type]p13:
@@ -5098,7 +5175,7 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
AutoTypeLoc TypeLoc,
QualType Deduced) {
ConstraintSatisfaction Satisfaction;
- ConceptDecl *Concept = Type.getTypeConstraintConcept();
+ ConceptDecl *Concept = cast<ConceptDecl>(Type.getTypeConstraintConcept());
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
TypeLoc.getRAngleLoc());
TemplateArgs.addArgument(
@@ -6654,6 +6731,18 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
Used[NTTP->getIndex()] = true;
return true;
}
+
+ bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override {
+ if (ULE->isConceptReference() || ULE->isVarDeclReference()) {
+ if (auto *TTP = ULE->getTemplateTemplateDecl()) {
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
+ }
+ for (auto &TLoc : ULE->template_arguments())
+ DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc);
+ }
+ return true;
+ }
};
}
@@ -6675,17 +6764,28 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
- const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(E, Depth);
- if (!NTTP)
+ E = unwrapExpressionForDeduction(E);
+ if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E);
+ ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) {
+ if (const auto *TTP = ULE->getTemplateTemplateDecl())
+ Used[TTP->getIndex()] = true;
+ for (auto &TLoc : ULE->template_arguments())
+ MarkUsedTemplateParameters(Ctx, TLoc.getArgument(), OnlyDeduced, Depth,
+ Used);
return;
+ }
- if (NTTP->getDepth() == Depth)
- Used[NTTP->getIndex()] = true;
+ const NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(E, Depth);
+ if (!NTTP)
+ return;
+ if (NTTP.getDepth() == Depth)
+ Used[NTTP.getIndex()] = true;
// In C++17 mode, additional arguments may be deduced from the type of a
// non-type argument.
if (Ctx.getLangOpts().CPlusPlus17)
- MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used);
+ MarkUsedTemplateParameters(Ctx, NTTP.getType(), OnlyDeduced, Depth, Used);
}
/// Mark the template parameters that are used by the given
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index d84d0ca1..0d96d18 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1899,8 +1899,7 @@ namespace {
private:
ExprResult
- transformNonTypeTemplateParmRef(Decl *AssociatedDecl,
- const NonTypeTemplateParmDecl *parm,
+ transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
SourceLocation loc, TemplateArgument arg,
UnsignedOrNone PackIndex, bool Final);
};
@@ -2338,22 +2337,25 @@ TemplateInstantiator::TransformOpenACCRoutineDeclAttr(
}
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
- Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm,
- SourceLocation loc, TemplateArgument arg, UnsignedOrNone PackIndex,
- bool Final) {
+ Decl *AssociatedDecl, const NamedDecl *parm, SourceLocation loc,
+ TemplateArgument arg, UnsignedOrNone PackIndex, bool Final) {
ExprResult result;
// Determine the substituted parameter type. We can usually infer this from
// the template argument, but not always.
auto SubstParamType = [&] {
- QualType T;
- if (parm->isExpandedParameterPack())
- T = parm->getExpansionType(*SemaRef.ArgPackSubstIndex);
- else
- T = parm->getType();
- if (parm->isParameterPack() && isa<PackExpansionType>(T))
- T = cast<PackExpansionType>(T)->getPattern();
- return SemaRef.SubstType(T, TemplateArgs, loc, parm->getDeclName());
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(parm)) {
+ QualType T;
+ if (NTTP->isExpandedParameterPack())
+ T = NTTP->getExpansionType(*SemaRef.ArgPackSubstIndex);
+ else
+ T = NTTP->getType();
+ if (parm->isParameterPack() && isa<PackExpansionType>(T))
+ T = cast<PackExpansionType>(T)->getPattern();
+ return SemaRef.SubstType(T, TemplateArgs, loc, parm->getDeclName());
+ }
+ return SemaRef.SubstType(arg.getAsExpr()->getType(), TemplateArgs, loc,
+ parm->getDeclName());
};
bool refParam = false;
@@ -2408,7 +2410,9 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
Expr *resultExpr = result.get();
return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr,
- AssociatedDecl, parm->getIndex(), PackIndex, refParam, Final);
+ AssociatedDecl,
+ clang::getDepthAndIndex(const_cast<NamedDecl *>(parm)).second, PackIndex,
+ refParam, Final);
}
ExprResult
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 233bb65..87ec4f7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3784,14 +3784,14 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
- D->getPosition(), D->getIdentifier(), D->wasDeclaredWithTypename(),
- InstParams, ExpandedParams);
+ D->getPosition(), D->getIdentifier(), D->templateParameterKind(),
+ D->wasDeclaredWithTypename(), InstParams, ExpandedParams);
else
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->isParameterPack(), D->getIdentifier(),
- D->wasDeclaredWithTypename(), InstParams);
+ D->templateParameterKind(), D->wasDeclaredWithTypename(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index b0a673d..d2baa2e 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -310,6 +310,16 @@ class CollectUnexpandedParameterPacksVisitor
return DynamicRecursiveASTVisitor::TraverseLambdaCapture(Lambda, C, Init);
}
+ bool TraverseUnresolvedLookupExpr(UnresolvedLookupExpr *E) override {
+ if (E->getNumDecls() == 1) {
+ NamedDecl *ND = *E->decls_begin();
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND);
+ TTP && TTP->isParameterPack())
+ addUnexpanded(ND, E->getBeginLoc());
+ }
+ return DynamicRecursiveASTVisitor::TraverseUnresolvedLookupExpr(E);
+ }
+
#ifndef NDEBUG
bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) override {
ContainsIntermediatePacks = true;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 7dbd4bb..1289bed 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1306,12 +1306,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
? AutoTypeKeyword::DecltypeAuto
: AutoTypeKeyword::Auto;
- ConceptDecl *TypeConstraintConcept = nullptr;
+ TemplateDecl *TypeConstraintConcept = nullptr;
llvm::SmallVector<TemplateArgument, 8> TemplateArgs;
if (DS.isConstrainedAuto()) {
if (TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId()) {
TypeConstraintConcept =
- cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl());
+ cast<TemplateDecl>(TemplateId->Template.get().getAsTemplateDecl());
TemplateArgumentListInfo TemplateArgsInfo;
TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc);
TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc);
@@ -3090,15 +3090,13 @@ InventTemplateParameter(TypeProcessingState &state, QualType T,
if (!Invalid) {
UsingShadowDecl *USD =
TemplateId->Template.get().getAsUsingShadowDecl();
- auto *CD =
- cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl());
+ TemplateDecl *CD = TemplateId->Template.get().getAsTemplateDecl();
S.AttachTypeConstraint(
D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context),
DeclarationNameInfo(DeclarationName(TemplateId->Name),
TemplateId->TemplateNameLoc),
CD,
- /*FoundDecl=*/
- USD ? cast<NamedDecl>(USD) : CD,
+ /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD,
TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
InventedTemplateParam, D.getEllipsisLoc());
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c7428d1..f2e800a 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -610,6 +610,10 @@ public:
TemplateArgumentLoc &Output,
bool Uneval = false);
+ TemplateArgument
+ TransformNamedTemplateTemplateArgument(CXXScopeSpec &SS, TemplateName Name,
+ SourceLocation NameLoc);
+
/// Transform the given set of template arguments.
///
/// By default, this operation transforms all of the template arguments
@@ -4843,6 +4847,15 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
llvm_unreachable("overloaded function decl survived to here");
}
+template <typename Derived>
+TemplateArgument TreeTransform<Derived>::TransformNamedTemplateTemplateArgument(
+ CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc) {
+ TemplateName TN = getDerived().TransformTemplateName(SS, Name, NameLoc);
+ if (TN.isNull())
+ return TemplateArgument();
+ return TemplateArgument(TN);
+}
+
template<typename Derived>
void TreeTransform<Derived>::InventTemplateArgumentLoc(
const TemplateArgument &Arg,
@@ -4927,13 +4940,13 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- TemplateName Template = getDerived().TransformTemplateName(
+
+ TemplateArgument Out = getDerived().TransformNamedTemplateTemplateArgument(
SS, Arg.getAsTemplate(), Input.getTemplateNameLoc());
- if (Template.isNull())
+ if (Out.isNull())
return true;
-
- Output = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template),
- QualifierLoc, Input.getTemplateNameLoc());
+ Output = TemplateArgumentLoc(SemaRef.Context, Out, QualifierLoc,
+ Input.getTemplateNameLoc());
return false;
}
@@ -5029,10 +5042,8 @@ template<typename InputIterator>
bool TreeTransform<Derived>::TransformTemplateArguments(
InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs,
bool Uneval) {
- for (; First != Last; ++First) {
+ for (TemplateArgumentLoc In : llvm::make_range(First, Last)) {
TemplateArgumentLoc Out;
- TemplateArgumentLoc In = *First;
-
if (In.getArgument().getKind() == TemplateArgument::Pack) {
// Unpack argument packs, which we translate them into separate
// arguments.
@@ -5042,11 +5053,10 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
typedef TemplateArgumentLocInventIterator<Derived,
TemplateArgument::pack_iterator>
PackLocIterator;
- if (TransformTemplateArguments(PackLocIterator(*this,
- In.getArgument().pack_begin()),
- PackLocIterator(*this,
- In.getArgument().pack_end()),
- Outputs, Uneval))
+ if (TransformTemplateArguments(
+ PackLocIterator(*this, In.getArgument().pack_begin()),
+ PackLocIterator(*this, In.getArgument().pack_end()), Outputs,
+ Uneval))
return true;
continue;
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index cdaf38d..2c7beb4 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2742,6 +2742,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
VisitTemplateDecl(D);
+ D->ParameterKind = static_cast<TemplateNameKind>(Record.readInt());
D->setDeclaredWithTypename(Record.readBool());
// TemplateParmPosition.
D->setDepth(Record.readInt());
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 0166e49..3f37dfb 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2086,13 +2086,12 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
assert((E->hasTemplateKWAndArgsInfo() == HasTemplateKWAndArgsInfo) &&
"Wrong HasTemplateKWAndArgsInfo!");
+ unsigned NumTemplateArgs = 0;
if (HasTemplateKWAndArgsInfo) {
- unsigned NumTemplateArgs = Record.readInt();
+ NumTemplateArgs = Record.readInt();
ReadTemplateKWAndArgsInfo(*E->getTrailingASTTemplateKWAndArgsInfo(),
E->getTrailingTemplateArgumentLoc(),
NumTemplateArgs);
- assert((E->getNumTemplateArgs() == NumTemplateArgs) &&
- "Wrong NumTemplateArgs!");
}
UnresolvedSet<8> Decls;
@@ -2108,6 +2107,9 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
Results[I] = (Iter + I).getPair();
}
+ assert((E->getNumTemplateArgs() == NumTemplateArgs) &&
+ "Wrong NumTemplateArgs!");
+
E->NameInfo = Record.readDeclarationNameInfo();
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index e414910..6fd25b9 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -2149,6 +2149,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Record.push_back(D->getNumExpansionTemplateParameters());
VisitTemplateDecl(D);
+ Record.push_back(D->templateParameterKind());
Record.push_back(D->wasDeclaredWithTypename());
// TemplateParmPosition.
Record.push_back(D->getDepth());
diff --git a/clang/test/CodeGenCXX/mangle-concept.cpp b/clang/test/CodeGenCXX/mangle-concept.cpp
index aa0940c..63e819b 100644
--- a/clang/test/CodeGenCXX/mangle-concept.cpp
+++ b/clang/test/CodeGenCXX/mangle-concept.cpp
@@ -6,7 +6,8 @@
namespace test1 {
template <bool> struct S {};
template <typename> concept C = true;
-template <typename T = int> S<C<T>> f0() { return S<C<T>>{}; }
+template <typename T = int>
+S<C<T>> f0() { return S<C<T>>{}; }
template S<C<int>> f0<>();
// CHECK: @_ZN5test12f0IiEENS_1SIX1CIT_EEEEv(
// CLANG17: @_ZN5test12f0IiEENS_1SIL_ZNS_1CIT_EEEEEv(
diff --git a/clang/test/Frontend/dump-minimization-hints-cpp20-modules.cpp b/clang/test/Frontend/dump-minimization-hints-cpp20-modules.cpp
new file mode 100644
index 0000000..a28acba
--- /dev/null
+++ b/clang/test/Frontend/dump-minimization-hints-cpp20-modules.cpp
@@ -0,0 +1,117 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -std=c++20 %t/foo.cppm -emit-module-interface -o %t/foo.pcm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/use.cpp -dump-minimization-hints=%t/decls
+// RUN: cat %t/decls
+// RUN: cat %t/decls | FileCheck -check-prefix=RANGE %s
+// RANGE:{
+// RANGE-NEXT:"required_ranges": [
+// RANGE-NEXT: {
+// RANGE-NEXT: "file": "{{.+}}foo.cppm",
+// RANGE-NEXT: "range": [
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 3,
+// RANGE-NEXT: "column": 1
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 3,
+// RANGE-NEXT: "column": 22
+// RANGE-NEXT: }
+// RANGE-NEXT: },
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 4,
+// RANGE-NEXT: "column": 3
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 4,
+// RANGE-NEXT: "column": 9
+// RANGE-NEXT: }
+// RANGE-NEXT: },
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 4,
+// RANGE-NEXT: "column": 10
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 4,
+// RANGE-NEXT: "column": 43
+// RANGE-NEXT: }
+// RANGE-NEXT: },
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 6,
+// RANGE-NEXT: "column": 1
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 6,
+// RANGE-NEXT: "column": 2
+// RANGE-NEXT: }
+// RANGE-NEXT: },
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 8,
+// RANGE-NEXT: "column": 1
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 8,
+// RANGE-NEXT: "column": 7
+// RANGE-NEXT: }
+// RANGE-NEXT: },
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 8,
+// RANGE-NEXT: "column": 8
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 8,
+// RANGE-NEXT: "column": 25
+// RANGE-NEXT: }
+// RANGE-NEXT: },
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 9,
+// RANGE-NEXT: "column": 3
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 9,
+// RANGE-NEXT: "column": 36
+// RANGE-NEXT: }
+// RANGE-NEXT: },
+// RANGE-NEXT: {
+// RANGE-NEXT: "from": {
+// RANGE-NEXT: "line": 11,
+// RANGE-NEXT: "column": 1
+// RANGE-NEXT: },
+// RANGE-NEXT: "to": {
+// RANGE-NEXT: "line": 11,
+// RANGE-NEXT: "column": 2
+// RANGE-NEXT: }
+// RANGE-NEXT: }
+// RANGE-NEXT: ]
+// RANGE-NEXT: }
+// RANGE-NEXT:]
+// RANGE-NEXT:}
+
+//--- foo.cppm
+export module foo;
+
+namespace piecemeal { // line 3
+ export int used(int n) { return n + 1; }
+ export int unused(int n) { return n + 2; }
+}
+
+export namespace whole { // line 8
+ int used(int n) { return n + 1; }
+ int unused(int n) { return n + 3; }
+} // line 11
+
+//--- use.cpp
+import foo;
+
+int main() {
+ piecemeal::used(4); // only one of the functions used from each namespace.
+ whole::used(4);
+}
diff --git a/clang/test/Parser/cxx-template-template-recovery.cpp b/clang/test/Parser/cxx-template-template-recovery.cpp
index 5700b16..61ef82d 100644
--- a/clang/test/Parser/cxx-template-template-recovery.cpp
+++ b/clang/test/Parser/cxx-template-template-recovery.cpp
@@ -22,18 +22,18 @@ auto V3 = true; // #V3
template <template <typename T> typename C>
constexpr bool test = true;
-static_assert(test<a::C1>); // expected-error {{too few template arguments for concept 'C1'}} \
+static_assert(test<a::C1>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#C1 {{here}}
-static_assert(test<a::b::C2>); // expected-error {{too few template arguments for concept 'C2'}} \
+static_assert(test<a::b::C2>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#C2 {{here}}
-static_assert(test<C3>); // expected-error {{too few template arguments for concept 'C3'}} \
+static_assert(test<C3>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#C3 {{here}}
-static_assert(test<a::V1>); // expected-error {{use of variable template 'a::V1' requires template arguments}} \
+static_assert(test<a::V1>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#V1 {{here}}
-static_assert(test<a::b::V2>); // expected-error {{use of variable template 'a::b::V2' requires template arguments}} \
+static_assert(test<a::b::V2>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#V2 {{here}}
-static_assert(test<V3>); // expected-error {{use of variable template 'V3' requires template arguments}} \
+static_assert(test<V3>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#V3 {{here}}
diff --git a/clang/test/Parser/cxx2a-concept-declaration.cpp b/clang/test/Parser/cxx2a-concept-declaration.cpp
index 0a7af84..fea6084 100644
--- a/clang/test/Parser/cxx2a-concept-declaration.cpp
+++ b/clang/test/Parser/cxx2a-concept-declaration.cpp
@@ -9,11 +9,6 @@ template<concept T> concept D1 = true;
// expected-error@-1{{expected template parameter}}
// expected-error@-2{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}}
-template<template<typename> concept T> concept D2 = true;
-// expected-error@-1{{expected identifier}}
-// expected-error@-2{{template template parameter requires 'class' or 'typename' after the parameter list}}
-// expected-error@-3{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}}
-
struct S1 {
template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}}
};
diff --git a/clang/test/Parser/cxx2c-template-template-param.cpp b/clang/test/Parser/cxx2c-template-template-param.cpp
new file mode 100644
index 0000000..e8c7621
--- /dev/null
+++ b/clang/test/Parser/cxx2c-template-template-param.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -std=c++2c -verify %s
+
+template<template<typename> auto Var>
+struct A{};
+template<template<auto> auto Var>
+struct B{};
+template<template<typename> auto Var>
+struct C{};
+template<template<typename> concept C>
+struct D{};
+template<template<auto> concept C>
+struct E{};
+
+template<template<typename> auto Var>
+int V1;
+template<template<auto> auto Var>
+int V2;
+template<template<typename> auto Var>
+int V3;
+template<template<typename> concept C>
+int V4;
+template<template<auto> concept C>
+int V5;
+
+namespace packs {
+
+template<template<typename> auto... Var>
+struct A{};
+template<template<auto> auto... Var>
+struct B{};
+template<template<typename> auto... Var>
+struct C{};
+template<template<typename> concept... C>
+struct D{};
+template<template<auto> concept... C>
+struct E{};
+
+template<template<typename> auto... Var>
+int V1;
+template<template<auto> auto... Var>
+int V2;
+template<template<typename> auto... Var>
+int V3;
+template<template<typename> concept... C>
+int V4;
+template<template<auto> concept... C>
+int V5;
+
+}
+
+namespace concepts {
+template<template<auto> concept...>
+struct A{};
+template<template<auto> concept... C>
+struct B{};
+template<template<auto> concept& C> // expected-error{{expected identifier}} \
+ // expected-error {{in declaration of struct 'C'}}
+struct C{};
+}
+
+namespace vars {
+template<template<auto> auto...>
+struct A{};
+template<template<auto> auto & C> // expected-error {{expected identifier}} \
+ // expected-error {{extraneous 'template<>'}}
+struct B{};
+template<template<auto> const auto> // expected-error {{expected identifier}} \
+ // expected-error {{extraneous 'template<>'}}
+struct C{};
+}
+
+namespace errors {
+template<concept> // expected-error {{expected template parameter}} \
+ // expected-error {{extraneous 'template<>' in declaration of struct 'A'}}
+struct A{};
+template<template<concept> auto> // expected-error {{expected template parameter}} \
+ // expected-error {{template template parameter must have its own template parameters}}
+struct B{};
+}
diff --git a/clang/test/SemaCXX/cxx2c-template-template-param.cpp b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
new file mode 100644
index 0000000..ed55a059
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
@@ -0,0 +1,352 @@
+// RUN: %clang_cc1 -std=c++2c -verify %s
+
+namespace Errors {
+
+template <template<typename T> auto>
+struct S1;
+template <template<auto T> auto>
+struct S2;
+template <template<typename T> concept>
+struct S3;
+template <template<auto T> concept>
+struct S4;
+int a;
+
+template <typename T>
+concept C = true; // expected-note 2{{template argument refers to a concept 'C', here}}
+template <typename T>
+auto Var = 0; // expected-note 2{{template argument refers to a variable template 'Var', here}}
+
+S1<1> t1; // expected-error {{template argument for template template parameter must be a variable template}}
+S1<a> t2; // expected-error {{template argument for template template parameter must be a variable template}}
+S1<int> t3; // expected-error {{template argument for template template parameter must be a variable template}}
+S1<C> t4; // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+S2<1> t5; // expected-error {{template argument for template template parameter must be a variable template}}
+S2<a> t6; // expected-error {{template argument for template template parameter must be a variable template}}
+S2<int> t7; // expected-error {{template argument for template template parameter must be a variable template}}
+S2<C> t8; // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+S3<1> t9; // expected-error {{template argument for template template parameter must be a concept}}
+S3<a> t10; // expected-error {{template argument for template template parameter must be a concept}}
+S3<int> t11; // expected-error {{template argument for template template parameter must be a concept}}
+S3<Var> t12; // expected-error {{template argument does not refer to a concept, or template template parameter}}
+S4<1> t13; // expected-error {{template argument for template template parameter must be a concept}}
+S4<a> t14; // expected-error {{template argument for template template parameter must be a concept}}
+S4<int> t15; // expected-error {{template argument for template template parameter must be a concept}}
+S4<Var> t16; // expected-error {{template argument does not refer to a concept, or template template parameter}}
+
+}
+
+template <template<typename T> auto V> // expected-note {{previous template template parameter is here}} \
+ // expected-error{{template argument for non-type template parameter must be an expression}}
+struct S1 {
+ static_assert(V<int> == 42);
+ static_assert(V<const int> == 84);
+ static_assert(V<double> == 0);
+};
+template <template<auto T> auto V> // expected-error {{template argument for template type parameter must be a type}} \
+ // expected-note {{previous template template parameter is here}}
+struct S2 {
+ static_assert(V<0> == 1);
+ static_assert(V<1> == 0);
+};
+template <template<typename T> concept C > // expected-error {{template argument for non-type template parameter must be an expression}} \
+ // expected-note {{previous template template parameter is here}}
+struct S3 {
+ static_assert(C<int>);
+};
+template <template<auto> concept C> // expected-error {{template argument for template type parameter must be a type}} \
+ // expected-note {{previous template template parameter is here}}
+struct S4 {
+ static_assert(C<0>);
+};
+
+template <typename T> // expected-note {{template parameter is declared here}}
+concept C = true;
+
+template <auto I> // expected-note {{template parameter is declared here}}
+concept CI = true;
+
+template <typename T> // expected-note {{template parameter is declared here}}
+constexpr auto Var = 42;
+template <typename T>
+constexpr auto Var<const T> = 84;
+template <>
+constexpr auto Var<double> = 0;
+
+template <auto N> // expected-note {{template parameter is declared here}}
+constexpr auto Var2 = 0;
+template <auto N>
+requires (N%2 == 0)
+constexpr auto Var2<N> = 1;
+
+void test () {
+ S1<Var2> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
+ S2<Var> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
+ S1<Var> s1;
+ S2<Var2> s2;
+ S3<C> s3;
+ S4<C> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
+ S4<CI> s4;
+ S3<CI> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
+}
+
+
+namespace template_type_constraints {
+
+
+template <typename T>
+concept Unary = true;
+template <typename T, typename = int>
+concept BinaryDefaulted = true;
+
+template <typename T>
+concept UnaryFalse = false; // expected-note 3{{because 'false' evaluated to false}}
+template <typename T, typename = int>
+concept BinaryDefaultedFalse = false;
+
+template <template <typename...> concept C, typename T>
+struct S {
+ template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+ void f(TT); // expected-note {{ignored}}
+ void g(C auto); // expected-note {{ignored}} \
+ // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+
+ auto h() -> C auto { // expected-error {{deduced type 'int' does not satisfy 'UnaryFalse'}}
+ return 0;
+ };
+
+ void test() {
+ C auto a = 0;
+ }
+};
+
+template <template <typename...> concept C, typename T>
+struct SArg {
+ template <C<int> TT>
+ void f(TT);
+ void g(C<int> auto);
+
+ auto h() -> C<int> auto {
+ return 0;
+ };
+ void test() {
+ C<int> auto a = 0;
+ }
+};
+
+void test() {
+ S<Unary, int> s;
+ s.f(0);
+ s.g(0);
+ s.h();
+ S<BinaryDefaulted, int> s2;
+ s2.f(0);
+ s2.g(0);
+ s2.h();
+
+ SArg<BinaryDefaulted, int> s3;
+ s3.f(0);
+ s3.g(0);
+ s3.h();
+}
+
+void test_errors() {
+ S<UnaryFalse, int> s;
+ s.f(0); // expected-error {{no matching member function for call to 'f'}}
+ s.g(0); // expected-error {{no matching member function for call to 'g'}}
+ s.h(); // expected-note {{in instantiation of member function 'template_type_constraints::S<template_type_constraints::UnaryFalse, int>::h'}}
+}
+
+}
+
+template <typename T>
+concept Unary = true;
+template <typename T, typename = int>
+concept BinaryDefaulted = true;
+
+template <typename T>
+concept UnaryFalse = false; // expected-note 3{{because 'false' evaluated to false}}
+template <typename T, typename = int>
+concept BinaryDefaultedFalse = false;
+
+template <template <typename...> concept C, typename T>
+struct S {
+ template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+ void f(TT); // expected-note {{ignored}}
+ void g(C auto); // expected-note {{ignored}} \
+ // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+
+ auto h() -> C auto { // expected-error {{deduced type 'int' does not satisfy 'UnaryFalse'}}
+ return 0;
+ };
+
+ void test() {
+ C auto a = 0;
+ }
+};
+
+template <template <typename...> concept C, typename T>
+struct SArg {
+ template <C<int> TT>
+ void f(TT);
+ void g(C<int> auto);
+
+ auto h() -> C<int> auto {
+ return 0;
+ };
+ void test() {
+ C<int> auto a = 0;
+ }
+};
+
+void test_args() {
+ S<Unary, int> s;
+ s.f(0);
+ s.g(0);
+ s.h();
+ S<BinaryDefaulted, int> s2;
+ s2.f(0);
+ s2.g(0);
+ s2.h();
+
+ SArg<BinaryDefaulted, int> s3;
+ s3.f(0);
+ s3.g(0);
+ s3.h();
+}
+
+void test_errors() {
+ S<UnaryFalse, int> s;
+ s.f(0); // expected-error {{no matching member function for call to 'f'}}
+ s.g(0); // expected-error {{no matching member function for call to 'g'}}
+ s.h(); // expected-note {{in instantiation of member function 'S<UnaryFalse, int>::h'}}
+}
+
+namespace non_type {
+
+template <auto>
+concept Unary = true;
+
+template <template <auto> concept C>
+struct S {
+ template <C Foo> // expected-error {{concept named in type constraint is not a type concept}}
+ void f();
+ // FIXME, bad diagnostic
+ void g(C auto); // expected-error{{concept named in type constraint is not a type concept}}
+ auto h() -> C auto { // expected-error{{concept named in type constraint is not a type concept}}
+ }
+ void i() {
+ C auto a = 0; // expected-error{{concept named in type constraint is not a type concept}}
+ }
+};
+
+}
+
+namespace default_args {
+
+template <typename T>
+concept Concept = false; // expected-note 2{{template argument refers to a concept 'Concept', here}} \
+ // expected-note 2{{because 'false' evaluated to false}}
+
+template <typename T>
+constexpr auto Var = false; // expected-note 2{{template argument refers to a variable template 'Var', here}}
+
+template <typename T>
+struct Type; // expected-note 2{{template argument refers to a class template 'Type', here}}
+
+
+template <template <typename> auto = Concept> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+struct E1;
+
+template <template <typename> auto = Type> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+struct E2;
+
+template <template <typename> typename = Concept> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+struct E3;
+
+template <template <typename> typename = Var> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+struct E4;
+
+template <template <typename> concept = Var> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+struct E4;
+
+template <template <typename> concept = Type> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+struct E4;
+
+template <
+ template <typename> concept TConcept, // expected-note 2{{template argument refers to a concept 'TConcept', here}}
+ template <typename> auto TVar, // expected-note 2{{template argument refers to a variable template 'TVar', here}}
+ template <typename> typename TType // expected-note 2{{template argument refers to a class template 'TType', here}}
+>
+struct Nested {
+ template <template <typename> auto = TConcept> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+ struct E1;
+
+ template <template <typename> auto = TType> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+ struct E2;
+
+ template <template <typename> typename = TConcept> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+ struct E3;
+
+ template <template <typename> typename = TVar> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+ struct E4;
+
+ template <template <typename> concept = TVar> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+ struct E4;
+
+ template <template <typename> concept = TType> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+ struct E4;
+};
+
+
+template <template <typename> concept C = Concept>
+struct TestDefaultConcept {
+ template <template <typename> concept CC = C>
+ void f() {
+ static_assert(C<int>); // expected-error {{static assertion failed}} \
+ // expected-note {{because 'int' does not satisfy 'Concept'}}
+ static_assert(CC<int>); // expected-error {{static assertion failed}} \
+ // expected-note {{because 'int' does not satisfy 'Concept'}}
+ }
+};
+void do_test_concept() {
+ TestDefaultConcept<>{}.f(); // expected-note {{in instantiation}}
+}
+
+template <template <typename> auto V = Var>
+struct TestDefaultVar {
+ template <template <typename> auto VV = V>
+ void f() {
+ static_assert(V<int>); // expected-error {{static assertion failed}}
+ static_assert(VV<int>); // expected-error {{static assertion failed}}
+ }
+};
+void do_test_var() {
+ TestDefaultVar<>{}.f(); // expected-note {{in instantiation}}
+}
+
+}
+
+namespace TTPDependence {
+template <template <typename... > concept C>
+concept A = C<>;
+template <template <typename... > concept C>
+concept B = C<int>;
+
+template <template <typename... > auto Var>
+concept C = Var<>;
+template <template <typename... > auto Var>
+concept D = Var<int>;
+
+}
+
+namespace InvalidName {
+template <typename T, template <typename> concept C>
+concept A = C<T>; // expected-note {{here}}
+
+template <A<concept missing<int>> T> // expected-error {{expected expression}} \
+ // expected-error {{too few template arguments for concept 'A'}} \
+ // expected-error {{unknown type name 'T'}} \
+ // expected-error {{expected unqualified-id}}
+auto f();
+}
diff --git a/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp b/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp
index 310ae89..7c0cda0 100644
--- a/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp
@@ -52,7 +52,8 @@ ParseTemplateParameterList(ParserState &PS,
Code << TemplateCode << " auto *" << ParmName
<< " = TemplateTemplateParmDecl::Create(C, DC, SourceLocation(), "
<< PS.CurrentDepth << ", " << Position++
- << ", /*ParameterPack=*/false, /*Id=*/nullptr, /*Typename=*/false, "
+ << ", /*ParameterPack=*/false, /*Id=*/nullptr, "
+ "/*Kind=*/TNK_Type_template, /*Typename=*/false, "
<< TPLName << ");\n";
} else if (Arg->isSubClassOf("Class")) {
Code << " auto *" << ParmName
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
index 98b965c..36e075b 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -72,6 +72,16 @@ struct CVTagRecord {
return cvunion.Name;
}
+ CompilerContextKind contextKind() const {
+ if (m_kind == Struct || m_kind == Class)
+ return CompilerContextKind::ClassOrStruct;
+ if (m_kind == Enum)
+ return CompilerContextKind::Enum;
+
+ assert(m_kind == Union);
+ return CompilerContextKind::Union;
+ }
+
private:
CVTagRecord(llvm::codeview::ClassRecord &&c);
CVTagRecord(llvm::codeview::UnionRecord &&u);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 20d8c1a..7af53e1 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1720,18 +1720,22 @@ void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- std::vector<TypeIndex> matches =
- m_index->tpi().findRecordsByName(query.GetTypeBasename().GetStringRef());
-
- for (TypeIndex type_idx : matches) {
- TypeSP type_sp = GetOrCreateType(type_idx);
- if (!type_sp)
+ // We can't query for the full name because the type might reside
+ // in an anonymous namespace. Search for the basename in our map and check the
+ // matching types afterwards.
+ std::vector<uint32_t> matches;
+ m_type_base_names.GetValues(query.GetTypeBasename(), matches);
+
+ for (uint32_t match_idx : matches) {
+ std::vector context = GetContextForType(TypeIndex(match_idx));
+ if (context.empty())
continue;
- // We resolved a type. Get the fully qualified name to ensure it matches.
- ConstString name = type_sp->GetQualifiedName();
- TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);
- if (query.ContextMatches(type_match.GetContextRef())) {
+ if (query.ContextMatches(context)) {
+ TypeSP type_sp = GetOrCreateType(TypeIndex(match_idx));
+ if (!type_sp)
+ continue;
+
results.InsertUnique(type_sp);
if (results.Done(query))
return;
@@ -2201,11 +2205,15 @@ void SymbolFileNativePDB::BuildParentMap() {
CVTagRecord tag = CVTagRecord::create(type);
RecordIndices &indices = record_indices[tag.asTag().getUniqueName()];
- if (tag.asTag().isForwardRef())
+ if (tag.asTag().isForwardRef()) {
indices.forward = *ti;
- else
+ } else {
indices.full = *ti;
+ auto base_name = MSVCUndecoratedNameParser::DropScope(tag.name());
+ m_type_base_names.Append(ConstString(base_name), ti->getIndex());
+ }
+
if (indices.full != TypeIndex::None() &&
indices.forward != TypeIndex::None()) {
forward_to_full[indices.forward] = indices.full;
@@ -2261,6 +2269,10 @@ void SymbolFileNativePDB::BuildParentMap() {
llvm::consumeError(std::move(error));
}
+ // After calling Append(), the type-name map needs to be sorted again to be
+ // able to look up a type by its name.
+ m_type_base_names.Sort();
+
// Now that we know the forward -> full mapping of all type indices, we can
// re-write all the indices. At the end of this process, we want a mapping
// consisting of fwd -> full and full -> full for all child -> parent indices.
@@ -2353,3 +2365,52 @@ SymbolFileNativePDB::GetParentType(llvm::codeview::TypeIndex ti) {
return std::nullopt;
return parent_iter->second;
}
+
+std::vector<CompilerContext>
+SymbolFileNativePDB::GetContextForType(TypeIndex ti) {
+ CVType type = m_index->tpi().getType(ti);
+ if (!IsTagRecord(type))
+ return {};
+
+ CVTagRecord tag = CVTagRecord::create(type);
+
+ std::optional<Type::ParsedName> parsed_name =
+ Type::GetTypeScopeAndBasename(tag.name());
+ if (!parsed_name)
+ return {{tag.contextKind(), ConstString(tag.name())}};
+
+ std::vector<CompilerContext> ctx;
+ // assume everything is a namespace at first
+ for (llvm::StringRef scope : parsed_name->scope) {
+ ctx.emplace_back(CompilerContextKind::Namespace, ConstString(scope));
+ }
+ // we know the kind of our own type
+ ctx.emplace_back(tag.contextKind(), ConstString(parsed_name->basename));
+
+ // try to find the kind of parents
+ for (auto &el : llvm::reverse(llvm::drop_end(ctx))) {
+ std::optional<TypeIndex> parent = GetParentType(ti);
+ if (!parent)
+ break;
+
+ ti = *parent;
+ type = m_index->tpi().getType(ti);
+ switch (type.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ el.kind = CompilerContextKind::ClassOrStruct;
+ continue;
+ case LF_UNION:
+ el.kind = CompilerContextKind::Union;
+ continue;
+ case LF_ENUM:
+ el.kind = CompilerContextKind::Enum;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ return ctx;
+}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 9891313..eda375d 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -258,6 +258,8 @@ private:
void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
+ std::vector<CompilerContext> GetContextForType(llvm::codeview::TypeIndex ti);
+
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;
@@ -278,6 +280,8 @@ private:
llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
m_parent_types;
+
+ lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;
};
} // namespace npdb
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 8dd6aa0..fedc500a 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1642,11 +1642,12 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
// type that includes a template template argument. Only the name matters for
// this purpose, so we use dummy values for the other characteristics of the
// type.
- return TemplateTemplateParmDecl::Create(ast, decl_ctx, SourceLocation(),
- /*Depth=*/0, /*Position=*/0,
- /*IsParameterPack=*/false,
- &identifier_info, /*Typename=*/false,
- template_param_list);
+ return TemplateTemplateParmDecl::Create(
+ ast, decl_ctx, SourceLocation(),
+ /*Depth*/ 0, /*Position*/ 0,
+ /*IsParameterPack=*/false, &identifier_info,
+ TemplateNameKind::TNK_Type_template, /*DeclaredWithTypename=*/true,
+ template_param_list);
}
ClassTemplateSpecializationDecl *
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
index b7adae4..952b2bd 100644
--- a/lldb/source/Symbol/Type.cpp
+++ b/lldb/source/Symbol/Type.cpp
@@ -817,10 +817,12 @@ Type::GetTypeScopeAndBasename(llvm::StringRef name) {
case ':':
if (prev_is_colon && template_depth == 0) {
llvm::StringRef scope_name = name.slice(name_begin, pos.index() - 1);
- // The itanium demangler uses this string to represent anonymous
+ // The demanglers use these strings to represent anonymous
// namespaces. Convert it to a more language-agnostic form (which is
// also used in DWARF).
- if (scope_name == "(anonymous namespace)")
+ if (scope_name == "(anonymous namespace)" ||
+ scope_name == "`anonymous namespace'" ||
+ scope_name == "`anonymous-namespace'")
scope_name = "";
result.scope.push_back(scope_name);
name_begin = pos.index() + 1;
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
new file mode 100644
index 0000000..f6c1ccf
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
@@ -0,0 +1,135 @@
+# REQUIRES: target-windows
+
+# Test namespace lookup.
+# RUN: split-file %s %t
+# RUN: %build --nodefaultlib -o %t.exe -- %t/main.cpp
+# RUN: %lldb -f %t.exe -s \
+# RUN: %t/commands.input 2>&1 | FileCheck %s
+
+#--- main.cpp
+
+struct S {
+ char a[1];
+};
+
+namespace Outer {
+
+ struct S {
+ char a[2];
+ };
+
+ namespace Inner1 {
+ struct S {
+ char a[3];
+ };
+
+ namespace Inner2 {
+ struct S {
+ char a[4];
+ };
+ } // namespace Inner2
+ } // namespace Inner1
+
+ namespace Inner2 {
+ struct S {
+ char a[5];
+ };
+ } // namespace Inner2
+
+ namespace {
+ struct A {
+ char a[6];
+ };
+ } // namespace
+
+} // namespace Outer
+
+namespace {
+ struct A {
+ char a[7];
+ };
+} // namespace
+
+int main(int argc, char **argv) {
+ S s;
+ Outer::S os;
+ Outer::Inner1::S oi1s;
+ Outer::Inner1::Inner2::S oi1i2s;
+ Outer::Inner2::S oi2s;
+ A a1;
+ Outer::A a2;
+ return sizeof(s) + sizeof(os) + sizeof(oi1s) + sizeof(oi1i2s) + sizeof(oi2s) + sizeof(a1) + sizeof(a2);
+}
+
+#--- commands.input
+
+b main
+r
+
+type lookup S
+type lookup ::S
+type lookup Outer::S
+type lookup Outer::Inner1::S
+type lookup Inner1::S
+type lookup Outer::Inner1::Inner2::S
+type lookup Inner2::S
+type lookup Outer::Inner2::S
+type lookup Outer::A
+type lookup A
+type lookup ::A
+expr sizeof(S)
+expr sizeof(A)
+
+quit
+
+# CHECK: (lldb) type lookup S
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: }
+# CHECK-NEXT: (lldb) type lookup ::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[1];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[2];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::Inner1::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[3];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Inner1::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[3];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::Inner1::Inner2::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[4];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Inner2::S
+# CHECK-NEXT: struct S {
+# CHECK: struct S {
+# CHECK: }
+# CHECK-NEXT: (lldb) type lookup Outer::Inner2::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[5];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::A
+# CHECK-NEXT: struct A {
+# CHECK-NEXT: char a[6];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup A
+# CHECK-NEXT: struct A {
+# CHECK: struct A {
+# CHECK: }
+# CHECK-NEXT: (lldb) type lookup ::A
+# CHECK-NEXT: struct A {
+# CHECK-NEXT: char a[7];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) expr sizeof(S)
+# CHECK-NEXT: (__size_t) $0 = 1
+# CHECK-NEXT: (lldb) expr sizeof(A)
+# CHECK-NEXT: (__size_t) $1 = 7
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 2a8f0af..d8cd3b8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -26658,14 +26658,17 @@ Arguments:
The first argument is a constant integer, which is ignored and will be removed
in the future.
-The second argument is a pointer to an ``alloca`` instruction.
+The second argument is either a pointer to an ``alloca`` instruction or
+a ``poison`` value.
Semantics:
""""""""""
-The stack-allocated object that ``ptr`` points to is initially marked as dead.
-After '``llvm.lifetime.start``', the stack object is marked as alive and has an
-uninitialized value.
+If ``ptr`` is a ``poison`` value, the intrinsic has no effect.
+
+Otherwise, the stack-allocated object that ``ptr`` points to is initially
+marked as dead. After '``llvm.lifetime.start``', the stack object is marked as
+alive and has an uninitialized value.
The stack object is marked as dead when either
:ref:`llvm.lifetime.end <int_lifeend>` to the alloca is executed or the
function returns.
@@ -26699,13 +26702,16 @@ Arguments:
The first argument is a constant integer, which is ignored and will be removed
in the future.
-The second argument is a pointer to an ``alloca`` instruction.
+The second argument is either a pointer to an ``alloca`` instruction or
+a ``poison`` value.
Semantics:
""""""""""
-The stack-allocated object that ``ptr`` points to becomes dead after the call
-to this intrinsic.
+If ``ptr`` is a ``poison`` value, the intrinsic has no effect.
+
+Otherwise, the stack-allocated object that ``ptr`` points to becomes dead after
+the call to this intrinsic.
Calling ``llvm.lifetime.end`` on an already dead alloca is no-op.
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index e31573b..384b7f2 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -1151,6 +1151,10 @@ defvar LibmHasFrexpF128 = LibcallImpls<(add frexp_f128), isNotOSWindowsOrIsCygwi
defvar LibmHasLdexpF128 = LibcallImpls<(add ldexp_f128), isNotOSWindowsOrIsCygwinMinGW>;
defvar has__stack_chk_fail = LibcallImpls<(add __stack_chk_fail), isNotOSOpenBSD>;
+defvar has__stack_smash_handler = LibcallImpls<(add __stack_smash_handler), isOSOpenBSD>;
+
+defvar DefaultStackProtector = (add has__stack_chk_fail,
+ has__stack_smash_handler);
//===----------------------------------------------------------------------===//
// Objective-C Runtime Libcalls
@@ -1229,7 +1233,7 @@ def AArch64SystemLibrary : SystemRuntimeLibrary<
DarwinExp10, DarwinSinCosStret,
LibmHasSinCosF32, LibmHasSinCosF64, LibmHasSinCosF128,
DefaultLibmExp10,
- has__stack_chk_fail)
+ DefaultStackProtector)
>;
// Prepend a # to every name
@@ -1506,7 +1510,7 @@ def ARMSystemLibrary
LibcallImpls<(add __divmodsi4, __udivmodsi4),
RuntimeLibcallPredicate<[{TT.isOSBinFormatMachO() &&
(!TT.isiOS() || !TT.isOSVersionLT(5, 0))}]>>,
- has__stack_chk_fail)> {
+ DefaultStackProtector)> {
let DefaultLibcallCallingConv = LibcallCallingConv<[{
(!TT.isOSDarwin() && !TT.isiOS() && !TT.isWatchOS() && !TT.isDriverKit()) ?
(FloatABI == FloatABI::Hard ? CallingConv::ARM_AAPCS_VFP
@@ -2015,7 +2019,7 @@ def PPCSystemLibrary
LibmHasSinCosPPCF128,
AvailableIf<memcpy, isNotAIX>,
LibcallImpls<(add Int128RTLibcalls), isPPC64>,
- has__stack_chk_fail)>;
+ DefaultStackProtector)>;
//===----------------------------------------------------------------------===//
// RISCV Runtime Libcalls
@@ -2030,7 +2034,7 @@ def RISCVSystemLibrary
exp10f, exp10, exp10l_f128,
__riscv_flush_icache,
LibcallImpls<(add Int128RTLibcalls), isRISCV64>,
- has__stack_chk_fail)>;
+ DefaultStackProtector)>;
//===----------------------------------------------------------------------===//
// SPARC Runtime Libcalls
@@ -2098,7 +2102,7 @@ def SPARCSystemLibrary
LibcallImpls<(add _Q_qtoll, _Q_qtoull, _Q_lltoq, _Q_ulltoq), isSPARC32>,
LibcallImpls<(add SPARC64_MulDivCalls, Int128RTLibcalls), isSPARC64>,
LibmHasSinCosF32, LibmHasSinCosF64, LibmHasSinCosF128,
- has__stack_chk_fail)
+ DefaultStackProtector)
>;
//===----------------------------------------------------------------------===//
@@ -2159,7 +2163,7 @@ defvar X86CommonLibcalls =
// FIXME: MSVCRT doesn't have powi. The f128 case is added as a
// hack for one test relying on it.
__powitf2_f128,
- has__stack_chk_fail
+ DefaultStackProtector
);
defvar Windows32DivRemMulCalls =
@@ -2328,5 +2332,5 @@ def LegacyDefaultSystemLibrary
exp10f, exp10, exp10l_f128,
__powisf2, __powidf2, __powitf2_f128,
LibcallImpls<(add Int128RTLibcalls), isArch64Bit>,
- has__stack_chk_fail
+ DefaultStackProtector
)>;
diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h
index ffde5ca2..afd38d2 100644
--- a/llvm/include/llvm/MC/MCAssembler.h
+++ b/llvm/include/llvm/MC/MCAssembler.h
@@ -120,6 +120,7 @@ private:
bool relaxCVInlineLineTable(MCCVInlineLineTableFragment &DF);
bool relaxCVDefRange(MCCVDefRangeFragment &DF);
bool relaxFill(MCFillFragment &F);
+ bool relaxOrg(MCOrgFragment &F);
public:
/// Construct a new assembler instance.
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index b9e813b..23d422e 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -52,9 +52,6 @@ class MCObjectStreamer : public MCStreamer {
DenseMap<const MCSymbol *, SmallVector<PendingAssignment, 1>>
pendingAssignments;
- SmallVector<std::unique_ptr<uint8_t[]>, 0> FragStorage;
- // Available bytes in the current block for trailing data or new fragments.
- size_t FragSpace = 0;
// Used to allocate special fragments that do not use MCFragment's fixed-size
// part.
BumpPtrAllocator SpecialFragAllocator;
@@ -89,28 +86,25 @@ public:
/// \name MCStreamer Interface
/// @{
- uint8_t *getCurFragEnd() const {
- return reinterpret_cast<uint8_t *>(CurFrag + 1) + CurFrag->getFixedSize();
- }
- MCFragment *allocFragSpace(size_t Headroom);
// Add a new fragment to the current section without a variable-size tail.
void newFragment();
+ template <typename FT, typename... Args> FT *allocFragment(Args &&...args) {
+ auto *F = new (SpecialFragAllocator.Allocate(sizeof(FT), alignof(FT)))
+ FT(std::forward<Args>(args)...);
+ return F;
+ }
// Add a new special fragment to the current section and start a new empty
// fragment.
template <typename FT, typename... Args>
FT *newSpecialFragment(Args &&...args) {
- auto *F = new (SpecialFragAllocator.Allocate(sizeof(FT), alignof(FT)))
- FT(std::forward<Args>(args)...);
+ auto *F = allocFragment<FT, Args...>(std::forward<Args>(args)...);
addSpecialFragment(F);
return F;
}
- void ensureHeadroom(size_t Headroom);
void appendContents(ArrayRef<char> Contents);
- void appendContents(size_t Num, uint8_t Elt);
- // Add a fixup to the current fragment. Call ensureHeadroom beforehand to
- // ensure the fixup and appended content apply to the same fragment.
+ void appendContents(size_t Num, char Elt);
void addFixup(const MCExpr *Value, MCFixupKind Kind);
void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h
index 4022ea7..cc191ae 100644
--- a/llvm/include/llvm/MC/MCSection.h
+++ b/llvm/include/llvm/MC/MCSection.h
@@ -93,10 +93,10 @@ private:
bool AllowAutoPadding : 1;
// Track content and fixups for the fixed-size part as fragments are
- // appended to the section. The content is stored as trailing data of the
- // MCFragment. The content remains immutable, except when modified by
- // applyFixup.
- uint32_t FixedSize = 0;
+ // appended to the section. The content remains immutable, except when
+ // modified by applyFixup.
+ uint32_t ContentStart = 0;
+ uint32_t ContentEnd = 0;
uint32_t FixupStart = 0;
uint32_t FixupEnd = 0;
@@ -189,6 +189,18 @@ public:
//== Content-related functions manage parent's storage using ContentStart and
// ContentSize.
+ // Get a SmallVector reference. The caller should call doneAppending to update
+ // `ContentEnd`.
+ SmallVectorImpl<char> &getContentsForAppending();
+ void doneAppending();
+ void appendContents(ArrayRef<char> Contents) {
+ getContentsForAppending().append(Contents.begin(), Contents.end());
+ doneAppending();
+ }
+ void appendContents(size_t Num, char Elt) {
+ getContentsForAppending().append(Num, Elt);
+ doneAppending();
+ }
MutableArrayRef<char> getContents();
ArrayRef<char> getContents() const;
@@ -197,10 +209,10 @@ public:
MutableArrayRef<char> getVarContents();
ArrayRef<char> getVarContents() const;
- size_t getFixedSize() const { return FixedSize; }
+ size_t getFixedSize() const { return ContentEnd - ContentStart; }
size_t getVarSize() const { return VarContentEnd - VarContentStart; }
size_t getSize() const {
- return FixedSize + (VarContentEnd - VarContentStart);
+ return ContentEnd - ContentStart + (VarContentEnd - VarContentStart);
}
//== Fixup-related functions manage parent's storage using FixupStart and
@@ -371,13 +383,16 @@ class MCOrgFragment : public MCFragment {
/// Source location of the directive that this fragment was created for.
SMLoc Loc;
+ uint64_t Size = 0;
+
public:
MCOrgFragment(const MCExpr &Offset, int8_t Value, SMLoc Loc)
: MCFragment(FT_Org), Value(Value), Offset(&Offset), Loc(Loc) {}
const MCExpr &getOffset() const { return *Offset; }
-
uint8_t getValue() const { return Value; }
+ uint64_t getSize() const { return Size; }
+ void setSize(uint64_t Value) { Size = Value; }
SMLoc getLoc() const { return Loc; }
@@ -615,11 +630,28 @@ public:
bool isBssSection() const { return IsBss; }
};
+inline SmallVectorImpl<char> &MCFragment::getContentsForAppending() {
+ SmallVectorImpl<char> &S = getParent()->ContentStorage;
+ if (LLVM_UNLIKELY(ContentEnd != S.size())) {
+ // Move the elements to the end. Reserve space to avoid invalidating
+ // S.begin()+I for `append`.
+ auto Size = ContentEnd - ContentStart;
+ auto I = std::exchange(ContentStart, S.size());
+ S.reserve(S.size() + Size);
+ S.append(S.begin() + I, S.begin() + I + Size);
+ }
+ return S;
+}
+inline void MCFragment::doneAppending() {
+ ContentEnd = getParent()->ContentStorage.size();
+}
inline MutableArrayRef<char> MCFragment::getContents() {
- return {reinterpret_cast<char *>(this + 1), FixedSize};
+ return MutableArrayRef(getParent()->ContentStorage)
+ .slice(ContentStart, ContentEnd - ContentStart);
}
inline ArrayRef<char> MCFragment::getContents() const {
- return {reinterpret_cast<const char *>(this + 1), FixedSize};
+ return ArrayRef(getParent()->ContentStorage)
+ .slice(ContentStart, ContentEnd - ContentStart);
}
inline MutableArrayRef<char> MCFragment::getVarContents() {
diff --git a/llvm/include/llvm/MC/MCSymbol.h b/llvm/include/llvm/MC/MCSymbol.h
index 123e96e..ddc560e 100644
--- a/llvm/include/llvm/MC/MCSymbol.h
+++ b/llvm/include/llvm/MC/MCSymbol.h
@@ -41,11 +41,9 @@ class raw_ostream;
/// it is a reference to an external entity, it has a null section.
class MCSymbol {
protected:
- /// A symbol can contain an Offset, or Value, or be Common, but never more
- /// than one of these.
+ // A symbol can be regular, equated to an expression, or a common symbol.
enum Contents : uint8_t {
SymContentsUnset,
- SymContentsOffset,
SymContentsVariable,
SymContentsCommon,
SymContentsTargetCommon, // Index stores the section index
@@ -294,20 +292,15 @@ public:
Index = Value;
}
- bool isUnset() const { return SymbolContents == SymContentsUnset; }
-
uint64_t getOffset() const {
- assert((SymbolContents == SymContentsUnset ||
- SymbolContents == SymContentsOffset) &&
+ assert(SymbolContents == SymContentsUnset &&
"Cannot get offset for a common/variable symbol");
return Offset;
}
void setOffset(uint64_t Value) {
- assert((SymbolContents == SymContentsUnset ||
- SymbolContents == SymContentsOffset) &&
+ assert(SymbolContents == SymContentsUnset &&
"Cannot set offset for a common/variable symbol");
Offset = Value;
- SymbolContents = SymContentsOffset;
}
/// Return the size of a 'common' symbol.
diff --git a/llvm/lib/Analysis/StackLifetime.cpp b/llvm/lib/Analysis/StackLifetime.cpp
index 34a7a04..b3f9994 100644
--- a/llvm/lib/Analysis/StackLifetime.cpp
+++ b/llvm/lib/Analysis/StackLifetime.cpp
@@ -63,7 +63,10 @@ bool StackLifetime::isAliveAfter(const AllocaInst *AI,
// markers has the same size and points to the alloca start.
static const AllocaInst *findMatchingAlloca(const IntrinsicInst &II,
const DataLayout &DL) {
- const AllocaInst *AI = cast<AllocaInst>(II.getArgOperand(1));
+ const AllocaInst *AI = dyn_cast<AllocaInst>(II.getArgOperand(1));
+ if (!AI)
+ return nullptr;
+
auto AllocaSize = AI->getAllocationSize(DL);
if (!AllocaSize)
return nullptr;
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index fd38c30..ab6fb30 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -2189,8 +2189,8 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
unsigned Op = ID == Intrinsic::lifetime_start ? TargetOpcode::LIFETIME_START
: TargetOpcode::LIFETIME_END;
- const AllocaInst *AI = cast<AllocaInst>(CI.getArgOperand(1));
- if (!AI->isStaticAlloca())
+ const AllocaInst *AI = dyn_cast<AllocaInst>(CI.getArgOperand(1));
+ if (!AI || !AI->isStaticAlloca())
return true;
MIRBuilder.buildInstr(Op).addFrameIndex(getOrCreateFrameIndex(*AI));
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 306e068..ac0440f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -7598,7 +7598,9 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
if (TM.getOptLevel() == CodeGenOptLevel::None)
return;
- const AllocaInst *LifetimeObject = cast<AllocaInst>(I.getArgOperand(1));
+ const AllocaInst *LifetimeObject = dyn_cast<AllocaInst>(I.getArgOperand(1));
+ if (!LifetimeObject)
+ return;
// First check that the Alloca is static, otherwise it won't have a
// valid frame index.
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index bfe2a3d..b6e2cac 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -73,13 +73,8 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
EABI EABIVersion, StringRef ABIName) {
setTargetRuntimeLibcallSets(TT, FloatABI);
- if (TT.isX86() || TT.isVE() || TT.isARM() || TT.isThumb()) {
- if (ExceptionModel == ExceptionHandling::SjLj)
- setLibcallImpl(RTLIB::UNWIND_RESUME, RTLIB::_Unwind_SjLj_Resume);
- }
-
- if (TT.isOSOpenBSD())
- setLibcallImpl(RTLIB::STACK_SMASH_HANDLER, RTLIB::__stack_smash_handler);
+ if (ExceptionModel == ExceptionHandling::SjLj)
+ setLibcallImpl(RTLIB::UNWIND_RESUME, RTLIB::_Unwind_SjLj_Resume);
if (TT.isARM() || TT.isThumb()) {
setARMLibcallNames(*this, TT, FloatABI, EABIVersion);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 3ff9895..ca3f148 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -6769,10 +6769,13 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
break;
}
case Intrinsic::lifetime_start:
- case Intrinsic::lifetime_end:
- Check(isa<AllocaInst>(Call.getArgOperand(1)),
- "llvm.lifetime.start/end can only be used on alloca", &Call);
+ case Intrinsic::lifetime_end: {
+ Value *Ptr = Call.getArgOperand(1);
+ Check(isa<AllocaInst>(Ptr) || isa<PoisonValue>(Ptr),
+ "llvm.lifetime.start/end can only be used on alloca or poison",
+ &Call);
break;
+ }
};
// Verify that there aren't any unmediated control transfers between funclets.
diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp
index 5c8e904..d172ad1 100644
--- a/llvm/lib/MC/MCAssembler.cpp
+++ b/llvm/lib/MC/MCAssembler.cpp
@@ -945,6 +945,14 @@ bool MCAssembler::relaxFill(MCFillFragment &F) {
return true;
}
+bool MCAssembler::relaxOrg(MCOrgFragment &F) {
+ uint64_t Size = computeFragmentSize(F);
+ if (F.getSize() == Size)
+ return false;
+ F.setSize(Size);
+ return true;
+}
+
bool MCAssembler::relaxFragment(MCFragment &F) {
switch(F.getKind()) {
default:
@@ -966,6 +974,8 @@ bool MCAssembler::relaxFragment(MCFragment &F) {
return relaxCVDefRange(cast<MCCVDefRangeFragment>(F));
case MCFragment::FT_Fill:
return relaxFill(cast<MCFillFragment>(F));
+ case MCFragment::FT_Org:
+ return relaxOrg(static_cast<MCOrgFragment &>(F));
}
}
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index bcc77c0..db63f19 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -46,79 +46,23 @@ MCAssembler *MCObjectStreamer::getAssemblerPtr() {
return nullptr;
}
-constexpr size_t FragBlockSize = 16384;
-// Ensure the new fragment can at least store a few bytes.
-constexpr size_t NewFragHeadroom = 8;
-
-static_assert(NewFragHeadroom >= alignof(MCFragment));
-static_assert(FragBlockSize >= sizeof(MCFragment) + NewFragHeadroom);
-
-MCFragment *MCObjectStreamer::allocFragSpace(size_t Headroom) {
- auto Size = std::max(FragBlockSize, sizeof(MCFragment) + Headroom);
- FragSpace = Size - sizeof(MCFragment);
- auto Block = std::unique_ptr<uint8_t[]>(new uint8_t[Size]);
- auto *F = reinterpret_cast<MCFragment *>(Block.get());
- FragStorage.push_back(std::move(Block));
- return F;
-}
-
void MCObjectStreamer::newFragment() {
- MCFragment *F;
- if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
- auto End = reinterpret_cast<size_t>(getCurFragEnd());
- F = reinterpret_cast<MCFragment *>(
- alignToPowerOf2(End, alignof(MCFragment)));
- FragSpace -= size_t(F) - End + sizeof(MCFragment);
- } else {
- F = allocFragSpace(0);
- }
- new (F) MCFragment();
- addFragment(F);
-}
-
-void MCObjectStreamer::ensureHeadroom(size_t Headroom) {
- if (Headroom <= FragSpace)
- return;
- auto *F = allocFragSpace(Headroom);
- new (F) MCFragment();
- addFragment(F);
+ addFragment(allocFragment<MCFragment>());
}
void MCObjectStreamer::addSpecialFragment(MCFragment *Frag) {
assert(Frag->getKind() != MCFragment::FT_Data &&
- "F should have a variable-size tail");
- // Frag is not connected to FragSpace. Before modifying CurFrag with
- // addFragment(Frag), allocate an empty fragment to maintain FragSpace
- // connectivity, potentially reusing CurFrag's associated space.
- MCFragment *F;
- if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
- auto End = reinterpret_cast<size_t>(getCurFragEnd());
- F = reinterpret_cast<MCFragment *>(
- alignToPowerOf2(End, alignof(MCFragment)));
- FragSpace -= size_t(F) - End + sizeof(MCFragment);
- } else {
- F = allocFragSpace(0);
- }
- new (F) MCFragment();
-
+ "Frag should have a variable-size tail");
addFragment(Frag);
- addFragment(F);
+ newFragment();
}
void MCObjectStreamer::appendContents(ArrayRef<char> Contents) {
- ensureHeadroom(Contents.size());
- assert(FragSpace >= Contents.size());
- llvm::copy(Contents, getCurFragEnd());
- CurFrag->FixedSize += Contents.size();
- FragSpace -= Contents.size();
+ CurFrag->appendContents(Contents);
}
-void MCObjectStreamer::appendContents(size_t Num, uint8_t Elt) {
- ensureHeadroom(Num);
- MutableArrayRef<uint8_t> Data(getCurFragEnd(), Num);
- llvm::fill(Data, Elt);
- CurFrag->FixedSize += Num;
- FragSpace -= Num;
+void MCObjectStreamer::appendContents(size_t Num, char Elt) {
+ CurFrag->appendContents(Num, Elt);
}
void MCObjectStreamer::addFixup(const MCExpr *Value, MCFixupKind Kind) {
@@ -171,8 +115,6 @@ void MCObjectStreamer::reset() {
}
EmitEHFrame = true;
EmitDebugFrame = false;
- FragStorage.clear();
- FragSpace = 0;
SpecialFragAllocator.Reset();
MCStreamer::reset();
}
@@ -202,6 +144,7 @@ void MCObjectStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {
void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
SMLoc Loc) {
MCStreamer::emitValueImpl(Value, Size, Loc);
+ MCFragment *DF = getCurrentFragment();
MCDwarfLineEntry::make(this, getCurrentSectionOnly());
@@ -216,9 +159,9 @@ void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
emitIntValue(AbsValue, Size);
return;
}
- ensureHeadroom(Size);
- addFixup(Value, MCFixup::getDataKindForSize(Size));
- appendContents(Size, 0);
+ DF->addFixup(MCFixup::create(DF->getContents().size(), Value,
+ MCFixup::getDataKindForSize(Size)));
+ DF->appendContents(Size, 0);
}
MCSymbol *MCObjectStreamer::emitCFILabel() {
@@ -252,7 +195,7 @@ void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
// section.
MCFragment *F = CurFrag;
Symbol->setFragment(F);
- Symbol->setOffset(F->getFixedSize());
+ Symbol->setOffset(F->getContents().size());
emitPendingAssignments(Symbol);
}
@@ -318,21 +261,6 @@ void MCObjectStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
F0 = CurFrag;
}
- // To maintain connectivity between CurFrag and FragSpace when CurFrag is
- // modified, allocate an empty fragment and append it to the fragment list.
- // (Subsections[I].second.Tail is not connected to FragSpace.)
- MCFragment *F;
- if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
- auto End = reinterpret_cast<size_t>(getCurFragEnd());
- F = reinterpret_cast<MCFragment *>(
- alignToPowerOf2(End, alignof(MCFragment)));
- FragSpace -= size_t(F) - End + sizeof(MCFragment);
- } else {
- F = allocFragSpace(0);
- }
- new (F) MCFragment();
- F->setParent(Section);
-
auto &Subsections = Section->Subsections;
size_t I = 0, E = Subsections.size();
while (I != E && Subsections[I].first < Subsection)
@@ -340,16 +268,13 @@ void MCObjectStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
// If the subsection number is not in the sorted Subsections list, create a
// new fragment list.
if (I == E || Subsections[I].first != Subsection) {
+ auto *F = allocFragment<MCFragment>();
+ F->setParent(Section);
Subsections.insert(Subsections.begin() + I,
{Subsection, MCSection::FragList{F, F}});
- Section->CurFragList = &Subsections[I].second;
- CurFrag = F;
- } else {
- Section->CurFragList = &Subsections[I].second;
- CurFrag = Subsections[I].second.Tail;
- // Ensure CurFrag is associated with FragSpace.
- addFragment(F);
}
+ Section->CurFragList = &Subsections[I].second;
+ CurFrag = Section->CurFragList->Tail;
// Define the section symbol at subsection 0's initial fragment if required.
if (!NewSec)
@@ -420,15 +345,11 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
MCFragment *F = getCurrentFragment();
// Append the instruction to the data fragment.
- size_t CodeOffset = getCurFragSize();
- SmallString<16> Content;
+ size_t CodeOffset = F->getContents().size();
SmallVector<MCFixup, 1> Fixups;
- getAssembler().getEmitter().encodeInstruction(Inst, Content, Fixups, STI);
- appendContents(Content);
- if (CurFrag != F) {
- F = CurFrag;
- CodeOffset = 0;
- }
+ getAssembler().getEmitter().encodeInstruction(
+ Inst, F->getContentsForAppending(), Fixups, STI);
+ F->doneAppending();
F->setHasInstructions(STI);
if (Fixups.empty())
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index c5611a38..7782dc1 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -6273,7 +6273,8 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef,
// used as a symbol, or it is an absolute symbol).
Sym = Parser.getContext().lookupSymbol(Name);
if (Sym) {
- if (!Sym->isUnset() && (!allow_redef || !Sym->isRedefinable()))
+ if ((Sym->isVariable() || Sym->isDefined()) &&
+ (!allow_redef || !Sym->isRedefinable()))
return Parser.Error(EqualLoc, "redefinition of '" + Name + "'");
// If the symbol is redefinable, clone it and update the symbol table
// to the new symbol. Existing references to the original symbol remain
diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index a87648a..72a8dd7 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -318,9 +318,6 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
// Emit the epilog instructions.
if (EnableUnwindV2) {
- // Ensure the fixups and appended content apply to the same fragment.
- OS->ensureHeadroom(info->EpilogMap.size() * 2);
-
bool IsLast = true;
for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
if (IsLast) {
diff --git a/llvm/lib/MC/MCWinCOFFStreamer.cpp b/llvm/lib/MC/MCWinCOFFStreamer.cpp
index a45936b..67baba7 100644
--- a/llvm/lib/MC/MCWinCOFFStreamer.cpp
+++ b/llvm/lib/MC/MCWinCOFFStreamer.cpp
@@ -279,7 +279,6 @@ void MCWinCOFFStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
void MCWinCOFFStreamer::emitCOFFSectionIndex(const MCSymbol *Symbol) {
visitUsedSymbol(*Symbol);
const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
- ensureHeadroom(2);
addFixup(SRE, FK_SecRel_2);
appendContents(2, 0);
}
@@ -293,7 +292,6 @@ void MCWinCOFFStreamer::emitCOFFSecRel32(const MCSymbol *Symbol,
if (Offset)
MCE = MCBinaryExpr::createAdd(
MCE, MCConstantExpr::create(Offset, getContext()), getContext());
- ensureHeadroom(4);
addFixup(MCE, FK_SecRel_4);
// Emit 4 bytes (zeros) to the object file.
appendContents(4, 0);
@@ -309,7 +307,6 @@ void MCWinCOFFStreamer::emitCOFFImgRel32(const MCSymbol *Symbol,
if (Offset)
MCE = MCBinaryExpr::createAdd(
MCE, MCConstantExpr::create(Offset, getContext()), getContext());
- ensureHeadroom(4);
addFixup(MCE, FK_Data_4);
// Emit 4 bytes (zeros) to the object file.
appendContents(4, 0);
@@ -320,7 +317,6 @@ void MCWinCOFFStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {
// Create Symbol for section number.
const MCExpr *MCE = MCCOFFSectionNumberTargetExpr::create(
*Symbol, this->getWriter(), getContext());
- ensureHeadroom(4);
addFixup(MCE, FK_Data_4);
// Emit 4 bytes (zeros) to the object file.
appendContents(4, 0);
@@ -331,7 +327,6 @@ void MCWinCOFFStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
// Create Symbol for section offset.
const MCExpr *MCE =
MCCOFFSectionOffsetTargetExpr::create(*Symbol, getContext());
- ensureHeadroom(4);
addFixup(MCE, FK_Data_4);
// Emit 4 bytes (zeros) to the object file.
appendContents(4, 0);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index 5df70c4..4056724 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -1034,14 +1034,12 @@ MCELFStreamer &MipsTargetELFStreamer::getStreamer() {
void MipsTargetELFStreamer::emitGPRel32Value(const MCExpr *Value) {
auto &S = getStreamer();
- S.ensureHeadroom(4);
S.addFixup(Value, Mips::fixup_Mips_GPREL32);
S.appendContents(4, 0);
}
void MipsTargetELFStreamer::emitGPRel64Value(const MCExpr *Value) {
auto &S = getStreamer();
- S.ensureHeadroom(8);
// fixup_Mips_GPREL32 desginates R_MIPS_GPREL32+R_MIPS_64 on MIPS64.
S.addFixup(Value, Mips::fixup_Mips_GPREL32);
S.appendContents(8, 0);
@@ -1049,28 +1047,24 @@ void MipsTargetELFStreamer::emitGPRel64Value(const MCExpr *Value) {
void MipsTargetELFStreamer::emitDTPRel32Value(const MCExpr *Value) {
auto &S = getStreamer();
- S.ensureHeadroom(4);
S.addFixup(Value, Mips::fixup_Mips_DTPREL32);
S.appendContents(4, 0);
}
void MipsTargetELFStreamer::emitDTPRel64Value(const MCExpr *Value) {
auto &S = getStreamer();
- S.ensureHeadroom(8);
S.addFixup(Value, Mips::fixup_Mips_DTPREL64);
S.appendContents(8, 0);
}
void MipsTargetELFStreamer::emitTPRel32Value(const MCExpr *Value) {
auto &S = getStreamer();
- S.ensureHeadroom(4);
S.addFixup(Value, Mips::fixup_Mips_TPREL32);
S.appendContents(4, 0);
}
void MipsTargetELFStreamer::emitTPRel64Value(const MCExpr *Value) {
auto &S = getStreamer();
- S.ensureHeadroom(8);
S.addFixup(Value, Mips::fixup_Mips_TPREL64);
S.appendContents(8, 0);
}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 5265613..44a8245d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -14,6 +14,14 @@
// Operand and SDNode transformation definitions.
//===----------------------------------------------------------------------===//
+def SDT_SetMultiple : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>,
+ SDTCisSameAs<1, 3>,
+ SDTCisPtrTy<2>,
+ SDTCisVT<3, XLenVT>]>;
+
+def qc_setwmi : RVSDNode<"QC_SETWMI", SDT_SetMultiple,
+ [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
def uimm5nonzero : RISCVOp<XLenVT>,
ImmLeaf<XLenVT, [{return (Imm != 0) && isUInt<5>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<5, "NonZero">;
@@ -27,6 +35,8 @@ def uimm5nonzero : RISCVOp<XLenVT>,
}];
}
+def tuimm5nonzero : TImmLeaf<XLenVT, [{return (Imm != 0) && isUInt<5>(Imm);}]>;
+
def uimm5gt3 : RISCVOp<XLenVT>, ImmLeaf<XLenVT,
[{return (Imm > 3) && isUInt<5>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<5, "GT3">;
@@ -92,6 +102,8 @@ def uimm5slist : RISCVOp<XLenVT>, ImmLeaf<XLenVT,
}];
}
+def tuimm7_lsb00 : TImmLeaf<XLenVT,[{return isShiftedUInt<5, 2>(Imm);}]>;
+
def uimm10 : RISCVUImmLeafOp<10>;
def uimm11 : RISCVUImmLeafOp<11>;
@@ -1566,6 +1578,11 @@ def : QCISELECTIICCPat <SETEQ, QC_SELECTIIEQ>;
def : QCISELECTIICCPat <SETNE, QC_SELECTIINE>;
} // Predicates = [HasVendorXqcics, IsRV32]
+let Predicates = [HasVendorXqcilsm, IsRV32] in {
+def : Pat<(qc_setwmi GPR:$rs3, GPR:$rs1, tuimm5nonzero:$uimm5, tuimm7_lsb00:$uimm7),
+ (QC_SETWMI GPR:$rs3, GPR:$rs1, tuimm5nonzero:$uimm5, tuimm7_lsb00:$uimm7)>;
+} // Predicates = [HasVendorXqcilsm, IsRV32]
+
//===----------------------------------------------------------------------===/i
// Compress Instruction tablegen backend.
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.cpp b/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.cpp
index 6ecddad..041dd07 100644
--- a/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "RISCVSelectionDAGInfo.h"
+#include "RISCVSubtarget.h"
+#include "llvm/CodeGen/SelectionDAG.h"
#define GET_SDNODE_DESC
#include "RISCVGenSDNodeInfo.inc"
@@ -62,3 +64,94 @@ void RISCVSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
}
#endif
}
+
+SDValue RISCVSelectionDAGInfo::EmitTargetCodeForMemset(
+ SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
+ SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
+ MachinePointerInfo DstPtrInfo) const {
+ const auto &Subtarget = DAG.getSubtarget<RISCVSubtarget>();
+ // We currently do this only for Xqcilsm
+ if (!Subtarget.hasVendorXqcilsm())
+ return SDValue();
+
+ // Do this only if we know the size at compile time.
+ ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
+ if (!ConstantSize)
+ return SDValue();
+
+ uint64_t NumberOfBytesToWrite = ConstantSize->getZExtValue();
+
+ // Do this only if it is word aligned and we write a multiple of 4 bytes.
+ if (!(Alignment >= 4) || !((NumberOfBytesToWrite & 3) == 0))
+ return SDValue();
+
+ SmallVector<SDValue, 8> OutChains;
+ SDValue SrcValueReplicated = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
+ int NumberOfWords = NumberOfBytesToWrite / 4;
+ MachineFunction &MF = DAG.getMachineFunction();
+ auto Volatile =
+ isVolatile ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone;
+
+ // Helper for constructing the QC_SETWMI instruction
+ auto getSetwmiNode = [&](uint8_t SizeWords, uint8_t OffsetSetwmi) -> SDValue {
+ SDValue Ops[] = {Chain, SrcValueReplicated, Dst,
+ DAG.getTargetConstant(SizeWords, dl, MVT::i32),
+ DAG.getTargetConstant(OffsetSetwmi, dl, MVT::i32)};
+ MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
+ DstPtrInfo.getWithOffset(OffsetSetwmi),
+ MachineMemOperand::MOStore | Volatile, SizeWords * 4, Align(4));
+ return DAG.getMemIntrinsicNode(RISCVISD::QC_SETWMI, dl,
+ DAG.getVTList(MVT::Other), Ops, MVT::i32,
+ BaseMemOperand);
+ };
+
+ // If i8 type and constant non-zero value.
+ if ((Src.getValueType() == MVT::i8) && !isNullConstant(Src))
+ // Replicate byte to word by multiplication with 0x01010101.
+ SrcValueReplicated =
+ DAG.getNode(ISD::MUL, dl, MVT::i32, SrcValueReplicated,
+ DAG.getConstant(0x01010101ul, dl, MVT::i32));
+
+ // We limit a QC_SETWMI to 16 words or less to improve interruptibility.
+ // So for 1-16 words we use a single QC_SETWMI:
+ //
+ // QC_SETWMI reg1, N, 0(reg2)
+ //
+ // For 17-32 words we use two QC_SETWMI's with the first as 16 words and the
+ // second for the remainder:
+ //
+ // QC_SETWMI reg1, 16, 0(reg2)
+ // QC_SETWMI reg1, N, 64(reg2)
+ //
+ // For 33-48 words, we would like to use (16, 16, n), but that means the last
+ // QC_SETWMI needs an offset of 128 which the instruction doesn't support.
+ // So in this case we use a length of 15 for the second instruction and we do
+ // the rest with the third instruction.
+ // This means the maximum inlined number of words is 47 (for now):
+ //
+ // QC_SETWMI R2, R0, 16, 0
+ // QC_SETWMI R2, R0, 15, 64
+ // QC_SETWMI R2, R0, N, 124
+ //
+ // For 48 words or more, call the target independent memset
+ if (NumberOfWords >= 48)
+ return SDValue();
+
+ if (NumberOfWords <= 16) {
+ // 1 - 16 words
+ return getSetwmiNode(NumberOfWords, 0);
+ }
+
+ if (NumberOfWords <= 32) {
+ // 17 - 32 words
+ OutChains.push_back(getSetwmiNode(NumberOfWords - 16, 64));
+ OutChains.push_back(getSetwmiNode(16, 0));
+ } else {
+ // 33 - 47 words
+ OutChains.push_back(getSetwmiNode(NumberOfWords - 31, 124));
+ OutChains.push_back(getSetwmiNode(15, 64));
+ OutChains.push_back(getSetwmiNode(16, 0));
+ }
+
+ return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
+}
diff --git a/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.h b/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.h
index 641189f..08c8d11 100644
--- a/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.h
@@ -34,6 +34,12 @@ public:
void verifyTargetNode(const SelectionDAG &DAG,
const SDNode *N) const override;
+ SDValue EmitTargetCodeForMemset(SelectionDAG &DAG, const SDLoc &dl,
+ SDValue Chain, SDValue Dst, SDValue Src,
+ SDValue Size, Align Alignment,
+ bool isVolatile, bool AlwaysInline,
+ MachinePointerInfo DstPtrInfo) const override;
+
bool hasPassthruOp(unsigned Opcode) const {
return GenNodeInfo.getDesc(Opcode).TSFlags & RISCVISD::HasPassthruOpMask;
}
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index e87bee7..8da65c5 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -1222,9 +1222,9 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
!ConstantInt::isValueValidForType(IntptrTy, SizeValue))
return;
// Find alloca instruction that corresponds to llvm.lifetime argument.
- AllocaInst *AI = cast<AllocaInst>(II.getArgOperand(1));
+ AllocaInst *AI = dyn_cast<AllocaInst>(II.getArgOperand(1));
// We're interested only in allocas we can handle.
- if (!ASan.isInterestingAlloca(*AI))
+ if (!AI || !ASan.isInterestingAlloca(*AI))
return;
bool DoPoison = (ID == Intrinsic::lifetime_end);
AllocaPoisonCall APC = {&II, AI, SizeValue, DoPoison};
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 54d9a83..7d3c940 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -3301,8 +3301,9 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
void handleLifetimeStart(IntrinsicInst &I) {
if (!PoisonStack)
return;
- AllocaInst *AI = cast<AllocaInst>(I.getArgOperand(1));
- LifetimeStartList.push_back(std::make_pair(&I, AI));
+ AllocaInst *AI = dyn_cast<AllocaInst>(I.getArgOperand(1));
+ if (AI)
+ LifetimeStartList.push_back(std::make_pair(&I, AI));
}
void handleBswap(IntrinsicInst &I) {
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index babd7f6..3852f1a 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -482,6 +482,9 @@ bool llvm::wouldInstructionBeTriviallyDead(const Instruction *I,
if (II->isLifetimeStartOrEnd()) {
auto *Arg = II->getArgOperand(1);
+ if (isa<PoisonValue>(Arg))
+ return true;
+
// If the only uses of the alloca are lifetime intrinsics, then the
// intrinsics are dead.
return llvm::all_of(Arg->uses(), [](Use &Use) {
diff --git a/llvm/lib/Transforms/Utils/MemoryTaggingSupport.cpp b/llvm/lib/Transforms/Utils/MemoryTaggingSupport.cpp
index bea76d3..472c03f 100644
--- a/llvm/lib/Transforms/Utils/MemoryTaggingSupport.cpp
+++ b/llvm/lib/Transforms/Utils/MemoryTaggingSupport.cpp
@@ -155,8 +155,9 @@ void StackInfoBuilder::visit(OptimizationRemarkEmitter &ORE,
return;
}
if (auto *II = dyn_cast<LifetimeIntrinsic>(&Inst)) {
- AllocaInst *AI = cast<AllocaInst>(II->getArgOperand(1));
- if (getAllocaInterestingness(*AI) != AllocaInterestingness::kInteresting)
+ AllocaInst *AI = dyn_cast<AllocaInst>(II->getArgOperand(1));
+ if (!AI ||
+ getAllocaInterestingness(*AI) != AllocaInterestingness::kInteresting)
return;
if (II->getIntrinsicID() == Intrinsic::lifetime_start)
Info.AllocasToInstrument[AI].LifetimeStart.push_back(II);
diff --git a/llvm/test/CodeGen/AArch64/arm64-ext.ll b/llvm/test/CodeGen/AArch64/arm64-ext.ll
index 50df6a0..8bf2b82 100644
--- a/llvm/test/CodeGen/AArch64/arm64-ext.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-ext.ll
@@ -135,3 +135,68 @@ define <2 x ptr> @test_v2p0(<2 x ptr> %a, <2 x ptr> %b) {
%s = shufflevector <2 x ptr> %a, <2 x ptr> %b, <2 x i32> <i32 3, i32 0>
ret <2 x ptr> %s
}
+
+define <16 x i8> @reverse_vector_s8x16b(<16 x i8> noundef %x) {
+; CHECK-SD-LABEL: reverse_vector_s8x16b:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: rev64 v1.16b, v0.16b
+; CHECK-SD-NEXT: ext v0.16b, v1.16b, v1.16b, #8
+; CHECK-SD-NEXT: mov v0.d[1], v1.d[0]
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: reverse_vector_s8x16b:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: rev64 v1.16b, v0.16b
+; CHECK-GI-NEXT: mov d0, v1.d[1]
+; CHECK-GI-NEXT: mov v0.d[1], v1.d[0]
+; CHECK-GI-NEXT: ret
+entry:
+ %shuffle.i = shufflevector <16 x i8> %x, <16 x i8> poison, <16 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8>
+ %shuffle.i6 = shufflevector <16 x i8> %shuffle.i, <16 x i8> poison, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %shuffle.i7 = shufflevector <16 x i8> %shuffle.i, <16 x i8> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %shuffle.i5 = shufflevector <8 x i8> %shuffle.i6, <8 x i8> %shuffle.i7, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i5
+}
+
+define <8 x i16> @reverse_vector_s16x8b(<8 x i16> noundef %x) {
+; CHECK-SD-LABEL: reverse_vector_s16x8b:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: rev64 v1.8h, v0.8h
+; CHECK-SD-NEXT: ext v0.16b, v1.16b, v1.16b, #8
+; CHECK-SD-NEXT: mov v0.d[1], v1.d[0]
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: reverse_vector_s16x8b:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: rev64 v1.8h, v0.8h
+; CHECK-GI-NEXT: mov d0, v1.d[1]
+; CHECK-GI-NEXT: mov v0.d[1], v1.d[0]
+; CHECK-GI-NEXT: ret
+entry:
+ %shuffle.i = shufflevector <8 x i16> %x, <8 x i16> poison, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
+ %shuffle.i6 = shufflevector <8 x i16> %shuffle.i, <8 x i16> poison, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ %shuffle.i7 = shufflevector <8 x i16> %shuffle.i, <8 x i16> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %shuffle.i5 = shufflevector <4 x i16> %shuffle.i6, <4 x i16> %shuffle.i7, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i5
+}
+
+define <4 x i32> @reverse_vector_s32x4b(<4 x i32> noundef %x) {
+; CHECK-SD-LABEL: reverse_vector_s32x4b:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: rev64 v0.4s, v0.4s
+; CHECK-SD-NEXT: ext v0.16b, v0.16b, v0.16b, #8
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: reverse_vector_s32x4b:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: rev64 v1.4s, v0.4s
+; CHECK-GI-NEXT: mov d0, v1.d[1]
+; CHECK-GI-NEXT: mov v0.d[1], v1.d[0]
+; CHECK-GI-NEXT: ret
+entry:
+ %shuffle.i = shufflevector <4 x i32> %x, <4 x i32> poison, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
+ %shuffle.i6 = shufflevector <4 x i32> %shuffle.i, <4 x i32> poison, <2 x i32> <i32 2, i32 3>
+ %shuffle.i7 = shufflevector <4 x i32> %shuffle.i, <4 x i32> poison, <2 x i32> <i32 0, i32 1>
+ %shuffle.i5 = shufflevector <2 x i32> %shuffle.i6, <2 x i32> %shuffle.i7, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i5
+}
diff --git a/llvm/test/CodeGen/AArch64/arm64-neon-copy.ll b/llvm/test/CodeGen/AArch64/arm64-neon-copy.ll
index 367105f7..f4e59fe 100644
--- a/llvm/test/CodeGen/AArch64/arm64-neon-copy.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-neon-copy.ll
@@ -1708,7 +1708,7 @@ define <16 x i8> @test_concat_v16i8_v8i8_v16i8(<8 x i8> %x, <16 x i8> %y) #0 {
; CHECK-GI-LABEL: test_concat_v16i8_v8i8_v16i8:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov v2.16b, v1.16b
-; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0 def $q0 def $q0 def $q0 def $q0 def $q0 def $q0 def $q0
; CHECK-GI-NEXT: adrp x8, .LCPI127_0
; CHECK-GI-NEXT: mov v1.b[0], v0.b[0]
; CHECK-GI-NEXT: mov v1.b[1], v0.b[1]
@@ -1752,7 +1752,7 @@ define <16 x i8> @test_concat_v16i8_v16i8_v8i8(<16 x i8> %x, <8 x i8> %y) #0 {
; CHECK-GI-LABEL: test_concat_v16i8_v16i8_v8i8:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov b2, v0.b[0]
-; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1 def $q1 def $q1 def $q1 def $q1 def $q1 def $q1 def $q1
; CHECK-GI-NEXT: mov v2.b[1], v0.b[1]
; CHECK-GI-NEXT: mov v2.b[2], v0.b[2]
; CHECK-GI-NEXT: mov v2.b[3], v0.b[3]
@@ -1816,9 +1816,9 @@ define <16 x i8> @test_concat_v16i8_v8i8_v8i8(<8 x i8> %x, <8 x i8> %y) #0 {
;
; CHECK-GI-LABEL: test_concat_v16i8_v8i8_v8i8:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0 def $q0 def $q0 def $q0 def $q0 def $q0 def $q0 def $q0
; CHECK-GI-NEXT: mov v2.b[0], v0.b[0]
-; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1 def $q1 def $q1 def $q1 def $q1 def $q1 def $q1 def $q1
; CHECK-GI-NEXT: mov v2.b[1], v0.b[1]
; CHECK-GI-NEXT: mov v2.b[2], v0.b[2]
; CHECK-GI-NEXT: mov v2.b[3], v0.b[3]
@@ -1901,7 +1901,7 @@ define <8 x i16> @test_concat_v8i16_v4i16_v8i16(<4 x i16> %x, <8 x i16> %y) #0 {
; CHECK-GI-LABEL: test_concat_v8i16_v4i16_v8i16:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov v2.16b, v1.16b
-; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0 def $q0 def $q0 def $q0
; CHECK-GI-NEXT: adrp x8, .LCPI131_0
; CHECK-GI-NEXT: mov v1.h[0], v0.h[0]
; CHECK-GI-NEXT: mov v1.h[1], v0.h[1]
@@ -1933,7 +1933,7 @@ define <8 x i16> @test_concat_v8i16_v8i16_v4i16(<8 x i16> %x, <4 x i16> %y) #0 {
; CHECK-GI-LABEL: test_concat_v8i16_v8i16_v4i16:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov h2, v0.h[0]
-; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1 def $q1 def $q1 def $q1
; CHECK-GI-NEXT: mov v2.h[1], v0.h[1]
; CHECK-GI-NEXT: mov v2.h[2], v0.h[2]
; CHECK-GI-NEXT: mov v2.h[3], v0.h[3]
@@ -1973,9 +1973,9 @@ define <8 x i16> @test_concat_v8i16_v4i16_v4i16(<4 x i16> %x, <4 x i16> %y) #0 {
;
; CHECK-GI-LABEL: test_concat_v8i16_v4i16_v4i16:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0 def $q0 def $q0 def $q0
; CHECK-GI-NEXT: mov v2.h[0], v0.h[0]
-; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1 def $q1 def $q1 def $q1
; CHECK-GI-NEXT: mov v2.h[1], v0.h[1]
; CHECK-GI-NEXT: mov v2.h[2], v0.h[2]
; CHECK-GI-NEXT: mov v2.h[3], v0.h[3]
@@ -2034,7 +2034,7 @@ define <4 x i32> @test_concat_v4i32_v2i32_v4i32(<2 x i32> %x, <4 x i32> %y) #0 {
; CHECK-GI-LABEL: test_concat_v4i32_v2i32_v4i32:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov v2.16b, v1.16b
-; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0 def $q0
; CHECK-GI-NEXT: adrp x8, .LCPI135_0
; CHECK-GI-NEXT: mov v1.s[0], v0.s[0]
; CHECK-GI-NEXT: mov v1.s[1], v0.s[1]
@@ -2060,7 +2060,7 @@ define <4 x i32> @test_concat_v4i32_v4i32_v2i32(<4 x i32> %x, <2 x i32> %y) #0 {
; CHECK-GI-LABEL: test_concat_v4i32_v4i32_v2i32:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov s2, v0.s[0]
-; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1 def $q1
; CHECK-GI-NEXT: mov v2.s[1], v0.s[1]
; CHECK-GI-NEXT: mov v2.s[2], v1.s[0]
; CHECK-GI-NEXT: mov v2.s[3], v1.s[1]
diff --git a/llvm/test/CodeGen/AArch64/arm64-vext.ll b/llvm/test/CodeGen/AArch64/arm64-vext.ll
index a56bd6b..e522c05 100644
--- a/llvm/test/CodeGen/AArch64/arm64-vext.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-vext.ll
@@ -1,8 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s
define void @test_vext_s8() nounwind ssp {
- ; CHECK-LABEL: test_vext_s8:
- ; CHECK: {{ext.8.*#1}}
+; CHECK-LABEL: test_vext_s8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: ext.8b v1, v0, v0, #1
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xS8x8 = alloca <8 x i8>, align 8
%__a = alloca <8 x i8>, align 8
%__b = alloca <8 x i8>, align 8
@@ -18,8 +26,15 @@ define void @test_vext_s8() nounwind ssp {
}
define void @test_vext_u8() nounwind ssp {
- ; CHECK-LABEL: test_vext_u8:
- ; CHECK: {{ext.8.*#2}}
+; CHECK-LABEL: test_vext_u8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: ext.8b v1, v0, v0, #2
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xU8x8 = alloca <8 x i8>, align 8
%__a = alloca <8 x i8>, align 8
%__b = alloca <8 x i8>, align 8
@@ -35,8 +50,15 @@ define void @test_vext_u8() nounwind ssp {
}
define void @test_vext_p8() nounwind ssp {
- ; CHECK-LABEL: test_vext_p8:
- ; CHECK: {{ext.8.*#3}}
+; CHECK-LABEL: test_vext_p8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: ext.8b v1, v0, v0, #3
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xP8x8 = alloca <8 x i8>, align 8
%__a = alloca <8 x i8>, align 8
%__b = alloca <8 x i8>, align 8
@@ -52,8 +74,15 @@ define void @test_vext_p8() nounwind ssp {
}
define void @test_vext_s16() nounwind ssp {
- ; CHECK-LABEL: test_vext_s16:
- ; CHECK: {{ext.8.*#2}}
+; CHECK-LABEL: test_vext_s16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: ext.8b v1, v0, v0, #2
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xS16x4 = alloca <4 x i16>, align 8
%__a = alloca <4 x i16>, align 8
%__b = alloca <4 x i16>, align 8
@@ -73,8 +102,15 @@ define void @test_vext_s16() nounwind ssp {
}
define void @test_vext_u16() nounwind ssp {
- ; CHECK-LABEL: test_vext_u16:
- ; CHECK: {{ext.8.*#4}}
+; CHECK-LABEL: test_vext_u16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: ext.8b v1, v0, v0, #4
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xU16x4 = alloca <4 x i16>, align 8
%__a = alloca <4 x i16>, align 8
%__b = alloca <4 x i16>, align 8
@@ -94,8 +130,15 @@ define void @test_vext_u16() nounwind ssp {
}
define void @test_vext_p16() nounwind ssp {
- ; CHECK-LABEL: test_vext_p16:
- ; CHECK: {{ext.8.*#6}}
+; CHECK-LABEL: test_vext_p16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: ext.8b v1, v0, v0, #6
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xP16x4 = alloca <4 x i16>, align 8
%__a = alloca <4 x i16>, align 8
%__b = alloca <4 x i16>, align 8
@@ -115,8 +158,15 @@ define void @test_vext_p16() nounwind ssp {
}
define void @test_vext_s32() nounwind ssp {
- ; CHECK-LABEL: test_vext_s32:
- ; CHECK: {{rev64.2s.*}}
+; CHECK-LABEL: test_vext_s32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: rev64.2s v1, v0
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xS32x2 = alloca <2 x i32>, align 8
%__a = alloca <2 x i32>, align 8
%__b = alloca <2 x i32>, align 8
@@ -136,8 +186,15 @@ define void @test_vext_s32() nounwind ssp {
}
define void @test_vext_u32() nounwind ssp {
- ; CHECK-LABEL: test_vext_u32:
- ; CHECK: {{rev64.2s.*}}
+; CHECK-LABEL: test_vext_u32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: rev64.2s v1, v0
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xU32x2 = alloca <2 x i32>, align 8
%__a = alloca <2 x i32>, align 8
%__b = alloca <2 x i32>, align 8
@@ -157,8 +214,15 @@ define void @test_vext_u32() nounwind ssp {
}
define void @test_vext_f32() nounwind ssp {
- ; CHECK-LABEL: test_vext_f32:
- ; CHECK: {{rev64.2s.*}}
+; CHECK-LABEL: test_vext_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: rev64.2s v1, v0
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: str d1, [sp, #24]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
%xF32x2 = alloca <2 x float>, align 8
%__a = alloca <2 x float>, align 8
%__b = alloca <2 x float>, align 8
@@ -178,7 +242,13 @@ define void @test_vext_f32() nounwind ssp {
}
define void @test_vext_s64() nounwind ssp {
- ; CHECK-LABEL: test_vext_s64:
+; CHECK-LABEL: test_vext_s64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
; CHECK_FIXME: {{rev64.2s.*}}
; this just turns into a load of the second element
%xS64x1 = alloca <1 x i64>, align 8
@@ -200,7 +270,13 @@ define void @test_vext_s64() nounwind ssp {
}
define void @test_vext_u64() nounwind ssp {
- ; CHECK-LABEL: test_vext_u64:
+; CHECK-LABEL: test_vext_u64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: ldr d0, [sp, #24]
+; CHECK-NEXT: stp d0, d0, [sp, #8]
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
; CHECK_FIXME: {{ext.8.*#1}}
; this is turned into a simple load of the 2nd element
%xU64x1 = alloca <1 x i64>, align 8
@@ -222,8 +298,15 @@ define void @test_vext_u64() nounwind ssp {
}
define void @test_vextq_s8() nounwind ssp {
- ; CHECK-LABEL: test_vextq_s8:
- ; CHECK: {{ext.16.*#4}}
+; CHECK-LABEL: test_vextq_s8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #4
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xS8x16 = alloca <16 x i8>, align 16
%__a = alloca <16 x i8>, align 16
%__b = alloca <16 x i8>, align 16
@@ -239,8 +322,15 @@ define void @test_vextq_s8() nounwind ssp {
}
define void @test_vextq_u8() nounwind ssp {
- ; CHECK-LABEL: test_vextq_u8:
- ; CHECK: {{ext.16.*#5}}
+; CHECK-LABEL: test_vextq_u8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #5
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xU8x16 = alloca <16 x i8>, align 16
%__a = alloca <16 x i8>, align 16
%__b = alloca <16 x i8>, align 16
@@ -256,8 +346,15 @@ define void @test_vextq_u8() nounwind ssp {
}
define void @test_vextq_p8() nounwind ssp {
- ; CHECK-LABEL: test_vextq_p8:
- ; CHECK: {{ext.16.*#6}}
+; CHECK-LABEL: test_vextq_p8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #6
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xP8x16 = alloca <16 x i8>, align 16
%__a = alloca <16 x i8>, align 16
%__b = alloca <16 x i8>, align 16
@@ -273,8 +370,15 @@ define void @test_vextq_p8() nounwind ssp {
}
define void @test_vextq_s16() nounwind ssp {
- ; CHECK-LABEL: test_vextq_s16:
- ; CHECK: {{ext.16.*#14}}
+; CHECK-LABEL: test_vextq_s16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #14
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xS16x8 = alloca <8 x i16>, align 16
%__a = alloca <8 x i16>, align 16
%__b = alloca <8 x i16>, align 16
@@ -294,8 +398,15 @@ define void @test_vextq_s16() nounwind ssp {
}
define void @test_vextq_u16() nounwind ssp {
- ; CHECK-LABEL: test_vextq_u16:
- ; CHECK: {{ext.16.*#8}}
+; CHECK-LABEL: test_vextq_u16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #8
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xU16x8 = alloca <8 x i16>, align 16
%__a = alloca <8 x i16>, align 16
%__b = alloca <8 x i16>, align 16
@@ -315,8 +426,15 @@ define void @test_vextq_u16() nounwind ssp {
}
define void @test_vextq_p16() nounwind ssp {
- ; CHECK-LABEL: test_vextq_p16:
- ; CHECK: {{ext.16.*#10}}
+; CHECK-LABEL: test_vextq_p16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #10
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xP16x8 = alloca <8 x i16>, align 16
%__a = alloca <8 x i16>, align 16
%__b = alloca <8 x i16>, align 16
@@ -336,8 +454,15 @@ define void @test_vextq_p16() nounwind ssp {
}
define void @test_vextq_s32() nounwind ssp {
- ; CHECK-LABEL: test_vextq_s32:
- ; CHECK: {{ext.16.*#4}}
+; CHECK-LABEL: test_vextq_s32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #4
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xS32x4 = alloca <4 x i32>, align 16
%__a = alloca <4 x i32>, align 16
%__b = alloca <4 x i32>, align 16
@@ -357,8 +482,15 @@ define void @test_vextq_s32() nounwind ssp {
}
define void @test_vextq_u32() nounwind ssp {
- ; CHECK-LABEL: test_vextq_u32:
- ; CHECK: {{ext.16.*#8}}
+; CHECK-LABEL: test_vextq_u32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #8
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xU32x4 = alloca <4 x i32>, align 16
%__a = alloca <4 x i32>, align 16
%__b = alloca <4 x i32>, align 16
@@ -378,8 +510,15 @@ define void @test_vextq_u32() nounwind ssp {
}
define void @test_vextq_f32() nounwind ssp {
- ; CHECK-LABEL: test_vextq_f32:
- ; CHECK: {{ext.16.*#12}}
+; CHECK-LABEL: test_vextq_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #12
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xF32x4 = alloca <4 x float>, align 16
%__a = alloca <4 x float>, align 16
%__b = alloca <4 x float>, align 16
@@ -399,8 +538,15 @@ define void @test_vextq_f32() nounwind ssp {
}
define void @test_vextq_s64() nounwind ssp {
- ; CHECK-LABEL: test_vextq_s64:
- ; CHECK: {{ext.16.*#8}}
+; CHECK-LABEL: test_vextq_s64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #8
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xS64x2 = alloca <2 x i64>, align 16
%__a = alloca <2 x i64>, align 16
%__b = alloca <2 x i64>, align 16
@@ -420,8 +566,15 @@ define void @test_vextq_s64() nounwind ssp {
}
define void @test_vextq_u64() nounwind ssp {
- ; CHECK-LABEL: test_vextq_u64:
- ; CHECK: {{ext.16.*#8}}
+; CHECK-LABEL: test_vextq_u64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #48
+; CHECK-NEXT: ldr q0, [sp, #32]
+; CHECK-NEXT: ext.16b v1, v0, v0, #8
+; CHECK-NEXT: stp q0, q0, [sp]
+; CHECK-NEXT: str q1, [sp, #32]
+; CHECK-NEXT: add sp, sp, #48
+; CHECK-NEXT: ret
%xU64x2 = alloca <2 x i64>, align 16
%__a = alloca <2 x i64>, align 16
%__b = alloca <2 x i64>, align 16
@@ -445,18 +598,21 @@ define void @test_vextq_u64() nounwind ssp {
; rdar://12051674
define <16 x i8> @vext1(<16 x i8> %_a) nounwind {
; CHECK-LABEL: vext1:
-; CHECK: ext.16b v0, v0, v0, #8
+; CHECK: // %bb.0:
+; CHECK-NEXT: ext.16b v0, v0, v0, #8
+; CHECK-NEXT: ret
%vext = shufflevector <16 x i8> %_a, <16 x i8> undef, <16 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
ret <16 x i8> %vext
}
; <rdar://problem/12212062>
define <2 x i64> @vext2(<2 x i64> %p0, <2 x i64> %p1) nounwind readnone ssp {
-entry:
; CHECK-LABEL: vext2:
-; CHECK: add.2d v0, v0, v1
-; CHECK-NEXT: ext.16b v0, v0, v0, #8
-; CHECK-NEXT: ret
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: add.2d v0, v0, v1
+; CHECK-NEXT: ext.16b v0, v0, v0, #8
+; CHECK-NEXT: ret
+entry:
%t0 = shufflevector <2 x i64> %p1, <2 x i64> undef, <2 x i32> <i32 1, i32 0>
%t1 = shufflevector <2 x i64> %p0, <2 x i64> undef, <2 x i32> <i32 1, i32 0>
%t2 = add <2 x i64> %t1, %t0
diff --git a/llvm/test/CodeGen/AArch64/arm64-vext_reverse.ll b/llvm/test/CodeGen/AArch64/arm64-vext_reverse.ll
index c51ea17..9829ca3 100644
--- a/llvm/test/CodeGen/AArch64/arm64-vext_reverse.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-vext_reverse.ll
@@ -1,172 +1,217 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=arm64-linux-gnuabi < %s | FileCheck %s
-; The following tests is to check the correctness of reversing input operand
+; The following tests is to check the correctness of reversing input operand
; of vext by enumerating all cases of using two undefs in shuffle masks.
define <4 x i16> @vext_6701_0(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_6701_0:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 6, i32 7, i32 0, i32 1>
ret <4 x i16> %x
}
define <4 x i16> @vext_6701_12(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_6701_12:
-; CHECK: dup v0.2s, v0.s[0]
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-NEXT: dup v0.2s, v0.s[0]
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 undef, i32 0, i32 1>
ret <4 x i16> %x
}
define <4 x i16> @vext_6701_13(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_6701_13:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 7, i32 undef, i32 1>
ret <4 x i16> %x
}
define <4 x i16> @vext_6701_14(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_6701_14:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 7, i32 0, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_6701_23(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_6701_23:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 6, i32 undef, i32 undef, i32 1>
ret <4 x i16> %x
}
define <4 x i16> @vext_6701_24(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_6701_24:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #4
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 6, i32 undef, i32 0, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_6701_34(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_6701_34:
-; CHECK: dup v0.2s, v1.s[1]
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-NEXT: dup v0.2s, v1.s[1]
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 6, i32 7, i32 undef, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_5670_0(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_5670_0:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 5, i32 6, i32 7, i32 0>
ret <4 x i16> %x
}
define <4 x i16> @vext_5670_12(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_5670_12:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 undef, i32 7, i32 0>
ret <4 x i16> %x
}
define <4 x i16> @vext_5670_13(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_5670_13:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 6, i32 undef, i32 0>
ret <4 x i16> %x
}
define <4 x i16> @vext_5670_14(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_5670_14:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 6, i32 7, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_5670_23(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_5670_23:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 5, i32 undef, i32 undef, i32 0>
ret <4 x i16> %x
}
define <4 x i16> @vext_5670_24(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_5670_24:
-; CHECK: rev32 v0.4h, v1.4h
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: rev32 v0.4h, v1.4h
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 5, i32 undef, i32 7, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_5670_34(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_5670_34:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #2
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 5, i32 6, i32 undef, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_7012_0(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_7012_0:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 7, i32 0, i32 1, i32 2>
ret <4 x i16> %x
}
define <4 x i16> @vext_7012_12(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_7012_12:
-; CHECK: ext v0.8b, v0.8b, v0.8b, #6
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v0.8b, v0.8b, #6
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 undef, i32 1, i32 2>
ret <4 x i16> %x
}
define <4 x i16> @vext_7012_13(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_7012_13:
-; CHECK: rev32 v0.4h, v0.4h
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: rev32 v0.4h, v0.4h
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 0, i32 undef, i32 2>
ret <4 x i16> %x
}
define <4 x i16> @vext_7012_14(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_7012_14:
-; CHECK: ext v0.8b, v0.8b, v0.8b, #6
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v0.8b, v0.8b, #6
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 undef, i32 0, i32 1, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_7012_23(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_7012_23:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 7, i32 undef, i32 undef, i32 2>
ret <4 x i16> %x
}
define <4 x i16> @vext_7012_24(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_7012_24:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 7, i32 undef, i32 1, i32 undef>
ret <4 x i16> %x
}
define <4 x i16> @vext_7012_34(<4 x i16> %a1, <4 x i16> %a2) {
-entry:
; CHECK-LABEL: vext_7012_34:
-; CHECK: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ext v0.8b, v1.8b, v0.8b, #6
+; CHECK-NEXT: ret
+entry:
%x = shufflevector <4 x i16> %a1, <4 x i16> %a2, <4 x i32> <i32 7, i32 0, i32 undef, i32 undef>
ret <4 x i16> %x
}
diff --git a/llvm/test/CodeGen/AArch64/extend_inreg_of_concat_subvectors.ll b/llvm/test/CodeGen/AArch64/extend_inreg_of_concat_subvectors.ll
index 1f1bfe6..6df8d2b 100644
--- a/llvm/test/CodeGen/AArch64/extend_inreg_of_concat_subvectors.ll
+++ b/llvm/test/CodeGen/AArch64/extend_inreg_of_concat_subvectors.ll
@@ -1,20 +1,19 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=arm64-apple-ios -mattr=+sve -o - %s | FileCheck %s
-; RUN: llc -mtriple=aarch64_be-unknown-linux -mattr=+sve -o - %s | FileCheck --check-prefix=CHECK-BE %s
-; RUN: llc -mtriple=arm64-apple-ios -mattr=+global-isel -mattr=+sve -o - %s | FileCheck %s
-; RUN: llc -mtriple=aarch64_be-unknown-linux -mattr=+global-isel -mattr=+sve -o - %s | FileCheck --check-prefix=CHECK-BE %s
+; RUN: llc -mtriple=arm64-apple-ios -mattr=+sve -o - %s | FileCheck %s --check-prefix=CHECK-LE-SD
+; RUN: llc -mtriple=aarch64_be-unknown-linux -mattr=+sve -o - %s | FileCheck %s --check-prefix=CHECK-BE
+; RUN: llc -mtriple=arm64-apple-ios -global-isel -mattr=+sve -o - %s | FileCheck %s --check-prefix=CHECK-LE-GI
define void @zext_of_concat(ptr %a, ptr %b, ptr %c, ptr %d) nounwind {
-; CHECK-LABEL: zext_of_concat:
-; CHECK: ; %bb.0:
-; CHECK-NEXT: ldr d0, [x0]
-; CHECK-NEXT: ldr d1, [x1]
-; CHECK-NEXT: add.2s v0, v0, v1
-; CHECK-NEXT: ldr q1, [x2]
-; CHECK-NEXT: ushll.2d v0, v0, #0
-; CHECK-NEXT: add.4s v0, v0, v1
-; CHECK-NEXT: str q0, [x2]
-; CHECK-NEXT: ret
+; CHECK-LE-SD-LABEL: zext_of_concat:
+; CHECK-LE-SD: ; %bb.0:
+; CHECK-LE-SD-NEXT: ldr d0, [x0]
+; CHECK-LE-SD-NEXT: ldr d1, [x1]
+; CHECK-LE-SD-NEXT: add.2s v0, v0, v1
+; CHECK-LE-SD-NEXT: ldr q1, [x2]
+; CHECK-LE-SD-NEXT: ushll.2d v0, v0, #0
+; CHECK-LE-SD-NEXT: add.4s v0, v0, v1
+; CHECK-LE-SD-NEXT: str q0, [x2]
+; CHECK-LE-SD-NEXT: ret
;
; CHECK-BE-LABEL: zext_of_concat:
; CHECK-BE: // %bb.0:
@@ -28,6 +27,23 @@ define void @zext_of_concat(ptr %a, ptr %b, ptr %c, ptr %d) nounwind {
; CHECK-BE-NEXT: add v0.4s, v0.4s, v1.4s
; CHECK-BE-NEXT: st1 { v0.4s }, [x2]
; CHECK-BE-NEXT: ret
+;
+; CHECK-LE-GI-LABEL: zext_of_concat:
+; CHECK-LE-GI: ; %bb.0:
+; CHECK-LE-GI-NEXT: ldr d0, [x0]
+; CHECK-LE-GI-NEXT: ldr d1, [x1]
+; CHECK-LE-GI-NEXT: movi.2d v3, #0000000000000000
+; CHECK-LE-GI-NEXT: Lloh0:
+; CHECK-LE-GI-NEXT: adrp x8, lCPI0_0@PAGE
+; CHECK-LE-GI-NEXT: add.2s v2, v0, v1
+; CHECK-LE-GI-NEXT: Lloh1:
+; CHECK-LE-GI-NEXT: ldr q0, [x8, lCPI0_0@PAGEOFF]
+; CHECK-LE-GI-NEXT: ldr q1, [x2]
+; CHECK-LE-GI-NEXT: tbl.16b v0, { v2, v3 }, v0
+; CHECK-LE-GI-NEXT: add.4s v0, v0, v1
+; CHECK-LE-GI-NEXT: str q0, [x2]
+; CHECK-LE-GI-NEXT: ret
+; CHECK-LE-GI-NEXT: .loh AdrpLdr Lloh0, Lloh1
%i0.a = load <2 x i32>, ptr %a
%i0.b = load <2 x i32>, ptr %b
%i0 = add <2 x i32> %i0.a, %i0.b
@@ -40,19 +56,19 @@ define void @zext_of_concat(ptr %a, ptr %b, ptr %c, ptr %d) nounwind {
}
define void @zext_of_concat_extrause(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) nounwind {
-; CHECK-LABEL: zext_of_concat_extrause:
-; CHECK: ; %bb.0:
-; CHECK-NEXT: ldr d0, [x1]
-; CHECK-NEXT: ldr d1, [x0]
-; CHECK-NEXT: add.2s v0, v1, v0
-; CHECK-NEXT: movi.2d v1, #0000000000000000
-; CHECK-NEXT: mov.d v0[1], v0[0]
-; CHECK-NEXT: zip1.4s v1, v0, v1
-; CHECK-NEXT: str q0, [x4]
-; CHECK-NEXT: ldr q0, [x2]
-; CHECK-NEXT: add.4s v0, v1, v0
-; CHECK-NEXT: str q0, [x2]
-; CHECK-NEXT: ret
+; CHECK-LE-SD-LABEL: zext_of_concat_extrause:
+; CHECK-LE-SD: ; %bb.0:
+; CHECK-LE-SD-NEXT: ldr d0, [x1]
+; CHECK-LE-SD-NEXT: ldr d1, [x0]
+; CHECK-LE-SD-NEXT: add.2s v0, v1, v0
+; CHECK-LE-SD-NEXT: movi.2d v1, #0000000000000000
+; CHECK-LE-SD-NEXT: mov.d v0[1], v0[0]
+; CHECK-LE-SD-NEXT: zip1.4s v1, v0, v1
+; CHECK-LE-SD-NEXT: str q0, [x4]
+; CHECK-LE-SD-NEXT: ldr q0, [x2]
+; CHECK-LE-SD-NEXT: add.4s v0, v1, v0
+; CHECK-LE-SD-NEXT: str q0, [x2]
+; CHECK-LE-SD-NEXT: ret
;
; CHECK-BE-LABEL: zext_of_concat_extrause:
; CHECK-BE: // %bb.0:
@@ -68,6 +84,25 @@ define void @zext_of_concat_extrause(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) nou
; CHECK-BE-NEXT: add v0.4s, v0.4s, v1.4s
; CHECK-BE-NEXT: st1 { v0.4s }, [x2]
; CHECK-BE-NEXT: ret
+;
+; CHECK-LE-GI-LABEL: zext_of_concat_extrause:
+; CHECK-LE-GI: ; %bb.0:
+; CHECK-LE-GI-NEXT: ldr d0, [x0]
+; CHECK-LE-GI-NEXT: ldr d1, [x1]
+; CHECK-LE-GI-NEXT: movi.2d v3, #0000000000000000
+; CHECK-LE-GI-NEXT: Lloh2:
+; CHECK-LE-GI-NEXT: adrp x8, lCPI1_0@PAGE
+; CHECK-LE-GI-NEXT: add.2s v2, v0, v1
+; CHECK-LE-GI-NEXT: Lloh3:
+; CHECK-LE-GI-NEXT: ldr q0, [x8, lCPI1_0@PAGEOFF]
+; CHECK-LE-GI-NEXT: mov.d v2[1], v2[0]
+; CHECK-LE-GI-NEXT: tbl.16b v0, { v2, v3 }, v0
+; CHECK-LE-GI-NEXT: str q2, [x4]
+; CHECK-LE-GI-NEXT: ldr q1, [x2]
+; CHECK-LE-GI-NEXT: add.4s v0, v0, v1
+; CHECK-LE-GI-NEXT: str q0, [x2]
+; CHECK-LE-GI-NEXT: ret
+; CHECK-LE-GI-NEXT: .loh AdrpLdr Lloh2, Lloh3
%i0.a = load <2 x i32>, ptr %a
%i0.b = load <2 x i32>, ptr %b
%i0 = add <2 x i32> %i0.a, %i0.b
@@ -81,16 +116,16 @@ define void @zext_of_concat_extrause(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) nou
}
define void @aext_of_concat(ptr %a, ptr %b, ptr %c, ptr %d) nounwind {
-; CHECK-LABEL: aext_of_concat:
-; CHECK: ; %bb.0:
-; CHECK-NEXT: ldr d0, [x0]
-; CHECK-NEXT: ldr d1, [x1]
-; CHECK-NEXT: add.2s v0, v0, v1
-; CHECK-NEXT: ldr q1, [x2]
-; CHECK-NEXT: ushll.2d v0, v0, #0
-; CHECK-NEXT: add.4s v0, v0, v1
-; CHECK-NEXT: str q0, [x2]
-; CHECK-NEXT: ret
+; CHECK-LE-SD-LABEL: aext_of_concat:
+; CHECK-LE-SD: ; %bb.0:
+; CHECK-LE-SD-NEXT: ldr d0, [x0]
+; CHECK-LE-SD-NEXT: ldr d1, [x1]
+; CHECK-LE-SD-NEXT: add.2s v0, v0, v1
+; CHECK-LE-SD-NEXT: ldr q1, [x2]
+; CHECK-LE-SD-NEXT: ushll.2d v0, v0, #0
+; CHECK-LE-SD-NEXT: add.4s v0, v0, v1
+; CHECK-LE-SD-NEXT: str q0, [x2]
+; CHECK-LE-SD-NEXT: ret
;
; CHECK-BE-LABEL: aext_of_concat:
; CHECK-BE: // %bb.0:
@@ -102,6 +137,17 @@ define void @aext_of_concat(ptr %a, ptr %b, ptr %c, ptr %d) nounwind {
; CHECK-BE-NEXT: add v0.4s, v0.4s, v1.4s
; CHECK-BE-NEXT: st1 { v0.4s }, [x2]
; CHECK-BE-NEXT: ret
+;
+; CHECK-LE-GI-LABEL: aext_of_concat:
+; CHECK-LE-GI: ; %bb.0:
+; CHECK-LE-GI-NEXT: ldr d0, [x0]
+; CHECK-LE-GI-NEXT: ldr d1, [x1]
+; CHECK-LE-GI-NEXT: add.2s v0, v0, v1
+; CHECK-LE-GI-NEXT: ldr q1, [x2]
+; CHECK-LE-GI-NEXT: zip1.4s v0, v0, v0
+; CHECK-LE-GI-NEXT: add.4s v0, v0, v1
+; CHECK-LE-GI-NEXT: str q0, [x2]
+; CHECK-LE-GI-NEXT: ret
%i0.a = load <2 x i32>, ptr %a
%i0.b = load <2 x i32>, ptr %b
%i0 = add <2 x i32> %i0.a, %i0.b
@@ -114,19 +160,19 @@ define void @aext_of_concat(ptr %a, ptr %b, ptr %c, ptr %d) nounwind {
}
define void @aext_of_concat_extrause(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) nounwind {
-; CHECK-LABEL: aext_of_concat_extrause:
-; CHECK: ; %bb.0:
-; CHECK-NEXT: ldr d0, [x1]
-; CHECK-NEXT: ldr d1, [x0]
-; CHECK-NEXT: add.2s v0, v1, v0
-; CHECK-NEXT: mov.16b v1, v0
-; CHECK-NEXT: mov.d v1[1], v0[0]
-; CHECK-NEXT: zip1.4s v0, v0, v0
-; CHECK-NEXT: str q1, [x4]
-; CHECK-NEXT: ldr q1, [x2]
-; CHECK-NEXT: add.4s v0, v0, v1
-; CHECK-NEXT: str q0, [x2]
-; CHECK-NEXT: ret
+; CHECK-LE-SD-LABEL: aext_of_concat_extrause:
+; CHECK-LE-SD: ; %bb.0:
+; CHECK-LE-SD-NEXT: ldr d0, [x1]
+; CHECK-LE-SD-NEXT: ldr d1, [x0]
+; CHECK-LE-SD-NEXT: add.2s v0, v1, v0
+; CHECK-LE-SD-NEXT: mov.16b v1, v0
+; CHECK-LE-SD-NEXT: mov.d v1[1], v0[0]
+; CHECK-LE-SD-NEXT: zip1.4s v0, v0, v0
+; CHECK-LE-SD-NEXT: str q1, [x4]
+; CHECK-LE-SD-NEXT: ldr q1, [x2]
+; CHECK-LE-SD-NEXT: add.4s v0, v0, v1
+; CHECK-LE-SD-NEXT: str q0, [x2]
+; CHECK-LE-SD-NEXT: ret
;
; CHECK-BE-LABEL: aext_of_concat_extrause:
; CHECK-BE: // %bb.0:
@@ -141,6 +187,19 @@ define void @aext_of_concat_extrause(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) nou
; CHECK-BE-NEXT: add v0.4s, v0.4s, v1.4s
; CHECK-BE-NEXT: st1 { v0.4s }, [x2]
; CHECK-BE-NEXT: ret
+;
+; CHECK-LE-GI-LABEL: aext_of_concat_extrause:
+; CHECK-LE-GI: ; %bb.0:
+; CHECK-LE-GI-NEXT: ldr d0, [x0]
+; CHECK-LE-GI-NEXT: ldr d1, [x1]
+; CHECK-LE-GI-NEXT: add.2s v0, v0, v1
+; CHECK-LE-GI-NEXT: mov.d v0[1], v0[0]
+; CHECK-LE-GI-NEXT: zip1.4s v1, v0, v0
+; CHECK-LE-GI-NEXT: str q0, [x4]
+; CHECK-LE-GI-NEXT: ldr q0, [x2]
+; CHECK-LE-GI-NEXT: add.4s v0, v1, v0
+; CHECK-LE-GI-NEXT: str q0, [x2]
+; CHECK-LE-GI-NEXT: ret
%i0.a = load <2 x i32>, ptr %a
%i0.b = load <2 x i32>, ptr %b
%i0 = add <2 x i32> %i0.a, %i0.b
diff --git a/llvm/test/CodeGen/AArch64/lifetime-poison.ll b/llvm/test/CodeGen/AArch64/lifetime-poison.ll
new file mode 100644
index 0000000..e04530d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/lifetime-poison.ll
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=aarch64 -global-isel=0 < %s | FileCheck %s
+; RUN: llc -mtriple=aarch64 -global-isel=1 < %s | FileCheck %s
+
+; Check that lifetime.start/end with poison argument are ignored.
+
+define void @test() {
+; CHECK-LABEL: test:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ret
+ call void @llvm.lifetime.start.p0(i64 4, ptr poison)
+ call void @llvm.lifetime.end.p0(i64 4, ptr poison)
+ ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/xqcilsm-memset.ll b/llvm/test/CodeGen/RISCV/xqcilsm-memset.ll
new file mode 100644
index 0000000..988bb6f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcilsm-memset.ll
@@ -0,0 +1,900 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefixes=RV32I
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -mattr=+experimental-xqcilsm < %s \
+; RUN: | FileCheck %s -check-prefixes=RV32IXQCILSM
+
+%struct.anon = type { [16 x i32] }
+%struct.anon.0 = type { [47 x i32] }
+%struct.anon.1 = type { [48 x i32] }
+%struct.anon.2 = type { [64 x i8] }
+%struct.struct1_t = type { [16 x i32] }
+
+@struct1 = common dso_local local_unnamed_addr global %struct.anon zeroinitializer, align 4
+@struct4b = common dso_local local_unnamed_addr global %struct.anon.0 zeroinitializer, align 4
+@struct4b1 = common dso_local local_unnamed_addr global %struct.anon.1 zeroinitializer, align 4
+@struct2 = common dso_local local_unnamed_addr global %struct.anon.2 zeroinitializer, align 1
+@arr1 = common dso_local local_unnamed_addr global [100 x i32] zeroinitializer, align 4
+@struct1_ = common dso_local local_unnamed_addr global %struct.struct1_t zeroinitializer, align 4
+
+define void @test1(ptr nocapture %p, i32 %n) nounwind {
+; RV32I-LABEL: test1:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: mv a2, a1
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test1:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: mv a2, a1
+; RV32IXQCILSM-NEXT: li a1, 0
+; RV32IXQCILSM-NEXT: tail memset
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 1 %p, i8 0, i32 %n, i1 false)
+ ret void
+}
+
+declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1)
+
+define void @test2(ptr nocapture %p) nounwind {
+; RV32I-LABEL: test2:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a1, 165
+; RV32I-NEXT: li a2, 128
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test2:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a1, 678490
+; RV32IXQCILSM-NEXT: addi a1, a1, 1445
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %p, i8 -91, i32 128, i1 false)
+ ret void
+}
+
+define void @test2a(ptr nocapture %p) nounwind {
+; RV32I-LABEL: test2a:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a1, 165
+; RV32I-NEXT: li a2, 188
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test2a:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a1, 678490
+; RV32IXQCILSM-NEXT: addi a1, a1, 1445
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 15, 64(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 124(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %p, i8 -91, i32 188, i1 false)
+ ret void
+}
+
+define void @test2b(ptr nocapture %p) nounwind {
+; RV32I-LABEL: test2b:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a1, 165
+; RV32I-NEXT: li a2, 192
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test2b:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: li a1, 165
+; RV32IXQCILSM-NEXT: li a2, 192
+; RV32IXQCILSM-NEXT: tail memset
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %p, i8 -91, i32 192, i1 false)
+ ret void
+}
+
+define void @test2c(ptr nocapture %p) nounwind {
+; RV32I-LABEL: test2c:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a1, 165
+; RV32I-NEXT: li a2, 128
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test2c:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a1, 678490
+; RV32IXQCILSM-NEXT: addi a1, a1, 1445
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %p, i8 -91, i32 128, i1 false)
+ ret void
+}
+
+define void @test2d(ptr nocapture %p) nounwind {
+; RV32I-LABEL: test2d:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a1, -91
+; RV32I-NEXT: lui a2, 1048570
+; RV32I-NEXT: lui a3, 678490
+; RV32I-NEXT: addi a2, a2, 1445
+; RV32I-NEXT: addi a3, a3, 1445
+; RV32I-NEXT: sw a3, 0(a0)
+; RV32I-NEXT: sw a3, 4(a0)
+; RV32I-NEXT: sh a2, 8(a0)
+; RV32I-NEXT: sb a1, 10(a0)
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test2d:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: li a1, -91
+; RV32IXQCILSM-NEXT: lui a2, 1048570
+; RV32IXQCILSM-NEXT: lui a3, 678490
+; RV32IXQCILSM-NEXT: addi a2, a2, 1445
+; RV32IXQCILSM-NEXT: addi a3, a3, 1445
+; RV32IXQCILSM-NEXT: sw a3, 0(a0)
+; RV32IXQCILSM-NEXT: sw a3, 4(a0)
+; RV32IXQCILSM-NEXT: sh a2, 8(a0)
+; RV32IXQCILSM-NEXT: sb a1, 10(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %p, i8 -91, i32 11, i1 false)
+ ret void
+}
+
+
+define ptr @test3(ptr %p) nounwind {
+; RV32I-LABEL: test3:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a2, 256
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test3:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: li a2, 256
+; RV32IXQCILSM-NEXT: li a1, 0
+; RV32IXQCILSM-NEXT: tail memset
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %p, i8 0, i32 256, i1 false)
+ ret ptr %p
+}
+
+define ptr @test3a(ptr %p) nounwind {
+; RV32I-LABEL: test3a:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a2, 128
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test3a:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %p, i8 0, i32 128, i1 false)
+ ret ptr %p
+}
+
+define void @test4() nounwind {
+; RV32I-LABEL: test4:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(struct1)
+; RV32I-NEXT: addi a0, a0, %lo(struct1)
+; RV32I-NEXT: li a2, 64
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test4:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(struct1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(struct1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @struct1, i8 0, i32 64, i1 false)
+ ret void
+}
+
+define void @test4a(ptr nocapture %s) nounwind {
+; RV32I-LABEL: test4a:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: li a1, 166
+; RV32I-NEXT: li a2, 64
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test4a:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a1, 682602
+; RV32IXQCILSM-NEXT: addi a1, a1, 1702
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 %s, i8 -90, i32 64, i1 false)
+ ret void
+}
+
+declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
+
+declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
+
+define void @test4b() nounwind {
+; RV32I-LABEL: test4b:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: lui a0, %hi(struct4b)
+; RV32I-NEXT: addi a0, a0, %lo(struct4b)
+; RV32I-NEXT: li a2, 188
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: call memset
+; RV32I-NEXT: lui a0, %hi(struct4b1)
+; RV32I-NEXT: addi a0, a0, %lo(struct4b1)
+; RV32I-NEXT: li a2, 192
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test4b:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a1, %hi(struct4b)
+; RV32IXQCILSM-NEXT: addi a1, a1, %lo(struct4b)
+; RV32IXQCILSM-NEXT: lui a0, %hi(struct4b1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(struct4b1)
+; RV32IXQCILSM-NEXT: li a2, 192
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 15, 64(a1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 124(a1)
+; RV32IXQCILSM-NEXT: li a1, 0
+; RV32IXQCILSM-NEXT: tail memset
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @struct4b, i8 0, i32 188, i1 false)
+ tail call void @llvm.memset.p0.i32(ptr align 4 @struct4b1, i8 0, i32 192, i1 false)
+ ret void
+}
+
+define void @test5() nounwind {
+; RV32I-LABEL: test5:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(struct2)
+; RV32I-NEXT: addi a0, a0, %lo(struct2)
+; RV32I-NEXT: li a2, 64
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test5:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(struct2)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(struct2)
+; RV32IXQCILSM-NEXT: li a2, 64
+; RV32IXQCILSM-NEXT: li a1, 0
+; RV32IXQCILSM-NEXT: tail memset
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 1 @struct2, i8 0, i32 64, i1 false)
+ ret void
+}
+
+define i32 @test6() nounwind {
+; RV32I-LABEL: test6:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw zero, 12(sp)
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sw zero, 12(sp)
+; RV32IXQCILSM-NEXT: li a0, 0
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i32, align 4
+ call void @llvm.memset.p0.i32(ptr align 4 %x, i8 0, i32 4, i1 false)
+ %0 = load i32, ptr %x, align 4
+ ret i32 %0
+}
+
+define zeroext i8 @test6b_c() nounwind {
+; RV32I-LABEL: test6b_c:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sb zero, 12(sp)
+; RV32I-NEXT: lbu a0, 12(sp)
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6b_c:
+; RV32IXQCILSM: # %bb.0:
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sb zero, 12(sp)
+; RV32IXQCILSM-NEXT: lbu a0, 12(sp)
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+ %x = alloca i8, align 4
+ call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %x)
+ call void @llvm.memset.p0.i32(ptr nonnull align 4 %x, i8 0, i32 1, i1 false)
+ %x.0.x.0. = load volatile i8, ptr %x, align 4
+ call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %x)
+ ret i8 %x.0.x.0.
+}
+
+define signext i16 @test6b_s() nounwind {
+; RV32I-LABEL: test6b_s:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sh zero, 12(sp)
+; RV32I-NEXT: lh a0, 12(sp)
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6b_s:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sh zero, 12(sp)
+; RV32IXQCILSM-NEXT: lh a0, 12(sp)
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i16, align 4
+ call void @llvm.lifetime.start.p0(i64 2, ptr nonnull %x)
+ store i16 0, ptr %x, align 4
+ %x.0.x.0. = load volatile i16, ptr %x, align 4
+ call void @llvm.lifetime.end.p0(i64 2, ptr nonnull %x)
+ ret i16 %x.0.x.0.
+}
+
+define i32 @test6b_l() nounwind {
+; RV32I-LABEL: test6b_l:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw zero, 12(sp)
+; RV32I-NEXT: lw a0, 12(sp)
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6b_l:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sw zero, 12(sp)
+; RV32IXQCILSM-NEXT: lw a0, 12(sp)
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i32, align 4
+ call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %x)
+ store i32 0, ptr %x, align 4
+ %x.0.x.0. = load volatile i32, ptr %x, align 4
+ call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %x)
+ ret i32 %x.0.x.0.
+}
+
+define i64 @test6b_ll() nounwind {
+; RV32I-LABEL: test6b_ll:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw zero, 8(sp)
+; RV32I-NEXT: sw zero, 12(sp)
+; RV32I-NEXT: lw a0, 8(sp)
+; RV32I-NEXT: lw a1, 12(sp)
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6b_ll:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sw zero, 8(sp)
+; RV32IXQCILSM-NEXT: sw zero, 12(sp)
+; RV32IXQCILSM-NEXT: lw a0, 8(sp)
+; RV32IXQCILSM-NEXT: lw a1, 12(sp)
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i64, align 8
+ call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %x)
+ call void @llvm.memset.p0.i32(ptr nonnull align 8 %x, i8 0, i32 8, i1 false)
+ %x.0.x.0. = load volatile i64, ptr %x, align 8
+ call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %x)
+ ret i64 %x.0.x.0.
+}
+
+define zeroext i8 @test6c_c() nounwind {
+; RV32I-LABEL: test6c_c:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sb zero, 15(sp)
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6c_c:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sb zero, 15(sp)
+; RV32IXQCILSM-NEXT: li a0, 0
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i8
+ call void @llvm.memset.p0.i32(ptr align 1 %x, i8 0, i32 1, i1 false)
+ %0 = load i8, ptr %x, align 1
+ ret i8 %0
+}
+
+define signext i16 @test6c_s() nounwind {
+; RV32I-LABEL: test6c_s:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sh zero, 14(sp)
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6c_s:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sh zero, 14(sp)
+; RV32IXQCILSM-NEXT: li a0, 0
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i16
+ call void @llvm.memset.p0.i32(ptr align 2 %x, i8 0, i32 2, i1 false)
+ %0 = load i16, ptr %x, align 2
+ ret i16 %0
+}
+
+define i32 @test6c_l() nounwind {
+; RV32I-LABEL: test6c_l:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw zero, 12(sp)
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6c_l:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sw zero, 12(sp)
+; RV32IXQCILSM-NEXT: li a0, 0
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i32, align 4
+ call void @llvm.memset.p0.i32(ptr align 4 %x, i8 0, i32 4, i1 false)
+ %0 = load i32, ptr %x, align 4
+ ret i32 %0
+}
+
+define i64 @test6c_ll() nounwind {
+; RV32I-LABEL: test6c_ll:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw zero, 8(sp)
+; RV32I-NEXT: sw zero, 12(sp)
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test6c_ll:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: addi sp, sp, -16
+; RV32IXQCILSM-NEXT: sw zero, 8(sp)
+; RV32IXQCILSM-NEXT: sw zero, 12(sp)
+; RV32IXQCILSM-NEXT: li a0, 0
+; RV32IXQCILSM-NEXT: li a1, 0
+; RV32IXQCILSM-NEXT: addi sp, sp, 16
+; RV32IXQCILSM-NEXT: ret
+entry:
+ %x = alloca i64, align 8
+ call void @llvm.memset.p0.i32(ptr align 8 %x, i8 0, i32 8, i1 false)
+ %0 = load i64, ptr %x, align 8
+ ret i64 %0
+}
+
+define void @test7() nounwind {
+; RV32I-LABEL: test7:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: sw zero, %lo(arr1)(a0)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: sw zero, 4(a0)
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test7:
+; RV32IXQCILSM: # %bb.0:
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: sw zero, %lo(arr1)(a0)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: sw zero, 4(a0)
+; RV32IXQCILSM-NEXT: ret
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 8, i1 false)
+ ret void
+}
+
+define void @test7a() nounwind {
+; RV32I-LABEL: test7a:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test7a:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: ret
+entry:
+ call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 0, i1 false)
+ ret void
+}
+
+define void @test7a_unalign() nounwind {
+; RV32I-LABEL: test7a_unalign:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: li a1, -1
+; RV32I-NEXT: sw a1, %lo(arr1)(a0)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: sw a1, 4(a0)
+; RV32I-NEXT: sw a1, 8(a0)
+; RV32I-NEXT: sw a1, 12(a0)
+; RV32I-NEXT: sb a1, 16(a0)
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test7a_unalign:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: li a1, -1
+; RV32IXQCILSM-NEXT: sw a1, %lo(arr1)(a0)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: sw a1, 4(a0)
+; RV32IXQCILSM-NEXT: sw a1, 8(a0)
+; RV32IXQCILSM-NEXT: sw a1, 12(a0)
+; RV32IXQCILSM-NEXT: sb a1, 16(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 -1, i32 17, i1 false)
+ ret void
+}
+
+define void @test7b() nounwind {
+; RV32I-LABEL: test7b:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a1, 255
+; RV32I-NEXT: li a2, 68
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test7b:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: li a1, -1
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 1, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 -1, i32 68, i1 false)
+ ret void
+}
+
+define void @test7c() nounwind {
+; RV32I-LABEL: test7c:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a1, 128
+; RV32I-NEXT: li a2, 128
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test7c:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: lui a1, 526344
+; RV32IXQCILSM-NEXT: addi a1, a1, 128
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 -128, i32 128, i1 false)
+ ret void
+}
+
+define void @test7d() nounwind {
+; RV32I-LABEL: test7d:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a1, 13
+; RV32I-NEXT: li a2, 148
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test7d:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: lui a1, 53457
+; RV32IXQCILSM-NEXT: addi a1, a1, -755
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 15, 64(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 6, 124(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 13, i32 148, i1 false)
+ ret void
+}
+
+define void @test7e() nounwind {
+; RV32I-LABEL: test7e:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a1, 239
+; RV32I-NEXT: li a2, 100
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test7e:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: lui a1, 982783
+; RV32IXQCILSM-NEXT: addi a1, a1, -17
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi a1, 9, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 -17, i32 100, i1 false)
+ ret void
+}
+
+define void @test8() nounwind {
+; RV32I-LABEL: test8:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: sw zero, %lo(arr1)(a0)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: sw zero, 4(a0)
+; RV32I-NEXT: sw zero, 8(a0)
+; RV32I-NEXT: sw zero, 12(a0)
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test8:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: sw zero, %lo(arr1)(a0)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: sw zero, 4(a0)
+; RV32IXQCILSM-NEXT: sw zero, 8(a0)
+; RV32IXQCILSM-NEXT: sw zero, 12(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 16, i1 false)
+ ret void
+}
+
+define void @test9() nounwind {
+; RV32I-LABEL: test9:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: sw zero, %lo(arr1)(a0)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: sw zero, 20(a0)
+; RV32I-NEXT: sw zero, 24(a0)
+; RV32I-NEXT: sw zero, 28(a0)
+; RV32I-NEXT: sw zero, 4(a0)
+; RV32I-NEXT: sw zero, 8(a0)
+; RV32I-NEXT: sw zero, 12(a0)
+; RV32I-NEXT: sw zero, 16(a0)
+; RV32I-NEXT: ret
+;
+; RV32IXQCILSM-LABEL: test9:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: sw zero, %lo(arr1)(a0)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: sw zero, 20(a0)
+; RV32IXQCILSM-NEXT: sw zero, 24(a0)
+; RV32IXQCILSM-NEXT: sw zero, 28(a0)
+; RV32IXQCILSM-NEXT: sw zero, 4(a0)
+; RV32IXQCILSM-NEXT: sw zero, 8(a0)
+; RV32IXQCILSM-NEXT: sw zero, 12(a0)
+; RV32IXQCILSM-NEXT: sw zero, 16(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 32, i1 false)
+ ret void
+}
+
+define void @test10() nounwind {
+; RV32I-LABEL: test10:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 60
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test10:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 15, 0(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 60, i1 false)
+ ret void
+}
+
+define void @test11() nounwind {
+; RV32I-LABEL: test11:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 64
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test11:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 64, i1 false)
+ ret void
+}
+
+define void @test12() nounwind {
+; RV32I-LABEL: test12:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 120
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test12:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 14, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 120, i1 false)
+ ret void
+}
+
+define void @test13() nounwind {
+; RV32I-LABEL: test13:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 124
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test13:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 15, 64(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 124, i1 false)
+ ret void
+}
+
+define void @test14() nounwind {
+; RV32I-LABEL: test14:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 180
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test14:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 15, 64(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 14, 124(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 180, i1 false)
+ ret void
+}
+
+define void @test15() nounwind {
+; RV32I-LABEL: test15:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 184
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test15:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 15, 64(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 15, 124(a0)
+; RV32IXQCILSM-NEXT: ret
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 184, i1 false)
+ ret void
+}
+
+define void @test15a() nounwind {
+; RV32I-LABEL: test15a:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a1, 165
+; RV32I-NEXT: li a2, 192
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test15a:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: li a1, 165
+; RV32IXQCILSM-NEXT: li a2, 192
+; RV32IXQCILSM-NEXT: tail memset
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 -91, i32 192, i1 false)
+ ret void
+}
+
+define void @test15b() nounwind {
+; RV32I-LABEL: test15b:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 188
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test15b:
+; RV32IXQCILSM: # %bb.0:
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 0(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 15, 64(a0)
+; RV32IXQCILSM-NEXT: qc.setwmi zero, 16, 124(a0)
+; RV32IXQCILSM-NEXT: ret
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 188, i1 false)
+ ret void
+}
+
+define void @test15c() nounwind {
+; RV32I-LABEL: test15c:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: lui a0, %hi(arr1)
+; RV32I-NEXT: addi a0, a0, %lo(arr1)
+; RV32I-NEXT: li a2, 192
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: tail memset
+;
+; RV32IXQCILSM-LABEL: test15c:
+; RV32IXQCILSM: # %bb.0: # %entry
+; RV32IXQCILSM-NEXT: lui a0, %hi(arr1)
+; RV32IXQCILSM-NEXT: addi a0, a0, %lo(arr1)
+; RV32IXQCILSM-NEXT: li a2, 192
+; RV32IXQCILSM-NEXT: li a1, 0
+; RV32IXQCILSM-NEXT: tail memset
+entry:
+ tail call void @llvm.memset.p0.i32(ptr align 4 @arr1, i8 0, i32 192, i1 false)
+ ret void
+}
diff --git a/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll b/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll
index bbfe00b..9594370 100644
--- a/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll
+++ b/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll
@@ -334,6 +334,21 @@ entry:
ret void
}
+
+; Lifetimes on poison should be ignored.
+define void @lifetime_poison(i64 %a) #0 {
+; CHECK-LABEL: define void @lifetime_poison(
+; CHECK-SAME: i64 [[A:%.*]]) {
+; CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
+; CHECK-NEXT: store i64 [[A]], ptr [[A_ADDR]], align 8
+; CHECK-NEXT: ret void
+;
+ %a.addr = alloca i64, align 8
+ call void @llvm.lifetime.start.p0(i64 8, ptr poison)
+ store i64 %a, ptr %a.addr, align 8
+ call void @llvm.lifetime.end.p0(i64 8, ptr poison)
+ ret void
+}
;.
; CHECK-DEFAULT: [[PROF1]] = !{!"branch_weights", i32 1, i32 1048575}
;.
diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll
index e96ca91..60af551 100644
--- a/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll
@@ -395,6 +395,25 @@ entry:
ret i32 0
}
+; Check that lifetimes on poison are ignored.
+define i32 @test_lifetime_poison(ptr %a) sanitize_hwaddress {
+entry:
+ ; CHECK-LABEL: @test_lifetime_poison
+ ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+ ; NOSAFETY: call {{.*}}__hwasan_store
+ ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+ ; SAFETY-NOT: call {{.*}}__hwasan_store
+ ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+ ; NOSTACK-NOT: call {{.*}}__hwasan_store
+ ; SAFETY-REMARKS: --- !Passed{{[[:space:]]}}Pass: hwasan{{[[:space:]]}}Name: safeAlloca{{[[:space:]]}}Function: test_lifetime_poison
+ ; SAFETY-REMARKS: --- !Passed{{[[:space:]]}}Pass: hwasan{{[[:space:]]}}Name: ignoreAccess{{[[:space:]]}}Function: test_lifetime_poison
+ %buf.sroa.0 = alloca i8, align 4
+ call void @llvm.lifetime.start.p0(i64 1, ptr poison)
+ store volatile i8 0, ptr %buf.sroa.0, align 4, !tbaa !8
+ call void @llvm.lifetime.end.p0(i64 1, ptr poison)
+ ret i32 0
+}
+
; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
diff --git a/llvm/test/MC/ELF/many-instructions.s b/llvm/test/MC/ELF/many-instructions.s
deleted file mode 100644
index cbdb2a7..0000000
--- a/llvm/test/MC/ELF/many-instructions.s
+++ /dev/null
@@ -1,10 +0,0 @@
-# REQUIRES: asserts
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o /dev/null -debug-only=mc-dump
-
-## Test that encodeInstruction may cause a new fragment to be created.
-# CHECK: 0 Data Size:16200
-# CHECK: 16200 Data Size:180
-
-.rept 16384/10
-movabsq $foo, %rax
-.endr
diff --git a/llvm/test/MC/ELF/mc-dump.s b/llvm/test/MC/ELF/mc-dump.s
index 51b3ff4..a590e1c 100644
--- a/llvm/test/MC/ELF/mc-dump.s
+++ b/llvm/test/MC/ELF/mc-dump.s
@@ -30,7 +30,7 @@
# CHECK-NEXT:5 LEB Size:0+1 [15] Value:.Ltmp0-_start Signed:0
# CHECK:]
-# CHECK: 2 assembler - Number of fixup evaluations for relaxation
+# CHECK: 3 assembler - Number of fixup evaluations for relaxation
# CHECK: 8 assembler - Number of fixups
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t -debug-only=mc-dump -save-temp-labels -g 2>&1 | FileCheck %s --check-prefix=CHECK2
diff --git a/llvm/test/Transforms/InstCombine/pr150338.ll b/llvm/test/Transforms/InstCombine/pr150338.ll
deleted file mode 100644
index 2ad454e..0000000
--- a/llvm/test/Transforms/InstCombine/pr150338.ll
+++ /dev/null
@@ -1,16 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -S -passes=instcombine < %s | FileCheck %s
-
-; Make sure this does not crash.
-define void @test(ptr %arg) {
-; CHECK-LABEL: define void @test(
-; CHECK-SAME: ptr [[ARG:%.*]]) {
-; CHECK-NEXT: store i1 true, ptr poison, align 1
-; CHECK-NEXT: ret void
-;
- %a = alloca i32
- store ptr %a, ptr %arg
- store i1 true, ptr poison
- call void @llvm.lifetime.end.p0(i64 4, ptr %a)
- ret void
-}
diff --git a/llvm/test/Transforms/InstCombine/unreachable-alloca-lifetime-markers.ll b/llvm/test/Transforms/InstCombine/unreachable-alloca-lifetime-markers.ll
new file mode 100644
index 0000000..ab744c62
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/unreachable-alloca-lifetime-markers.ll
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+; Make sure this does not crash.
+
+define void @pr150338(ptr %arg) {
+; CHECK-LABEL: define void @pr150338(
+; CHECK-SAME: ptr [[ARG:%.*]]) {
+; CHECK-NEXT: store i1 true, ptr poison, align 1
+; CHECK-NEXT: ret void
+;
+ %a = alloca i32
+ store ptr %a, ptr %arg
+ store i1 true, ptr poison
+ call void @llvm.lifetime.end.p0(i64 4, ptr %a)
+ ret void
+}
+
+define ptr @pr151119() {
+; CHECK-LABEL: define ptr @pr151119() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store i1 false, ptr poison, align 1
+; CHECK-NEXT: br i1 false, label %[[BB1:.*]], label %[[BB2:.*]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: br label %[[BB2]]
+; CHECK: [[BB2]]:
+; CHECK-NEXT: br label %[[BB1]]
+;
+entry:
+ %a = alloca i32, align 4
+ store i1 false, ptr poison
+ br i1 false, label %bb1, label %bb2
+
+bb1:
+ %phi1 = phi ptr [ null, %entry ], [ %phi2, %bb2 ]
+ call void @llvm.lifetime.start.p0(i64 4, ptr %a)
+ br label %bb2
+
+bb2:
+ %phi2 = phi ptr [ null, %entry ], [ %a, %bb1 ]
+ br label %bb1
+}
+
+define void @lifetime_poison() {
+; CHECK-LABEL: define void @lifetime_poison() {
+; CHECK-NEXT: ret void
+;
+ call void @llvm.lifetime.start.p0(i64 4, ptr poison)
+ call void @llvm.lifetime.end.p0(i64 4, ptr poison)
+ ret void
+}
diff --git a/llvm/test/tools/llvm-reduce/reduce-operands-alloca.ll b/llvm/test/tools/llvm-reduce/reduce-operands-alloca.ll
index 61c4618..b68f718 100644
--- a/llvm/test/tools/llvm-reduce/reduce-operands-alloca.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-operands-alloca.ll
@@ -67,3 +67,15 @@ define void @alloca_constexpr_elt() {
store i32 0, ptr %alloca
ret void
}
+
+; CHECK-LABEL: @alloca_lifetimes(
+; ZERO: call void @llvm.lifetime.start.p0(i64 4, ptr %alloca)
+; ONE: call void @llvm.lifetime.start.p0(i64 4, ptr %alloca)
+; POISON: call void @llvm.lifetime.start.p0(i64 4, ptr %alloca)
+define void @alloca_lifetimes() {
+ %alloca = alloca i32
+ call void @llvm.lifetime.start.p0(i64 4, ptr %alloca)
+ store i32 0, ptr %alloca
+ call void @llvm.lifetime.end.p0(i64 4, ptr %alloca)
+ ret void
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp
index 8b64467..79272fe 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp
@@ -73,6 +73,9 @@ static bool shouldReduceOperand(Use &Op) {
if (&CB->getCalledOperandUse() == &Op)
return false;
}
+ // lifetime intrinsic argument must be an alloca.
+ if (isa<LifetimeIntrinsic>(Op.getUser()))
+ return false;
return true;
}