aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-01-24 22:11:32 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-01-24 22:11:32 +0000
commit8b67a9f01da8048d4ed0a3fefc890e684526cd6a (patch)
tree3a477c21c59c764e17d8a794f3e240fc18bb740a
parentd225fe9c6746d065ebe184f96f2cfbafec025668 (diff)
Notes
-rw-r--r--clang/include/clang/AST/ASTConcept.h31
-rw-r--r--clang/include/clang/AST/ASTContext.h7
-rw-r--r--clang/include/clang/AST/ASTNodeTraverser.h4
-rw-r--r--clang/include/clang/AST/DeclCXX.h31
-rw-r--r--clang/include/clang/AST/DeclTemplate.h43
-rw-r--r--clang/include/clang/AST/ExprCXX.h94
-rw-r--r--clang/include/clang/AST/ExprConcepts.h540
-rw-r--r--clang/include/clang/AST/PropertiesBase.td2
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h39
-rw-r--r--clang/include/clang/AST/Stmt.h12
-rw-r--r--clang/include/clang/AST/StmtVisitor.h1
-rw-r--r--clang/include/clang/AST/TemplateBase.h7
-rw-r--r--clang/include/clang/AST/Type.h74
-rw-r--r--clang/include/clang/AST/TypeLoc.h138
-rw-r--r--clang/include/clang/AST/TypeProperties.td11
-rw-r--r--clang/include/clang/Basic/AttrDocs.td2
-rw-r--r--clang/include/clang/Basic/Builtins.def3
-rw-r--r--clang/include/clang/Basic/CodeGenOptions.def1
-rw-r--r--clang/include/clang/Basic/DeclNodes.td1
-rw-r--r--clang/include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--clang/include/clang/Basic/DiagnosticFrontendKinds.td3
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td42
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td68
-rw-r--r--clang/include/clang/Basic/LangOptions.def2
-rw-r--r--clang/include/clang/Basic/StmtNodes.td1
-rw-r--r--clang/include/clang/Basic/TokenKinds.def2
-rw-r--r--clang/include/clang/Driver/CC1Options.td8
-rw-r--r--clang/include/clang/Driver/Driver.h2
-rw-r--r--clang/include/clang/Driver/Options.td2
-rw-r--r--clang/include/clang/Parse/Parser.h25
-rw-r--r--clang/include/clang/Sema/DeclSpec.h81
-rw-r--r--clang/include/clang/Sema/ParsedTemplate.h24
-rw-r--r--clang/include/clang/Sema/Scope.h6
-rw-r--r--clang/include/clang/Sema/ScopeInfo.h20
-rw-r--r--clang/include/clang/Sema/Sema.h164
-rw-r--r--clang/include/clang/Sema/SemaConcept.h7
-rw-r--r--clang/include/clang/Sema/TemplateDeduction.h1
-rw-r--r--clang/include/clang/Serialization/ASTBitCodes.h4
-rw-r--r--clang/lib/AST/ASTConcept.cpp13
-rw-r--r--clang/lib/AST/ASTContext.cpp152
-rw-r--r--clang/lib/AST/ASTImporter.cpp18
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp26
-rw-r--r--clang/lib/AST/DeclBase.cpp2
-rw-r--r--clang/lib/AST/DeclCXX.cpp10
-rw-r--r--clang/lib/AST/DeclTemplate.cpp50
-rw-r--r--clang/lib/AST/Expr.cpp1
-rw-r--r--clang/lib/AST/ExprCXX.cpp79
-rw-r--r--clang/lib/AST/ExprClassification.cpp1
-rw-r--r--clang/lib/AST/ExprConcepts.cpp185
-rw-r--r--clang/lib/AST/ExprConstant.cpp5
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp2
-rw-r--r--clang/lib/AST/ODRHash.cpp7
-rw-r--r--clang/lib/AST/Stmt.cpp1
-rw-r--r--clang/lib/AST/StmtPrinter.cpp54
-rw-r--r--clang/lib/AST/StmtProfile.cpp49
-rw-r--r--clang/lib/AST/TemplateBase.cpp2
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp5
-rw-r--r--clang/lib/AST/Type.cpp36
-rw-r--r--clang/lib/AST/TypeLoc.cpp95
-rw-r--r--clang/lib/AST/TypePrinter.cpp29
-rw-r--r--clang/lib/Basic/IdentifierTable.cpp2
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp2
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp4
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp17
-rw-r--r--clang/lib/Driver/Compilation.cpp2
-rw-r--r--clang/lib/Driver/Job.cpp2
-rw-r--r--clang/lib/Driver/ToolChain.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp11
-rw-r--r--clang/lib/Driver/ToolChains/HIP.cpp23
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp2
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp7
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp4
-rw-r--r--clang/lib/Frontend/InitPreprocessor.cpp4
-rw-r--r--clang/lib/Headers/ppc_wrappers/emmintrin.h4
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp4
-rw-r--r--clang/lib/Parse/ParseDecl.cpp111
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp12
-rw-r--r--clang/lib/Parse/ParseExpr.cpp13
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp335
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp195
-rw-r--r--clang/lib/Parse/ParseTentative.cpp87
-rw-r--r--clang/lib/Parse/Parser.cpp33
-rw-r--r--clang/lib/Sema/DeclSpec.cpp9
-rw-r--r--clang/lib/Sema/Sema.cpp34
-rw-r--r--clang/lib/Sema/SemaConcept.cpp280
-rw-r--r--clang/lib/Sema/SemaDecl.cpp41
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp4
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp47
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--clang/lib/Sema/SemaExpr.cpp13
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp217
-rw-r--r--clang/lib/Sema/SemaLambda.cpp3
-rw-r--r--clang/lib/Sema/SemaLookup.cpp4
-rw-r--r--clang/lib/Sema/SemaStmt.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp338
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp127
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp250
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp28
-rw-r--r--clang/lib/Sema/SemaType.cpp235
-rw-r--r--clang/lib/Sema/TreeTransform.h357
-rw-r--r--clang/lib/Serialization/ASTCommon.cpp1
-rw-r--r--clang/lib/Serialization/ASTReader.cpp11
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp29
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp162
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp13
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp9
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp105
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--clang/tools/driver/driver.cpp22
-rw-r--r--libcxx/include/__config5
-rw-r--r--libcxx/include/__threading_support2
-rw-r--r--lld/COFF/InputFiles.cpp11
-rw-r--r--lld/ELF/Arch/PPC.cpp1
-rw-r--r--lld/ELF/Arch/PPC64.cpp1
-rw-r--r--lld/ELF/Arch/RISCV.cpp9
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/Driver.cpp7
-rw-r--r--lld/ELF/Relocations.cpp8
-rw-r--r--lld/ELF/Symbols.cpp6
-rw-r--r--lld/ELF/Target.cpp2
-rw-r--r--lld/ELF/Writer.cpp4
-rw-r--r--llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def2
-rw-r--r--llvm/include/llvm/CodeGen/AsmPrinter.h6
-rw-r--r--llvm/include/llvm/MC/MCAsmBackend.h8
-rw-r--r--llvm/include/llvm/MC/MCFixupKindInfo.h5
-rw-r--r--llvm/include/llvm/Target/Target.td4
-rw-r--r--llvm/include/llvm/Transforms/Utils/SizeOpts.h16
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp35
-rw-r--r--llvm/lib/CodeGen/CodeGenPrepare.cpp1
-rw-r--r--llvm/lib/CodeGen/PatchableFunction.cpp11
-rw-r--r--llvm/lib/CodeGen/StackColoring.cpp19
-rw-r--r--llvm/lib/CodeGen/TargetPassConfig.cpp12
-rw-r--r--llvm/lib/IR/Verifier.cpp21
-rw-r--r--llvm/lib/MC/MCAssembler.cpp7
-rw-r--r--llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp3
-rw-r--r--llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp13
-rw-r--r--llvm/lib/Target/ARM/ARMMCInstLower.cpp5
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp97
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h14
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp69
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h7
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.cpp4
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp7
-rw-r--r--llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp18
145 files changed, 4899 insertions, 1094 deletions
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index 896d857d8c96..30c4706d2a15 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -22,10 +22,25 @@
#include <utility>
namespace clang {
class ConceptDecl;
+class ConceptSpecializationExpr;
+
+/// The result of a constraint satisfaction check, containing the necessary
+/// information to diagnose an unsatisfied constraint.
+class ConstraintSatisfaction : public llvm::FoldingSetNode {
+ // The template-like entity that 'owns' the constraint checked here (can be a
+ // constrained entity or a concept).
+ NamedDecl *ConstraintOwner = nullptr;
+ llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
+
+public:
+
+ ConstraintSatisfaction() = default;
+
+ ConstraintSatisfaction(NamedDecl *ConstraintOwner,
+ ArrayRef<TemplateArgument> TemplateArgs) :
+ ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
+ TemplateArgs.end()) { }
-/// \brief The result of a constraint satisfaction check, containing the
-/// necessary information to diagnose an unsatisfied constraint.
-struct ConstraintSatisfaction {
using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
@@ -37,9 +52,13 @@ struct ConstraintSatisfaction {
/// invalid expression.
llvm::SmallVector<std::pair<const Expr *, Detail>, 4> Details;
- // This can leak if used in an AST node, use ASTConstraintSatisfaction
- // instead.
- void *operator new(size_t bytes, ASTContext &C) = delete;
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
+ Profile(ID, C, ConstraintOwner, TemplateArgs);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
+ NamedDecl *ConstraintOwner,
+ ArrayRef<TemplateArgument> TemplateArgs);
};
/// Pairs of unsatisfied atomic constraint expressions along with the
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index fb269cef1ce8..f8403cf13c4a 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -88,6 +88,7 @@ class AtomicExpr;
class BlockExpr;
class BuiltinTemplateDecl;
class CharUnits;
+class ConceptDecl;
class CXXABI;
class CXXConstructorDecl;
class CXXMethodDecl;
@@ -211,7 +212,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
mutable llvm::FoldingSet<DependentUnaryTransformType>
DependentUnaryTransformTypes;
- mutable llvm::FoldingSet<AutoType> AutoTypes;
+ mutable llvm::ContextualFoldingSet<AutoType, ASTContext&> AutoTypes;
mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
DeducedTemplateSpecializationTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
@@ -1542,7 +1543,9 @@ public:
/// C++11 deduced auto type.
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
- bool IsDependent, bool IsPack = false) const;
+ bool IsDependent, bool IsPack = false,
+ ConceptDecl *TypeConstraintConcept = nullptr,
+ ArrayRef<TemplateArgument> TypeConstraintArgs ={}) const;
/// C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index e0ebb020e697..9ebf64a12af5 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -548,8 +548,8 @@ public:
}
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
- if (const auto *TC = D->getPlaceholderTypeConstraint())
- Visit(TC->getImmediatelyDeclaredConstraint());
+ if (const auto *E = D->getPlaceholderTypeConstraint())
+ Visit(E);
if (D->hasDefaultArgument())
Visit(D->getDefaultArgument(), SourceRange(),
D->getDefaultArgStorage().getInheritedFrom(),
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index b716ea453a5a..2e8e31dbf4c7 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1893,6 +1893,37 @@ public:
static bool classofKind(Kind K) { return K == CXXDeductionGuide; }
};
+/// \brief Represents the body of a requires-expression.
+///
+/// This decl exists merely to serve as the DeclContext for the local
+/// parameters of the requires expression as well as other declarations inside
+/// it.
+///
+/// \code
+/// template<typename T> requires requires (T t) { {t++} -> regular; }
+/// \endcode
+///
+/// In this example, a RequiresExpr object will be generated for the expression,
+/// and a RequiresExprBodyDecl will be created to hold the parameter t and the
+/// template argument list imposed by the compound requirement.
+class RequiresExprBodyDecl : public Decl, public DeclContext {
+ RequiresExprBodyDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc)
+ : Decl(RequiresExprBody, DC, StartLoc), DeclContext(RequiresExprBody) {}
+
+public:
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+
+ static RequiresExprBodyDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc);
+
+ static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == RequiresExprBody; }
+};
+
/// Represents a static or instance method of a struct/union/class.
///
/// In the terminology of the C++ Standard, these are the (static and
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 7a55d04a0f35..7a9f623d8152 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -1102,6 +1102,17 @@ public:
/// template.
ArrayRef<TemplateArgument> getInjectedTemplateArgs();
+ /// Return whether this function template is an abbreviated function template,
+ /// e.g. `void foo(auto x)` or `template<typename T> void foo(auto x)`
+ bool isAbbreviated() const {
+ // Since the invented template parameters generated from 'auto' parameters
+ // are either appended to the end of the explicit template parameter list or
+ // form a new template paramter list, we can simply observe the last
+ // parameter to determine if such a thing happened.
+ const TemplateParameterList *TPL = getTemplateParameters();
+ return TPL->getParam(TPL->size() - 1)->isImplicit();
+ }
+
/// Merge \p Prev with our RedeclarableTemplateDecl::Common.
void mergePrevDecl(FunctionTemplateDecl *Prev);
@@ -1215,7 +1226,6 @@ public:
bool ParameterPack,
bool HasTypeConstraint = false,
Optional<unsigned> NumExpanded = None);
-
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
unsigned ID);
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
@@ -1374,7 +1384,8 @@ class NonTypeTemplateParmDecl final
: public DeclaratorDecl,
protected TemplateParmPosition,
private llvm::TrailingObjects<NonTypeTemplateParmDecl,
- std::pair<QualType, TypeSourceInfo *>> {
+ std::pair<QualType, TypeSourceInfo *>,
+ Expr *> {
friend class ASTDeclReader;
friend TrailingObjects;
@@ -1429,10 +1440,12 @@ public:
ArrayRef<TypeSourceInfo *> ExpandedTInfos);
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
- unsigned ID);
+ unsigned ID,
+ bool HasTypeConstraint);
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
- unsigned NumExpandedTypes);
+ unsigned NumExpandedTypes,
+ bool HasTypeConstraint);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::setDepth;
@@ -1543,20 +1556,22 @@ public:
return TypesAndInfos[I].second;
}
- /// Return the type-constraint in the placeholder type of this non-type
+ /// Return the constraint introduced by the placeholder type of this non-type
/// template parameter (if any).
- TypeConstraint *getPlaceholderTypeConstraint() const {
- // TODO: Concepts: Implement once we have actual placeholders with type
- // constraints.
- return nullptr;
+ Expr *getPlaceholderTypeConstraint() const {
+ return hasPlaceholderTypeConstraint() ? *getTrailingObjects<Expr *>() :
+ nullptr;
+ }
+
+ void setPlaceholderTypeConstraint(Expr *E) {
+ *getTrailingObjects<Expr *>() = E;
}
/// Determine whether this non-type template parameter's type has a
/// placeholder with a type-constraint.
bool hasPlaceholderTypeConstraint() const {
- // TODO: Concepts: Implement once we have actual placeholders with type
- // constraints.
- return false;
+ auto *AT = getType()->getContainedAutoType();
+ return AT && AT->isConstrained();
}
/// \brief Get the associated-constraints of this template parameter.
@@ -1566,8 +1581,8 @@ public:
/// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
/// concepts APIs that accept an ArrayRef of constraint expressions.
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
- if (TypeConstraint *TC = getPlaceholderTypeConstraint())
- AC.push_back(TC->getImmediatelyDeclaredConstraint());
+ if (Expr *E = getPlaceholderTypeConstraint())
+ AC.push_back(E);
}
// Implement isa/cast/dyncast/etc.
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 2c29409e0ca5..cea360d12e91 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_AST_EXPRCXX_H
#define LLVM_CLANG_AST_EXPRCXX_H
-#include "clang/AST/ASTConcept.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -4836,99 +4835,6 @@ public:
}
};
-/// \brief Represents the specialization of a concept - evaluates to a prvalue
-/// of type bool.
-///
-/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
-/// specialization of a concept results in a prvalue of type bool.
-class ConceptSpecializationExpr final : public Expr, public ConceptReference,
- private llvm::TrailingObjects<ConceptSpecializationExpr,
- TemplateArgument> {
- friend class ASTStmtReader;
- friend TrailingObjects;
-public:
- using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
-
-protected:
- /// \brief The number of template arguments in the tail-allocated list of
- /// converted template arguments.
- unsigned NumTemplateArgs;
-
- /// \brief Information about the satisfaction of the named concept with the
- /// given arguments. If this expression is value dependent, this is to be
- /// ignored.
- ASTConstraintSatisfaction *Satisfaction;
-
- ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc,
- DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction);
-
- ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
-
-public:
-
- static ConceptSpecializationExpr *
- Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction);
-
- static ConceptSpecializationExpr *
- Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
-
- ArrayRef<TemplateArgument> getTemplateArguments() const {
- return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
- NumTemplateArgs);
- }
-
- /// \brief Set new template arguments for this concept specialization.
- void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
-
- /// \brief Whether or not the concept with the given arguments was satisfied
- /// when the expression was created.
- /// The expression must not be dependent.
- bool isSatisfied() const {
- assert(!isValueDependent()
- && "isSatisfied called on a dependent ConceptSpecializationExpr");
- return Satisfaction->IsSatisfied;
- }
-
- /// \brief Get elaborated satisfaction info about the template arguments'
- /// satisfaction of the named concept.
- /// The expression must not be dependent.
- const ASTConstraintSatisfaction &getSatisfaction() const {
- assert(!isValueDependent()
- && "getSatisfaction called on dependent ConceptSpecializationExpr");
- return *Satisfaction;
- }
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ConceptSpecializationExprClass;
- }
-
- SourceLocation getBeginLoc() const LLVM_READONLY {
- return ConceptName.getBeginLoc();
- }
-
- SourceLocation getEndLoc() const LLVM_READONLY {
- return ArgsAsWritten->RAngleLoc;
- }
-
- // Iterators
- child_range children() {
- return child_range(child_iterator(), child_iterator());
- }
- const_child_range children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
- }
-};
-
} // namespace clang
#endif // LLVM_CLANG_AST_EXPRCXX_H
diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h
new file mode 100644
index 000000000000..2a64326e8604
--- /dev/null
+++ b/clang/include/clang/AST/ExprConcepts.h
@@ -0,0 +1,540 @@
+//===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Defines Expressions and AST nodes for C++2a concepts.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
+#define LLVM_CLANG_AST_EXPRCONCEPTS_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConcept.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/TrailingObjects.h"
+#include <utility>
+#include <string>
+
+namespace clang {
+class ASTStmtReader;
+class ASTStmtWriter;
+
+/// \brief Represents the specialization of a concept - evaluates to a prvalue
+/// of type bool.
+///
+/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
+/// specialization of a concept results in a prvalue of type bool.
+class ConceptSpecializationExpr final : public Expr, public ConceptReference,
+ private llvm::TrailingObjects<ConceptSpecializationExpr,
+ TemplateArgument> {
+ friend class ASTStmtReader;
+ friend TrailingObjects;
+public:
+ using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
+
+protected:
+ /// \brief The number of template arguments in the tail-allocated list of
+ /// converted template arguments.
+ unsigned NumTemplateArgs;
+
+ /// \brief Information about the satisfaction of the named concept with the
+ /// given arguments. If this expression is value dependent, this is to be
+ /// ignored.
+ ASTConstraintSatisfaction *Satisfaction;
+
+ ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc,
+ DeclarationNameInfo ConceptNameInfo,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction);
+
+ ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
+
+public:
+
+ static ConceptSpecializationExpr *
+ Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction);
+
+ static ConceptSpecializationExpr *
+ Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
+
+ ArrayRef<TemplateArgument> getTemplateArguments() const {
+ return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
+ NumTemplateArgs);
+ }
+
+ /// \brief Set new template arguments for this concept specialization.
+ void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
+
+ /// \brief Whether or not the concept with the given arguments was satisfied
+ /// when the expression was created.
+ /// The expression must not be dependent.
+ bool isSatisfied() const {
+ assert(!isValueDependent()
+ && "isSatisfied called on a dependent ConceptSpecializationExpr");
+ return Satisfaction->IsSatisfied;
+ }
+
+ /// \brief Get elaborated satisfaction info about the template arguments'
+ /// satisfaction of the named concept.
+ /// The expression must not be dependent.
+ const ASTConstraintSatisfaction &getSatisfaction() const {
+ assert(!isValueDependent()
+ && "getSatisfaction called on dependent ConceptSpecializationExpr");
+ return *Satisfaction;
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ConceptSpecializationExprClass;
+ }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY {
+ return ConceptName.getBeginLoc();
+ }
+
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return ArgsAsWritten->RAngleLoc;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+};
+
+namespace concepts {
+
+/// \brief A static requirement that can be used in a requires-expression to
+/// check properties of types and expression.
+class Requirement {
+public:
+ // Note - simple and compound requirements are both represented by the same
+ // class (ExprRequirement).
+ enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
+private:
+ const RequirementKind Kind;
+ bool Dependent : 1;
+ bool ContainsUnexpandedParameterPack : 1;
+ bool Satisfied : 1;
+public:
+ struct SubstitutionDiagnostic {
+ StringRef SubstitutedEntity;
+ // FIXME: Store diagnostics semantically and not as prerendered strings.
+ // Fixing this probably requires serialization of PartialDiagnostic
+ // objects.
+ SourceLocation DiagLoc;
+ StringRef DiagMessage;
+ };
+
+ Requirement(RequirementKind Kind, bool IsDependent,
+ bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
+ Kind(Kind), Dependent(IsDependent),
+ ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
+ Satisfied(IsSatisfied) {}
+
+ RequirementKind getKind() const { return Kind; }
+
+ bool isSatisfied() const {
+ assert(!Dependent &&
+ "isSatisfied can only be called on non-dependent requirements.");
+ return Satisfied;
+ }
+
+ void setSatisfied(bool IsSatisfied) {
+ assert(!Dependent &&
+ "setSatisfied can only be called on non-dependent requirements.");
+ Satisfied = IsSatisfied;
+ }
+
+ void setDependent(bool IsDependent) { Dependent = IsDependent; }
+ bool isDependent() const { return Dependent; }
+
+ void setContainsUnexpandedParameterPack(bool Contains) {
+ ContainsUnexpandedParameterPack = Contains;
+ }
+ bool containsUnexpandedParameterPack() const {
+ return ContainsUnexpandedParameterPack;
+ }
+};
+
+/// \brief A requires-expression requirement which queries the existence of a
+/// type name or type template specialization ('type' requirements).
+class TypeRequirement : public Requirement {
+public:
+ enum SatisfactionStatus {
+ SS_Dependent,
+ SS_SubstitutionFailure,
+ SS_Satisfied
+ };
+private:
+ llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
+ SatisfactionStatus Status;
+public:
+ friend ASTStmtReader;
+ friend ASTStmtWriter;
+
+ /// \brief Construct a type requirement from a type. If the given type is not
+ /// dependent, this indicates that the type exists and the requirement will be
+ /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
+ /// used.
+ TypeRequirement(TypeSourceInfo *T);
+
+ /// \brief Construct a type requirement when the nested name specifier is
+ /// invalid due to a bad substitution. The requirement is unsatisfied.
+ TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
+ Requirement(RK_Type, false, false, false), Value(Diagnostic),
+ Status(SS_SubstitutionFailure) {}
+
+ SatisfactionStatus getSatisfactionStatus() const { return Status; }
+ void setSatisfactionStatus(SatisfactionStatus Status) {
+ this->Status = Status;
+ }
+
+ bool isSubstitutionFailure() const {
+ return Status == SS_SubstitutionFailure;
+ }
+
+ SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
+ assert(Status == SS_SubstitutionFailure &&
+ "Attempted to get substitution diagnostic when there has been no "
+ "substitution failure.");
+ return Value.get<SubstitutionDiagnostic *>();
+ }
+
+ TypeSourceInfo *getType() const {
+ assert(!isSubstitutionFailure() &&
+ "Attempted to get type when there has been a substitution failure.");
+ return Value.get<TypeSourceInfo *>();
+ }
+
+ static bool classof(const Requirement *R) {
+ return R->getKind() == RK_Type;
+ }
+};
+
+/// \brief A requires-expression requirement which queries the validity and
+/// properties of an expression ('simple' and 'compound' requirements).
+class ExprRequirement : public Requirement {
+public:
+ enum SatisfactionStatus {
+ SS_Dependent,
+ SS_ExprSubstitutionFailure,
+ SS_NoexceptNotMet,
+ SS_TypeRequirementSubstitutionFailure,
+ SS_ConstraintsNotSatisfied,
+ SS_Satisfied
+ };
+ class ReturnTypeRequirement {
+ llvm::PointerIntPair<
+ llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
+ 1, bool>
+ TypeConstraintInfo;
+ public:
+ friend ASTStmtReader;
+ friend ASTStmtWriter;
+
+ /// \brief No return type requirement was specified.
+ ReturnTypeRequirement() : TypeConstraintInfo(nullptr, 0) {}
+
+ /// \brief A return type requirement was specified but it was a
+ /// substitution failure.
+ ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
+ TypeConstraintInfo(SubstDiag, 0) {}
+
+ /// \brief A 'type constraint' style return type requirement.
+ /// \param TPL an invented template parameter list containing a single
+ /// type parameter with a type-constraint.
+ // TODO: Can we maybe not save the whole template parameter list and just
+ // the type constraint? Saving the whole TPL makes it easier to handle in
+ // serialization but is less elegant.
+ ReturnTypeRequirement(TemplateParameterList *TPL);
+
+ bool isDependent() const {
+ return TypeConstraintInfo.getInt();
+ }
+
+ bool containsUnexpandedParameterPack() const {
+ if (!isTypeConstraint())
+ return false;
+ return getTypeConstraintTemplateParameterList()
+ ->containsUnexpandedParameterPack();
+ }
+
+ bool isEmpty() const {
+ return TypeConstraintInfo.getPointer().isNull();
+ }
+
+ bool isSubstitutionFailure() const {
+ return !isEmpty() &&
+ TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
+ }
+
+ bool isTypeConstraint() const {
+ return !isEmpty() &&
+ TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
+ }
+
+ SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
+ assert(isSubstitutionFailure());
+ return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
+ }
+
+ const TypeConstraint *getTypeConstraint() const;
+
+ TemplateParameterList *getTypeConstraintTemplateParameterList() const {
+ assert(isTypeConstraint());
+ return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
+ }
+ };
+private:
+ llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
+ SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
+ ReturnTypeRequirement TypeReq;
+ ConceptSpecializationExpr *SubstitutedConstraintExpr;
+ SatisfactionStatus Status;
+public:
+ friend ASTStmtReader;
+ friend ASTStmtWriter;
+
+ /// \brief Construct a compound requirement.
+ /// \param E the expression which is checked by this requirement.
+ /// \param IsSimple whether this was a simple requirement in source.
+ /// \param NoexceptLoc the location of the noexcept keyword, if it was
+ /// specified, otherwise an empty location.
+ /// \param Req the requirement for the type of the checked expression.
+ /// \param Status the satisfaction status of this requirement.
+ ExprRequirement(
+ Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ ReturnTypeRequirement Req, SatisfactionStatus Status,
+ ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
+
+ /// \brief Construct a compound requirement whose expression was a
+ /// substitution failure. The requirement is not satisfied.
+ /// \param E the diagnostic emitted while instantiating the original
+ /// expression.
+ /// \param IsSimple whether this was a simple requirement in source.
+ /// \param NoexceptLoc the location of the noexcept keyword, if it was
+ /// specified, otherwise an empty location.
+ /// \param Req the requirement for the type of the checked expression (omit
+ /// if no requirement was specified).
+ ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
+ SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
+
+ bool isSimple() const { return getKind() == RK_Simple; }
+ bool isCompound() const { return getKind() == RK_Compound; }
+
+ bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
+ SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
+
+ SatisfactionStatus getSatisfactionStatus() const { return Status; }
+
+ bool isExprSubstitutionFailure() const {
+ return Status == SS_ExprSubstitutionFailure;
+ }
+
+ const ReturnTypeRequirement &getReturnTypeRequirement() const {
+ return TypeReq;
+ }
+
+ ConceptSpecializationExpr *
+ getReturnTypeRequirementSubstitutedConstraintExpr() const {
+ assert(Status >= SS_TypeRequirementSubstitutionFailure);
+ return SubstitutedConstraintExpr;
+ }
+
+ SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
+ assert(isExprSubstitutionFailure() &&
+ "Attempted to get expression substitution diagnostic when there has "
+ "been no expression substitution failure");
+ return Value.get<SubstitutionDiagnostic *>();
+ }
+
+ Expr *getExpr() const {
+ assert(!isExprSubstitutionFailure() &&
+ "ExprRequirement has no expression because there has been a "
+ "substitution failure.");
+ return Value.get<Expr *>();
+ }
+
+ static bool classof(const Requirement *R) {
+ return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
+ }
+};
+
+/// \brief A requires-expression requirement which is satisfied when a general
+/// constraint expression is satisfied ('nested' requirements).
+class NestedRequirement : public Requirement {
+ llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
+ const ASTConstraintSatisfaction *Satisfaction = nullptr;
+
+public:
+ friend ASTStmtReader;
+ friend ASTStmtWriter;
+
+ NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
+ Requirement(RK_Nested, /*Dependent=*/false,
+ /*ContainsUnexpandedParameterPack*/false,
+ /*Satisfied=*/false), Value(SubstDiag) {}
+
+ NestedRequirement(Expr *Constraint) :
+ Requirement(RK_Nested, /*Dependent=*/true,
+ Constraint->containsUnexpandedParameterPack()),
+ Value(Constraint) {
+ assert(Constraint->isInstantiationDependent() &&
+ "Nested requirement with non-dependent constraint must be "
+ "constructed with a ConstraintSatisfaction object");
+ }
+
+ NestedRequirement(ASTContext &C, Expr *Constraint,
+ const ConstraintSatisfaction &Satisfaction) :
+ Requirement(RK_Nested, Constraint->isInstantiationDependent(),
+ Constraint->containsUnexpandedParameterPack(),
+ Satisfaction.IsSatisfied),
+ Value(Constraint),
+ Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
+
+ bool isSubstitutionFailure() const {
+ return Value.is<SubstitutionDiagnostic *>();
+ }
+
+ SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
+ assert(isSubstitutionFailure() &&
+ "getSubstitutionDiagnostic() may not be called when there was no "
+ "substitution failure.");
+ return Value.get<SubstitutionDiagnostic *>();
+ }
+
+ Expr *getConstraintExpr() const {
+ assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
+ "on nested requirements with "
+ "substitution failures.");
+ return Value.get<Expr *>();
+ }
+
+ const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
+ assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
+ "called on nested requirements with "
+ "substitution failures.");
+ return *Satisfaction;
+ }
+
+ static bool classof(const Requirement *R) {
+ return R->getKind() == RK_Nested;
+ }
+};
+
+} // namespace concepts
+
+/// C++2a [expr.prim.req]:
+/// A requires-expression provides a concise way to express requirements on
+/// template arguments. A requirement is one that can be checked by name
+/// lookup (6.4) or by checking properties of types and expressions.
+/// [...]
+/// A requires-expression is a prvalue of type bool [...]
+class RequiresExpr final : public Expr,
+ llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
+ concepts::Requirement *> {
+ friend TrailingObjects;
+ friend class ASTStmtReader;
+
+ unsigned NumLocalParameters;
+ unsigned NumRequirements;
+ RequiresExprBodyDecl *Body;
+ SourceLocation RBraceLoc;
+
+ unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
+ return NumLocalParameters;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
+ return NumRequirements;
+ }
+
+ RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc);
+ RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
+ unsigned NumRequirements);
+
+public:
+ static RequiresExpr *
+ Create(ASTContext &C, SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc);
+ static RequiresExpr *
+ Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
+ unsigned NumRequirements);
+
+ ArrayRef<ParmVarDecl *> getLocalParameters() const {
+ return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
+ }
+
+ RequiresExprBodyDecl *getBody() const { return Body; }
+
+ ArrayRef<concepts::Requirement *> getRequirements() const {
+ return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
+ }
+
+ /// \brief Whether or not the requires clause is satisfied.
+ /// The expression must not be dependent.
+ bool isSatisfied() const {
+ assert(!isValueDependent()
+ && "isSatisfied called on a dependent RequiresExpr");
+ return RequiresExprBits.IsSatisfied;
+ }
+
+ SourceLocation getRequiresKWLoc() const {
+ return RequiresExprBits.RequiresKWLoc;
+ }
+
+ SourceLocation getRBraceLoc() const { return RBraceLoc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == RequiresExprClass;
+ }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY {
+ return RequiresExprBits.RequiresKWLoc;
+ }
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return RBraceLoc;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_EXPRCONCEPTS_H \ No newline at end of file
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 9aacdb9fee36..ba0f237a3bc3 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -99,6 +99,8 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
SubclassPropertyType<"TagDecl", DeclRef>;
def TemplateDeclRef :
SubclassPropertyType<"TemplateDecl", DeclRef>;
+ def ConceptDeclRef :
+ SubclassPropertyType<"ConceptDecl", DeclRef>;
def TemplateTypeParmDeclRef :
SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
def TemplateTemplateParmDeclRef :
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index f8ab8e451d8c..86521d82c6ff 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -23,6 +23,7 @@
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
@@ -1039,7 +1040,13 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
TRY_TO(TraverseType(T->getUnderlyingType()));
})
-DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
+DEF_TRAVERSE_TYPE(AutoType, {
+ TRY_TO(TraverseType(T->getDeducedType()));
+ if (T->isConstrained()) {
+ TRY_TO(TraverseDecl(T->getTypeConstraintConcept()));
+ TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
+ }
+})
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
TRY_TO(TraverseTemplateName(T->getTemplateName()));
TRY_TO(TraverseType(T->getDeducedType()));
@@ -1286,6 +1293,12 @@ DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
DEF_TRAVERSE_TYPELOC(AutoType, {
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
+ if (TL.isConstrained()) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo()));
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
+ TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
+ }
})
DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
@@ -2138,6 +2151,8 @@ DEF_TRAVERSE_DECL(ParmVarDecl, {
TRY_TO(TraverseStmt(D->getDefaultArg()));
})
+DEF_TRAVERSE_DECL(RequiresExprBodyDecl, {})
+
#undef DEF_TRAVERSE_DECL
// ----------------- Stmt traversal -----------------
@@ -2709,6 +2724,28 @@ DEF_TRAVERSE_STMT(ConceptSpecializationExpr, {
TRY_TO(TraverseConceptReference(*S));
})
+DEF_TRAVERSE_STMT(RequiresExpr, {
+ TRY_TO(TraverseDecl(S->getBody()));
+ for (ParmVarDecl *Parm : S->getLocalParameters())
+ TRY_TO(TraverseDecl(Parm));
+ for (concepts::Requirement *Req : S->getRequirements())
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) {
+ if (!TypeReq->isSubstitutionFailure())
+ TRY_TO(TraverseTypeLoc(TypeReq->getType()->getTypeLoc()));
+ } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) {
+ if (!ExprReq->isExprSubstitutionFailure())
+ TRY_TO(TraverseStmt(ExprReq->getExpr()));
+ auto &RetReq = ExprReq->getReturnTypeRequirement();
+ if (RetReq.isTypeConstraint())
+ TRY_TO(TraverseTemplateParameterListHelper(
+ RetReq.getTypeConstraintTemplateParameterList()));
+ } else {
+ auto *NestedReq = cast<concepts::NestedRequirement>(Req);
+ if (!NestedReq->isSubstitutionFailure())
+ TRY_TO(TraverseStmt(NestedReq->getConstraintExpr()));
+ }
+})
+
// These literals (all of them) do not need any action.
DEF_TRAVERSE_STMT(IntegerLiteral, {})
DEF_TRAVERSE_STMT(FixedPointLiteral, {})
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index eaacb1a5b252..253b76941991 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -910,6 +910,17 @@ protected:
SourceLocation NameLoc;
};
+ class RequiresExprBitfields {
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+ friend class RequiresExpr;
+
+ unsigned : NumExprBits;
+
+ unsigned IsSatisfied : 1;
+ SourceLocation RequiresKWLoc;
+ };
+
//===--- C++ Coroutines TS bitfields classes ---===//
class CoawaitExprBitfields {
@@ -1008,6 +1019,7 @@ protected:
UnresolvedMemberExprBitfields UnresolvedMemberExprBits;
CXXNoexceptExprBitfields CXXNoexceptExprBits;
SubstNonTypeTemplateParmExprBitfields SubstNonTypeTemplateParmExprBits;
+ RequiresExprBitfields RequiresExprBits;
// C++ Coroutines TS expressions
CoawaitExprBitfields CoawaitBits;
diff --git a/clang/include/clang/AST/StmtVisitor.h b/clang/include/clang/AST/StmtVisitor.h
index d3be93d228cc..3e5155199eac 100644
--- a/clang/include/clang/AST/StmtVisitor.h
+++ b/clang/include/clang/AST/StmtVisitor.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_STMTVISITOR_H
#define LLVM_CLANG_AST_STMTVISITOR_H
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index 058a5bc0a067..93f7b62b8aea 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -637,7 +637,7 @@ public:
}
static const ASTTemplateArgumentListInfo *
- Create(ASTContext &C, const TemplateArgumentListInfo &List);
+ Create(const ASTContext &C, const TemplateArgumentListInfo &List);
};
/// Represents an explicit template argument list in C++, e.g.,
@@ -702,6 +702,11 @@ inline const TemplateArgument &
return getArgs()[Idx];
}
+inline const TemplateArgument &AutoType::getArg(unsigned Idx) const {
+ assert(Idx < getNumArgs() && "Template argument out of range");
+ return getArgs()[Idx];
+}
+
} // namespace clang
#endif // LLVM_CLANG_AST_TEMPLATEBASE_H
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index f5955c45fafc..abc8136653fa 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -58,6 +58,7 @@ namespace clang {
class ExtQuals;
class QualType;
+class ConceptDecl;
class TagDecl;
class Type;
@@ -1683,6 +1684,15 @@ protected:
/// Was this placeholder type spelled as 'auto', 'decltype(auto)',
/// or '__auto_type'? AutoTypeKeyword value.
unsigned Keyword : 2;
+
+ /// The number of template arguments in the type-constraints, which is
+ /// expected to be able to hold at least 1024 according to [implimits].
+ /// However as this limit is somewhat easy to hit with template
+ /// metaprogramming we'd prefer to keep it as large as possible.
+ /// At the moment it has been left as a non-bitfield since this type
+ /// safely fits in 64 bits as an unsigned, so there is no reason to
+ /// introduce the performance impact of a bitfield.
+ unsigned NumArgs;
};
class SubstTemplateTypeParmPackTypeBitfields {
@@ -4814,8 +4824,7 @@ public:
/// Common base class for placeholders for types that get replaced by
/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
-/// class template types, and (eventually) constrained type names from the C++
-/// Concepts TS.
+/// class template types, and constrained type names.
///
/// These types are usually a placeholder for a deduced type. However, before
/// the initializer is attached, or (usually) if the initializer is
@@ -4860,18 +4869,50 @@ public:
}
};
-/// Represents a C++11 auto or C++14 decltype(auto) type.
-class AutoType : public DeducedType, public llvm::FoldingSetNode {
+/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
+/// by a type-constraint.
+class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these
+ ConceptDecl *TypeConstraintConcept;
+
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
- bool IsDeducedAsDependent, bool IsDeducedAsPack)
- : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
- IsDeducedAsDependent, IsDeducedAsPack) {
- AutoTypeBits.Keyword = (unsigned)Keyword;
+ bool IsDeducedAsDependent, bool IsDeducedAsPack, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> TypeConstraintArgs);
+
+ const TemplateArgument *getArgBuffer() const {
+ return reinterpret_cast<const TemplateArgument*>(this+1);
+ }
+
+ TemplateArgument *getArgBuffer() {
+ return reinterpret_cast<TemplateArgument*>(this+1);
}
public:
+ /// Retrieve the template arguments.
+ const TemplateArgument *getArgs() const {
+ return getArgBuffer();
+ }
+
+ /// Retrieve the number of template arguments.
+ unsigned getNumArgs() const {
+ return AutoTypeBits.NumArgs;
+ }
+
+ const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
+
+ ArrayRef<TemplateArgument> getTypeConstraintArguments() const {
+ return {getArgs(), getNumArgs()};
+ }
+
+ ConceptDecl *getTypeConstraintConcept() const {
+ return TypeConstraintConcept;
+ }
+
+ bool isConstrained() const {
+ return TypeConstraintConcept != nullptr;
+ }
+
bool isDecltypeAuto() const {
return getKeyword() == AutoTypeKeyword::DecltypeAuto;
}
@@ -4880,18 +4921,15 @@ public:
return (AutoTypeKeyword)AutoTypeBits.Keyword;
}
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDeducedType(), getKeyword(), isDependentType(),
- containsUnexpandedParameterPack());
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
+ getTypeConstraintConcept(), getTypeConstraintArguments());
}
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
- AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) {
- ID.AddPointer(Deduced.getAsOpaquePtr());
- ID.AddInteger((unsigned)Keyword);
- ID.AddBoolean(IsDependent);
- ID.AddBoolean(IsPack);
- }
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Deduced, AutoTypeKeyword Keyword,
+ bool IsDependent, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> Arguments);
static bool classof(const Type *T) {
return T->getTypeClass() == Auto;
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index c3baaa3e4174..3fc53d823c37 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_AST_TYPELOC_H
#define LLVM_CLANG_AST_TYPELOC_H
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
@@ -34,6 +35,7 @@ namespace clang {
class Attr;
class ASTContext;
class CXXRecordDecl;
+class ConceptDecl;
class Expr;
class ObjCInterfaceDecl;
class ObjCProtocolDecl;
@@ -181,6 +183,11 @@ public:
/// AttributedTypeLoc, for those type attributes that behave as qualifiers
TypeLoc findExplicitQualifierLoc() const;
+ /// Get the typeloc of an AutoType whose type will be deduced for a variable
+ /// with an initializer of this type. This looks through declarators like
+ /// pointer types, but not through decltype or typedefs.
+ AutoTypeLoc getContainedAutoTypeLoc() const;
+
/// Initializes this to state that every location in this
/// type is the given location.
///
@@ -1923,8 +1930,137 @@ class DeducedTypeLoc
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DeducedTypeLoc,
DeducedType> {};
+struct AutoTypeLocInfo : TypeSpecLocInfo {
+ NestedNameSpecifierLoc NestedNameSpec;
+ SourceLocation TemplateKWLoc;
+ SourceLocation ConceptNameLoc;
+ NamedDecl *FoundDecl;
+ SourceLocation LAngleLoc;
+ SourceLocation RAngleLoc;
+};
+
class AutoTypeLoc
- : public InheritingConcreteTypeLoc<DeducedTypeLoc, AutoTypeLoc, AutoType> {
+ : public ConcreteTypeLoc<DeducedTypeLoc,
+ AutoTypeLoc,
+ AutoType,
+ AutoTypeLocInfo> {
+public:
+ AutoTypeKeyword getAutoKeyword() const {
+ return getTypePtr()->getKeyword();
+ }
+
+ bool isConstrained() const {
+ return getTypePtr()->isConstrained();
+ }
+
+ const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
+ return getLocalData()->NestedNameSpec;
+ }
+
+ void setNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ getLocalData()->NestedNameSpec = NNS;
+ }
+
+ SourceLocation getTemplateKWLoc() const {
+ return getLocalData()->TemplateKWLoc;
+ }
+
+ void setTemplateKWLoc(SourceLocation Loc) {
+ getLocalData()->TemplateKWLoc = Loc;
+ }
+
+ SourceLocation getConceptNameLoc() const {
+ return getLocalData()->ConceptNameLoc;
+ }
+
+ void setConceptNameLoc(SourceLocation Loc) {
+ getLocalData()->ConceptNameLoc = Loc;
+ }
+
+ NamedDecl *getFoundDecl() const {
+ return getLocalData()->FoundDecl;
+ }
+
+ void setFoundDecl(NamedDecl *D) {
+ getLocalData()->FoundDecl = D;
+ }
+
+ ConceptDecl *getNamedConcept() const {
+ return getTypePtr()->getTypeConstraintConcept();
+ }
+
+ DeclarationNameInfo getConceptNameInfo() const;
+
+ bool hasExplicitTemplateArgs() const {
+ return getLocalData()->LAngleLoc.isValid();
+ }
+
+ SourceLocation getLAngleLoc() const {
+ return this->getLocalData()->LAngleLoc;
+ }
+
+ void setLAngleLoc(SourceLocation Loc) {
+ this->getLocalData()->LAngleLoc = Loc;
+ }
+
+ SourceLocation getRAngleLoc() const {
+ return this->getLocalData()->RAngleLoc;
+ }
+
+ void setRAngleLoc(SourceLocation Loc) {
+ this->getLocalData()->RAngleLoc = Loc;
+ }
+
+ unsigned getNumArgs() const {
+ return getTypePtr()->getNumArgs();
+ }
+
+ void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
+ getArgInfos()[i] = AI;
+ }
+
+ TemplateArgumentLocInfo getArgLocInfo(unsigned i) const {
+ return getArgInfos()[i];
+ }
+
+ TemplateArgumentLoc getArgLoc(unsigned i) const {
+ return TemplateArgumentLoc(getTypePtr()->getTypeConstraintArguments()[i],
+ getArgLocInfo(i));
+ }
+
+ SourceRange getLocalSourceRange() const {
+ return{
+ isConstrained()
+ ? (getNestedNameSpecifierLoc()
+ ? getNestedNameSpecifierLoc().getBeginLoc()
+ : (getTemplateKWLoc().isValid()
+ ? getTemplateKWLoc()
+ : getConceptNameLoc()))
+ : getNameLoc(),
+ getNameLoc()
+ };
+ }
+
+ void copy(AutoTypeLoc Loc) {
+ unsigned size = getFullDataSize();
+ assert(size == Loc.getFullDataSize());
+ memcpy(Data, Loc.Data, size);
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc);
+
+ unsigned getExtraLocalDataSize() const {
+ return getNumArgs() * sizeof(TemplateArgumentLocInfo);
+ }
+
+ unsigned getExtraLocalDataAlignment() const {
+ return alignof(TemplateArgumentLocInfo);
+ }
+
+private:
+ TemplateArgumentLocInfo *getArgInfos() const {
+ return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData());
+ }
};
class DeducedTemplateSpecializationTypeLoc
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 4df2e2f77e2b..3cf56e5a5629 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -395,6 +395,13 @@ let Class = AutoType in {
def : Property<"keyword", AutoTypeKeyword> {
let Read = [{ node->getKeyword() }];
}
+ def : Property<"typeConstraintConcept", Optional<ConceptDeclRef>> {
+ let Read = [{ makeOptionalFromPointer(
+ const_cast<const ConceptDecl*>(node->getTypeConstraintConcept())) }];
+ }
+ def : Property<"typeConstraintArguments", Array<TemplateArgument>> {
+ let Read = [{ node->getTypeConstraintArguments() }];
+ }
// FIXME: better enumerated value
// Only really required when the deduced type is null
def : Property<"dependence", UInt32> {
@@ -406,7 +413,9 @@ let Class = AutoType in {
def : Creator<[{
return ctx.getAutoType(makeNullableFromOptional(deducedType), keyword,
/*isDependentWithoutDeducedType*/ dependence > 0,
- /*isPackWithoutDeducedType*/ dependence > 1);
+ /*isPackWithoutDeducedType*/ dependence > 1,
+ makePointerFromOptional(typeConstraintConcept),
+ typeConstraintArguments);
}]>;
}
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 03d36ae7ab32..7976d08a5258 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3995,8 +3995,6 @@ def PatchableFunctionEntryDocs : Documentation {
before the function entry and N-M NOPs after the function entry. This attribute
takes precedence over the command line option ``-fpatchable-function-entry=N,M``.
``M`` defaults to 0 if omitted.
-
-Currently, only M=0 is supported.
}];
}
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index d388afe7fae6..1a6c85ce2dd3 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -788,6 +788,9 @@ BUILTIN(__builtin_abort, "v", "Fnr")
BUILTIN(__builtin_index, "c*cC*i", "Fn")
BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
+// ignored glibc builtin, see https://sourceware.org/bugzilla/show_bug.cgi?id=25399
+BUILTIN(__warn_memset_zero_len, "v", "nU")
+
// Microsoft builtins. These are only active with -fms-extensions.
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__annotation, "wC*.","n", ALL_MS_LANGUAGES)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 50fc1836282f..1ecae98b13b1 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -111,6 +111,7 @@ CODEGENOPT(XRayAlwaysEmitTypedEvents , 1, 0)
VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200)
VALUE_CODEGENOPT(PatchableFunctionEntryCount , 32, 0) ///< Number of NOPs at function entry
+VALUE_CODEGENOPT(PatchableFunctionEntryOffset , 32, 0)
CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
CODEGENOPT(CallFEntry , 1, 0) ///< Set when -mfentry is enabled.
diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td
index c2c23237285b..d5bbc604819f 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -100,5 +100,6 @@ def OMPThreadPrivate : DeclNode<Decl>;
def OMPAllocate : DeclNode<Decl>;
def OMPRequires : DeclNode<Decl>;
def Empty : DeclNode<Decl>;
+def RequiresExprBody : DeclNode<Decl>, DeclContext;
def LifetimeExtendedTemporary : DeclNode<Decl>;
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 0fe14e4e05be..2da41bef2669 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -408,7 +408,7 @@ def err_drv_unsupported_indirect_jump_opt : Error<
def err_drv_unknown_indirect_jump_opt : Error<
"unknown '-mindirect-jump=' option '%0'">;
def err_drv_unsupported_fpatchable_function_entry_argument : Error<
- "the second argument of '-fpatchable-function-entry' must be 0 or omitted">;
+ "the second argument of '-fpatchable-function-entry' must be smaller than the first argument">;
def warn_drv_unable_to_find_directory_expected : Warning<
"unable to find %0 directory, expected to be in '%1'">,
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index a798b498d4e9..ed2092fb4c84 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -105,6 +105,9 @@ def err_fe_invalid_wchar_type
: Error<"invalid wchar_t type '%0'; must be one of 'char', 'short', 'int'">;
def err_fe_invalid_exception_model
: Error<"invalid exception model '%0' for target '%1'">;
+def warn_fe_concepts_ts_flag : Warning<
+ "-fconcepts-ts is deprecated - use '-std=c++2a' for Concepts support">,
+ InGroup<Deprecated>;
def warn_fe_serialized_diag_merge_failure : Warning<
"unable to merge a subprocess's serialized diagnostics">,
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index cc6a74ac3e6d..04b103e3087a 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -33,10 +33,6 @@ def err_asm_goto_cannot_have_output : Error<
let CategoryName = "Parse Issue" in {
-def warn_cxx2a_compat_explicit_bool : Warning<
- "this expression will be parsed as explicit(bool) in C++2a">,
- InGroup<CXX2aCompat>, DefaultIgnore;
-
def ext_empty_translation_unit : Extension<
"ISO C requires a translation unit to contain at least one declaration">,
InGroup<DiagGroup<"empty-translation-unit">>;
@@ -684,6 +680,15 @@ def err_ms_property_expected_comma_or_rparen : Error<
def err_ms_property_initializer : Error<
"property declaration cannot have an in-class initializer">;
+def warn_cxx2a_compat_explicit_bool : Warning<
+ "this expression will be parsed as explicit(bool) in C++2a">,
+ InGroup<CXX2aCompat>, DefaultIgnore;
+def warn_cxx17_compat_explicit_bool : Warning<
+ "explicit(bool) is incompatible with C++ standards before C++2a">,
+ InGroup<CXXPre2aCompat>, DefaultIgnore;
+def ext_explicit_bool : ExtWarn<"explicit(bool) is a C++2a extension">,
+ InGroup<CXX2a>;
+
/// C++ Templates
def err_expected_template : Error<"expected template">;
def err_unknown_template_name : Error<
@@ -739,6 +744,33 @@ def err_friend_explicit_instantiation : Error<
def err_explicit_instantiation_enum : Error<
"enumerations cannot be explicitly instantiated">;
def err_expected_template_parameter : Error<"expected template parameter">;
+def note_ill_formed_requires_expression_outside_template : Note<
+ "requires expression outside a template declaration may not contain invalid "
+ "types or expressions">;
+def err_empty_requires_expr : Error<
+ "a requires expression must contain at least one requirement">;
+def err_requires_expr_parameter_list_ellipsis : Error<
+ "varargs not allowed in requires expression">;
+def err_requires_expr_type_req_illegal_identifier : Error<
+ "expected identifier or template-id in type requirement">;
+def err_requires_expr_type_req_template_args_on_non_template : Error<
+ "template arguments provided for non-template '%0'">;
+def err_expected_semi_requirement : Error<
+ "expected ';' at end of requirement">;
+def err_requires_expr_missing_arrow : Error<
+ "expected '->' before expression type requirement">;
+def err_requires_expr_expected_type_constraint : Error<
+ "expected concept name with optional arguments">;
+def err_requires_expr_simple_requirement_noexcept : Error<
+ "'noexcept' can only be used in a compound requirement (with '{' '}' around "
+ "the expression)">;
+def err_requires_expr_simple_requirement_unexpected_tok : Error<
+ "unexpected %0 after expression; did you intend to use a compound "
+ "requirement (with '{' '}' around the expression)?">;
+def warn_requires_expr_in_simple_requirement : Warning<
+ "this requires expression will only be checked for syntactic validity; did "
+ "you intend to place it in a nested requirement? (add another 'requires' "
+ "before the expression)">, InGroup<DiagGroup<"requires-expression">>;
def err_missing_dependent_template_keyword : Error<
"use 'template' keyword to treat '%0' as a dependent template name">;
@@ -1339,6 +1371,8 @@ def err_concept_definition_not_identifier : Error<
def ext_concept_legacy_bool_keyword : ExtWarn<
"ISO C++2a does not permit the 'bool' keyword after 'concept'">,
InGroup<DiagGroup<"concepts-ts-compat">>;
+def err_placeholder_expected_auto_or_decltype_auto : Error<
+ "expected 'auto' or 'decltype(auto)' after concept name">;
}
} // end of Parser diagnostics
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7d8231d140e4..7636d04a34c3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2102,12 +2102,18 @@ def err_auto_not_allowed : Error<
"|in template argument|in typedef|in type alias|in function return type"
"|in conversion function type|here|in lambda parameter"
"|in type allocated by 'new'|in K&R-style function parameter"
- "|in template parameter|in friend declaration}1">;
+ "|in template parameter|in friend declaration|in function prototype that is "
+ "not a function declaration|in requires expression parameter}1">;
def err_dependent_deduced_tst : Error<
"typename specifier refers to "
"%select{class template|function template|variable template|alias template|"
"template template parameter|template}0 member in %1; "
"argument deduction not allowed here">;
+def err_deduced_tst : Error<
+ "typename specifier refers to "
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}0; argument deduction not allowed "
+ "here">;
def err_auto_not_allowed_var_inst : Error<
"'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
@@ -2590,25 +2596,65 @@ def note_constraints_not_satisfied : Note<
def note_substituted_constraint_expr_is_ill_formed : Note<
"because substituted constraint expression is ill-formed%0">;
def note_atomic_constraint_evaluated_to_false : Note<
- "%select{and |because }0'%1' evaluated to false">;
+ "%select{and|because}0 '%1' evaluated to false">;
def note_concept_specialization_constraint_evaluated_to_false : Note<
- "%select{and |because }0'%1' evaluated to false">;
+ "%select{and|because}0 '%1' evaluated to false">;
def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note<
- "%select{and |because }0%1 does not satisfy %2">;
+ "%select{and|because}0 %1 does not satisfy %2">;
def note_atomic_constraint_evaluated_to_false_elaborated : Note<
- "%select{and |because }0'%1' (%2 %3 %4) evaluated to false">;
+ "%select{and|because}0 '%1' (%2 %3 %4) evaluated to false">;
def err_constrained_virtual_method : Error<
"virtual function cannot have a requires clause">;
def err_trailing_requires_clause_on_deduction_guide : Error<
"deduction guide cannot have a requires clause">;
def err_reference_to_function_with_unsatisfied_constraints : Error<
"invalid reference to function %0: constraints not satisfied">;
+def note_requires_expr_ill_formed_expr : Note<
+ "expression is invalid: %0">;
+def note_requires_expr_no_implicit_conversion : Note<
+ "no implicit conversion exists between expression type %0 and expected type "
+ "%1">;
+def err_requires_expr_local_parameter_default_argument : Error<
+ "default arguments not allowed for parameters of a requires expression">;
+def err_requires_expr_parameter_referenced_in_evaluated_context : Error<
+ "constraint variable %0 cannot be used in an evaluated context">;
+def note_expr_requirement_expr_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid: %2">;
+def note_expr_requirement_expr_unknown_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid">;
+def note_expr_requirement_noexcept_not_met : Note<
+ "%select{and|because}0 '%1' may throw an exception">;
+def note_expr_requirement_type_requirement_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid: %2">;
+def note_expr_requirement_type_requirement_unknown_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid">;
+def note_expr_requirement_constraints_not_satisfied : Note<
+ "%select{and|because}0 type constraint '%1' was not satisfied:">;
+def note_expr_requirement_constraints_not_satisfied_simple : Note<
+ "%select{and|because}0 %1 does not satisfy %2:">;
+def note_type_requirement_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid: %2">;
+def note_type_requirement_unknown_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid">;
+def err_type_requirement_non_type_template : Error<
+ "'%0' refers to a %select{class template|function template|"
+ "variable template|alias template|template template parameter|template}1, "
+ "not a type template">;
+def err_type_requirement_no_such_type : Error<
+ "'%0' does not name a type">;
+def note_nested_requirement_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid: %2">;
+def note_nested_requirement_unknown_substitution_error : Note<
+ "%select{and|because}0 '%1' would be invalid">;
def note_ambiguous_atomic_constraints : Note<
"similar constraint expressions not considered equivalent; constraint "
"expressions cannot be considered equivalent unless they originate from the "
"same concept">;
def note_ambiguous_atomic_constraints_similar_expression : Note<
"similar constraint expression here">;
+def err_unsupported_placeholder_constraint : Error<
+ "constrained placeholder types other than simple 'auto' on non-type template "
+ "parameters not supported yet">;
def err_template_different_requires_clause : Error<
"requires clause differs in template redeclaration">;
@@ -2623,6 +2669,8 @@ def err_type_constraint_non_type_concept : Error<
def err_type_constraint_missing_arguments : Error<
"%0 requires more than 1 template argument; provide the remaining arguments "
"explicitly to use it here">;
+def err_placeholder_constraints_not_satisfied : Error<
+ "deduced type %0 does not satisfy %1">;
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
@@ -4588,6 +4636,8 @@ def note_template_type_alias_instantiation_here : Note<
"in instantiation of template type alias %0 requested here">;
def note_template_exception_spec_instantiation_here : Note<
"in instantiation of exception specification for %0 requested here">;
+def note_template_requirement_instantiation_here : Note<
+ "in instantiation of requirement here">;
def warn_var_template_missing : Warning<"instantiation of variable %q0 "
"required here, but no definition is available">,
InGroup<UndefinedVarTemplate>;
@@ -4623,6 +4673,8 @@ def note_template_default_arg_checking : Note<
"while checking a default template argument used here">;
def note_concept_specialization_here : Note<
"while checking the satisfaction of concept '%0' requested here">;
+def note_nested_requirement_here : Note<
+ "while checking the satisfaction of nested requirement requested here">;
def note_checking_constraints_for_template_id_here : Note<
"while checking constraint satisfaction for template '%0' required here">;
def note_checking_constraints_for_var_spec_id_here : Note<
@@ -4756,8 +4808,12 @@ def err_typename_nested_not_found_requirement : Error<
"declaration">;
def err_typename_nested_not_type : Error<
"typename specifier refers to non-type member %0 in %1">;
-def note_typename_refers_here : Note<
+def err_typename_not_type : Error<
+ "typename specifier refers to non-type %0">;
+def note_typename_member_refers_here : Note<
"referenced member %0 is declared here">;
+def note_typename_refers_here : Note<
+ "referenced %0 is declared here">;
def err_typename_missing : Error<
"missing 'typename' prior to dependent type name '%0%1'">;
def err_typename_missing_template : Error<
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 068f206f4484..3319a3123976 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -237,7 +237,7 @@ LANGOPT(SizedDeallocation , 1, 0, "sized deallocation")
LANGOPT(AlignedAllocation , 1, 0, "aligned allocation")
LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable")
LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'")
-LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts")
+LANGOPT(ConceptSatisfactionCaching , 1, 1, "enable satisfaction caching for C++2a Concepts")
BENIGN_LANGOPT(ModulesCodegen , 1, 0, "Modules code generation")
BENIGN_LANGOPT(ModulesDebugInfo , 1, 0, "Modules debug info")
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 294993298a18..41923cddc493 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -164,6 +164,7 @@ def CoyieldExpr : StmtNode<CoroutineSuspendExpr>;
// C++2a Concepts expressions
def ConceptSpecializationExpr : StmtNode<Expr>;
+def RequiresExpr : StmtNode<Expr>;
// Obj-C Expressions.
def ObjCStringLiteral : StmtNode<Expr>;
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index d58b0d987d71..fec029ae995e 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -373,7 +373,7 @@ CXX11_KEYWORD(nullptr , 0)
CXX11_KEYWORD(static_assert , KEYMSCOMPAT)
CXX11_KEYWORD(thread_local , 0)
-// C++2a / concepts TS keywords
+// C++2a keywords
CONCEPTS_KEYWORD(concept)
CONCEPTS_KEYWORD(requires)
diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td
index 1d550eb15ea8..9387285518de 100644
--- a/clang/include/clang/Driver/CC1Options.td
+++ b/clang/include/clang/Driver/CC1Options.td
@@ -372,6 +372,9 @@ def fsanitize_coverage_no_prune
def fsanitize_coverage_stack_depth
: Flag<["-"], "fsanitize-coverage-stack-depth">,
HelpText<"Enable max stack depth tracing">;
+def fpatchable_function_entry_offset_EQ
+ : Joined<["-"], "fpatchable-function-entry-offset=">, MetaVarName<"<M>">,
+ HelpText<"Generate M NOPs before function entry">;
def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">,
HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, "
"or none">, Values<"none,clang,llvm">;
@@ -553,7 +556,10 @@ def ftest_module_file_extension_EQ :
HelpText<"introduce a module file extension for testing purposes. "
"The argument is parsed as blockname:major:minor:hashed:user info">;
def fconcepts_ts : Flag<["-"], "fconcepts-ts">,
- HelpText<"Enable C++ Extensions for Concepts.">;
+ HelpText<"Enable C++ Extensions for Concepts. (deprecated - use -std=c++2a)">;
+def fno_concept_satisfaction_caching : Flag<["-"],
+ "fno-concept-satisfaction-caching">,
+ HelpText<"Disable satisfaction caching for C++2a Concepts.">;
let Group = Action_Group in {
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index fd25663bd358..6c3feaba0568 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -208,7 +208,7 @@ public:
/// When the clangDriver lib is used through clang.exe, this provides a
/// shortcut for executing the -cc1 command-line directly, in the same
/// process.
- typedef int (*CC1ToolFunc)(ArrayRef<const char *> argv);
+ typedef int (*CC1ToolFunc)(SmallVectorImpl<const char *> &ArgV);
CC1ToolFunc CC1Main = nullptr;
private:
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index abfa767afea8..0a60873443fc 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1707,7 +1707,7 @@ def fno_max_type_align : Flag<["-"], "fno-max-type-align">, Group<f_Group>;
def fpascal_strings : Flag<["-"], "fpascal-strings">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Recognize and construct Pascal-style string literals">;
def fpatchable_function_entry_EQ : Joined<["-"], "fpatchable-function-entry=">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Generate N NOPs at function entry">;
+ MetaVarName<"<N,M>">, HelpText<"Generate M NOPs before function entry and N-M NOPs after function entry">;
def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Override the default ABI to return all structs on the stack">;
def fpch_preprocess : Flag<["-"], "fpch-preprocess">, Group<f_Group>;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index e320c9647818..41f46861d089 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -806,6 +806,16 @@ public:
bool IsNewScope);
bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
+ bool MightBeCXXScopeToken() {
+ return Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ (Tok.is(tok::annot_template_id) &&
+ NextToken().is(tok::coloncolon)) ||
+ Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super);
+ }
+ bool TryAnnotateOptionalCXXScopeToken(bool EnteringContext = false) {
+ return MightBeCXXScopeToken() && TryAnnotateCXXScopeToken(EnteringContext);
+ }
+
private:
enum AnnotatedNameKind {
/// Annotation has failed and emitted an error.
@@ -1923,6 +1933,7 @@ private:
//===--------------------------------------------------------------------===//
// C++ Concepts
+ ExprResult ParseRequiresExpression();
void ParseTrailingRequiresClause(Declarator &D);
//===--------------------------------------------------------------------===//
@@ -2395,6 +2406,11 @@ private:
/// rather than a less-than expression.
TPResult isTemplateArgumentList(unsigned TokensToSkip);
+ /// Determine whether an '(' after an 'explicit' keyword is part of a C++20
+ /// 'explicit(bool)' declaration, in earlier language modes where that is an
+ /// extension.
+ TPResult isExplicitBool();
+
/// Determine whether an identifier has been tentatively declared as a
/// non-type. Such tentative declarations should not be found to name a type
/// during a tentative parse, but also should not be annotated as a non-type.
@@ -2756,7 +2772,7 @@ private:
Declarator &D,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo);
void ParseParameterDeclarationClause(
- Declarator &D,
+ DeclaratorContext DeclaratorContext,
ParsedAttributes &attrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc);
@@ -3064,13 +3080,13 @@ private:
SourceLocation &RAngleLoc);
bool ParseTemplateParameterList(unsigned Depth,
SmallVectorImpl<NamedDecl*> &TemplateParams);
- bool isStartOfTemplateTypeParameter(bool &ScopeError);
+ TPResult isStartOfTemplateTypeParameter();
NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position);
NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position);
NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position);
NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position);
bool isTypeConstraintAnnotation();
- bool TryAnnotateTypeConstraint(CXXScopeSpec &SS);
+ bool TryAnnotateTypeConstraint();
NamedDecl *
ParseConstrainedTemplateTypeParameter(unsigned Depth, unsigned Position);
void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
@@ -3096,7 +3112,8 @@ private:
UnqualifiedId &TemplateName,
bool AllowTypeAnnotation = true,
bool TypeConstraint = false);
- void AnnotateTemplateIdTokenAsType(bool IsClassName = false);
+ void AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
+ bool IsClassName = false);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
ParsedTemplateArgument ParseTemplateTemplateArgument();
ParsedTemplateArgument ParseTemplateArgument();
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index aceec9cbe1c9..1559b51ea77f 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -349,6 +349,7 @@ private:
unsigned TypeSpecOwned : 1;
unsigned TypeSpecPipe : 1;
unsigned TypeSpecSat : 1;
+ unsigned ConstrainedAuto : 1;
// type-qualifiers
unsigned TypeQualifiers : 5; // Bitwise OR of TQ.
@@ -369,6 +370,7 @@ private:
UnionParsedType TypeRep;
Decl *DeclRep;
Expr *ExprRep;
+ TemplateIdAnnotation *TemplateIdRep;
};
/// ExplicitSpecifier - Store information about explicit spicifer.
@@ -413,6 +415,9 @@ private:
static bool isExprRep(TST T) {
return (T == TST_typeofExpr || T == TST_decltype);
}
+ static bool isTemplateIdRep(TST T) {
+ return (T == TST_auto || T == TST_decltype_auto);
+ }
DeclSpec(const DeclSpec &) = delete;
void operator=(const DeclSpec &) = delete;
@@ -430,7 +435,8 @@ public:
TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified),
TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
- TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified),
+ TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
+ TypeQualifiers(TQ_unspecified),
FS_inline_specified(false), FS_forceinline_specified(false),
FS_virtual_specified(false), FS_noreturn_specified(false),
Friend_specified(false), ConstexprSpecifier(CSK_unspecified),
@@ -478,6 +484,7 @@ public:
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
bool isTypeSpecPipe() const { return TypeSpecPipe; }
bool isTypeSpecSat() const { return TypeSpecSat; }
+ bool isConstrainedAuto() const { return ConstrainedAuto; }
ParsedType getRepAsType() const {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
@@ -491,6 +498,11 @@ public:
assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
return ExprRep;
}
+ TemplateIdAnnotation *getRepAsTemplateId() const {
+ assert(isTemplateIdRep((TST) TypeSpecType) &&
+ "DeclSpec does not store a template id");
+ return TemplateIdRep;
+ }
CXXScopeSpec &getTypeSpecScope() { return TypeScope; }
const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; }
@@ -666,6 +678,9 @@ public:
SourceLocation TagNameLoc, const char *&PrevSpec,
unsigned &DiagID, Decl *Rep, bool Owned,
const PrintingPolicy &Policy);
+ bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID, TemplateIdAnnotation *Rep,
+ const PrintingPolicy &Policy);
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, Expr *Rep,
@@ -1757,7 +1772,8 @@ enum class DeclaratorContext {
TemplateArgContext, // Any template argument (in template argument list).
TemplateTypeArgContext, // Template type argument (in default argument).
AliasDeclContext, // C++11 alias-declaration.
- AliasTemplateContext // C++11 alias-declaration template.
+ AliasTemplateContext, // C++11 alias-declaration template.
+ RequiresExprContext // C++2a requires-expression.
};
@@ -1830,6 +1846,14 @@ private:
/// requires-clause, or null if no such clause was specified.
Expr *TrailingRequiresClause;
+ /// If this declarator declares a template, its template parameter lists.
+ ArrayRef<TemplateParameterList *> TemplateParameterLists;
+
+ /// If the declarator declares an abbreviated function template, the innermost
+ /// template parameter list containing the invented and explicit template
+ /// parameters (if any).
+ TemplateParameterList *InventedTemplateParameterList;
+
#ifndef _MSC_VER
union {
#endif
@@ -1860,7 +1884,8 @@ public:
Redeclaration(false), Extension(false), ObjCIvar(false),
ObjCWeakProperty(false), InlineStorageUsed(false),
Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
- TrailingRequiresClause(nullptr) {}
+ TrailingRequiresClause(nullptr),
+ InventedTemplateParameterList(nullptr) {}
~Declarator() {
clear();
@@ -1981,6 +2006,7 @@ public:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
+ case DeclaratorContext::RequiresExprContext:
return true;
}
llvm_unreachable("unknown context kind!");
@@ -2003,6 +2029,7 @@ public:
case DeclaratorContext::TemplateParamContext:
case DeclaratorContext::CXXCatchContext:
case DeclaratorContext::ObjCCatchContext:
+ case DeclaratorContext::RequiresExprContext:
return true;
case DeclaratorContext::TypeNameContext:
@@ -2039,6 +2066,7 @@ public:
case DeclaratorContext::MemberContext:
case DeclaratorContext::PrototypeContext:
case DeclaratorContext::TemplateParamContext:
+ case DeclaratorContext::RequiresExprContext:
// Maybe one day...
return false;
@@ -2116,6 +2144,7 @@ public:
case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
+ case DeclaratorContext::RequiresExprContext:
return false;
}
llvm_unreachable("unknown context kind!");
@@ -2337,6 +2366,7 @@ public:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
+ case DeclaratorContext::RequiresExprContext:
return false;
}
llvm_unreachable("unknown context kind!");
@@ -2370,6 +2400,7 @@ public:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
case DeclaratorContext::TemplateTypeArgContext:
+ case DeclaratorContext::RequiresExprContext:
return false;
case DeclaratorContext::BlockContext:
@@ -2422,6 +2453,30 @@ public:
return TrailingRequiresClause != nullptr;
}
+ /// Sets the template parameter lists that preceded the declarator.
+ void setTemplateParameterLists(ArrayRef<TemplateParameterList *> TPLs) {
+ TemplateParameterLists = TPLs;
+ }
+
+ /// The template parameter lists that preceded the declarator.
+ ArrayRef<TemplateParameterList *> getTemplateParameterLists() const {
+ return TemplateParameterLists;
+ }
+
+ /// Sets the template parameter list generated from the explicit template
+ /// parameters along with any invented template parameters from
+ /// placeholder-typed parameters.
+ void setInventedTemplateParameterList(TemplateParameterList *Invented) {
+ InventedTemplateParameterList = Invented;
+ }
+
+ /// The template parameter list generated from the explicit template
+ /// parameters along with any invented template parameters from
+ /// placeholder-typed parameters, if there were any such parameters.
+ TemplateParameterList * getInventedTemplateParameterList() const {
+ return InventedTemplateParameterList;
+ }
+
/// takeAttributes - Takes attributes from the given parsed-attributes
/// set and add them to this declarator.
///
@@ -2622,6 +2677,26 @@ struct LambdaIntroducer {
}
};
+struct InventedTemplateParameterInfo {
+ /// The number of parameters in the template parameter list that were
+ /// explicitly specified by the user, as opposed to being invented by use
+ /// of an auto parameter.
+ unsigned NumExplicitTemplateParams = 0;
+
+ /// If this is a generic lambda or abbreviated function template, use this
+ /// as the depth of each 'auto' parameter, during initial AST construction.
+ unsigned AutoTemplateParameterDepth = 0;
+
+ /// Store the list of the template parameters for a generic lambda or an
+ /// abbreviated function template.
+ /// If this is a generic lambda or abbreviated function template, this holds
+ /// the explicit template parameters followed by the auto parameters
+ /// converted into TemplateTypeParmDecls.
+ /// It can be used to construct the generic lambda or abbreviated template's
+ /// template parameter list during initial AST construction.
+ SmallVector<NamedDecl*, 4> TemplateParams;
+};
+
} // end namespace clang
#endif // LLVM_CLANG_SEMA_DECLSPEC_H
diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h
index 0874905b38a5..82d00494b0d6 100644
--- a/clang/include/clang/Sema/ParsedTemplate.h
+++ b/clang/include/clang/Sema/ParsedTemplate.h
@@ -139,9 +139,8 @@ namespace clang {
/// Information about a template-id annotation
/// token.
///
- /// A template-id annotation token contains the template declaration,
- /// template arguments, whether those template arguments were types,
- /// expressions, or template names, and the source locations for important
+ /// A template-id annotation token contains the template name,
+ /// template arguments, and the source locations for important
/// tokens. All of the information about template arguments is allocated
/// directly after this structure.
/// A template-id annotation token can also be generated by a type-constraint
@@ -152,9 +151,6 @@ namespace clang {
: private llvm::TrailingObjects<TemplateIdAnnotation,
ParsedTemplateArgument> {
friend TrailingObjects;
- /// The nested-name-specifier that precedes the template name.
- CXXScopeSpec SS;
-
/// TemplateKWLoc - The location of the template keyword.
/// For e.g. typename T::template Y<U>
SourceLocation TemplateKWLoc;
@@ -195,16 +191,15 @@ namespace clang {
/// Creates a new TemplateIdAnnotation with NumArgs arguments and
/// appends it to List.
static TemplateIdAnnotation *
- Create(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
- SourceLocation TemplateNameLoc, IdentifierInfo *Name,
- OverloadedOperatorKind OperatorKind,
+ Create(SourceLocation TemplateKWLoc, SourceLocation TemplateNameLoc,
+ IdentifierInfo *Name, OverloadedOperatorKind OperatorKind,
ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind,
SourceLocation LAngleLoc, SourceLocation RAngleLoc,
ArrayRef<ParsedTemplateArgument> TemplateArgs,
SmallVectorImpl<TemplateIdAnnotation *> &CleanupList) {
TemplateIdAnnotation *TemplateId = new (llvm::safe_malloc(
totalSizeToAlloc<ParsedTemplateArgument>(TemplateArgs.size())))
- TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name,
+ TemplateIdAnnotation(TemplateKWLoc, TemplateNameLoc, Name,
OperatorKind, OpaqueTemplateName, TemplateKind,
LAngleLoc, RAngleLoc, TemplateArgs);
CleanupList.push_back(TemplateId);
@@ -221,17 +216,16 @@ namespace clang {
private:
TemplateIdAnnotation(const TemplateIdAnnotation &) = delete;
- TemplateIdAnnotation(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
+ TemplateIdAnnotation(SourceLocation TemplateKWLoc,
SourceLocation TemplateNameLoc, IdentifierInfo *Name,
OverloadedOperatorKind OperatorKind,
ParsedTemplateTy OpaqueTemplateName,
TemplateNameKind TemplateKind,
SourceLocation LAngleLoc, SourceLocation RAngleLoc,
ArrayRef<ParsedTemplateArgument> TemplateArgs) noexcept
- : SS(SS), TemplateKWLoc(TemplateKWLoc),
- TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind),
- Template(OpaqueTemplateName), Kind(TemplateKind),
- LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
+ : TemplateKWLoc(TemplateKWLoc), TemplateNameLoc(TemplateNameLoc),
+ Name(Name), Operator(OperatorKind), Template(OpaqueTemplateName),
+ Kind(TemplateKind), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumArgs(TemplateArgs.size()) {
std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(),
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 7848df8f70d9..6133425a42a6 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -385,6 +385,12 @@ public:
return getFlags() & Scope::FunctionPrototypeScope;
}
+ /// isFunctionDeclarationScope - Return true if this scope is a
+ /// function prototype scope.
+ bool isFunctionDeclarationScope() const {
+ return getFlags() & Scope::FunctionDeclarationScope;
+ }
+
/// isAtCatchScope - Return true if this scope is \@catch.
bool isAtCatchScope() const {
return getFlags() & Scope::AtCatchScope;
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 4f7534f9ef1a..3c4847a2932c 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -22,6 +22,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/CleanupInfo.h"
+#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/MapVector.h"
@@ -789,7 +790,8 @@ public:
}
};
-class LambdaScopeInfo final : public CapturingScopeInfo {
+class LambdaScopeInfo final :
+ public CapturingScopeInfo, public InventedTemplateParameterInfo {
public:
/// The class that describes the lambda.
CXXRecordDecl *Lambda = nullptr;
@@ -823,25 +825,9 @@ public:
/// Packs introduced by this lambda, if any.
SmallVector<NamedDecl*, 4> LocalPacks;
- /// If this is a generic lambda, use this as the depth of
- /// each 'auto' parameter, during initial AST construction.
- unsigned AutoTemplateParameterDepth = 0;
-
- /// The number of parameters in the template parameter list that were
- /// explicitly specified by the user, as opposed to being invented by use
- /// of an auto parameter.
- unsigned NumExplicitTemplateParams = 0;
-
/// Source range covering the explicit template parameter list (if it exists).
SourceRange ExplicitTemplateParamsRange;
- /// Store the list of the template parameters for a generic lambda.
- /// If this is a generic lambda, this holds the explicit template parameters
- /// followed by the auto parameters converted into TemplateTypeParmDecls.
- /// It can be used to construct the generic lambda's template parameter list
- /// during initial AST construction.
- SmallVector<NamedDecl*, 4> TemplateParams;
-
/// If this is a generic lambda, and the template parameter
/// list has been created (from the TemplateParams) then store
/// a reference to it (cache it to avoid reconstructing it).
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 47a055f696b1..a88dd2814487 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -21,6 +21,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExternalASTSource.h"
@@ -619,6 +620,13 @@ public:
/// function, block, and method scopes that are currently active.
SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
+ /// Stack containing information needed when in C++2a an 'auto' is encountered
+ /// in a function declaration parameter type specifier in order to invent a
+ /// corresponding template parameter in the enclosing abbreviated function
+ /// template. This information is also present in LambdaScopeInfo, stored in
+ /// the FunctionScopes stack.
+ SmallVector<InventedTemplateParameterInfo, 4> InventedParameterInfos;
+
typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadExtVectorDecls, 2, 2>
ExtVectorDeclsType;
@@ -1424,6 +1432,11 @@ public:
/// Retrieve the module loader associated with the preprocessor.
ModuleLoader &getModuleLoader() const;
+ /// Invent a new identifier for parameters of abbreviated templates.
+ IdentifierInfo *
+ InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
+ unsigned Index);
+
void emitAndClearUnusedLocalTypedefWarnings();
enum TUFragmentKind {
@@ -1518,6 +1531,15 @@ public:
/// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls
SmallVectorImpl<Decl *> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
+ /// Called before parsing a function declarator belonging to a function
+ /// declaration.
+ void ActOnStartFunctionDeclarationDeclarator(Declarator &D,
+ unsigned TemplateParameterDepth);
+
+ /// Called after parsing a function declarator belonging to a function
+ /// declaration.
+ void ActOnFinishFunctionDeclarationDeclarator(Declarator &D);
+
void ActOnComment(SourceRange Comment);
//===--------------------------------------------------------------------===//
@@ -1921,6 +1943,8 @@ public:
NC_FunctionTemplate,
/// The name was classified as an ADL-only function template name.
NC_UndeclaredTemplate,
+ /// The name was classified as a concept name.
+ NC_Concept,
};
class NameClassification {
@@ -1985,6 +2009,12 @@ public:
return Result;
}
+ static NameClassification Concept(TemplateName Name) {
+ NameClassification Result(NC_Concept);
+ Result.Template = Name;
+ return Result;
+ }
+
static NameClassification UndeclaredTemplate(TemplateName Name) {
NameClassification Result(NC_UndeclaredTemplate);
Result.Template = Name;
@@ -2010,7 +2040,8 @@ public:
TemplateName getTemplateName() const {
assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate ||
- Kind == NC_VarTemplate || Kind == NC_UndeclaredTemplate);
+ Kind == NC_VarTemplate || Kind == NC_Concept ||
+ Kind == NC_UndeclaredTemplate);
return Template;
}
@@ -2022,6 +2053,8 @@ public:
return TNK_Function_template;
case NC_VarTemplate:
return TNK_Var_template;
+ case NC_Concept:
+ return TNK_Concept_template;
case NC_UndeclaredTemplate:
return TNK_Undeclared_template;
default:
@@ -6199,6 +6232,9 @@ private:
llvm::DenseMap<NamedDecl *, NormalizedConstraint *>
NormalizationCache;
+ llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
+ SatisfactionCache;
+
public:
const NormalizedConstraint *
getNormalizedAssociatedConstraints(
@@ -6225,6 +6261,8 @@ public:
/// \brief Check whether the given list of constraint expressions are
/// satisfied (as if in a 'conjunction') given template arguments.
+ /// \param Template the template-like entity that triggered the constraints
+ /// check (either a concept or a constrained entity).
/// \param ConstraintExprs a list of constraint expressions, treated as if
/// they were 'AND'ed together.
/// \param TemplateArgs the list of template arguments to substitute into the
@@ -6236,23 +6274,10 @@ public:
/// expression.
/// \returns true if an error occurred and satisfaction could not be checked,
/// false otherwise.
- bool CheckConstraintSatisfaction(TemplateDecl *Template,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction);
-
- bool CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl *TD,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction);
-
- bool CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl *TD,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction);
+ bool CheckConstraintSatisfaction(
+ NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
/// \brief Check whether the given non-dependent constraint expression is
/// satisfied. Returns false and updates Satisfaction with the satisfaction
@@ -6282,13 +6307,17 @@ public:
/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied.
+ /// \param First whether this is the first time an unsatisfied constraint is
+ /// diagnosed for this error.
void
- DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction);
+ DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction,
+ bool First = true);
/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied.
void
- DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction& Satisfaction);
+ DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction,
+ bool First = true);
/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied because it was ill-formed.
@@ -6873,7 +6902,8 @@ public:
SourceLocation EqualLoc,
ParsedType DefaultArg, bool HasTypeConstraint);
- bool ActOnTypeConstraint(TemplateIdAnnotation *TypeConstraint,
+ bool ActOnTypeConstraint(const CXXScopeSpec &SS,
+ TemplateIdAnnotation *TypeConstraint,
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc);
@@ -6884,6 +6914,10 @@ public:
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc);
+ bool AttachTypeConstraint(AutoTypeLoc TL,
+ NonTypeTemplateParmDecl *ConstrainedParameter,
+ SourceLocation EllipsisLoc);
+
QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
SourceLocation Loc);
QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
@@ -6933,7 +6967,8 @@ public:
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists,
- bool IsFriend, bool &IsMemberSpecialization, bool &Invalid);
+ bool IsFriend, bool &IsMemberSpecialization, bool &Invalid,
+ bool SuppressDiagnostic = false);
DeclResult CheckClassTemplate(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
@@ -7028,8 +7063,8 @@ public:
DeclResult ActOnClassTemplateSpecialization(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
- SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId,
- const ParsedAttributesView &Attr,
+ SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
+ TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
MultiTemplateParamsArg TemplateParameterLists,
SkipBodyInfo *SkipBody = nullptr);
@@ -7261,7 +7296,17 @@ public:
SourceLocation KeywordLoc,
NestedNameSpecifierLoc QualifierLoc,
const IdentifierInfo &II,
- SourceLocation IILoc);
+ SourceLocation IILoc,
+ TypeSourceInfo **TSI,
+ bool DeducedTSTContext);
+
+ QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ SourceLocation KeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ const IdentifierInfo &II,
+ SourceLocation IILoc,
+ bool DeducedTSTContext = true);
+
TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
SourceLocation Loc,
@@ -7281,11 +7326,52 @@ public:
const TemplateArgument *Args,
unsigned NumArgs);
- // Concepts
+ //===--------------------------------------------------------------------===//
+ // C++ Concepts
+ //===--------------------------------------------------------------------===//
Decl *ActOnConceptDefinition(
Scope *S, MultiTemplateParamsArg TemplateParameterLists,
IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr);
+ RequiresExprBodyDecl *
+ ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ Scope *BodyScope);
+ void ActOnFinishRequiresExpr();
+ concepts::Requirement *ActOnSimpleRequirement(Expr *E);
+ concepts::Requirement *ActOnTypeRequirement(
+ SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc,
+ IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId);
+ concepts::Requirement *ActOnCompoundRequirement(Expr *E,
+ SourceLocation NoexceptLoc);
+ concepts::Requirement *
+ ActOnCompoundRequirement(
+ Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS,
+ TemplateIdAnnotation *TypeConstraint, unsigned Depth);
+ concepts::Requirement *ActOnNestedRequirement(Expr *Constraint);
+ concepts::ExprRequirement *
+ BuildExprRequirement(
+ Expr *E, bool IsSatisfied, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement);
+ concepts::ExprRequirement *
+ BuildExprRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *ExprSubstDiag,
+ bool IsSatisfied, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement);
+ concepts::TypeRequirement *BuildTypeRequirement(TypeSourceInfo *Type);
+ concepts::TypeRequirement *
+ BuildTypeRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag);
+ concepts::NestedRequirement *BuildNestedRequirement(Expr *E);
+ concepts::NestedRequirement *
+ BuildNestedRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag);
+ ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation ClosingBraceLoc);
+
//===--------------------------------------------------------------------===//
// C++ Variadic Templates (C++0x [temp.variadic])
//===--------------------------------------------------------------------===//
@@ -7794,10 +7880,12 @@ public:
DeduceAutoResult
DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result,
- Optional<unsigned> DependentDeductionDepth = None);
+ Optional<unsigned> DependentDeductionDepth = None,
+ bool IgnoreConstraints = false);
DeduceAutoResult
DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result,
- Optional<unsigned> DependentDeductionDepth = None);
+ Optional<unsigned> DependentDeductionDepth = None,
+ bool IgnoreConstraints = false);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
@@ -7932,6 +8020,13 @@ public:
/// template which was deferred until it was needed.
ExceptionSpecInstantiation,
+ /// We are instantiating a requirement of a requires expression.
+ RequirementInstantiation,
+
+ /// We are checking the satisfaction of a nested requirement of a requires
+ /// expression.
+ NestedRequirementConstraintsCheck,
+
/// We are declaring an implicit special member function.
DeclaringSpecialMember,
@@ -8253,6 +8348,19 @@ public:
ParameterMappingSubstitution, NamedDecl *Template,
SourceRange InstantiationRange);
+ /// \brief Note that we are substituting template arguments into a part of
+ /// a requirement of a requires expression.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ concepts::Requirement *Req,
+ sema::TemplateDeductionInfo &DeductionInfo,
+ SourceRange InstantiationRange = SourceRange());
+
+ /// \brief Note that we are checking the satisfaction of the constraint
+ /// expression inside of a nested requirement.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ concepts::NestedRequirement *Req, ConstraintsCheck,
+ SourceRange InstantiationRange = SourceRange());
+
/// Note that we have finished instantiating this template.
void Clear();
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index acd1e604211a..7fc42a4816ec 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -13,10 +13,17 @@
#ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H
#define LLVM_CLANG_SEMA_SEMACONCEPT_H
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
+#include <string>
+#include <utility>
+
namespace clang {
class Sema;
diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h
index b60939c97872..f787c2689d85 100644
--- a/clang/include/clang/Sema/TemplateDeduction.h
+++ b/clang/include/clang/Sema/TemplateDeduction.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
#include "clang/Sema/Ownership.h"
+#include "clang/Sema/SemaConcept.h"
#include "clang/AST/ASTConcept.h"
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclTemplate.h"
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 1bfcbda8c9f1..44a12c875da7 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1403,6 +1403,9 @@ namespace serialization {
/// An LifetimeExtendedTemporaryDecl record.
DECL_LIFETIME_EXTENDED_TEMPORARY,
+ /// A RequiresExprBodyDecl record.
+ DECL_REQUIRES_EXPR_BODY,
+
/// An ObjCTypeParamDecl record.
DECL_OBJC_TYPE_PARAM,
@@ -1785,6 +1788,7 @@ namespace serialization {
EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
EXPR_CXX_FOLD, // CXXFoldExpr
EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr
+ EXPR_REQUIRES, // RequiresExpr
// CUDA
EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index fc32e768d92f..c28a06bdf0b2 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -14,6 +14,10 @@
#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/TemplateBase.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/FoldingSet.h"
using namespace clang;
ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C,
@@ -53,3 +57,12 @@ ASTConstraintSatisfaction::Create(const ASTContext &C,
void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
}
+
+void ConstraintSatisfaction::Profile(
+ llvm::FoldingSetNodeID &ID, const ASTContext &C, NamedDecl *ConstraintOwner,
+ ArrayRef<TemplateArgument> TemplateArgs) {
+ ID.AddPointer(ConstraintOwner);
+ ID.AddInteger(TemplateArgs.size());
+ for (auto &Arg : TemplateArgs)
+ Arg.Profile(ID, C);
+}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a51429264dbe..6d1db38e36cc 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -716,6 +716,61 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
RequiresClause->Profile(ID, C, /*Canonical=*/true);
}
+static Expr *
+canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
+ QualType ConstrainedType) {
+ // This is a bit ugly - we need to form a new immediately-declared
+ // constraint that references the new parameter; this would ideally
+ // require semantic analysis (e.g. template<C T> struct S {}; - the
+ // converted arguments of C<T> could be an argument pack if C is
+ // declared as template<typename... T> concept C = ...).
+ // We don't have semantic analysis here so we dig deep into the
+ // ready-made constraint expr and change the thing manually.
+ ConceptSpecializationExpr *CSE;
+ if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
+ CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
+ else
+ CSE = cast<ConceptSpecializationExpr>(IDC);
+ ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
+ SmallVector<TemplateArgument, 3> NewConverted;
+ NewConverted.reserve(OldConverted.size());
+ if (OldConverted.front().getKind() == TemplateArgument::Pack) {
+ // The case:
+ // template<typename... T> concept C = true;
+ // template<C<int> T> struct S; -> constraint is C<{T, int}>
+ NewConverted.push_back(ConstrainedType);
+ for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
+ NewConverted.push_back(Arg);
+ TemplateArgument NewPack(NewConverted);
+
+ NewConverted.clear();
+ NewConverted.push_back(NewPack);
+ assert(OldConverted.size() == 1 &&
+ "Template parameter pack should be the last parameter");
+ } else {
+ assert(OldConverted.front().getKind() == TemplateArgument::Type &&
+ "Unexpected first argument kind for immediately-declared "
+ "constraint");
+ NewConverted.push_back(ConstrainedType);
+ for (auto &Arg : OldConverted.drop_front(1))
+ NewConverted.push_back(Arg);
+ }
+ Expr *NewIDC = ConceptSpecializationExpr::Create(
+ C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
+ CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
+ CSE->getNamedConcept(),
+ // Actually canonicalizing a TemplateArgumentLoc is difficult so we
+ // simply omit the ArgsAsWritten
+ /*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
+
+ if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
+ NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,
+ BinaryOperatorKind::BO_LAnd,
+ SourceLocation(), /*RHS=*/nullptr,
+ SourceLocation(), /*NumExpansions=*/None);
+ return NewIDC;
+}
+
TemplateTemplateParmDecl *
ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *TTP) const {
@@ -743,68 +798,23 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TTP->isExpandedParameterPack() ?
llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
if (const auto *TC = TTP->getTypeConstraint()) {
- // This is a bit ugly - we need to form a new immediately-declared
- // constraint that references the new parameter; this would ideally
- // require semantic analysis (e.g. template<C T> struct S {}; - the
- // converted arguments of C<T> could be an argument pack if C is
- // declared as template<typename... T> concept C = ...).
- // We don't have semantic analysis here so we dig deep into the
- // ready-made constraint expr and change the thing manually.
- Expr *IDC = TC->getImmediatelyDeclaredConstraint();
- ConceptSpecializationExpr *CSE;
- if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
- CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
- else
- CSE = cast<ConceptSpecializationExpr>(IDC);
- ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
- SmallVector<TemplateArgument, 3> NewConverted;
- NewConverted.reserve(OldConverted.size());
-
QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
- if (OldConverted.front().getKind() == TemplateArgument::Pack) {
- // The case:
- // template<typename... T> concept C = true;
- // template<C<int> T> struct S; -> constraint is C<{T, int}>
- NewConverted.push_back(ParamAsArgument);
- for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
- NewConverted.push_back(Arg);
- TemplateArgument NewPack(NewConverted);
-
- NewConverted.clear();
- NewConverted.push_back(NewPack);
- assert(OldConverted.size() == 1 &&
- "Template parameter pack should be the last parameter");
- } else {
- assert(OldConverted.front().getKind() == TemplateArgument::Type &&
- "Unexpected first argument kind for immediately-declared "
- "constraint");
- NewConverted.push_back(ParamAsArgument);
- for (auto &Arg : OldConverted.drop_front(1))
- NewConverted.push_back(Arg);
- }
- Expr *NewIDC = ConceptSpecializationExpr::Create(*this,
- NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
- CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
- CSE->getNamedConcept(),
- // Actually canonicalizing a TemplateArgumentLoc is difficult so we
- // simply omit the ArgsAsWritten
- /*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
-
- if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
- NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(),
- SourceLocation(), NewIDC,
- BinaryOperatorKind::BO_LAnd,
- SourceLocation(), /*RHS=*/nullptr,
- SourceLocation(),
- /*NumExpansions=*/None);
-
+ Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint(
+ *this, TC->getImmediatelyDeclaredConstraint(),
+ ParamAsArgument);
+ TemplateArgumentListInfo CanonArgsAsWritten;
+ if (auto *Args = TC->getTemplateArgsAsWritten())
+ for (const auto &ArgLoc : Args->arguments())
+ CanonArgsAsWritten.addArgument(
+ TemplateArgumentLoc(ArgLoc.getArgument(),
+ TemplateArgumentLocInfo()));
NewTTP->setTypeConstraint(
NestedNameSpecifierLoc(),
DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
SourceLocation()), /*FoundDecl=*/nullptr,
// Actually canonicalizing a TemplateArgumentLoc is difficult so we
// simply omit the ArgsAsWritten
- CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
+ TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
}
CanonParams.push_back(NewTTP);
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
@@ -839,6 +849,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
NTTP->isParameterPack(),
TInfo);
}
+ if (AutoType *AT = T->getContainedAutoType()) {
+ if (AT->isConstrained()) {
+ Param->setPlaceholderTypeConstraint(
+ canonicalizeImmediatelyDeclaredConstraint(
+ *this, NTTP->getPlaceholderTypeConstraint(), T));
+ }
+ }
CanonParams.push_back(Param);
} else
@@ -943,7 +960,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
Builtin::Context &builtins)
: ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
TemplateSpecializationTypes(this_()),
- DependentTemplateSpecializationTypes(this_()),
+ DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
SubstTemplateTemplateParmPacks(this_()),
CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
@@ -5124,21 +5141,29 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
/// getAutoType - Return the uniqued reference to the 'auto' type which has been
/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
/// canonical deduced-but-dependent 'auto' type.
-QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
- bool IsDependent, bool IsPack) const {
+QualType
+ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
+ bool IsDependent, bool IsPack,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs) const {
assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
- if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
+ if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
+ !TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
- AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack);
+ AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent,
+ TypeConstraintConcept, TypeConstraintArgs);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
- auto *AT = new (*this, TypeAlignment)
- AutoType(DeducedType, Keyword, IsDependent, IsPack);
+ void *Mem = Allocate(sizeof(AutoType) +
+ sizeof(TemplateArgument) * TypeConstraintArgs.size(),
+ TypeAlignment);
+ auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack,
+ TypeConstraintConcept, TypeConstraintArgs);
Types.push_back(AT);
if (InsertPos)
AutoTypes.InsertNode(AT, InsertPos);
@@ -5200,7 +5225,8 @@ QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
- /*dependent*/false, /*pack*/false),
+ /*dependent*/false, /*pack*/false,
+ /*concept*/nullptr, /*args*/{}),
0);
return AutoDeductTy;
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 22fb67478c96..1f2ce30398c9 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1366,9 +1366,21 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) {
if (!ToDeducedTypeOrErr)
return ToDeducedTypeOrErr.takeError();
- return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr,
- T->getKeyword(),
- /*IsDependent*/false);
+ ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept());
+ if (!ToTypeConstraintConcept)
+ return ToTypeConstraintConcept.takeError();
+
+ SmallVector<TemplateArgument, 2> ToTemplateArgs;
+ ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments();
+ if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(),
+ FromTemplateArgs.size(),
+ ToTemplateArgs))
+ return std::move(Err);
+
+ return Importer.getToContext().getAutoType(
+ *ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false,
+ /*IsPack=*/false, cast_or_null<ConceptDecl>(*ToTypeConstraintConcept),
+ ToTemplateArgs);
}
ExpectedType ASTNodeImporter::VisitInjectedClassNameType(
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index db48405055cd..91a2f3a8391b 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -729,11 +729,31 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
- case Type::Auto:
- if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
- cast<AutoType>(T2)->getDeducedType()))
+ case Type::Auto: {
+ auto *Auto1 = cast<AutoType>(T1);
+ auto *Auto2 = cast<AutoType>(T2);
+ if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
+ Auto2->getDeducedType()))
return false;
+ if (Auto1->isConstrained() != Auto2->isConstrained())
+ return false;
+ if (Auto1->isConstrained()) {
+ if (Auto1->getTypeConstraintConcept() !=
+ Auto2->getTypeConstraintConcept())
+ return false;
+ ArrayRef<TemplateArgument> Auto1Args =
+ Auto1->getTypeConstraintArguments();
+ ArrayRef<TemplateArgument> Auto2Args =
+ Auto2->getTypeConstraintArguments();
+ if (Auto1Args.size() != Auto2Args.size())
+ return false;
+ for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
+ return false;
+ }
+ }
break;
+ }
case Type::DeducedTemplateSpecialization: {
const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 6ee767ccecf7..cb4d61cac2c7 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -804,6 +804,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case OMPCapturedExpr:
case Empty:
case LifetimeExtendedTemporary:
+ case RequiresExprBody:
// Never looked up by name.
return 0;
}
@@ -1177,6 +1178,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::Captured:
case Decl::OMPDeclareReduction:
case Decl::OMPDeclareMapper:
+ case Decl::RequiresExprBody:
// There is only one DeclContext for these entities.
return this;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 2ead1e70ea0d..48e310e858b2 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1968,6 +1968,16 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
QualType(), nullptr, SourceLocation());
}
+RequiresExprBodyDecl *RequiresExprBodyDecl::Create(
+ ASTContext &C, DeclContext *DC, SourceLocation StartLoc) {
+ return new (C, DC) RequiresExprBodyDecl(C, DC, StartLoc);
+}
+
+RequiresExprBodyDecl *RequiresExprBodyDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID) RequiresExprBodyDecl(C, nullptr, SourceLocation());
+}
+
void CXXMethodDecl::anchor() {}
bool CXXMethodDecl::isStatic() const {
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 95a2e26e0df8..b5e4ec2d7f43 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -164,10 +164,15 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
void TemplateParameterList::
getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
if (HasConstrainedParameters)
- for (const NamedDecl *Param : *this)
- if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ for (const NamedDecl *Param : *this) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (const auto *TC = TTP->getTypeConstraint())
AC.push_back(TC->getImmediatelyDeclaredConstraint());
+ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
+ AC.push_back(E);
+ }
+ }
if (HasRequiresClause)
AC.push_back(getRequiresClause());
}
@@ -483,7 +488,10 @@ static void ProfileTemplateParameterList(ASTContext &C,
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {
ID.AddInteger(1);
ID.AddBoolean(TTP->isParameterPack());
- // TODO: Concepts: profile type-constraints.
+ ID.AddBoolean(TTP->hasTypeConstraint());
+ if (const TypeConstraint *TC = TTP->getTypeConstraint())
+ TC->getImmediatelyDeclaredConstraint()->Profile(ID, C,
+ /*Canonical=*/true);
continue;
}
const auto *TTP = cast<TemplateTemplateParmDecl>(D);
@@ -684,8 +692,14 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, bool ParameterPack,
TypeSourceInfo *TInfo) {
- return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
- T, ParameterPack, TInfo);
+ AutoType *AT =
+ C.getLangOpts().CPlusPlus2a ? T->getContainedAutoType() : nullptr;
+ return new (C, DC,
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(0,
+ AT && AT->isConstrained() ? 1 : 0))
+ NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack,
+ TInfo);
}
NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
@@ -693,26 +707,34 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
ArrayRef<TypeSourceInfo *> ExpandedTInfos) {
+ AutoType *AT = TInfo->getType()->getContainedAutoType();
return new (C, DC,
- additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
- ExpandedTypes.size()))
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(
+ ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0))
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
ExpandedTypes, ExpandedTInfos);
}
NonTypeTemplateParmDecl *
-NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(),
- SourceLocation(), 0, 0, nullptr,
- QualType(), false, nullptr);
+NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ bool HasTypeConstraint) {
+ return new (C, ID, additionalSizeToAlloc<std::pair<QualType,
+ TypeSourceInfo *>,
+ Expr *>(0,
+ HasTypeConstraint ? 1 : 0))
+ NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
+ 0, 0, nullptr, QualType(), false, nullptr);
}
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
- unsigned NumExpandedTypes) {
+ unsigned NumExpandedTypes,
+ bool HasTypeConstraint) {
auto *NTTP =
- new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
- NumExpandedTypes))
+ new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(
+ NumExpandedTypes, HasTypeConstraint ? 1 : 0))
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
0, 0, nullptr, QualType(), nullptr, None,
None);
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 73ddbc62482d..835198958766 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3457,6 +3457,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case OpaqueValueExprClass:
case SourceLocExprClass:
case ConceptSpecializationExprClass:
+ case RequiresExprClass:
// These never have a side-effect.
return false;
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 422227d787b1..e4bd218ae2d3 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/LambdaCapture.h"
@@ -1764,81 +1765,3 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx,
alignof(CUDAKernelCallExpr));
return new (Mem) CUDAKernelCallExpr(NumArgs, Empty);
}
-
-ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C,
- NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
- DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
- ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction)
- : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
- /*TypeDependent=*/false,
- // All the flags below are set in setTemplateArguments.
- /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false,
- /*ContainsUnexpandedParameterPacks=*/false),
- ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
- NamedConcept, ArgsAsWritten),
- NumTemplateArgs(ConvertedArgs.size()),
- Satisfaction(Satisfaction ?
- ASTConstraintSatisfaction::Create(C, *Satisfaction) :
- nullptr) {
- setTemplateArguments(ConvertedArgs);
-}
-
-ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
- unsigned NumTemplateArgs)
- : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
- NumTemplateArgs(NumTemplateArgs) { }
-
-void ConceptSpecializationExpr::setTemplateArguments(
- ArrayRef<TemplateArgument> Converted) {
- assert(Converted.size() == NumTemplateArgs);
- std::uninitialized_copy(Converted.begin(), Converted.end(),
- getTrailingObjects<TemplateArgument>());
- bool IsInstantiationDependent = false;
- bool ContainsUnexpandedParameterPack = false;
- for (const TemplateArgument& Arg : Converted) {
- if (Arg.isInstantiationDependent())
- IsInstantiationDependent = true;
- if (Arg.containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
- if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
- break;
- }
-
- // Currently guaranteed by the fact concepts can only be at namespace-scope.
- assert(!NestedNameSpec ||
- (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
- !NestedNameSpec.getNestedNameSpecifier()
- ->containsUnexpandedParameterPack()));
- setInstantiationDependent(IsInstantiationDependent);
- setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
- assert((!isValueDependent() || isInstantiationDependent()) &&
- "should not be value-dependent");
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(const ASTContext &C,
- NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc,
- DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl,
- ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- ConvertedArgs.size()));
- return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
- ConceptNameInfo, FoundDecl,
- NamedConcept, ArgsAsWritten,
- ConvertedArgs, Satisfaction);
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
- unsigned NumTemplateArgs) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- NumTemplateArgs));
- return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
-}
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 9dbf6fe9e0f0..d201af31f521 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -193,6 +193,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::DesignatedInitUpdateExprClass:
case Expr::SourceLocExprClass:
case Expr::ConceptSpecializationExprClass:
+ case Expr::RequiresExprClass:
return Cl::CL_PRValue;
case Expr::ConstantExprClass:
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
new file mode 100644
index 000000000000..76d57ed5d5b1
--- /dev/null
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -0,0 +1,185 @@
+//===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the subclesses of Expr class declared in ExprCXX.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ExprConcepts.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConcept.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/TrailingObjects.h"
+#include <algorithm>
+#include <utility>
+#include <string>
+
+using namespace clang;
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C,
+ NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
+ DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction)
+ : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false,
+ // All the flags below are set in setTemplateArguments.
+ /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false,
+ /*ContainsUnexpandedParameterPacks=*/false),
+ ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
+ NamedConcept, ArgsAsWritten),
+ NumTemplateArgs(ConvertedArgs.size()),
+ Satisfaction(Satisfaction ?
+ ASTConstraintSatisfaction::Create(C, *Satisfaction) :
+ nullptr) {
+ setTemplateArguments(ConvertedArgs);
+}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
+ unsigned NumTemplateArgs)
+ : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
+ NumTemplateArgs(NumTemplateArgs) { }
+
+void ConceptSpecializationExpr::setTemplateArguments(
+ ArrayRef<TemplateArgument> Converted) {
+ assert(Converted.size() == NumTemplateArgs);
+ std::uninitialized_copy(Converted.begin(), Converted.end(),
+ getTrailingObjects<TemplateArgument>());
+ bool IsInstantiationDependent = false;
+ bool ContainsUnexpandedParameterPack = false;
+ for (const TemplateArgument& Arg : Converted) {
+ if (Arg.isInstantiationDependent())
+ IsInstantiationDependent = true;
+ if (Arg.containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
+ break;
+ }
+
+ // Currently guaranteed by the fact concepts can only be at namespace-scope.
+ assert(!NestedNameSpec ||
+ (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
+ !NestedNameSpec.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()));
+ setInstantiationDependent(IsInstantiationDependent);
+ setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
+ assert((!isValueDependent() || isInstantiationDependent()) &&
+ "should not be value-dependent");
+}
+
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(const ASTContext &C,
+ NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc,
+ DeclarationNameInfo ConceptNameInfo,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ const ConstraintSatisfaction *Satisfaction) {
+ void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
+ ConvertedArgs.size()));
+ return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
+ ConceptNameInfo, FoundDecl,
+ NamedConcept, ArgsAsWritten,
+ ConvertedArgs, Satisfaction);
+}
+
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
+ unsigned NumTemplateArgs) {
+ void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
+ NumTemplateArgs));
+ return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
+}
+
+const TypeConstraint *
+concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
+ assert(isTypeConstraint());
+ auto TPL =
+ TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
+ return cast<TemplateTypeParmDecl>(TPL->getParam(0))
+ ->getTypeConstraint();
+}
+
+RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc)
+ : Expr(RequiresExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+ /*TD=*/false, /*VD=*/false, /*ID=*/false,
+ /*ContainsUnexpandedParameterPack=*/false),
+ NumLocalParameters(LocalParameters.size()),
+ NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
+ RequiresExprBits.IsSatisfied = false;
+ RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
+ bool Dependent = false;
+ bool ContainsUnexpandedParameterPack = false;
+ for (ParmVarDecl *P : LocalParameters) {
+ Dependent |= P->getType()->isInstantiationDependentType();
+ ContainsUnexpandedParameterPack |=
+ P->getType()->containsUnexpandedParameterPack();
+ }
+ RequiresExprBits.IsSatisfied = true;
+ for (concepts::Requirement *R : Requirements) {
+ Dependent |= R->isDependent();
+ ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
+ if (!Dependent) {
+ RequiresExprBits.IsSatisfied = R->isSatisfied();
+ if (!RequiresExprBits.IsSatisfied)
+ break;
+ }
+ }
+ std::copy(LocalParameters.begin(), LocalParameters.end(),
+ getTrailingObjects<ParmVarDecl *>());
+ std::copy(Requirements.begin(), Requirements.end(),
+ getTrailingObjects<concepts::Requirement *>());
+ RequiresExprBits.IsSatisfied |= Dependent;
+ setValueDependent(Dependent);
+ setInstantiationDependent(Dependent);
+ setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
+}
+
+RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
+ unsigned NumLocalParameters,
+ unsigned NumRequirements)
+ : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
+ NumRequirements(NumRequirements) { }
+
+RequiresExpr *
+RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc) {
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
+ LocalParameters.size(), Requirements.size()),
+ alignof(RequiresExpr));
+ return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
+ Requirements, RBraceLoc);
+}
+
+RequiresExpr *
+RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
+ unsigned NumLocalParameters, unsigned NumRequirements) {
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
+ NumLocalParameters, NumRequirements),
+ alignof(RequiresExpr));
+ return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
+}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index c4b27b5d1daa..c79973507323 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9912,6 +9912,7 @@ public:
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
bool VisitSourceLocExpr(const SourceLocExpr *E);
bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
+ bool VisitRequiresExpr(const RequiresExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
@@ -12524,6 +12525,9 @@ bool IntExprEvaluator::VisitConceptSpecializationExpr(
return Success(E->isSatisfied(), E);
}
+bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) {
+ return Success(E->isSatisfied(), E);
+}
bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
@@ -14182,6 +14186,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::CXXScalarValueInitExprClass:
case Expr::TypeTraitExprClass:
case Expr::ConceptSpecializationExprClass:
+ case Expr::RequiresExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 0d567edac521..5d485e000750 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
@@ -3668,6 +3669,7 @@ recurse:
case Expr::ConvertVectorExprClass:
case Expr::StmtExprClass:
case Expr::TypeTraitExprClass:
+ case Expr::RequiresExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 27fdca1c4b9c..1f9ff9e407dc 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -857,6 +857,13 @@ public:
void VisitAutoType(const AutoType *T) {
ID.AddInteger((unsigned)T->getKeyword());
+ ID.AddInteger(T->isConstrained());
+ if (T->isConstrained()) {
+ AddDecl(T->getTypeConstraintConcept());
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->getTypeConstraintArguments())
+ Hash.AddTemplateArgument(TA);
+ }
VisitDeducedType(T);
}
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index b6e4d8aff21e..7409ae7ddc9e 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index c14bb886bb11..45fd8ceae8d3 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2269,6 +2269,60 @@ void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
Policy);
}
+void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) {
+ OS << "requires ";
+ auto LocalParameters = E->getLocalParameters();
+ if (!LocalParameters.empty()) {
+ OS << "(";
+ for (ParmVarDecl *LocalParam : LocalParameters) {
+ PrintRawDecl(LocalParam);
+ if (LocalParam != LocalParameters.back())
+ OS << ", ";
+ }
+
+ OS << ") ";
+ }
+ OS << "{ ";
+ auto Requirements = E->getRequirements();
+ for (concepts::Requirement *Req : Requirements) {
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) {
+ if (TypeReq->isSubstitutionFailure())
+ OS << "<<error-type>>";
+ else
+ TypeReq->getType()->getType().print(OS, Policy);
+ } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) {
+ if (ExprReq->isCompound())
+ OS << "{ ";
+ if (ExprReq->isExprSubstitutionFailure())
+ OS << "<<error-expression>>";
+ else
+ PrintExpr(ExprReq->getExpr());
+ if (ExprReq->isCompound()) {
+ OS << " }";
+ if (ExprReq->getNoexceptLoc().isValid())
+ OS << " noexcept";
+ const auto &RetReq = ExprReq->getReturnTypeRequirement();
+ if (!RetReq.isEmpty()) {
+ OS << " -> ";
+ if (RetReq.isSubstitutionFailure())
+ OS << "<<error-type>>";
+ else if (RetReq.isTypeConstraint())
+ RetReq.getTypeConstraint()->print(OS, Policy);
+ }
+ }
+ } else {
+ auto *NestedReq = cast<concepts::NestedRequirement>(Req);
+ OS << "requires ";
+ if (NestedReq->isSubstitutionFailure())
+ OS << "<<error-expression>>";
+ else
+ PrintExpr(NestedReq->getConstraintExpr());
+ }
+ OS << "; ";
+ }
+ OS << "}";
+}
+
// C++ Coroutines TS
void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 2aa5106e90fa..382ea5c8d7ef 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1335,9 +1335,52 @@ void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
void StmtProfiler::VisitConceptSpecializationExpr(
const ConceptSpecializationExpr *S) {
VisitExpr(S);
- VisitDecl(S->getFoundDecl());
- VisitTemplateArguments(S->getTemplateArgsAsWritten()->getTemplateArgs(),
- S->getTemplateArgsAsWritten()->NumTemplateArgs);
+ VisitDecl(S->getNamedConcept());
+ for (const TemplateArgument &Arg : S->getTemplateArguments())
+ VisitTemplateArgument(Arg);
+}
+
+void StmtProfiler::VisitRequiresExpr(const RequiresExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getLocalParameters().size());
+ for (ParmVarDecl *LocalParam : S->getLocalParameters())
+ VisitDecl(LocalParam);
+ ID.AddInteger(S->getRequirements().size());
+ for (concepts::Requirement *Req : S->getRequirements()) {
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) {
+ ID.AddInteger(concepts::Requirement::RK_Type);
+ ID.AddBoolean(TypeReq->isSubstitutionFailure());
+ if (!TypeReq->isSubstitutionFailure())
+ VisitType(TypeReq->getType()->getType());
+ } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) {
+ ID.AddInteger(concepts::Requirement::RK_Compound);
+ ID.AddBoolean(ExprReq->isExprSubstitutionFailure());
+ if (!ExprReq->isExprSubstitutionFailure())
+ Visit(ExprReq->getExpr());
+ // C++2a [expr.prim.req.compound]p1 Example:
+ // [...] The compound-requirement in C1 requires that x++ is a valid
+ // expression. It is equivalent to the simple-requirement x++; [...]
+ // We therefore do not profile isSimple() here.
+ ID.AddBoolean(ExprReq->getNoexceptLoc().isValid());
+ const concepts::ExprRequirement::ReturnTypeRequirement &RetReq =
+ ExprReq->getReturnTypeRequirement();
+ if (RetReq.isEmpty()) {
+ ID.AddInteger(0);
+ } else if (RetReq.isTypeConstraint()) {
+ ID.AddInteger(1);
+ Visit(RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint());
+ } else {
+ assert(RetReq.isSubstitutionFailure());
+ ID.AddInteger(2);
+ }
+ } else {
+ ID.AddInteger(concepts::Requirement::RK_Nested);
+ auto *NestedReq = cast<concepts::NestedRequirement>(Req);
+ ID.AddBoolean(NestedReq->isSubstitutionFailure());
+ if (!NestedReq->isSubstitutionFailure())
+ Visit(NestedReq->getConstraintExpr());
+ }
+ }
}
static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index db16c2a06b64..6f0ebf232e77 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -561,7 +561,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
}
const ASTTemplateArgumentListInfo *
-ASTTemplateArgumentListInfo::Create(ASTContext &C,
+ASTTemplateArgumentListInfo::Create(const ASTContext &C,
const TemplateArgumentListInfo &List) {
std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());
void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo));
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 965ad17fcfa5..c9b571862c19 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1201,6 +1201,11 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
OS << " decltype(auto)";
if (!T->isDeduced())
OS << " undeduced";
+ if (T->isConstrained()) {
+ dumpDeclRef(T->getTypeConstraintConcept());
+ for (const auto &Arg : T->getTypeConstraintArguments())
+ VisitTemplateArgument(Arg);
+ }
}
void TextNodeDumper::VisitTemplateSpecializationType(
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index c5ad711d872e..5099494da5fd 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1114,7 +1114,9 @@ public:
return QualType(T, 0);
return Ctx.getAutoType(deducedType, T->getKeyword(),
- T->isDependentType());
+ T->isDependentType(), /*IsPack=*/false,
+ T->getTypeConstraintConcept(),
+ T->getTypeConstraintArguments());
}
// FIXME: Non-trivial to implement, but important for C++
@@ -4158,3 +4160,35 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
/*HasUnsignedPadding=*/false);
APFixedPoint(Val, FXSema).toString(Str);
}
+
+AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
+ bool IsDeducedAsDependent, bool IsDeducedAsPack,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs)
+ : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
+ IsDeducedAsDependent, IsDeducedAsPack) {
+ AutoTypeBits.Keyword = (unsigned)Keyword;
+ AutoTypeBits.NumArgs = TypeConstraintArgs.size();
+ this->TypeConstraintConcept = TypeConstraintConcept;
+ if (TypeConstraintConcept) {
+ TemplateArgument *ArgBuffer = getArgBuffer();
+ for (const TemplateArgument &Arg : TypeConstraintArgs) {
+ if (Arg.containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
+ new (ArgBuffer++) TemplateArgument(Arg);
+ }
+ }
+}
+
+void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Deduced, AutoTypeKeyword Keyword,
+ bool IsDependent, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> Arguments) {
+ ID.AddPointer(Deduced.getAsOpaquePtr());
+ ID.AddInteger((unsigned)Keyword);
+ ID.AddBoolean(IsDependent);
+ ID.AddPointer(CD);
+ for (const TemplateArgument &Arg : Arguments)
+ Arg.Profile(ID, Context);
+}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index 6e67ca8e0af7..665a86f2c143 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
@@ -589,3 +590,97 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
}
}
}
+
+DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const {
+ return DeclarationNameInfo(getNamedConcept()->getDeclName(),
+ getLocalData()->ConceptNameLoc);
+}
+
+void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
+ setTemplateKWLoc(Loc);
+ setConceptNameLoc(Loc);
+ setFoundDecl(nullptr);
+ setRAngleLoc(Loc);
+ setLAngleLoc(Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
+ getTypePtr()->getArgs(),
+ getArgInfos(), Loc);
+ setNameLoc(Loc);
+}
+
+
+namespace {
+
+ class GetContainedAutoTypeLocVisitor :
+ public TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc> {
+ public:
+ using TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc>::Visit;
+
+ TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) {
+ return TL;
+ }
+
+ // Only these types can contain the desired 'auto' type.
+
+ TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) {
+ return Visit(T.getNamedTypeLoc());
+ }
+
+ TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) {
+ return Visit(T.getUnqualifiedLoc());
+ }
+
+ TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) {
+ return Visit(T.getElementLoc());
+ }
+
+ TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) {
+ return Visit(T.getReturnLoc());
+ }
+
+ TypeLoc VisitParenTypeLoc(ParenTypeLoc T) {
+ return Visit(T.getInnerLoc());
+ }
+
+ TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) {
+ return Visit(T.getModifiedLoc());
+ }
+
+ TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) {
+ return Visit(T.getInnerLoc());
+ }
+
+ TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) {
+ return Visit(T.getOriginalLoc());
+ }
+
+ TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) {
+ return Visit(T.getPatternLoc());
+ }
+ };
+
+} // namespace
+
+AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const {
+ TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this);
+ if (Res.isNull())
+ return AutoTypeLoc();
+ return Res.getAs<AutoTypeLoc>();
+}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index c2f4baec989e..4a7e765a2bd8 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1046,6 +1046,13 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
if (!T->getDeducedType().isNull()) {
printBefore(T->getDeducedType(), OS);
} else {
+ if (T->isConstrained()) {
+ OS << T->getTypeConstraintConcept()->getName();
+ auto Args = T->getTypeConstraintArguments();
+ if (!Args.empty())
+ printTemplateArgumentList(OS, Args, Policy);
+ OS << ' ';
+ }
switch (T->getKeyword()) {
case AutoTypeKeyword::Auto: OS << "auto"; break;
case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break;
@@ -1234,20 +1241,18 @@ void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {}
void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
raw_ostream &OS) {
- if (IdentifierInfo *Id = T->getIdentifier())
- OS << Id->getName();
- else {
- bool IsLambdaAutoParam = false;
- if (auto D = T->getDecl()) {
- if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
- IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
+ TemplateTypeParmDecl *D = T->getDecl();
+ if (D && D->isImplicit()) {
+ if (auto *TC = D->getTypeConstraint()) {
+ TC->print(OS, Policy);
+ OS << ' ';
}
+ OS << "auto";
+ } else if (IdentifierInfo *Id = T->getIdentifier())
+ OS << Id->getName();
+ else
+ OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
- if (IsLambdaAutoParam)
- OS << "auto";
- else
- OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
- }
spaceBeforePlaceHolder(OS);
}
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 4aebea19924f..ee25bd883caf 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -142,7 +142,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
// We treat bridge casts as objective-C keywords so we can warn on them
// in non-arc mode.
if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled;
- if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled;
+ if (LangOpts.CPlusPlus2a && (Flags & KEYCONCEPTS)) return KS_Enabled;
if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled;
if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled;
if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 09fd3087b494..2d20f92fbb3d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3222,6 +3222,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))),
ConvertType(E->getType())));
}
+ case Builtin::BI__warn_memset_zero_len:
+ return RValue::getIgnored();
case Builtin::BI__annotation: {
// Re-encode each wide string to UTF8 and make an MDString.
SmallVector<Metadata *, 1> Strings;
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 5aac7a8d54c7..60f1dba7c768 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -111,6 +111,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Empty:
case Decl::Concept:
case Decl::LifetimeExtendedTemporary:
+ case Decl::RequiresExprBody:
// None of these decls require codegen support.
return;
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 3f23fe11e4f5..de5c3a03fb68 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -680,6 +680,10 @@ public:
return Builder.getInt1(E->isSatisfied());
}
+ Value *VisitRequiresExpr(const RequiresExpr *E) {
+ return Builder.getInt1(E->isSatisfied());
+ }
+
Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue());
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2bf94f697e01..648e6d9c214a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -820,13 +820,18 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
}
+ unsigned Count, Offset;
if (const auto *Attr = D->getAttr<PatchableFunctionEntryAttr>()) {
- // Attr->getStart is currently ignored.
- Fn->addFnAttr("patchable-function-entry",
- std::to_string(Attr->getCount()));
- } else if (unsigned Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount) {
- Fn->addFnAttr("patchable-function-entry",
- std::to_string(Count));
+ Count = Attr->getCount();
+ Offset = Attr->getOffset();
+ } else {
+ Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount;
+ Offset = CGM.getCodeGenOpts().PatchableFunctionEntryOffset;
+ }
+ if (Count && Offset <= Count) {
+ Fn->addFnAttr("patchable-function-entry", std::to_string(Count - Offset));
+ if (Offset)
+ Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset));
}
}
diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp
index ba188f5c4083..25aec3690f21 100644
--- a/clang/lib/Driver/Compilation.cpp
+++ b/clang/lib/Driver/Compilation.cpp
@@ -172,7 +172,7 @@ int Compilation::ExecuteCommand(const Command &C,
}
if (getDriver().CCPrintOptions)
- *OS << "[Logging clang options]";
+ *OS << "[Logging clang options]\n";
C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
}
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index d57c3a1cdbb8..7dab2a022d92 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -373,7 +373,7 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
CrashReportInfo *CrashInfo) const {
- OS << " (in-process)";
+ OS << " (in-process)\n";
Command::Print(OS, Terminator, Quote, CrashInfo);
}
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 3ebbd30195b3..cab97b1a601a 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -68,8 +68,7 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args,
}
// -frtti is default, except for the PS4 CPU.
- return (Triple.isPS4CPU() || Triple.isNVPTX()) ? ToolChain::RM_Disabled
- : ToolChain::RM_Enabled;
+ return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled;
}
ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 9b3055413e9e..647465863d3e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5077,20 +5077,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) {
StringRef S0 = A->getValue(), S = S0;
- unsigned Size, Start = 0;
+ unsigned Size, Offset = 0;
if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 &&
Triple.getArch() != llvm::Triple::x86_64)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
else if (S.consumeInteger(10, Size) ||
(!S.empty() && (!S.consume_front(",") ||
- S.consumeInteger(10, Start) || !S.empty())))
+ S.consumeInteger(10, Offset) || !S.empty())))
D.Diag(diag::err_drv_invalid_argument_to_option)
<< S0 << A->getOption().getName();
- else if (Start)
+ else if (Size < Offset)
D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument);
- else
+ else {
CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size)));
+ CmdArgs.push_back(Args.MakeArgString(
+ "-fpatchable-function-entry-offset=" + Twine(Offset)));
+ }
}
if (TC.SupportsProfiling()) {
diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp
index f89e648948ab..da7004cf283f 100644
--- a/clang/lib/Driver/ToolChains/HIP.cpp
+++ b/clang/lib/Driver/ToolChains/HIP.cpp
@@ -105,9 +105,8 @@ const char *AMDGCN::Linker::constructLLVMLinkCommand(
CmdArgs.push_back("-o");
auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-linked", "bc");
CmdArgs.push_back(OutputFileName);
- SmallString<128> ExecPath(C.getDriver().Dir);
- llvm::sys::path::append(ExecPath, "llvm-link");
- const char *Exec = Args.MakeArgString(ExecPath);
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
return OutputFileName;
}
@@ -133,9 +132,8 @@ const char *AMDGCN::Linker::constructOptCommand(
auto OutputFileName =
getOutputFileName(C, OutputFilePrefix, "-optimized", "bc");
OptArgs.push_back(OutputFileName);
- SmallString<128> OptPath(C.getDriver().Dir);
- llvm::sys::path::append(OptPath, "opt");
- const char *OptExec = Args.MakeArgString(OptPath);
+ const char *OptExec =
+ Args.MakeArgString(getToolChain().GetProgramPath("opt"));
C.addCommand(std::make_unique<Command>(JA, *this, OptExec, OptArgs, Inputs));
return OutputFileName;
}
@@ -180,9 +178,7 @@ const char *AMDGCN::Linker::constructLlcCommand(
auto LlcOutputFile =
getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o");
LlcArgs.push_back(LlcOutputFile);
- SmallString<128> LlcPath(C.getDriver().Dir);
- llvm::sys::path::append(LlcPath, "llc");
- const char *Llc = Args.MakeArgString(LlcPath);
+ const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc"));
C.addCommand(std::make_unique<Command>(JA, *this, Llc, LlcArgs, Inputs));
return LlcOutputFile;
}
@@ -196,9 +192,7 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
// The output from ld.lld is an HSA code object file.
ArgStringList LldArgs{
"-flavor", "gnu", "-shared", "-o", Output.getFilename(), InputFileName};
- SmallString<128> LldPath(C.getDriver().Dir);
- llvm::sys::path::append(LldPath, "lld");
- const char *Lld = Args.MakeArgString(LldPath);
+ const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
C.addCommand(std::make_unique<Command>(JA, *this, Lld, LldArgs, Inputs));
}
@@ -230,9 +224,8 @@ void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
Args.MakeArgString(std::string("-outputs=").append(OutputFileName));
BundlerArgs.push_back(BundlerOutputArg);
- SmallString<128> BundlerPath(C.getDriver().Dir);
- llvm::sys::path::append(BundlerPath, "clang-offload-bundler");
- const char *Bundler = Args.MakeArgString(BundlerPath);
+ const char *Bundler = Args.MakeArgString(
+ T.getToolChain().GetProgramPath("clang-offload-bundler"));
C.addCommand(std::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs));
}
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index d5d394e61926..88564e02f23e 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -2596,7 +2596,7 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const {
/// otherwise.
static bool isKeywordWithCondition(const FormatToken &Tok) {
return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
- tok::kw_constexpr);
+ tok::kw_constexpr, tok::kw_catch);
}
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index e1e59565083b..4e5babdbaa03 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1103,6 +1103,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.PatchableFunctionEntryCount =
getLastArgIntValue(Args, OPT_fpatchable_function_entry_EQ, 0, Diags);
+ Opts.PatchableFunctionEntryOffset = getLastArgIntValue(
+ Args, OPT_fpatchable_function_entry_offset_EQ, 0, Diags);
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
Opts.CallFEntry = Args.hasArg(OPT_mfentry);
Opts.MNopMCount = Args.hasArg(OPT_mnop_mcount);
@@ -2852,7 +2854,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
<< A->getValue();
Opts.NewAlignOverride = 0;
}
- Opts.ConceptsTS = Args.hasArg(OPT_fconcepts_ts);
+ Opts.ConceptSatisfactionCaching =
+ !Args.hasArg(OPT_fno_concept_satisfaction_caching);
+ if (Args.hasArg(OPT_fconcepts_ts))
+ Diags.Report(diag::warn_fe_concepts_ts_flag);
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 8574d0a7e813..935c64a0fa13 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -429,6 +429,10 @@ private:
return "ConstraintNormalization";
case CodeSynthesisContext::ParameterMappingSubstitution:
return "ParameterMappingSubstitution";
+ case CodeSynthesisContext::RequirementInstantiation:
+ return "RequirementInstantiation";
+ case CodeSynthesisContext::NestedRequirementConstraintsCheck:
+ return "NestedRequirementConstraintsCheck";
}
return "";
}
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 2c7e3a56c043..8a0ff55e44fc 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -548,7 +548,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
// C++20 features.
if (LangOpts.CPlusPlus2a) {
//Builder.defineMacro("__cpp_aggregate_paren_init", "201902L");
- //Builder.defineMacro("__cpp_concepts", "201907L");
+ Builder.defineMacro("__cpp_concepts", "201907L");
Builder.defineMacro("__cpp_conditional_explicit", "201806L");
//Builder.defineMacro("__cpp_consteval", "201811L");
Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L");
@@ -564,8 +564,6 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
// TS features.
- if (LangOpts.ConceptsTS)
- Builder.defineMacro("__cpp_experimental_concepts", "1L");
if (LangOpts.Coroutines)
Builder.defineMacro("__cpp_coroutines", "201703L");
}
diff --git a/clang/lib/Headers/ppc_wrappers/emmintrin.h b/clang/lib/Headers/ppc_wrappers/emmintrin.h
index 293276cc9be0..4dcb8485e2e9 100644
--- a/clang/lib/Headers/ppc_wrappers/emmintrin.h
+++ b/clang/lib/Headers/ppc_wrappers/emmintrin.h
@@ -1749,7 +1749,7 @@ _mm_sll_epi64 (__m128i __A, __m128i __B)
lshift = vec_splat ((__v2du) __B, 0);
shmask = vec_cmplt (lshift, shmax);
result = vec_sl ((__v2du) __A, lshift);
- result = vec_sel ((__v2du) shmask, result, shmask);
+ result = (__v2du)vec_sel ((__v2df) shmask, (__v2df)result, shmask);
return (__m128i) result;
}
@@ -1843,7 +1843,7 @@ _mm_srl_epi64 (__m128i __A, __m128i __B)
rshift = vec_splat ((__v2du) __B, 0);
shmask = vec_cmplt (rshift, shmax);
result = vec_sr ((__v2du) __A, rshift);
- result = vec_sel ((__v2du) shmask, result, shmask);
+ result = (__v2du)vec_sel ((__v2df) shmask, (__v2df)result, shmask);
return (__m128i) result;
}
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index f8b5fec43800..a75965784168 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -133,7 +133,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
LexedMethod* LM = new LexedMethod(this, FnD);
getCurrentClass().LateParsedDeclarations.push_back(LM);
- LM->TemplateScope = getCurScope()->isTemplateParamScope();
+ LM->TemplateScope = getCurScope()->isTemplateParamScope() ||
+ (FnD && isa<FunctionTemplateDecl>(FnD) &&
+ cast<FunctionTemplateDecl>(FnD)->isAbbreviated());
CachedTokens &Toks = LM->Toks;
tok::TokenKind kind = Tok.getKind();
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 69a3ed9cbad7..4af993c4527f 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2962,6 +2962,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
case Sema::NC_ContextIndependentExpr:
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
+ case Sema::NC_Concept:
// Might be a redeclaration of a prior entity.
break;
}
@@ -3177,7 +3178,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DSContext == DeclSpecContext::DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
- isConstructorDeclarator(/*Unqualified*/ false)) {
+ isConstructorDeclarator(/*Unqualified=*/false)) {
// The user meant this to be an out-of-line constructor
// definition, but template arguments are not allowed
// there. Just allow this as a constructor; we'll
@@ -3189,7 +3190,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeAnnotationToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
- AnnotateTemplateIdTokenAsType();
+ AnnotateTemplateIdTokenAsType(SS);
+ continue;
+ }
+
+ if (Next.is(tok::annot_template_id) &&
+ static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
+ ->Kind == TNK_Concept_template &&
+ GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) {
+ DS.getTypeSpecScope() = SS;
+ // This is a qualified placeholder-specifier, e.g., ::C<int> auto ...
+ // Consume the scope annotation and continue to consume the template-id
+ // as a placeholder-specifier.
+ ConsumeAnnotationToken();
continue;
}
@@ -3235,6 +3248,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
// typename.
if (!TypeRep) {
+ if (TryAnnotateTypeConstraint())
+ goto DoneWithDeclSpec;
+ if (isTypeConstraintAnnotation())
+ continue;
// Eat the scope spec so the identifier is current.
ConsumeAnnotationToken();
ParsedAttributesWithRange Attrs(AttrFactory);
@@ -3384,6 +3401,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
if (!TypeRep) {
+ if (TryAnnotateTypeConstraint())
+ goto DoneWithDeclSpec;
+ if (isTypeConstraintAnnotation())
+ continue;
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
@@ -3433,9 +3454,51 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
- // type-name
+ // type-name or placeholder-specifier
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ if (TemplateId->Kind == TNK_Concept_template) {
+ if (NextToken().is(tok::identifier)) {
+ Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto)
+ << FixItHint::CreateInsertion(NextToken().getLocation(), "auto");
+ // Attempt to continue as if 'auto' was placed here.
+ isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
+ TemplateId, Policy);
+ break;
+ }
+ if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
+ goto DoneWithDeclSpec;
+ ConsumeAnnotationToken();
+ SourceLocation AutoLoc = Tok.getLocation();
+ if (TryConsumeToken(tok::kw_decltype)) {
+ BalancedDelimiterTracker Tracker(*this, tok::l_paren);
+ if (Tracker.consumeOpen()) {
+ // Something like `void foo(Iterator decltype i)`
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ } else {
+ if (!TryConsumeToken(tok::kw_auto)) {
+ // Something like `void foo(Iterator decltype(int) i)`
+ Tracker.skipToEnd();
+ Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto)
+ << FixItHint::CreateReplacement(SourceRange(AutoLoc,
+ Tok.getLocation()),
+ "auto");
+ } else {
+ Tracker.consumeClose();
+ }
+ }
+ ConsumedEnd = Tok.getLocation();
+ // Even if something went wrong above, continue as if we've seen
+ // `decltype(auto)`.
+ isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
+ DiagID, TemplateId, Policy);
+ } else {
+ isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
+ TemplateId, Policy);
+ }
+ break;
+ }
+
if (TemplateId->Kind != TNK_Type_template &&
TemplateId->Kind != TNK_Undeclared_template) {
// This template-id does not refer to a type name, so we're
@@ -3448,12 +3511,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
- isConstructorDeclarator(TemplateId->SS.isEmpty()))
+ isConstructorDeclarator(/*Unqualified=*/true))
goto DoneWithDeclSpec;
// Turn the template-id annotation token into a type annotation
// token, then try again to parse it as a type-specifier.
- AnnotateTemplateIdTokenAsType();
+ CXXScopeSpec SS;
+ AnnotateTemplateIdTokenAsType(SS);
continue;
}
@@ -3617,7 +3681,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumedEnd = ExplicitLoc;
ConsumeToken(); // kw_explicit
if (Tok.is(tok::l_paren)) {
- if (getLangOpts().CPlusPlus2a) {
+ if (getLangOpts().CPlusPlus2a || isExplicitBool() == TPResult::True) {
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_explicit_bool
+ : diag::ext_explicit_bool);
+
ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
BalancedDelimiterTracker Tracker(*this, tok::l_paren);
Tracker.consumeOpen();
@@ -3630,8 +3698,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
} else
Tracker.skipToEnd();
- } else
+ } else {
Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
+ }
}
isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
ExplicitSpec, CloseParenLoc);
@@ -6021,11 +6090,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
while (1) {
if (Tok.is(tok::l_paren)) {
+ bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration();
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope|Scope::DeclScope|
- (D.isFunctionDeclaratorAFunctionDeclaration()
+ (IsFunctionDeclaration
? Scope::FunctionDeclarationScope : 0));
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
@@ -6044,7 +6114,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
ParsedAttributes attrs(AttrFactory);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
+ if (IsFunctionDeclaration)
+ Actions.ActOnStartFunctionDeclarationDeclarator(D,
+ TemplateParameterDepth);
ParseFunctionDeclarator(D, attrs, T, IsAmbiguous);
+ if (IsFunctionDeclaration)
+ Actions.ActOnFinishFunctionDeclarationDeclarator(D);
PrototypeScope.Exit();
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
@@ -6360,7 +6435,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ProhibitAttributes(FnAttrs);
} else {
if (Tok.isNot(tok::r_paren))
- ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo,
+ ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo,
EllipsisLoc);
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -6578,9 +6653,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
/// after the opening parenthesis. This function will not parse a K&R-style
/// identifier list.
///
-/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the
-/// caller parsed those arguments immediately after the open paren - they should
-/// be considered to be part of the first parameter.
+/// DeclContext is the context of the declarator being parsed. If FirstArgAttrs
+/// is non-null, then the caller parsed those attributes immediately after the
+/// open paren - they should be considered to be part of the first parameter.
///
/// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
/// be the location of the ellipsis, if any was parsed.
@@ -6606,7 +6681,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
/// [C++11] attribute-specifier-seq parameter-declaration
///
void Parser::ParseParameterDeclarationClause(
- Declarator &D,
+ DeclaratorContext DeclaratorCtx,
ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc) {
@@ -6655,9 +6730,11 @@ void Parser::ParseParameterDeclarationClause(
// "LambdaExprParameterContext", because we must accept either
// 'declarator' or 'abstract-declarator' here.
Declarator ParmDeclarator(
- DS, D.getContext() == DeclaratorContext::LambdaExprContext
- ? DeclaratorContext::LambdaExprParameterContext
- : DeclaratorContext::PrototypeContext);
+ DS, DeclaratorCtx == DeclaratorContext::RequiresExprContext
+ ? DeclaratorContext::RequiresExprContext
+ : DeclaratorCtx == DeclaratorContext::LambdaExprContext
+ ? DeclaratorContext::LambdaExprParameterContext
+ : DeclaratorContext::PrototypeContext);
ParseDeclarator(ParmDeclarator);
// Parse GNU attributes, if present.
@@ -6711,7 +6788,7 @@ void Parser::ParseParameterDeclarationClause(
SourceLocation EqualLoc = Tok.getLocation();
// Parse the default argument
- if (D.getContext() == DeclaratorContext::MemberContext) {
+ if (DeclaratorCtx == DeclaratorContext::MemberContext) {
// If we're inside a class definition, cache the tokens
// corresponding to the default argument. We'll actually parse
// them when we see the end of the class definition.
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 081d4d8b1209..f872aa3a950c 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1142,7 +1142,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name ||
TemplateId->Kind == TNK_Undeclared_template) {
- AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+ AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
ParsedType Type = getTypeAnnotation(Tok);
@@ -1193,7 +1193,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
TemplateName))
return true;
if (TNK == TNK_Type_template || TNK == TNK_Dependent_template_name)
- AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+ AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
// If we didn't end up with a typename token, there's nothing more we
// can do.
@@ -1826,7 +1826,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
ProhibitAttributes(attrs);
TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
- TemplateId->SS,
+ SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
@@ -1876,7 +1876,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Build the class template specialization.
TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
- *TemplateId, attrs,
+ SS, *TemplateId, attrs,
MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
: nullptr,
TemplateParams ? TemplateParams->size() : 0),
@@ -2642,6 +2642,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::MemberContext);
+ if (TemplateInfo.TemplateParams)
+ DeclaratorInfo.setTemplateParameterLists(TemplateParams);
VirtSpecifiers VS;
// Hold late-parsed attributes so we can attach a Decl to them later.
@@ -3520,7 +3522,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
if (TemplateId && (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name ||
TemplateId->Kind == TNK_Undeclared_template)) {
- AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+ AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = getTypeAnnotation(Tok);
ConsumeAnnotationToken();
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 1442df046bb9..1eb3ad6afd1c 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -234,7 +234,7 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
/// \endverbatim
ExprResult Parser::ParseConstraintExpression() {
EnterExpressionEvaluationContext ConstantEvaluated(
- Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult LHS(ParseCastExpression(AnyCastExpr));
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) {
@@ -256,7 +256,7 @@ ExprResult Parser::ParseConstraintExpression() {
ExprResult
Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) {
EnterExpressionEvaluationContext ConstantEvaluated(
- Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
bool NotPrimaryExpression = false;
auto ParsePrimary = [&] () {
ExprResult E = ParseCastExpression(PrimaryExprOnly,
@@ -756,6 +756,7 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {
/// [C++11] user-defined-literal
/// '(' expression ')'
/// [C11] generic-selection
+/// [C++2a] requires-expression
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
/// [MS] '__FUNCDNAME__'
@@ -1530,7 +1531,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, nullptr,
/*EnteringContext=*/false);
- AnnotateTemplateIdTokenAsType();
+ AnnotateTemplateIdTokenAsType(SS);
return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
isTypeCast, isVectorLiteral,
NotPrimaryExpression);
@@ -1548,7 +1549,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// We have a template-id that we know refers to a type,
// translate it into a type and continue parsing as a cast
// expression.
- AnnotateTemplateIdTokenAsType();
+ CXXScopeSpec SS;
+ AnnotateTemplateIdTokenAsType(SS);
return ParseCastExpression(ParseKind, isAddressOfOperand,
NotCastExpr, isTypeCast, isVectorLiteral,
NotPrimaryExpression);
@@ -1600,6 +1602,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
*NotPrimaryExpression = true;
return ParseCXXDeleteExpression(false, Tok.getLocation());
+ case tok::kw_requires: // [C++2a] requires-expression
+ return ParseRequiresExpression();
+
case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'
if (NotPrimaryExpression)
*NotPrimaryExpression = true;
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index e685d5ea8a9c..036eabb94dd7 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Parse/ParseDiagnostic.h"
@@ -165,13 +167,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
- if (Tok.is(tok::annot_template_id)) {
- // If the current token is an annotated template id, it may already have
- // a scope specifier. Restore it.
- TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- SS = TemplateId->SS;
- }
-
// Has to happen before any "return false"s in this function.
bool CheckForDestructor = false;
if (MayBePseudoDestructor && *MayBePseudoDestructor) {
@@ -1306,9 +1301,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Actions.RecordParsingTemplateParameterDepth(
CurTemplateDepthTracker.getOriginalDepth());
- ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
-
- // For a generic lambda, each 'auto' within the parameter declaration
+ ParseParameterDeclarationClause(D.getContext(), Attr, ParamInfo,
+ EllipsisLoc);
+ // For a generic lambda, each 'auto' within the parameter declaration
// clause creates a template type parameter, so increment the depth.
// If we've parsed any explicit template parameters, then the depth will
// have already been incremented. So we make sure that at most a single
@@ -2405,7 +2400,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
: Id.OperatorFunctionId.Operator;
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
- SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
+ TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
Id.setTemplateId(TemplateId);
@@ -3262,6 +3257,324 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get());
}
+/// ParseRequiresExpression - Parse a C++2a requires-expression.
+/// C++2a [expr.prim.req]p1
+/// A requires-expression provides a concise way to express requirements on
+/// template arguments. A requirement is one that can be checked by name
+/// lookup (6.4) or by checking properties of types and expressions.
+///
+/// requires-expression:
+/// 'requires' requirement-parameter-list[opt] requirement-body
+///
+/// requirement-parameter-list:
+/// '(' parameter-declaration-clause[opt] ')'
+///
+/// requirement-body:
+/// '{' requirement-seq '}'
+///
+/// requirement-seq:
+/// requirement
+/// requirement-seq requirement
+///
+/// requirement:
+/// simple-requirement
+/// type-requirement
+/// compound-requirement
+/// nested-requirement
+ExprResult Parser::ParseRequiresExpression() {
+ assert(Tok.is(tok::kw_requires) && "Expected 'requires' keyword");
+ SourceLocation RequiresKWLoc = ConsumeToken(); // Consume 'requires'
+
+ llvm::SmallVector<ParmVarDecl *, 2> LocalParameterDecls;
+ if (Tok.is(tok::l_paren)) {
+ // requirement parameter list is present.
+ ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope |
+ Scope::DeclScope);
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ Parens.consumeOpen();
+ if (!Tok.is(tok::r_paren)) {
+ ParsedAttributes FirstArgAttrs(getAttrFactory());
+ SourceLocation EllipsisLoc;
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 2> LocalParameters;
+ DiagnosticErrorTrap Trap(Diags);
+ ParseParameterDeclarationClause(DeclaratorContext::RequiresExprContext,
+ FirstArgAttrs, LocalParameters,
+ EllipsisLoc);
+ if (EllipsisLoc.isValid())
+ Diag(EllipsisLoc, diag::err_requires_expr_parameter_list_ellipsis);
+ for (auto &ParamInfo : LocalParameters)
+ LocalParameterDecls.push_back(cast<ParmVarDecl>(ParamInfo.Param));
+ if (Trap.hasErrorOccurred())
+ SkipUntil(tok::r_paren, StopBeforeMatch);
+ }
+ Parens.consumeClose();
+ }
+
+ BalancedDelimiterTracker Braces(*this, tok::l_brace);
+ if (Braces.expectAndConsume())
+ return ExprError();
+
+ // Start of requirement list
+ llvm::SmallVector<concepts::Requirement *, 2> Requirements;
+
+ // C++2a [expr.prim.req]p2
+ // Expressions appearing within a requirement-body are unevaluated operands.
+ EnterExpressionEvaluationContext Ctx(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+
+ ParseScope BodyScope(this, Scope::DeclScope);
+ RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(
+ RequiresKWLoc, LocalParameterDecls, getCurScope());
+
+ if (Tok.is(tok::r_brace)) {
+ // Grammar does not allow an empty body.
+ // requirement-body:
+ // { requirement-seq }
+ // requirement-seq:
+ // requirement
+ // requirement-seq requirement
+ Diag(Tok, diag::err_empty_requires_expr);
+ // Continue anyway and produce a requires expr with no requirements.
+ } else {
+ while (!Tok.is(tok::r_brace)) {
+ switch (Tok.getKind()) {
+ case tok::l_brace: {
+ // Compound requirement
+ // C++ [expr.prim.req.compound]
+ // compound-requirement:
+ // '{' expression '}' 'noexcept'[opt]
+ // return-type-requirement[opt] ';'
+ // return-type-requirement:
+ // trailing-return-type
+ // '->' cv-qualifier-seq[opt] constrained-parameter
+ // cv-qualifier-seq[opt] abstract-declarator[opt]
+ BalancedDelimiterTracker ExprBraces(*this, tok::l_brace);
+ ExprBraces.consumeOpen();
+ ExprResult Expression =
+ Actions.CorrectDelayedTyposInExpr(ParseExpression());
+ if (!Expression.isUsable()) {
+ ExprBraces.skipToEnd();
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ if (ExprBraces.consumeClose())
+ ExprBraces.skipToEnd();
+
+ concepts::Requirement *Req = nullptr;
+ SourceLocation NoexceptLoc;
+ TryConsumeToken(tok::kw_noexcept, NoexceptLoc);
+ if (Tok.is(tok::semi)) {
+ Req = Actions.ActOnCompoundRequirement(Expression.get(), NoexceptLoc);
+ if (Req)
+ Requirements.push_back(Req);
+ break;
+ }
+ if (!TryConsumeToken(tok::arrow))
+ // User probably forgot the arrow, remind them and try to continue.
+ Diag(Tok, diag::err_requires_expr_missing_arrow)
+ << FixItHint::CreateInsertion(Tok.getLocation(), "->");
+ // Try to parse a 'type-constraint'
+ CXXScopeSpec SS;
+ if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ // If this is not a type-constraint,
+ // then this scope-spec is part of
+ // the typename of a non-type
+ // template parameter
+ /*IsTypename=*/true,
+ /*LastII=*/nullptr,
+ // We won't find concepts in
+ // non-namespaces anyway, so might as
+ // well parse this correctly for
+ // possible type names.
+ /*OnlyNamespace=*/false,
+ /*SuppressDiagnostic=*/true)) {
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ if (TryAnnotateTypeConstraint()) {
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ if (!isTypeConstraintAnnotation()) {
+ Diag(Tok, diag::err_requires_expr_expected_type_constraint);
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeAnnotationToken();
+
+ Req = Actions.ActOnCompoundRequirement(
+ Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok),
+ TemplateParameterDepth);
+ ConsumeAnnotationToken();
+ if (Req)
+ Requirements.push_back(Req);
+ break;
+ }
+ default: {
+ bool PossibleRequiresExprInSimpleRequirement = false;
+ if (Tok.is(tok::kw_requires)) {
+ auto IsNestedRequirement = [&] {
+ RevertingTentativeParsingAction TPA(*this);
+ ConsumeToken(); // 'requires'
+ if (Tok.is(tok::l_brace))
+ // This is a requires expression
+ // requires (T t) {
+ // requires { t++; };
+ // ... ^
+ // }
+ return false;
+ if (Tok.is(tok::l_paren)) {
+ // This might be the parameter list of a requires expression
+ ConsumeParen();
+ auto Res = TryParseParameterDeclarationClause();
+ if (Res != TPResult::False) {
+ // Skip to the closing parenthesis
+ // FIXME: Don't traverse these tokens twice (here and in
+ // TryParseParameterDeclarationClause).
+ unsigned Depth = 1;
+ while (Depth != 0) {
+ if (Tok.is(tok::l_paren))
+ Depth++;
+ else if (Tok.is(tok::r_paren))
+ Depth--;
+ ConsumeAnyToken();
+ }
+ // requires (T t) {
+ // requires () ?
+ // ... ^
+ // - OR -
+ // requires (int x) ?
+ // ... ^
+ // }
+ if (Tok.is(tok::l_brace))
+ // requires (...) {
+ // ^ - a requires expression as a
+ // simple-requirement.
+ return false;
+ }
+ }
+ return true;
+ };
+ if (IsNestedRequirement()) {
+ ConsumeToken();
+ // Nested requirement
+ // C++ [expr.prim.req.nested]
+ // nested-requirement:
+ // 'requires' constraint-expression ';'
+ ExprResult ConstraintExpr =
+ Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
+ if (ConstraintExpr.isInvalid() || !ConstraintExpr.isUsable()) {
+ SkipUntil(tok::semi, tok::r_brace,
+ SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ if (auto *Req =
+ Actions.ActOnNestedRequirement(ConstraintExpr.get()))
+ Requirements.push_back(Req);
+ else {
+ SkipUntil(tok::semi, tok::r_brace,
+ SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ break;
+ } else
+ PossibleRequiresExprInSimpleRequirement = true;
+ } else if (Tok.is(tok::kw_typename)) {
+ // This might be 'typename T::value_type;' (a type requirement) or
+ // 'typename T::value_type{};' (a simple requirement).
+ TentativeParsingAction TPA(*this);
+
+ // We need to consume the typename to allow 'requires { typename a; }'
+ SourceLocation TypenameKWLoc = ConsumeToken();
+ if (TryAnnotateCXXScopeToken()) {
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ CXXScopeSpec SS;
+ if (Tok.is(tok::annot_cxxscope)) {
+ Actions.RestoreNestedNameSpecifierAnnotation(
+ Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS);
+ ConsumeAnnotationToken();
+ }
+
+ if (Tok.isOneOf(tok::identifier, tok::annot_template_id) &&
+ !NextToken().isOneOf(tok::l_brace, tok::l_paren)) {
+ TPA.Commit();
+ SourceLocation NameLoc = Tok.getLocation();
+ IdentifierInfo *II = nullptr;
+ TemplateIdAnnotation *TemplateId = nullptr;
+ if (Tok.is(tok::identifier)) {
+ II = Tok.getIdentifierInfo();
+ ConsumeToken();
+ } else {
+ TemplateId = takeTemplateIdAnnotation(Tok);
+ ConsumeAnnotationToken();
+ }
+
+ if (auto *Req = Actions.ActOnTypeRequirement(TypenameKWLoc, SS,
+ NameLoc, II,
+ TemplateId)) {
+ Requirements.push_back(Req);
+ }
+ break;
+ }
+ TPA.Revert();
+ }
+ // Simple requirement
+ // C++ [expr.prim.req.simple]
+ // simple-requirement:
+ // expression ';'
+ SourceLocation StartLoc = Tok.getLocation();
+ ExprResult Expression =
+ Actions.CorrectDelayedTyposInExpr(ParseExpression());
+ if (!Expression.isUsable()) {
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ if (!Expression.isInvalid() && PossibleRequiresExprInSimpleRequirement)
+ Diag(StartLoc, diag::warn_requires_expr_in_simple_requirement)
+ << FixItHint::CreateInsertion(StartLoc, "requires");
+ if (auto *Req = Actions.ActOnSimpleRequirement(Expression.get()))
+ Requirements.push_back(Req);
+ else {
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ // User may have tried to put some compound requirement stuff here
+ if (Tok.is(tok::kw_noexcept)) {
+ Diag(Tok, diag::err_requires_expr_simple_requirement_noexcept)
+ << FixItHint::CreateInsertion(StartLoc, "{")
+ << FixItHint::CreateInsertion(Tok.getLocation(), "}");
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ break;
+ }
+ break;
+ }
+ }
+ if (ExpectAndConsumeSemi(diag::err_expected_semi_requirement)) {
+ SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
+ TryConsumeToken(tok::semi);
+ break;
+ }
+ }
+ if (Requirements.empty()) {
+ // Don't emit an empty requires expr here to avoid confusing the user with
+ // other diagnostics quoting an empty requires expression they never
+ // wrote.
+ Braces.consumeClose();
+ Actions.ActOnFinishRequiresExpr();
+ return ExprError();
+ }
+ }
+ Braces.consumeClose();
+ Actions.ActOnFinishRequiresExpr();
+ return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls,
+ Requirements, Braces.getCloseLocation());
+}
+
static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) {
switch (kind) {
default: llvm_unreachable("Not a known type trait");
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 1b9301b6591d..3bc4e3596f12 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -240,6 +240,8 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
// Parse the declarator.
ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
+ if (TemplateInfo.TemplateParams)
+ DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
ParseDeclarator(DeclaratorInfo);
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
@@ -499,10 +501,7 @@ Parser::ParseTemplateParameterList(const unsigned Depth,
/// Determine whether the parser is at the start of a template
/// type parameter.
-/// \param ScopeError will receive true if there was an error parsing a
-/// scope specifier at the current location.
-bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
- ScopeError = false;
+Parser::TPResult Parser::isStartOfTemplateTypeParameter() {
if (Tok.is(tok::kw_class)) {
// "class" may be the start of an elaborated-type-specifier or a
// type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter.
@@ -512,7 +511,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
case tok::greater:
case tok::greatergreater:
case tok::ellipsis:
- return true;
+ return TPResult::True;
case tok::identifier:
// This may be either a type-parameter or an elaborated-type-specifier.
@@ -520,7 +519,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
break;
default:
- return false;
+ return TPResult::False;
}
switch (GetLookAheadToken(2).getKind()) {
@@ -528,51 +527,28 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
case tok::comma:
case tok::greater:
case tok::greatergreater:
- return true;
+ return TPResult::True;
default:
- return false;
+ return TPResult::False;
}
}
- bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
- CXXScopeSpec SS;
- ScopeError =
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
- /*EnteringContext=*/false,
- /*MayBePseudoDestructor=*/nullptr,
- // If this is not a type-constraint, then
- // this scope-spec is part of the typename
- // of a non-type template parameter
- /*IsTypename=*/true, /*LastII=*/nullptr,
- // We won't find concepts in
- // non-namespaces anyway, so might as well
- // parse this correctly for possible type
- // names.
- /*OnlyNamespace=*/false);
- if (ScopeError)
- return false;
- if (TryAnnotateTypeConstraint(SS))
- return false;
- bool IsTypeConstraint = isTypeConstraintAnnotation();
- if (!IsTypeConstraint && SS.isNotEmpty()) {
- // This isn't a type-constraint but we've already parsed this scope
- // specifier - annotate it.
- AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation);
- return false;
- }
+ if (TryAnnotateTypeConstraint())
+ return TPResult::Error;
- if (IsTypeConstraint &&
+ if (isTypeConstraintAnnotation() &&
// Next token might be 'auto' or 'decltype', indicating that this
// type-constraint is in fact part of a placeholder-type-specifier of a
// non-type template parameter.
- !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
- return true;
+ !GetLookAheadToken(Tok.is(tok::annot_cxxscope) ? 2 : 1)
+ .isOneOf(tok::kw_auto, tok::kw_decltype))
+ return TPResult::True;
// 'typedef' is a reasonably-common typo/thinko for 'typename', and is
// ill-formed otherwise.
if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef))
- return false;
+ return TPResult::False;
// C++ [temp.param]p2:
// There is no semantic difference between class and typename in a
@@ -592,17 +568,17 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
case tok::greater:
case tok::greatergreater:
case tok::ellipsis:
- return true;
+ return TPResult::True;
case tok::kw_typename:
case tok::kw_typedef:
case tok::kw_class:
// These indicate that a comma was missed after a type parameter, not that
// we have found a non-type parameter.
- return true;
+ return TPResult::True;
default:
- return false;
+ return TPResult::False;
}
}
@@ -627,13 +603,9 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
/// typename
///
NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
- // We could be facing a type-constraint, which (could) start a type parameter.
- // Annotate it now (we might end up not using it if we determine this
- // type-constraint is in fact part of a placeholder-type-specifier of a
- // non-type template parameter.
- bool ScopeError;
- if (isStartOfTemplateTypeParameter(ScopeError)) {
+ switch (isStartOfTemplateTypeParameter()) {
+ case TPResult::True:
// Is there just a typo in the input code? ('typedef' instead of
// 'typename')
if (Tok.is(tok::kw_typedef)) {
@@ -649,8 +621,10 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
}
return ParseTypeParameter(Depth, Position);
- }
- if (ScopeError) {
+ case TPResult::False:
+ break;
+
+ case TPResult::Error: {
// We return an invalid parameter as opposed to null to avoid having bogus
// diagnostics about an empty template parameter list.
// FIXME: Fix ParseTemplateParameterList to better handle nullptr results
@@ -670,6 +644,11 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
StopAtSemi | StopBeforeMatch);
return ErrorParam;
}
+
+ case TPResult::Ambiguous:
+ llvm_unreachable("template param classification can't be ambiguous");
+ }
+
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
@@ -682,15 +661,15 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
/// Check whether the current token is a template-id annotation denoting a
/// type-constraint.
bool Parser::isTypeConstraintAnnotation() {
- if (Tok.isNot(tok::annot_template_id))
+ const Token &T = Tok.is(tok::annot_cxxscope) ? NextToken() : Tok;
+ if (T.isNot(tok::annot_template_id))
return false;
const auto *ExistingAnnot =
- static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ static_cast<TemplateIdAnnotation *>(T.getAnnotationValue());
return ExistingAnnot->Kind == TNK_Concept_template;
}
-/// Try parsing a type-constraint construct at the current location, after the
-/// optional scope specifier.
+/// Try parsing a type-constraint at the current location.
///
/// type-constraint:
/// nested-name-specifier[opt] concept-name
@@ -698,35 +677,61 @@ bool Parser::isTypeConstraintAnnotation() {
/// '<' template-argument-list[opt] '>'[opt]
///
/// \returns true if an error occurred, and false otherwise.
-bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {
- if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier))
+bool Parser::TryAnnotateTypeConstraint() {
+ if (!getLangOpts().CPlusPlus2a)
return false;
+ CXXScopeSpec SS;
+ bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+ if (ParseOptionalCXXScopeSpecifier(
+ SS, ParsedType(),
+ /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ // If this is not a type-constraint, then
+ // this scope-spec is part of the typename
+ // of a non-type template parameter
+ /*IsTypename=*/true, /*LastII=*/nullptr,
+ // We won't find concepts in
+ // non-namespaces anyway, so might as well
+ // parse this correctly for possible type
+ // names.
+ /*OnlyNamespace=*/false))
+ return true;
- UnqualifiedId PossibleConceptName;
- PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
- Tok.getLocation());
-
- TemplateTy PossibleConcept;
- bool MemberOfUnknownSpecialization = false;
- auto TNK = Actions.isTemplateName(getCurScope(), SS,
- /*hasTemplateKeyword=*/false,
- PossibleConceptName,
- /*ObjectType=*/ParsedType(),
- /*EnteringContext=*/false,
- PossibleConcept,
- MemberOfUnknownSpecialization);
- assert(!MemberOfUnknownSpecialization
- && "Member when we only allowed namespace scope qualifiers??");
- if (!PossibleConcept || TNK != TNK_Concept_template)
- return false;
+ if (Tok.is(tok::identifier)) {
+ UnqualifiedId PossibleConceptName;
+ PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
+ Tok.getLocation());
+
+ TemplateTy PossibleConcept;
+ bool MemberOfUnknownSpecialization = false;
+ auto TNK = Actions.isTemplateName(getCurScope(), SS,
+ /*hasTemplateKeyword=*/false,
+ PossibleConceptName,
+ /*ObjectType=*/ParsedType(),
+ /*EnteringContext=*/false,
+ PossibleConcept,
+ MemberOfUnknownSpecialization);
+ if (MemberOfUnknownSpecialization || !PossibleConcept ||
+ TNK != TNK_Concept_template) {
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return false;
+ }
- // At this point we're sure we're dealing with a constrained parameter. It
- // may or may not have a template parameter list following the concept name.
- return AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
- /*TemplateKWLoc=*/SourceLocation(),
- PossibleConceptName,
- /*AllowTypeAnnotation=*/false,
- /*TypeConstraint=*/true);
+ // At this point we're sure we're dealing with a constrained parameter. It
+ // may or may not have a template parameter list following the concept
+ // name.
+ if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
+ /*TemplateKWLoc=*/SourceLocation(),
+ PossibleConceptName,
+ /*AllowTypeAnnotation=*/false,
+ /*TypeConstraint=*/true))
+ return true;
+ }
+
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return false;
}
/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
@@ -739,13 +744,17 @@ bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {
/// 'typename' ...[opt][C++0x] identifier[opt]
/// 'typename' identifier[opt] '=' type-id
NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
- assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) &&
+ assert((Tok.isOneOf(tok::kw_class, tok::kw_typename) ||
+ isTypeConstraintAnnotation()) &&
"A type-parameter starts with 'class', 'typename' or a "
"type-constraint");
+ CXXScopeSpec TypeConstraintSS;
TemplateIdAnnotation *TypeConstraint = nullptr;
bool TypenameKeyword = false;
SourceLocation KeyLoc;
+ ParseOptionalCXXScopeSpecifier(TypeConstraintSS, nullptr,
+ /*EnteringContext*/ false);
if (Tok.is(tok::annot_template_id)) {
// Consume the 'type-constraint'.
TypeConstraint =
@@ -754,6 +763,9 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
"stray non-concept template-id annotation");
KeyLoc = ConsumeAnnotationToken();
} else {
+ assert(TypeConstraintSS.isEmpty() &&
+ "expected type constraint after scope specifier");
+
// Consume the 'class' or 'typename' keyword.
TypenameKeyword = Tok.is(tok::kw_typename);
KeyLoc = ConsumeToken();
@@ -795,7 +807,8 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
ParsedType DefaultArg;
if (TryConsumeToken(tok::equal, EqualLoc))
DefaultArg = ParseTypeName(/*Range=*/nullptr,
- DeclaratorContext::TemplateTypeArgContext).get();
+ DeclaratorContext::TemplateTypeArgContext)
+ .get();
NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(),
TypenameKeyword, EllipsisLoc,
@@ -804,10 +817,11 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
DefaultArg,
TypeConstraint != nullptr);
- if (TypeConstraint)
- Actions.ActOnTypeConstraint(TypeConstraint,
+ if (TypeConstraint) {
+ Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint,
cast<TemplateTypeParmDecl>(NewDecl),
EllipsisLoc);
+ }
return NewDecl;
}
@@ -1331,8 +1345,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
: TemplateName.OperatorFunctionId.Operator;
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
- SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
- LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
+ TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+ LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
@@ -1357,11 +1371,14 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
/// a type annotation token will still be created, but will have a
/// NULL type pointer to signify an error.
///
+/// \param SS The scope specifier appearing before the template-id, if any.
+///
/// \param IsClassName Is this template-id appearing in a context where we
/// know it names a class, such as in an elaborated-type-specifier or
/// base-specifier? ('typename' and 'template' are unneeded and disallowed
/// in those contexts.)
-void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
+void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
+ bool IsClassName) {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -1375,7 +1392,7 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
TypeResult Type
= Actions.ActOnTemplateIdType(getCurScope(),
- TemplateId->SS,
+ SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->Name,
@@ -1388,8 +1405,8 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
- if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name.
- Tok.setLocation(TemplateId->SS.getBeginLoc());
+ if (SS.isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(SS.getBeginLoc());
// End location stays the same
// Replace the template-id annotation token, and possible the scope-specifier
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 4d69fb4693fb..ad0a15b0c8a6 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -202,9 +202,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
}
}
- if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype,
- tok::annot_template_id) &&
- TryAnnotateCXXScopeToken())
+ if (TryAnnotateOptionalCXXScopeToken())
return TPResult::Error;
if (Tok.is(tok::annot_cxxscope))
ConsumeAnnotationToken();
@@ -785,9 +783,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
Parser::TPResult Parser::TryParsePtrOperatorSeq() {
while (true) {
- if (Tok.isOneOf(tok::coloncolon, tok::identifier))
- if (TryAnnotateCXXScopeToken(true))
- return TPResult::Error;
+ if (TryAnnotateOptionalCXXScopeToken(true))
+ return TPResult::Error;
if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
@@ -1316,6 +1313,18 @@ public:
Parser::TPResult
Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
bool *InvalidAsDeclSpec) {
+ auto IsPlaceholderSpecifier = [&] (TemplateIdAnnotation *TemplateId,
+ int Lookahead) {
+ // We have a placeholder-constraint (we check for 'auto' or 'decltype' to
+ // distinguish 'C<int>;' from 'C<int> auto c = 1;')
+ return TemplateId->Kind == TNK_Concept_template &&
+ GetLookAheadToken(Lookahead + 1).isOneOf(tok::kw_auto, tok::kw_decltype,
+ // If we have an identifier here, the user probably forgot the
+ // 'auto' in the placeholder constraint, e.g. 'C<int> x = 2;'
+ // This will be diagnosed nicely later, so disambiguate as a
+ // declaration.
+ tok::identifier);
+ };
switch (Tok.getKind()) {
case tok::identifier: {
// Check for need to substitute AltiVec __vector keyword
@@ -1519,10 +1528,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
*InvalidAsDeclSpec = NextToken().is(tok::l_paren);
return TPResult::Ambiguous;
}
+ if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/0))
+ return TPResult::True;
if (TemplateId->Kind != TNK_Type_template)
return TPResult::False;
CXXScopeSpec SS;
- AnnotateTemplateIdTokenAsType();
+ AnnotateTemplateIdTokenAsType(SS);
assert(Tok.is(tok::annot_typename));
goto case_typename;
}
@@ -1532,6 +1543,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error;
if (!Tok.is(tok::annot_typename)) {
+ if (Tok.is(tok::annot_cxxscope) &&
+ NextToken().is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId =
+ takeTemplateIdAnnotation(NextToken());
+ if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1))
+ return TPResult::True;
+ }
// If the next token is an identifier or a type qualifier, then this
// can't possibly be a valid expression either.
if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
@@ -2137,3 +2155,58 @@ Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) {
return TPResult::Ambiguous;
return TPResult::False;
}
+
+/// Determine whether we might be looking at the '(' of a C++20 explicit(bool)
+/// in an earlier language mode.
+Parser::TPResult Parser::isExplicitBool() {
+ assert(Tok.is(tok::l_paren) && "expected to be looking at a '(' token");
+
+ RevertingTentativeParsingAction PA(*this);
+ ConsumeParen();
+
+ // We can only have 'explicit' on a constructor, conversion function, or
+ // deduction guide. The declarator of a deduction guide cannot be
+ // parenthesized, so we know this isn't a deduction guide. So the only
+ // thing we need to check for is some number of parens followed by either
+ // the current class name or 'operator'.
+ while (Tok.is(tok::l_paren))
+ ConsumeParen();
+
+ if (TryAnnotateOptionalCXXScopeToken())
+ return TPResult::Error;
+
+ // Class-scope constructor and conversion function names can't really be
+ // qualified, but we get better diagnostics if we assume they can be.
+ CXXScopeSpec SS;
+ if (Tok.is(tok::annot_cxxscope)) {
+ Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+ Tok.getAnnotationRange(),
+ SS);
+ ConsumeAnnotationToken();
+ }
+
+ // 'explicit(operator' might be explicit(bool) or the declaration of a
+ // conversion function, but it's probably a conversion function.
+ if (Tok.is(tok::kw_operator))
+ return TPResult::Ambiguous;
+
+ // If this can't be a constructor name, it can only be explicit(bool).
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+ return TPResult::True;
+ if (!Actions.isCurrentClassName(Tok.is(tok::identifier)
+ ? *Tok.getIdentifierInfo()
+ : *takeTemplateIdAnnotation(Tok)->Name,
+ getCurScope(), &SS))
+ return TPResult::True;
+ // Formally, we must have a right-paren after the constructor name to match
+ // the grammar for a constructor. But clang permits a parenthesized
+ // constructor declarator, so also allow a constructor declarator to follow
+ // with no ')' token after the constructor name.
+ if (!NextToken().is(tok::r_paren) &&
+ !isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(),
+ /*DeductionGuide=*/false))
+ return TPResult::True;
+
+ // Might be explicit(bool) or a parenthesized constructor name.
+ return TPResult::Ambiguous;
+}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 4249de361b89..0b778bd24277 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1136,6 +1136,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Poison SEH identifiers so they are flagged as illegal in function bodies.
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
+ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
// If this is C90 and the declspecs were completely missing, fudge in an
// implicit int. We do this here because this is the only place where
@@ -1262,6 +1263,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// safe because we're always the sole owner.
D.getMutableDeclSpec().abort();
+ // With abbreviated function templates - we need to explicitly add depth to
+ // account for the implicit template parameter list induced by the template.
+ if (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res))
+ if (Template->isAbbreviated() &&
+ Template->getTemplateParameters()->getParam(0)->isImplicit())
+ // First template parameter is implicit - meaning no explicit template
+ // parameter list was specified.
+ CurTemplateDepthTracker.addDepth(1);
+
if (TryConsumeToken(tok::equal)) {
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
@@ -1732,6 +1742,20 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
return ANK_Error;
return ANK_Success;
}
+ case Sema::NC_Concept: {
+ UnqualifiedId Id;
+ Id.setIdentifier(Name, NameLoc);
+ if (Next.is(tok::less))
+ // We have a concept name followed by '<'. Consume the identifier token so
+ // we reach the '<' and annotate it.
+ ConsumeToken();
+ if (AnnotateTemplateIdToken(
+ TemplateTy::make(Classification.getTemplateName()),
+ Classification.getTemplateNameKind(), SS, SourceLocation(), Id,
+ /*AllowTypeAnnotation=*/false, /*TypeConstraint=*/true))
+ return ANK_Error;
+ return ANK_Success;
+ }
}
// Unable to classify the name, but maybe we can annotate a scope specifier.
@@ -1810,7 +1834,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
/*EnteringContext=*/false, nullptr,
/*IsTypename*/ true))
return true;
- if (!SS.isSet()) {
+ if (SS.isEmpty()) {
if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) ||
Tok.is(tok::annot_decltype)) {
// Attempt to recover by skipping the invalid 'typename'
@@ -1983,7 +2007,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
// template-id annotation in a context where we weren't allowed
// to produce a type annotation token. Update the template-id
// annotation token to a type annotation token now.
- AnnotateTemplateIdTokenAsType();
+ AnnotateTemplateIdTokenAsType(SS);
return false;
}
}
@@ -2005,10 +2029,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
- assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
- (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) ||
- Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)) &&
- "Cannot be a type or scope token!");
+ assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!");
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext))
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 639231c87232..94d87974624e 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -784,6 +784,15 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
return false;
}
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID, TemplateIdAnnotation *Rep,
+ const PrintingPolicy &Policy) {
+ assert(T == TST_auto || T == TST_decltype_auto);
+ ConstrainedAuto = true;
+ TemplateIdRep = Rep;
+ return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Policy);
+}
+
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 2cd158a8b43c..9cfce5a63b1d 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -52,6 +52,21 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {
ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
+IdentifierInfo *
+Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
+ unsigned int Index) {
+ std::string InventedName;
+ llvm::raw_string_ostream OS(InventedName);
+
+ if (!ParamName)
+ OS << "auto:" << Index + 1;
+ else
+ OS << ParamName->getName() << ":auto";
+
+ OS.flush();
+ return &Context.Idents.get(OS.str());
+}
+
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
@@ -153,10 +168,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TUKind(TUKind), NumSFINAEErrors(0),
FullyCheckedComparisonCategories(
static_cast<unsigned>(ComparisonCategoryType::Last) + 1),
- AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this),
+ SatisfactionCache(Context), AccessCheckingSFINAE(false),
+ InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
+ ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
+ DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
@@ -379,6 +394,14 @@ Sema::~Sema() {
if (isMultiplexExternalSource)
delete ExternalSource;
+ // Delete cached satisfactions.
+ std::vector<ConstraintSatisfaction *> Satisfactions;
+ Satisfactions.reserve(Satisfactions.size());
+ for (auto &Node : SatisfactionCache)
+ Satisfactions.push_back(&Node);
+ for (auto *Node : Satisfactions)
+ delete Node;
+
threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);
// Destroys data sharing attributes stack for OpenMP
@@ -1261,7 +1284,8 @@ DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
while (true) {
- if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) {
+ if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC) ||
+ isa<RequiresExprBodyDecl>(DC)) {
DC = DC->getParent();
} else if (isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 018ac2d7dc9d..81601b09ce0d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -17,7 +17,10 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/Template.h"
-#include "clang/AST/ExprCXX.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "llvm/ADT/DenseMap.h"
@@ -269,36 +272,56 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
return false;
}
-bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
- return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- Satisfaction);
-}
+bool Sema::CheckConstraintSatisfaction(
+ NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
+ ConstraintSatisfaction &OutSatisfaction) {
+ if (ConstraintExprs.empty()) {
+ OutSatisfaction.IsSatisfied = true;
+ return false;
+ }
-bool
-Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
- return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- Satisfaction);
-}
+ llvm::FoldingSetNodeID ID;
+ void *InsertPos;
+ ConstraintSatisfaction *Satisfaction = nullptr;
+ if (LangOpts.ConceptSatisfactionCaching) {
+ ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
+ Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
+ if (Satisfaction) {
+ OutSatisfaction = *Satisfaction;
+ return false;
+ }
+ Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs);
+ } else {
+ Satisfaction = &OutSatisfaction;
+ }
+ bool Failed;
+ if (auto *T = dyn_cast<TemplateDecl>(Template))
+ Failed = ::CheckConstraintSatisfaction(*this, T, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ *Satisfaction);
+ else if (auto *P =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
+ Failed = ::CheckConstraintSatisfaction(*this, P, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ *Satisfaction);
+ else
+ Failed = ::CheckConstraintSatisfaction(
+ *this, cast<VarTemplatePartialSpecializationDecl>(Template),
+ ConstraintExprs, TemplateArgs, TemplateIDRange, *Satisfaction);
+ if (Failed) {
+ if (LangOpts.ConceptSatisfactionCaching)
+ delete Satisfaction;
+ return true;
+ }
-bool
-Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
- return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- Satisfaction);
+ if (LangOpts.ConceptSatisfactionCaching) {
+ // We cannot use InsertNode here because CheckConstraintSatisfaction might
+ // have invalidated it.
+ SatisfactionCache.InsertNode(Satisfaction);
+ OutSatisfaction = *Satisfaction;
+ }
+ return false;
}
bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
@@ -336,6 +359,118 @@ bool Sema::EnsureTemplateArgumentListConstraints(
return false;
}
+static void diagnoseUnsatisfiedRequirement(Sema &S,
+ concepts::ExprRequirement *Req,
+ bool First) {
+ assert(!Req->isSatisfied()
+ && "Diagnose() can only be used on an unsatisfied requirement");
+ switch (Req->getSatisfactionStatus()) {
+ case concepts::ExprRequirement::SS_Dependent:
+ llvm_unreachable("Diagnosing a dependent requirement");
+ break;
+ case concepts::ExprRequirement::SS_ExprSubstitutionFailure: {
+ auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_expr_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity
+ << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_expr_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ break;
+ }
+ case concepts::ExprRequirement::SS_NoexceptNotMet:
+ S.Diag(Req->getNoexceptLoc(),
+ diag::note_expr_requirement_noexcept_not_met)
+ << (int)First << Req->getExpr();
+ break;
+ case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: {
+ auto *SubstDiag =
+ Req->getReturnTypeRequirement().getSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_type_requirement_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity
+ << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_type_requirement_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ break;
+ }
+ case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: {
+ ConceptSpecializationExpr *ConstraintExpr =
+ Req->getReturnTypeRequirementSubstitutedConstraintExpr();
+ if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1)
+ // A simple case - expr type is the type being constrained and the concept
+ // was not provided arguments.
+ S.Diag(ConstraintExpr->getBeginLoc(),
+ diag::note_expr_requirement_constraints_not_satisfied_simple)
+ << (int)First << S.BuildDecltypeType(Req->getExpr(),
+ Req->getExpr()->getBeginLoc())
+ << ConstraintExpr->getNamedConcept();
+ else
+ S.Diag(ConstraintExpr->getBeginLoc(),
+ diag::note_expr_requirement_constraints_not_satisfied)
+ << (int)First << ConstraintExpr;
+ S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction());
+ break;
+ }
+ case concepts::ExprRequirement::SS_Satisfied:
+ llvm_unreachable("We checked this above");
+ }
+}
+
+static void diagnoseUnsatisfiedRequirement(Sema &S,
+ concepts::TypeRequirement *Req,
+ bool First) {
+ assert(!Req->isSatisfied()
+ && "Diagnose() can only be used on an unsatisfied requirement");
+ switch (Req->getSatisfactionStatus()) {
+ case concepts::TypeRequirement::SS_Dependent:
+ llvm_unreachable("Diagnosing a dependent requirement");
+ return;
+ case concepts::TypeRequirement::SS_SubstitutionFailure: {
+ auto *SubstDiag = Req->getSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_type_requirement_substitution_error) << (int)First
+ << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_type_requirement_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ return;
+ }
+ default:
+ llvm_unreachable("Unknown satisfaction status");
+ return;
+ }
+}
+
+static void diagnoseUnsatisfiedRequirement(Sema &S,
+ concepts::NestedRequirement *Req,
+ bool First) {
+ if (Req->isSubstitutionFailure()) {
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag =
+ Req->getSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_nested_requirement_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity
+ << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_nested_requirement_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ return;
+ }
+ S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First);
+}
+
+
static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
Expr *SubstExpr,
bool First = true) {
@@ -412,6 +547,19 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
}
S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
return;
+ } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
+ for (concepts::Requirement *Req : RE->getRequirements())
+ if (!Req->isDependent() && !Req->isSatisfied()) {
+ if (auto *E = dyn_cast<concepts::ExprRequirement>(Req))
+ diagnoseUnsatisfiedRequirement(S, E, First);
+ else if (auto *T = dyn_cast<concepts::TypeRequirement>(Req))
+ diagnoseUnsatisfiedRequirement(S, T, First);
+ else
+ diagnoseUnsatisfiedRequirement(
+ S, cast<concepts::NestedRequirement>(Req), First);
+ break;
+ }
+ return;
}
S.Diag(SubstExpr->getSourceRange().getBegin(),
@@ -434,11 +582,11 @@ static void diagnoseUnsatisfiedConstraintExpr(
Record.template get<Expr *>(), First);
}
-void Sema::DiagnoseUnsatisfiedConstraint(
- const ConstraintSatisfaction& Satisfaction) {
+void
+Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction,
+ bool First) {
assert(!Satisfaction.IsSatisfied &&
"Attempted to diagnose a satisfied constraint");
- bool First = true;
for (auto &Pair : Satisfaction.Details) {
diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
First = false;
@@ -446,10 +594,10 @@ void Sema::DiagnoseUnsatisfiedConstraint(
}
void Sema::DiagnoseUnsatisfiedConstraint(
- const ASTConstraintSatisfaction &Satisfaction) {
+ const ASTConstraintSatisfaction &Satisfaction,
+ bool First) {
assert(!Satisfaction.IsSatisfied &&
"Attempted to diagnose a satisfied constraint");
- bool First = true;
for (auto &Pair : Satisfaction) {
diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
First = false;
@@ -826,3 +974,67 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1,
<< AmbiguousAtomic2->getSourceRange();
return true;
}
+
+concepts::ExprRequirement::ExprRequirement(
+ Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ ReturnTypeRequirement Req, SatisfactionStatus Status,
+ ConceptSpecializationExpr *SubstitutedConstraintExpr) :
+ Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
+ Status == SS_Dependent &&
+ (E->containsUnexpandedParameterPack() ||
+ Req.containsUnexpandedParameterPack()),
+ Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc),
+ TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr),
+ Status(Status) {
+ assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+ "Simple requirement must not have a return type requirement or a "
+ "noexcept specification");
+ assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) ==
+ (SubstitutedConstraintExpr != nullptr));
+}
+
+concepts::ExprRequirement::ExprRequirement(
+ SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
+ SourceLocation NoexceptLoc, ReturnTypeRequirement Req) :
+ Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
+ Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
+ Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
+ Status(SS_ExprSubstitutionFailure) {
+ assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+ "Simple requirement must not have a return type requirement or a "
+ "noexcept specification");
+}
+
+concepts::ExprRequirement::ReturnTypeRequirement::
+ReturnTypeRequirement(TemplateParameterList *TPL) :
+ TypeConstraintInfo(TPL, 0) {
+ assert(TPL->size() == 1);
+ const TypeConstraint *TC =
+ cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
+ assert(TC &&
+ "TPL must have a template type parameter with a type constraint");
+ auto *Constraint =
+ cast_or_null<ConceptSpecializationExpr>(
+ TC->getImmediatelyDeclaredConstraint());
+ bool Dependent = false;
+ if (Constraint->getTemplateArgsAsWritten()) {
+ for (auto &ArgLoc :
+ Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)) {
+ if (ArgLoc.getArgument().isDependent()) {
+ Dependent = true;
+ break;
+ }
+ }
+ }
+ TypeConstraintInfo.setInt(Dependent ? 1 : 0);
+}
+
+concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) :
+ Requirement(RK_Type, T->getType()->isDependentType(),
+ T->getType()->containsUnexpandedParameterPack(),
+ // We reach this ctor with either dependent types (in which
+ // IsSatisfied doesn't matter) or with non-dependent type in
+ // which the existence of the type indicates satisfaction.
+ /*IsSatisfied=*/true
+ ), Value(T),
+ Status(T->getType()->isDependentType() ? SS_Dependent : SS_Satisfied) {}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 507e4a6cd436..0bf490336537 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TreeTransform.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -1153,6 +1154,10 @@ Corrected:
return ParsedType::make(T);
}
+ if (isa<ConceptDecl>(FirstDecl))
+ return NameClassification::Concept(
+ TemplateName(cast<TemplateDecl>(FirstDecl)));
+
// We can have a type template here if we're classifying a template argument.
if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl) &&
!isa<VarTemplateDecl>(FirstDecl))
@@ -6468,6 +6473,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
return true;
if (DC->isRecord())
return false;
+ if (isa<RequiresExprBodyDecl>(DC))
+ return false;
llvm_unreachable("Unexpected context");
}
@@ -8654,11 +8661,21 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists,
+ MultiTemplateParamsArg TemplateParamListsRef,
bool &AddToScope) {
QualType R = TInfo->getType();
assert(R->isFunctionType());
+ SmallVector<TemplateParameterList *, 4> TemplateParamLists;
+ for (TemplateParameterList *TPL : TemplateParamListsRef)
+ TemplateParamLists.push_back(TPL);
+ if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) {
+ if (!TemplateParamLists.empty() &&
+ Invented->getDepth() == TemplateParamLists.back()->getDepth())
+ TemplateParamLists.back() = Invented;
+ else
+ TemplateParamLists.push_back(Invented);
+ }
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
@@ -8738,15 +8755,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
bool Invalid = false;
- if (TemplateParameterList *TemplateParams =
- MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(),
- D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
- ? D.getName().TemplateId
- : nullptr,
- TemplateParamLists, isFriend, isMemberSpecialization,
- Invalid)) {
+ TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(),
+ D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
+ ? D.getName().TemplateId
+ : nullptr,
+ TemplateParamLists, isFriend, isMemberSpecialization,
+ Invalid);
+ if (TemplateParams) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -8779,7 +8797,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// For source fidelity, store the other template param lists.
if (TemplateParamLists.size() > 1) {
NewFD->setTemplateParameterListsInfo(Context,
- TemplateParamLists.drop_back(1));
+ ArrayRef<TemplateParameterList *>(TemplateParamLists)
+ .drop_back(1));
}
} else {
// This is a function template specialization.
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 5c51b0f9b8cb..849bc09063b3 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4924,9 +4924,9 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
Expr *Arg = AL.getArgAsExpr(1);
if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true))
return;
- if (Offset) {
+ if (Count < Offset) {
S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range)
- << &AL << 0 << 0 << Arg->getBeginLoc();
+ << &AL << 0 << Count << Arg->getBeginLoc();
return;
}
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 9916d3be77e1..9fa5691983a1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17386,3 +17386,50 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
return NewPD;
}
+
+void Sema::ActOnStartFunctionDeclarationDeclarator(
+ Declarator &Declarator, unsigned TemplateParameterDepth) {
+ auto &Info = InventedParameterInfos.emplace_back();
+ TemplateParameterList *ExplicitParams = nullptr;
+ ArrayRef<TemplateParameterList *> ExplicitLists =
+ Declarator.getTemplateParameterLists();
+ if (!ExplicitLists.empty()) {
+ bool IsMemberSpecialization, IsInvalid;
+ ExplicitParams = MatchTemplateParametersToScopeSpecifier(
+ Declarator.getBeginLoc(), Declarator.getIdentifierLoc(),
+ Declarator.getCXXScopeSpec(), /*TemplateId=*/nullptr,
+ ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid,
+ /*SuppressDiagnostic=*/true);
+ }
+ if (ExplicitParams) {
+ Info.AutoTemplateParameterDepth = ExplicitParams->getDepth();
+ for (NamedDecl *Param : *ExplicitParams)
+ Info.TemplateParams.push_back(Param);
+ Info.NumExplicitTemplateParams = ExplicitParams->size();
+ } else {
+ Info.AutoTemplateParameterDepth = TemplateParameterDepth;
+ Info.NumExplicitTemplateParams = 0;
+ }
+}
+
+void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) {
+ auto &FSI = InventedParameterInfos.back();
+ if (FSI.TemplateParams.size() > FSI.NumExplicitTemplateParams) {
+ if (FSI.NumExplicitTemplateParams != 0) {
+ TemplateParameterList *ExplicitParams =
+ Declarator.getTemplateParameterLists().back();
+ Declarator.setInventedTemplateParameterList(
+ TemplateParameterList::Create(
+ Context, ExplicitParams->getTemplateLoc(),
+ ExplicitParams->getLAngleLoc(), FSI.TemplateParams,
+ ExplicitParams->getRAngleLoc(),
+ ExplicitParams->getRequiresClause()));
+ } else {
+ Declarator.setInventedTemplateParameterList(
+ TemplateParameterList::Create(
+ Context, SourceLocation(), SourceLocation(), FSI.TemplateParams,
+ SourceLocation(), /*RequiresClause=*/nullptr));
+ }
+ }
+ InventedParameterInfos.pop_back();
+}
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 5aedbe7644e4..193eaa3e01f9 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1386,6 +1386,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::StringLiteralClass:
case Expr::SourceLocExprClass:
case Expr::ConceptSpecializationExprClass:
+ case Expr::RequiresExprClass:
// These expressions can never throw.
return CT_Cannot;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5f4071924d3f..ea4b93ee6a5a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -350,6 +350,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
}
}
+ if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) &&
+ !isUnevaluatedContext()) {
+ // C++ [expr.prim.req.nested] p3
+ // A local parameter shall only appear as an unevaluated operand
+ // (Clause 8) within the constraint-expression.
+ Diag(Loc, diag::err_requires_expr_parameter_referenced_in_evaluated_context)
+ << D;
+ Diag(D->getLocation(), diag::note_entity_declared_at) << D;
+ return true;
+ }
+
return false;
}
@@ -1904,7 +1915,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
bool RefersToCapturedVariable =
isa<VarDecl>(D) &&
NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
-
+
DeclRefExpr *E = DeclRefExpr::Create(
Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index a73e6906fceb..192c237b6c1c 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -11,6 +11,7 @@
///
//===----------------------------------------------------------------------===//
+#include "clang/Sema/Template.h"
#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
#include "TypeLocBuilder.h"
@@ -7317,7 +7318,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(S,
- TemplateId->SS,
+ SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->Name,
@@ -7370,7 +7371,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(S,
- TemplateId->SS,
+ SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->Name,
@@ -8331,3 +8332,215 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
}
+
+concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) {
+ return BuildExprRequirement(E, /*IsSimple=*/true,
+ /*NoexceptLoc=*/SourceLocation(),
+ /*ReturnTypeRequirement=*/{});
+}
+
+concepts::Requirement *
+Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS,
+ SourceLocation NameLoc, IdentifierInfo *TypeName,
+ TemplateIdAnnotation *TemplateId) {
+ assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) &&
+ "Exactly one of TypeName and TemplateId must be specified.");
+ TypeSourceInfo *TSI = nullptr;
+ if (TypeName) {
+ QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc,
+ SS.getWithLocInContext(Context), *TypeName,
+ NameLoc, &TSI, /*DeducedTypeContext=*/false);
+ if (T.isNull())
+ return nullptr;
+ } else {
+ ASTTemplateArgsPtr ArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TypeResult T = ActOnTypenameType(CurScope, TypenameKWLoc, SS,
+ TemplateId->TemplateKWLoc,
+ TemplateId->Template, TemplateId->Name,
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc, ArgsPtr,
+ TemplateId->RAngleLoc);
+ if (T.isInvalid())
+ return nullptr;
+ if (GetTypeFromParser(T.get(), &TSI).isNull())
+ return nullptr;
+ }
+ return BuildTypeRequirement(TSI);
+}
+
+concepts::Requirement *
+Sema::ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc) {
+ return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc,
+ /*ReturnTypeRequirement=*/{});
+}
+
+concepts::Requirement *
+Sema::ActOnCompoundRequirement(
+ Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS,
+ TemplateIdAnnotation *TypeConstraint, unsigned Depth) {
+ // C++2a [expr.prim.req.compound] p1.3.3
+ // [..] the expression is deduced against an invented function template
+ // F [...] F is a void function template with a single type template
+ // parameter T declared with the constrained-parameter. Form a new
+ // cv-qualifier-seq cv by taking the union of const and volatile specifiers
+ // around the constrained-parameter. F has a single parameter whose
+ // type-specifier is cv T followed by the abstract-declarator. [...]
+ //
+ // The cv part is done in the calling function - we get the concept with
+ // arguments and the abstract declarator with the correct CV qualification and
+ // have to synthesize T and the single parameter of F.
+ auto &II = Context.Idents.get("expr-type");
+ auto *TParam = TemplateTypeParmDecl::Create(Context, CurContext,
+ SourceLocation(),
+ SourceLocation(), Depth,
+ /*Index=*/0, &II,
+ /*Typename=*/true,
+ /*ParameterPack=*/false,
+ /*HasTypeConstraint=*/true);
+
+ if (ActOnTypeConstraint(SS, TypeConstraint, TParam,
+ /*EllpsisLoc=*/SourceLocation()))
+ // Just produce a requirement with no type requirements.
+ return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {});
+
+ auto *TPL = TemplateParameterList::Create(Context, SourceLocation(),
+ SourceLocation(),
+ ArrayRef<NamedDecl *>(TParam),
+ SourceLocation(),
+ /*RequiresClause=*/nullptr);
+ return BuildExprRequirement(
+ E, /*IsSimple=*/false, NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement(TPL));
+}
+
+concepts::ExprRequirement *
+Sema::BuildExprRequirement(
+ Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) {
+ auto Status = concepts::ExprRequirement::SS_Satisfied;
+ ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr;
+ if (E->isInstantiationDependent() || ReturnTypeRequirement.isDependent())
+ Status = concepts::ExprRequirement::SS_Dependent;
+ else if (NoexceptLoc.isValid() && canThrow(E) == CanThrowResult::CT_Can)
+ Status = concepts::ExprRequirement::SS_NoexceptNotMet;
+ else if (ReturnTypeRequirement.isSubstitutionFailure())
+ Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure;
+ else if (ReturnTypeRequirement.isTypeConstraint()) {
+ // C++2a [expr.prim.req]p1.3.3
+ // The immediately-declared constraint ([temp]) of decltype((E)) shall
+ // be satisfied.
+ TemplateParameterList *TPL =
+ ReturnTypeRequirement.getTypeConstraintTemplateParameterList();
+ QualType MatchedType =
+ BuildDecltypeType(E, E->getBeginLoc()).getCanonicalType();
+ llvm::SmallVector<TemplateArgument, 1> Args;
+ Args.push_back(TemplateArgument(MatchedType));
+ TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args);
+ MultiLevelTemplateArgumentList MLTAL(TAL);
+ for (unsigned I = 0; I < TPL->getDepth(); ++I)
+ MLTAL.addOuterRetainedLevel();
+ Expr *IDC =
+ cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint()
+ ->getImmediatelyDeclaredConstraint();
+ ExprResult Constraint = SubstExpr(IDC, MLTAL);
+ assert(!Constraint.isInvalid() &&
+ "Substitution cannot fail as it is simply putting a type template "
+ "argument into a concept specialization expression's parameter.");
+
+ SubstitutedConstraintExpr =
+ cast<ConceptSpecializationExpr>(Constraint.get());
+ if (!SubstitutedConstraintExpr->isSatisfied())
+ Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied;
+ }
+ return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc,
+ ReturnTypeRequirement, Status,
+ SubstitutedConstraintExpr);
+}
+
+concepts::ExprRequirement *
+Sema::BuildExprRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *ExprSubstitutionDiagnostic,
+ bool IsSimple, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) {
+ return new (Context) concepts::ExprRequirement(ExprSubstitutionDiagnostic,
+ IsSimple, NoexceptLoc,
+ ReturnTypeRequirement);
+}
+
+concepts::TypeRequirement *
+Sema::BuildTypeRequirement(TypeSourceInfo *Type) {
+ return new (Context) concepts::TypeRequirement(Type);
+}
+
+concepts::TypeRequirement *
+Sema::BuildTypeRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return new (Context) concepts::TypeRequirement(SubstDiag);
+}
+
+concepts::Requirement *Sema::ActOnNestedRequirement(Expr *Constraint) {
+ return BuildNestedRequirement(Constraint);
+}
+
+concepts::NestedRequirement *
+Sema::BuildNestedRequirement(Expr *Constraint) {
+ ConstraintSatisfaction Satisfaction;
+ if (!Constraint->isInstantiationDependent() &&
+ CheckConstraintSatisfaction(Constraint, Satisfaction))
+ return nullptr;
+ return new (Context) concepts::NestedRequirement(Context, Constraint,
+ Satisfaction);
+}
+
+concepts::NestedRequirement *
+Sema::BuildNestedRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return new (Context) concepts::NestedRequirement(SubstDiag);
+}
+
+RequiresExprBodyDecl *
+Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ Scope *BodyScope) {
+ assert(BodyScope);
+
+ RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(Context, CurContext,
+ RequiresKWLoc);
+
+ PushDeclContext(BodyScope, Body);
+
+ for (ParmVarDecl *Param : LocalParameters) {
+ if (Param->hasDefaultArg())
+ // C++2a [expr.prim.req] p4
+ // [...] A local parameter of a requires-expression shall not have a
+ // default argument. [...]
+ Diag(Param->getDefaultArgRange().getBegin(),
+ diag::err_requires_expr_local_parameter_default_argument);
+ // Ignore default argument and move on
+
+ Param->setDeclContext(Body);
+ // If this has an identifier, add it to the scope stack.
+ if (Param->getIdentifier()) {
+ CheckShadow(BodyScope, Param);
+ PushOnScopeChains(Param, BodyScope);
+ }
+ }
+ return Body;
+}
+
+void Sema::ActOnFinishRequiresExpr() {
+ assert(CurContext && "DeclContext imbalance!");
+ CurContext = CurContext->getLexicalParent();
+ assert(CurContext && "Popped translation unit!");
+}
+
+ExprResult
+Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation ClosingBraceLoc) {
+ return RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters,
+ Requirements, ClosingBraceLoc);
+}
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c2d14a44f53d..ae89b146c409 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -791,7 +791,8 @@ QualType Sema::buildLambdaInitCaptureInitialization(
// deduce against.
QualType DeductType = Context.getAutoDeductType();
TypeLocBuilder TLB;
- TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
+ AutoTypeLoc TL = TLB.push<AutoTypeLoc>(DeductType);
+ TL.setNameLoc(Loc);
if (ByRef) {
DeductType = BuildReferenceType(DeductType, true, Loc, Id);
assert(!DeductType.isNull() && "can't build reference to auto");
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 0ed51de0cc13..8d96404a5c27 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1575,7 +1575,9 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
unsigned N = CodeSynthesisContexts.size();
for (unsigned I = CodeSynthesisContextLookupModules.size();
I != N; ++I) {
- Module *M = getDefiningModule(*this, CodeSynthesisContexts[I].Entity);
+ Module *M = CodeSynthesisContexts[I].Entity ?
+ getDefiningModule(*this, CodeSynthesisContexts[I].Entity) :
+ nullptr;
if (M && !LookupModulesCache.insert(M).second)
M = nullptr;
CodeSynthesisContextLookupModules.push_back(M);
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d6c3af9e84c8..ff6481006280 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2838,6 +2838,9 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
/// Suggest "const foo &x" to prevent the copy.
static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
const CXXForRangeStmt *ForStmt) {
+ if (SemaRef.inTemplateInstantiation())
+ return;
+
if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy,
ForStmt->getBeginLoc()) &&
SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy,
@@ -2860,6 +2863,9 @@ static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
if (!InitExpr)
return;
+ if (InitExpr->getExprLoc().isMacroID())
+ return;
+
if (VariableType->isReferenceType()) {
DiagnoseForRangeReferenceVariableCopies(SemaRef, VD,
ForStmt->getRangeInit()->getType());
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1184446796eb..f961244da072 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1050,7 +1050,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
return TemplateArgs;
}
-bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
+bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS,
+ TemplateIdAnnotation *TypeConstr,
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc) {
ConceptDecl *CD =
@@ -1080,14 +1081,57 @@ bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
makeTemplateArgumentListInfo(*this, *TypeConstr);
}
return AttachTypeConstraint(
- TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) :
- NestedNameSpecifierLoc(),
+ SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(),
DeclarationNameInfo(DeclarationName(TypeConstr->Name),
TypeConstr->TemplateNameLoc), CD,
TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,
ConstrainedParameter, EllipsisLoc);
}
+template<typename ArgumentLocAppender>
+static ExprResult formImmediatelyDeclaredConstraint(
+ Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo,
+ ConceptDecl *NamedConcept, SourceLocation LAngleLoc,
+ SourceLocation RAngleLoc, QualType ConstrainedType,
+ SourceLocation ParamNameLoc, ArgumentLocAppender Appender,
+ SourceLocation EllipsisLoc) {
+
+ TemplateArgumentListInfo ConstraintArgs;
+ ConstraintArgs.addArgument(
+ S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType),
+ /*NTTPType=*/QualType(), ParamNameLoc));
+
+ ConstraintArgs.setRAngleLoc(RAngleLoc);
+ ConstraintArgs.setLAngleLoc(LAngleLoc);
+ Appender(ConstraintArgs);
+
+ // C++2a [temp.param]p4:
+ // [...] This constraint-expression E is called the immediately-declared
+ // constraint of T. [...]
+ CXXScopeSpec SS;
+ SS.Adopt(NS);
+ ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
+ SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+ /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs);
+ if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
+ return ImmediatelyDeclaredConstraint;
+
+ // C++2a [temp.param]p4:
+ // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
+ //
+ // We have the following case:
+ //
+ // template<typename T> concept C1 = true;
+ // template<C1... T> struct s1;
+ //
+ // The constraint: (C1<T> && ...)
+ return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
+ ImmediatelyDeclaredConstraint.get(), BO_LAnd,
+ EllipsisLoc, /*RHS=*/nullptr,
+ /*RParenLoc=*/SourceLocation(),
+ /*NumExpansions=*/None);
+}
+
/// Attach a type-constraint to a template parameter.
/// \returns true if an error occured. This can happen if the
/// immediately-declared constraint could not be formed (e.g. incorrect number
@@ -1106,51 +1150,21 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
*TemplateArgs) : nullptr;
QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
- TemplateArgumentListInfo ConstraintArgs;
- ConstraintArgs.addArgument(
- TemplateArgumentLoc(
- TemplateArgument(ParamAsArgument),
- TemplateArgumentLocInfo(
- Context.getTrivialTypeSourceInfo(ParamAsArgument,
- ConstrainedParameter->getLocation()))));
- if (TemplateArgs) {
- ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc());
- ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc());
- for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments())
- ConstraintArgs.addArgument(ArgLoc);
- }
- // C++2a [temp.param]p4:
- // [...] This constraint-expression E is called the immediately-declared
- // constraint of T. [...]
- CXXScopeSpec SS;
- SS.Adopt(NS);
- ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS,
- /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept,
- NamedConcept, &ConstraintArgs);
+ ExprResult ImmediatelyDeclaredConstraint =
+ formImmediatelyDeclaredConstraint(
+ *this, NS, NameInfo, NamedConcept,
+ TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(),
+ TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(),
+ ParamAsArgument, ConstrainedParameter->getLocation(),
+ [&] (TemplateArgumentListInfo &ConstraintArgs) {
+ if (TemplateArgs)
+ for (const auto &ArgLoc : TemplateArgs->arguments())
+ ConstraintArgs.addArgument(ArgLoc);
+ }, EllipsisLoc);
if (ImmediatelyDeclaredConstraint.isInvalid())
return true;
- if (ConstrainedParameter->isParameterPack()) {
- // C++2a [temp.param]p4:
- // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
- //
- // We have the following case:
- //
- // template<typename T> concept C1 = true;
- // template<C1... T> struct s1;
- //
- // The constraint: (C1<T> && ...)
- ImmediatelyDeclaredConstraint =
- BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
- ImmediatelyDeclaredConstraint.get(), BO_LAnd,
- EllipsisLoc, /*RHS=*/nullptr,
- /*RParenLoc=*/SourceLocation(),
- /*NumExpansions=*/None).get();
- if (ImmediatelyDeclaredConstraint.isInvalid())
- return true;
- }
-
ConstrainedParameter->setTypeConstraint(NS, NameInfo,
/*FoundDecl=*/NamedConcept,
NamedConcept, ArgsAsWritten,
@@ -1158,6 +1172,38 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
return false;
}
+bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP,
+ SourceLocation EllipsisLoc) {
+ if (NTTP->getType() != TL.getType() ||
+ TL.getAutoKeyword() != AutoTypeKeyword::Auto) {
+ Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+ diag::err_unsupported_placeholder_constraint)
+ << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange();
+ return true;
+ }
+ // FIXME: Concepts: This should be the type of the placeholder, but this is
+ // unclear in the wording right now.
+ DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue,
+ NTTP->getLocation());
+ if (!Ref)
+ return true;
+ ExprResult ImmediatelyDeclaredConstraint =
+ formImmediatelyDeclaredConstraint(
+ *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
+ TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
+ BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(),
+ [&] (TemplateArgumentListInfo &ConstraintArgs) {
+ for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
+ ConstraintArgs.addArgument(TL.getArgLoc(I));
+ }, EllipsisLoc);
+ if (ImmediatelyDeclaredConstraint.isInvalid() ||
+ !ImmediatelyDeclaredConstraint.isUsable())
+ return true;
+
+ NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get());
+ return false;
+}
+
/// Check that the type of a non-type template parameter is
/// well-formed.
///
@@ -1319,6 +1365,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
TInfo);
Param->setAccess(AS_public);
+ if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc())
+ if (TL.isConstrained())
+ if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc()))
+ Invalid = true;
+
if (Invalid)
Param->setInvalidDecl();
@@ -2762,7 +2813,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
- bool &IsMemberSpecialization, bool &Invalid) {
+ bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) {
IsMemberSpecialization = false;
Invalid = false;
@@ -2870,8 +2921,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) {
if (SawNonEmptyTemplateParameterList) {
- Diag(DeclLoc, diag::err_specialize_member_of_template)
- << !Recovery << Range;
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << !Recovery << Range;
Invalid = true;
IsMemberSpecialization = false;
return true;
@@ -2892,9 +2944,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
else
ExpectedTemplateLoc = DeclStartLoc;
- Diag(DeclLoc, diag::err_template_spec_needs_header)
- << Range
- << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_template_spec_needs_header)
+ << Range
+ << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
return false;
};
@@ -2984,12 +3037,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() > 0) {
// The header has template parameters when it shouldn't. Complain.
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- diag::err_template_param_list_matches_nontemplate)
- << T
- << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
- ParamLists[ParamIdx]->getRAngleLoc())
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ if (!SuppressDiagnostic)
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << T
+ << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
+ ParamLists[ParamIdx]->getRAngleLoc())
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
Invalid = true;
return nullptr;
}
@@ -3025,7 +3079,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ExpectedTemplateParams &&
!TemplateParameterListsAreEqual(ParamLists[ParamIdx],
ExpectedTemplateParams,
- true, TPL_TemplateMatch))
+ !SuppressDiagnostic, TPL_TemplateMatch))
Invalid = true;
if (!Invalid &&
@@ -3037,9 +3091,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
continue;
}
- Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
- << T
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
+ << T
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
Invalid = true;
continue;
}
@@ -3075,16 +3130,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
AllExplicitSpecHeaders = false;
}
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
- : diag::err_template_spec_extra_headers)
- << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
- ParamLists[ParamLists.size() - 2]->getRAngleLoc());
+ if (!SuppressDiagnostic)
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
+ : diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[ParamLists.size() - 2]->getRAngleLoc());
// If there was a specialization somewhere, such that 'template<>' is
// not required, and there were any 'template<>' headers, note where the
// specialization occurred.
- if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader)
+ if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader &&
+ !SuppressDiagnostic)
Diag(ExplicitSpecLoc,
diag::note_explicit_template_spec_does_not_need_header)
<< NestedTypes.back();
@@ -4044,7 +4101,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
Converted) &&
- (!Context.getLangOpts().ConceptsTS ||
+ (!Context.getLangOpts().CPlusPlus2a ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
@@ -6530,7 +6587,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
DeductionArg = PE->getPattern();
if (DeduceAutoType(
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
- DeductionArg, ParamType, Depth) == DAR_Failed) {
+ DeductionArg, ParamType, Depth,
+ // We do not check constraints right now because the
+ // immediately-declared constraint of the auto type is also an
+ // associated constraint, and will be checked along with the other
+ // associated constraints after checking the template argument list.
+ /*IgnoreConstraints=*/true) == DAR_Failed) {
Diag(Arg->getExprLoc(),
diag::err_non_type_template_parm_type_deduction_failure)
<< Param->getDeclName() << Param->getType() << Arg->getType()
@@ -7102,6 +7164,11 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// [temp.constr.order].
SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
Params->getAssociatedConstraints(ParamsAC);
+ // C++2a[temp.arg.template]p3
+ // [...] In this comparison, if P is unconstrained, the constraints on A
+ // are not considered.
+ if (ParamsAC.empty())
+ return false;
Template->getAssociatedConstraints(TemplateAC);
bool IsParamAtLeastAsConstrained;
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
@@ -7872,13 +7939,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs(
DeclResult Sema::ActOnClassTemplateSpecialization(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
- SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId,
- const ParsedAttributesView &Attr,
+ SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
+ TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) {
assert(TUK != TUK_Reference && "References are not specializations");
- CXXScopeSpec &SS = TemplateId.SS;
-
// NOTE: KWLoc is the location of the tag keyword. This will instead
// store the location of the outermost template keyword in the declaration.
SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
@@ -8048,7 +8113,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization()) &&
- (!Context.getLangOpts().ConceptsTS ||
+ (!Context.getLangOpts().CPlusPlus2a ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
@@ -10012,24 +10077,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
<< FixItHint::CreateRemoval(TypenameLoc);
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
+ TypeSourceInfo *TSI = nullptr;
QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None,
- TypenameLoc, QualifierLoc, II, IdLoc);
+ TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
+ /*DeducedTSTContext=*/true);
if (T.isNull())
return true;
-
- TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
- if (isa<DependentNameType>(T)) {
- DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
- TL.setElaboratedKeywordLoc(TypenameLoc);
- TL.setQualifierLoc(QualifierLoc);
- TL.setNameLoc(IdLoc);
- } else {
- ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>();
- TL.setElaboratedKeywordLoc(TypenameLoc);
- TL.setQualifierLoc(QualifierLoc);
- TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
- }
-
return CreateParsedType(T, TSI);
}
@@ -10166,6 +10219,35 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
return true;
}
+QualType
+Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ SourceLocation KeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ const IdentifierInfo &II,
+ SourceLocation IILoc,
+ TypeSourceInfo **TSI,
+ bool DeducedTSTContext) {
+ QualType T = CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, II, IILoc,
+ DeducedTSTContext);
+ if (T.isNull())
+ return QualType();
+
+ *TSI = Context.CreateTypeSourceInfo(T);
+ if (isa<DependentNameType>(T)) {
+ DependentNameTypeLoc TL =
+ (*TSI)->getTypeLoc().castAs<DependentNameTypeLoc>();
+ TL.setElaboratedKeywordLoc(KeywordLoc);
+ TL.setQualifierLoc(QualifierLoc);
+ TL.setNameLoc(IILoc);
+ } else {
+ ElaboratedTypeLoc TL = (*TSI)->getTypeLoc().castAs<ElaboratedTypeLoc>();
+ TL.setElaboratedKeywordLoc(KeywordLoc);
+ TL.setQualifierLoc(QualifierLoc);
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IILoc);
+ }
+ return T;
+}
+
/// Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType
@@ -10173,32 +10255,38 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
SourceLocation KeywordLoc,
NestedNameSpecifierLoc QualifierLoc,
const IdentifierInfo &II,
- SourceLocation IILoc) {
+ SourceLocation IILoc, bool DeducedTSTContext) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- DeclContext *Ctx = computeDeclContext(SS);
- if (!Ctx) {
- // If the nested-name-specifier is dependent and couldn't be
- // resolved to a type, build a typename type.
- assert(QualifierLoc.getNestedNameSpecifier()->isDependent());
- return Context.getDependentNameType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
- &II);
+ DeclContext *Ctx = nullptr;
+ if (QualifierLoc) {
+ Ctx = computeDeclContext(SS);
+ if (!Ctx) {
+ // If the nested-name-specifier is dependent and couldn't be
+ // resolved to a type, build a typename type.
+ assert(QualifierLoc.getNestedNameSpecifier()->isDependent());
+ return Context.getDependentNameType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ &II);
+ }
+
+ // If the nested-name-specifier refers to the current instantiation,
+ // the "typename" keyword itself is superfluous. In C++03, the
+ // program is actually ill-formed. However, DR 382 (in C++0x CD1)
+ // allows such extraneous "typename" keywords, and we retroactively
+ // apply this DR to C++03 code with only a warning. In any case we continue.
+
+ if (RequireCompleteDeclContext(SS, Ctx))
+ return QualType();
}
- // If the nested-name-specifier refers to the current instantiation,
- // the "typename" keyword itself is superfluous. In C++03, the
- // program is actually ill-formed. However, DR 382 (in C++0x CD1)
- // allows such extraneous "typename" keywords, and we retroactively
- // apply this DR to C++03 code with only a warning. In any case we continue.
-
- if (RequireCompleteDeclContext(SS, Ctx))
- return QualType();
-
DeclarationName Name(&II);
LookupResult Result(*this, Name, IILoc, LookupOrdinaryName);
- LookupQualifiedName(Result, Ctx, SS);
+ if (Ctx)
+ LookupQualifiedName(Result, Ctx, SS);
+ else
+ LookupName(Result, CurScope);
unsigned DiagID = 0;
Decl *Referenced = nullptr;
switch (Result.getResultKind()) {
@@ -10207,7 +10295,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// a more specific diagnostic.
SourceRange CondRange;
Expr *Cond = nullptr;
- if (isEnableIf(QualifierLoc, II, CondRange, Cond)) {
+ if (Ctx && isEnableIf(QualifierLoc, II, CondRange, Cond)) {
// If we have a condition, narrow it down to the specific failed
// condition.
if (Cond) {
@@ -10223,12 +10311,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
return QualType();
}
- Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if)
+ Diag(CondRange.getBegin(),
+ diag::err_typename_nested_not_found_enable_if)
<< Ctx << CondRange;
return QualType();
}
- DiagID = diag::err_typename_nested_not_found;
+ DiagID = Ctx ? diag::err_typename_nested_not_found
+ : diag::err_unknown_typename;
break;
}
@@ -10294,6 +10384,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// is a placeholder for a deduced class type [...].
if (getLangOpts().CPlusPlus17) {
if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) {
+ if (!DeducedTSTContext) {
+ QualType T(QualifierLoc
+ ? QualifierLoc.getNestedNameSpecifier()->getAsType()
+ : nullptr, 0);
+ if (!T.isNull())
+ Diag(IILoc, diag::err_dependent_deduced_tst)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << T;
+ else
+ Diag(IILoc, diag::err_deduced_tst)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(TD));
+ Diag(TD->getLocation(), diag::note_template_decl_here);
+ return QualType();
+ }
return Context.getElaboratedType(
Keyword, QualifierLoc.getNestedNameSpecifier(),
Context.getDeducedTemplateSpecializationType(TemplateName(TD),
@@ -10301,12 +10404,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
}
}
- DiagID = diag::err_typename_nested_not_type;
+ DiagID = Ctx ? diag::err_typename_nested_not_type
+ : diag::err_typename_not_type;
Referenced = Result.getFoundDecl();
break;
case LookupResult::FoundOverloaded:
- DiagID = diag::err_typename_nested_not_type;
+ DiagID = Ctx ? diag::err_typename_nested_not_type
+ : diag::err_typename_not_type;
Referenced = *Result.begin();
break;
@@ -10318,9 +10423,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// type. Emit an appropriate diagnostic and return an error.
SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(),
IILoc);
- Diag(IILoc, DiagID) << FullRange << Name << Ctx;
+ if (Ctx)
+ Diag(IILoc, DiagID) << FullRange << Name << Ctx;
+ else
+ Diag(IILoc, DiagID) << FullRange << Name;
if (Referenced)
- Diag(Referenced->getLocation(), diag::note_typename_refers_here)
+ Diag(Referenced->getLocation(),
+ Ctx ? diag::note_typename_member_refers_here
+ : diag::note_typename_refers_here)
<< Name;
return QualType();
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1b9f1b2144d1..394c81c82794 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -724,38 +724,48 @@ private:
// Compute the set of template parameter indices that correspond to
// parameter packs expanded by the pack expansion.
llvm::SmallBitVector SawIndices(TemplateParams->size());
+ llvm::SmallVector<TemplateArgument, 4> ExtraDeductions;
auto AddPack = [&](unsigned Index) {
if (SawIndices[Index])
return;
SawIndices[Index] = true;
addPack(Index);
+
+ // Deducing a parameter pack that is a pack expansion also constrains the
+ // packs appearing in that parameter to have the same deduced arity. Also,
+ // in C++17 onwards, deducing a non-type template parameter deduces its
+ // type, so we need to collect the pending deduced values for those packs.
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(
+ TemplateParams->getParam(Index))) {
+ if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType()))
+ ExtraDeductions.push_back(Expansion->getPattern());
+ }
+ // FIXME: Also collect the unexpanded packs in any type and template
+ // parameter packs that are pack expansions.
};
- // First look for unexpanded packs in the pattern.
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == Info.getDeducedDepth())
- AddPack(Index);
- }
+ auto Collect = [&](TemplateArgument Pattern) {
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+ for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
+ unsigned Depth, Index;
+ std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+ if (Depth == Info.getDeducedDepth())
+ AddPack(Index);
+ }
+ };
+
+ // Look for unexpanded packs in the pattern.
+ Collect(Pattern);
assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
unsigned NumNamedPacks = Packs.size();
- // We can also have deduced template parameters that do not actually
- // appear in the pattern, but can be deduced by it (the type of a non-type
- // template parameter pack, in particular). These won't have prevented us
- // from partially expanding the pack.
- llvm::SmallBitVector Used(TemplateParams->size());
- MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true,
- Info.getDeducedDepth(), Used);
- for (int Index = Used.find_first(); Index != -1;
- Index = Used.find_next(Index))
- if (TemplateParams->getParam(Index)->isParameterPack())
- AddPack(Index);
+ // Also look for unexpanded packs that are indirectly deduced by deducing
+ // the sizes of the packs in this pattern.
+ while (!ExtraDeductions.empty())
+ Collect(ExtraDeductions.pop_back_val());
return NumNamedPacks;
}
@@ -4404,9 +4414,10 @@ namespace {
QualType Result = SemaRef.Context.getAutoType(
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(),
- ReplacementIsPack);
+ ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(),
+ TL.getTypePtr()->getTypeConstraintArguments());
auto NewTL = TLB.push<AutoTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.copy(TL);
return Result;
}
@@ -4441,9 +4452,10 @@ namespace {
Sema::DeduceAutoResult
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth) {
+ Optional<unsigned> DependentDeductionDepth,
+ bool IgnoreConstraints) {
return DeduceAutoType(Type->getTypeLoc(), Init, Result,
- DependentDeductionDepth);
+ DependentDeductionDepth, IgnoreConstraints);
}
/// Attempt to produce an informative diagostic explaining why auto deduction
@@ -4471,6 +4483,49 @@ static bool diagnoseAutoDeductionFailure(Sema &S,
}
}
+static Sema::DeduceAutoResult
+CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
+ AutoTypeLoc TypeLoc, QualType Deduced) {
+ ConstraintSatisfaction Satisfaction;
+ ConceptDecl *Concept = Type.getTypeConstraintConcept();
+ TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
+ TypeLoc.getRAngleLoc());
+ TemplateArgs.addArgument(
+ TemplateArgumentLoc(TemplateArgument(Deduced),
+ S.Context.getTrivialTypeSourceInfo(
+ Deduced, TypeLoc.getNameLoc())));
+ for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I)
+ TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
+ /*PartialTemplateArgs=*/false, Converted))
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
+ Converted, TypeLoc.getLocalSourceRange(),
+ Satisfaction))
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ if (!Satisfaction.IsSatisfied) {
+ std::string Buf;
+ llvm::raw_string_ostream OS(Buf);
+ OS << "'" << Concept->getName();
+ if (TypeLoc.hasExplicitTemplateArgs()) {
+ OS << "<";
+ for (const auto &Arg : Type.getTypeConstraintArguments())
+ Arg.print(S.getPrintingPolicy(), OS);
+ OS << ">";
+ }
+ OS << "'";
+ OS.flush();
+ S.Diag(TypeLoc.getConceptNameLoc(),
+ diag::err_placeholder_constraints_not_satisfied)
+ << Deduced << Buf << TypeLoc.getLocalSourceRange();
+ S.DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ }
+ return Sema::DAR_Succeeded;
+}
+
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// Note that this is done even if the initializer is dependent. (This is
@@ -4485,9 +4540,12 @@ static bool diagnoseAutoDeductionFailure(Sema &S,
/// dependent cases. This is necessary for template partial ordering with
/// 'auto' template parameters. The value specified is the template
/// parameter depth at which we should perform 'auto' deduction.
+/// \param IgnoreConstraints Set if we should not fail if the deduced type does
+/// not satisfy the type-constraint in the auto type.
Sema::DeduceAutoResult
Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth) {
+ Optional<unsigned> DependentDeductionDepth,
+ bool IgnoreConstraints) {
if (Init->getType()->isNonOverloadPlaceholderType()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
@@ -4528,6 +4586,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
// FIXME: Support a non-canonical deduced type for 'auto'.
Deduced = Context.getCanonicalType(Deduced);
+ if (AT->isConstrained() && !IgnoreConstraints) {
+ auto ConstraintsResult =
+ CheckDeducedPlaceholderConstraints(*this, *AT,
+ Type.getContainedAutoTypeLoc(),
+ Deduced);
+ if (ConstraintsResult != DAR_Succeeded)
+ return ConstraintsResult;
+ }
Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
@@ -4635,6 +4701,17 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
+ if (const auto *AT = Type.getType()->getAs<AutoType>()) {
+ if (AT->isConstrained() && !IgnoreConstraints) {
+ auto ConstraintsResult =
+ CheckDeducedPlaceholderConstraints(*this, *AT,
+ Type.getContainedAutoTypeLoc(),
+ DeducedType);
+ if (ConstraintsResult != DAR_Succeeded)
+ return ConstraintsResult;
+ }
+ }
+
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index af41e231134d..39bc28d62305 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -26,6 +26,7 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "clang/Sema/SemaConcept.h"
#include "llvm/Support/TimeProfiler.h"
using namespace clang;
@@ -199,8 +200,10 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case DeducedTemplateArgumentSubstitution:
case PriorTemplateArgumentSubstitution:
case ConstraintsCheck:
+ case NestedRequirementConstraintsCheck:
return true;
+ case RequirementInstantiation:
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DeclaringImplicitEqualityComparison:
@@ -247,7 +250,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Inst.InstantiationRange = InstantiationRange;
SemaRef.pushCodeSynthesisContext(Inst);
- AlreadyInstantiating =
+ AlreadyInstantiating = !Inst.Entity ? false :
!SemaRef.InstantiatingSpecializations
.insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind))
.second;
@@ -366,6 +369,26 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
+ concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::RequirementInstantiation,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
+ /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {}
+
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ concepts::NestedRequirement *Req, ConstraintsCheck,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
+ /*Template=*/nullptr, /*TemplateArgs=*/None) {}
+
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
ConstraintsCheck, NamedDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
: InstantiatingTemplate(
@@ -446,8 +469,9 @@ void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
if (!AlreadyInstantiating) {
auto &Active = SemaRef.CodeSynthesisContexts.back();
- SemaRef.InstantiatingSpecializations.erase(
- std::make_pair(Active.Entity, Active.Kind));
+ if (Active.Entity)
+ SemaRef.InstantiatingSpecializations.erase(
+ std::make_pair(Active.Entity, Active.Kind));
}
atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef,
@@ -684,6 +708,18 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
break;
+ case CodeSynthesisContext::RequirementInstantiation:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_requirement_instantiation_here)
+ << Active->InstantiationRange;
+ break;
+
+ case CodeSynthesisContext::NestedRequirementConstraintsCheck:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_nested_requirement_here)
+ << Active->InstantiationRange;
+ break;
+
case CodeSynthesisContext::DeclaringSpecialMember:
Diags.Report(Active->PointOfInstantiation,
diag::note_in_declaration_of_implicit_special_member)
@@ -788,6 +824,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ConstraintsCheck:
case CodeSynthesisContext::ParameterMappingSubstitution:
case CodeSynthesisContext::ConstraintNormalization:
+ case CodeSynthesisContext::NestedRequirementConstraintsCheck:
// This is a template instantiation, so there is no SFINAE.
return None;
@@ -802,9 +839,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
case CodeSynthesisContext::ConstraintSubstitution:
- // We're either substituting explicitly-specified template arguments
- // or deduced template arguments or a constraint expression, so SFINAE
- // applies.
+ case CodeSynthesisContext::RequirementInstantiation:
+ // We're either substituting explicitly-specified template arguments,
+ // deduced template arguments, a constraint expression or a requirement
+ // in a requires expression, so SFINAE applies.
assert(Active->DeductionInfo && "Missing deduction info pointer");
return Active->DeductionInfo;
@@ -1056,6 +1094,41 @@ namespace {
return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);
}
+ ExprResult TransformRequiresExpr(RequiresExpr *E) {
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ return TreeTransform<TemplateInstantiator>::TransformRequiresExpr(E);
+ }
+
+ bool TransformRequiresExprRequirements(
+ ArrayRef<concepts::Requirement *> Reqs,
+ SmallVectorImpl<concepts::Requirement *> &Transformed) {
+ bool SatisfactionDetermined = false;
+ for (concepts::Requirement *Req : Reqs) {
+ concepts::Requirement *TransReq = nullptr;
+ if (!SatisfactionDetermined) {
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
+ TransReq = TransformTypeRequirement(TypeReq);
+ else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
+ TransReq = TransformExprRequirement(ExprReq);
+ else
+ TransReq = TransformNestedRequirement(
+ cast<concepts::NestedRequirement>(Req));
+ if (!TransReq)
+ return true;
+ if (!TransReq->isDependent() && !TransReq->isSatisfied())
+ // [expr.prim.req]p6
+ // [...] The substitution and semantic constraint checking
+ // proceeds in lexical order and stops when a condition that
+ // determines the result of the requires-expression is
+ // encountered. [..]
+ SatisfactionDetermined = true;
+ } else
+ TransReq = Req;
+ Transformed.push_back(TransReq);
+ }
+ return false;
+ }
+
TemplateParameterList *TransformTemplateParameterList(
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
@@ -1065,6 +1138,14 @@ namespace {
/* DeclContext *Owner */ Owner, TemplateArgs);
return DeclInstantiator.SubstTemplateParams(OrigTPL);
}
+
+ concepts::TypeRequirement *
+ TransformTypeRequirement(concepts::TypeRequirement *Req);
+ concepts::ExprRequirement *
+ TransformExprRequirement(concepts::ExprRequirement *Req);
+ concepts::NestedRequirement *
+ TransformNestedRequirement(concepts::NestedRequirement *Req);
+
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,
@@ -1669,6 +1750,163 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
return Result;
}
+template<typename EntityPrinter>
+static concepts::Requirement::SubstitutionDiagnostic *
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+ SmallString<128> Message;
+ SourceLocation ErrorLoc;
+ if (Info.hasSFINAEDiagnostic()) {
+ PartialDiagnosticAt PDA(SourceLocation(),
+ PartialDiagnostic::NullDiagnostic{});
+ Info.takeSFINAEDiagnostic(PDA);
+ PDA.second.EmitToString(S.getDiagnostics(), Message);
+ ErrorLoc = PDA.first;
+ } else {
+ ErrorLoc = Info.getLocation();
+ }
+ char *MessageBuf = new (S.Context) char[Message.size()];
+ std::copy(Message.begin(), Message.end(), MessageBuf);
+ SmallString<128> Entity;
+ llvm::raw_svector_ostream OS(Entity);
+ Printer(OS);
+ char *EntityBuf = new (S.Context) char[Entity.size()];
+ std::copy(Entity.begin(), Entity.end(), EntityBuf);
+ return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+ StringRef(EntityBuf, Entity.size()), ErrorLoc,
+ StringRef(MessageBuf, Message.size())};
+}
+
+concepts::TypeRequirement *
+TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) {
+ if (!Req->isDependent() && !AlwaysRebuild())
+ return Req;
+ if (Req->isSubstitutionFailure()) {
+ if (AlwaysRebuild())
+ return RebuildTypeRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+
+ Sema::SFINAETrap Trap(SemaRef);
+ TemplateDeductionInfo Info(Req->getType()->getTypeLoc().getBeginLoc());
+ Sema::InstantiatingTemplate TypeInst(SemaRef,
+ Req->getType()->getTypeLoc().getBeginLoc(), Req, Info,
+ Req->getType()->getTypeLoc().getSourceRange());
+ if (TypeInst.isInvalid())
+ return nullptr;
+ TypeSourceInfo *TransType = TransformType(Req->getType());
+ if (!TransType || Trap.hasErrorOccurred())
+ return RebuildTypeRequirement(createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ Req->getType()->getType().print(OS, SemaRef.getPrintingPolicy());
+ }));
+ return RebuildTypeRequirement(TransType);
+}
+
+concepts::ExprRequirement *
+TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
+ if (!Req->isDependent() && !AlwaysRebuild())
+ return Req;
+
+ Sema::SFINAETrap Trap(SemaRef);
+ TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc());
+
+ llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *>
+ TransExpr;
+ if (Req->isExprSubstitutionFailure())
+ TransExpr = Req->getExprSubstitutionDiagnostic();
+ else {
+ Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(),
+ Req, Info,
+ Req->getExpr()->getSourceRange());
+ if (ExprInst.isInvalid())
+ return nullptr;
+ ExprResult TransExprRes = TransformExpr(Req->getExpr());
+ if (TransExprRes.isInvalid() || Trap.hasErrorOccurred())
+ TransExpr = createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ Req->getExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
+ });
+ else
+ TransExpr = TransExprRes.get();
+ }
+
+ llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ const auto &RetReq = Req->getReturnTypeRequirement();
+ if (RetReq.isEmpty())
+ TransRetReq.emplace();
+ else if (RetReq.isSubstitutionFailure())
+ TransRetReq.emplace(RetReq.getSubstitutionDiagnostic());
+ else if (RetReq.isTypeConstraint()) {
+ TemplateParameterList *OrigTPL =
+ RetReq.getTypeConstraintTemplateParameterList();
+ Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(),
+ Req, Info, OrigTPL->getSourceRange());
+ if (TPLInst.isInvalid())
+ return nullptr;
+ TemplateParameterList *TPL =
+ TransformTemplateParameterList(OrigTPL);
+ if (!TPL)
+ TransRetReq.emplace(createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint()
+ ->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
+ }));
+ else {
+ TPLInst.Clear();
+ TransRetReq.emplace(TPL);
+ }
+ }
+ assert(TransRetReq.hasValue() &&
+ "All code paths leading here must set TransRetReq");
+ if (Expr *E = TransExpr.dyn_cast<Expr *>())
+ return RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(),
+ std::move(*TransRetReq));
+ return RebuildExprRequirement(
+ TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(),
+ Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq));
+}
+
+concepts::NestedRequirement *
+TemplateInstantiator::TransformNestedRequirement(
+ concepts::NestedRequirement *Req) {
+ if (!Req->isDependent() && !AlwaysRebuild())
+ return Req;
+ if (Req->isSubstitutionFailure()) {
+ if (AlwaysRebuild())
+ return RebuildNestedRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+ Sema::InstantiatingTemplate ReqInst(SemaRef,
+ Req->getConstraintExpr()->getBeginLoc(), Req,
+ Sema::InstantiatingTemplate::ConstraintsCheck{},
+ Req->getConstraintExpr()->getSourceRange());
+
+ ExprResult TransConstraint;
+ TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc());
+ {
+ EnterExpressionEvaluationContext ContextRAII(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ Sema::SFINAETrap Trap(SemaRef);
+ Sema::InstantiatingTemplate ConstrInst(SemaRef,
+ Req->getConstraintExpr()->getBeginLoc(), Req, Info,
+ Req->getConstraintExpr()->getSourceRange());
+ if (ConstrInst.isInvalid())
+ return nullptr;
+ TransConstraint = TransformExpr(Req->getConstraintExpr());
+ if (TransConstraint.isInvalid() || Trap.hasErrorOccurred())
+ return RebuildNestedRequirement(createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ Req->getConstraintExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
+ }));
+ }
+ return RebuildNestedRequirement(TransConstraint.get());
+}
+
+
/// Perform substitution on the type T with a given set of template
/// arguments.
///
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 64500d0a26d5..fbbab8f00703 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1848,6 +1848,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// FIXME: Concepts: Do not substitute into constraint expressions
Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
if (TrailingRequiresClause) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
TemplateArgs);
if (SubstRC.isInvalid())
@@ -2186,6 +2188,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
// FIXME: Concepts: Do not substitute into constraint expressions
Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
if (TrailingRequiresClause) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
TemplateArgs);
if (SubstRC.isInvalid())
@@ -2685,6 +2689,16 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
+ if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc())
+ if (AutoLoc.isConstrained())
+ if (SemaRef.AttachTypeConstraint(
+ AutoLoc, Param,
+ IsExpandedParameterPack
+ ? DI->getTypeLoc().getAs<PackExpansionTypeLoc>()
+ .getEllipsisLoc()
+ : SourceLocation()))
+ Invalid = true;
+
Param->setAccess(AS_public);
Param->setImplicit(D->isImplicit());
if (Invalid)
@@ -3600,6 +3614,12 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
llvm_unreachable("Concept definitions cannot reside inside a template");
}
+Decl *
+TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
+ return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(),
+ D->getBeginLoc());
+}
+
Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
llvm_unreachable("Unexpected decl");
}
@@ -3713,6 +3733,8 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
// checking satisfaction.
Expr *InstRequiresClause = nullptr;
if (Expr *E = L->getRequiresClause()) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
if (Res.isInvalid() || !Res.isUsable()) {
return nullptr;
@@ -4236,9 +4258,9 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
MLTAL.getInnermost(), SourceRange());
if (Inst.isInvalid())
return true;
- if (addInstantiatedParametersToScope(*this, Decl,
- Decl->getTemplateInstantiationPattern(),
- Scope, MLTAL))
+ if (addInstantiatedParametersToScope(
+ *this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(),
+ Scope, MLTAL))
return true;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3884fdae8fe7..93ddd047e09b 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "TypeLocBuilder.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -27,6 +28,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
@@ -1251,6 +1253,26 @@ getImageAccess(const ParsedAttributesView &Attrs) {
return OpenCLAccessAttr::Keyword_read_only;
}
+static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS,
+ AutoTypeKeyword AutoKW) {
+ assert(DS.isConstrainedAuto());
+ TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
+ TemplateArgumentListInfo TemplateArgsInfo;
+ TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc);
+ TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ llvm::SmallVector<TemplateArgument, 8> TemplateArgs;
+ for (auto &ArgLoc : TemplateArgsInfo.arguments())
+ TemplateArgs.push_back(ArgLoc.getArgument());
+ return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false,
+ /*IsPack=*/false,
+ cast<ConceptDecl>(TemplateId->Template.get()
+ .getAsTemplateDecl()),
+ TemplateArgs);
+}
+
/// Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@@ -1595,6 +1617,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_auto:
+ if (DS.isConstrainedAuto()) {
+ Result = ConvertConstrainedAutoDeclSpecToType(S, DS,
+ AutoTypeKeyword::Auto);
+ break;
+ }
Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
break;
@@ -1603,6 +1630,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_decltype_auto:
+ if (DS.isConstrainedAuto()) {
+ Result =
+ ConvertConstrainedAutoDeclSpecToType(S, DS,
+ AutoTypeKeyword::DecltypeAuto);
+ break;
+ }
Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto,
/*IsDependent*/ false);
break;
@@ -2921,6 +2954,87 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
D.getDeclSpec().getUnalignedSpecLoc());
}
+static void CopyTypeConstraintFromAutoType(Sema &SemaRef, const AutoType *Auto,
+ AutoTypeLoc AutoLoc,
+ TemplateTypeParmDecl *TP,
+ SourceLocation EllipsisLoc) {
+
+ TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc());
+ for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx)
+ TAL.addArgument(AutoLoc.getArgLoc(Idx));
+
+ SemaRef.AttachTypeConstraint(
+ AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(),
+ AutoLoc.getNamedConcept(),
+ AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, TP, EllipsisLoc);
+}
+
+static QualType InventTemplateParameter(
+ TypeProcessingState &state, QualType T, TypeSourceInfo *TSI, AutoType *Auto,
+ InventedTemplateParameterInfo &Info) {
+ Sema &S = state.getSema();
+ Declarator &D = state.getDeclarator();
+
+ const unsigned TemplateParameterDepth = Info.AutoTemplateParameterDepth;
+ const unsigned AutoParameterPosition = Info.TemplateParams.size();
+ const bool IsParameterPack = D.hasEllipsis();
+
+ // If auto is mentioned in a lambda parameter or abbreviated function
+ // template context, convert it to a template parameter type.
+
+ // Create the TemplateTypeParmDecl here to retrieve the corresponding
+ // template parameter type. Template parameters are temporarily added
+ // to the TU until the associated TemplateDecl is created.
+ TemplateTypeParmDecl *InventedTemplateParam =
+ TemplateTypeParmDecl::Create(
+ S.Context, S.Context.getTranslationUnitDecl(),
+ /*KeyLoc=*/D.getDeclSpec().getTypeSpecTypeLoc(),
+ /*NameLoc=*/D.getIdentifierLoc(),
+ TemplateParameterDepth, AutoParameterPosition,
+ S.InventAbbreviatedTemplateParameterTypeName(
+ D.getIdentifier(), AutoParameterPosition), false,
+ IsParameterPack, /*HasTypeConstraint=*/Auto->isConstrained());
+ InventedTemplateParam->setImplicit();
+ Info.TemplateParams.push_back(InventedTemplateParam);
+ // Attach type constraints
+ if (Auto->isConstrained()) {
+ if (TSI) {
+ CopyTypeConstraintFromAutoType(
+ S, Auto, TSI->getTypeLoc().getContainedAutoTypeLoc(),
+ InventedTemplateParam, D.getEllipsisLoc());
+ } else {
+ TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId();
+ TemplateArgumentListInfo TemplateArgsInfo;
+ if (TemplateId->LAngleLoc.isValid()) {
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ }
+ S.AttachTypeConstraint(
+ D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context),
+ DeclarationNameInfo(DeclarationName(TemplateId->Name),
+ TemplateId->TemplateNameLoc),
+ cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()),
+ TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
+ InventedTemplateParam, D.getEllipsisLoc());
+ }
+ }
+
+ // If TSI is nullptr, this is a constrained declspec auto and the type
+ // constraint will be attached later in TypeSpecLocFiller
+
+ // Replace the 'auto' in the function parameter with this invented
+ // template type parameter.
+ // FIXME: Retain some type sugar to indicate that this was written
+ // as 'auto'?
+ return state.ReplaceAutoType(
+ T, QualType(InventedTemplateParam->getTypeForDecl(), 0));
+}
+
+static TypeSourceInfo *
+GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
+ QualType T, TypeSourceInfo *ReturnTypeInfo);
+
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
TypeSourceInfo *&ReturnTypeInfo) {
Sema &SemaRef = state.getSema();
@@ -2991,43 +3105,43 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
break;
case DeclaratorContext::ObjCParameterContext:
case DeclaratorContext::ObjCResultContext:
- case DeclaratorContext::PrototypeContext:
Error = 0;
break;
- case DeclaratorContext::LambdaExprParameterContext:
- // In C++14, generic lambdas allow 'auto' in their parameters.
- if (!SemaRef.getLangOpts().CPlusPlus14 ||
- !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto)
- Error = 16;
- else {
- // If auto is mentioned in a lambda parameter context, convert it to a
- // template parameter type.
- sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
- assert(LSI && "No LambdaScopeInfo on the stack!");
- const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
- const unsigned AutoParameterPosition = LSI->TemplateParams.size();
- const bool IsParameterPack = D.hasEllipsis();
-
- // Create the TemplateTypeParmDecl here to retrieve the corresponding
- // template parameter type. Template parameters are temporarily added
- // to the TU until the associated TemplateDecl is created.
- TemplateTypeParmDecl *CorrespondingTemplateParam =
- TemplateTypeParmDecl::Create(
- SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
- /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
- TemplateParameterDepth, AutoParameterPosition,
- /*Identifier*/ nullptr, false, IsParameterPack,
- /*HasTypeConstraint=*/false);
- CorrespondingTemplateParam->setImplicit();
- LSI->TemplateParams.push_back(CorrespondingTemplateParam);
- // Replace the 'auto' in the function parameter with this invented
- // template type parameter.
- // FIXME: Retain some type sugar to indicate that this was written
- // as 'auto'.
- T = state.ReplaceAutoType(
- T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0));
+ case DeclaratorContext::RequiresExprContext:
+ Error = 22;
+ break;
+ case DeclaratorContext::PrototypeContext:
+ case DeclaratorContext::LambdaExprParameterContext: {
+ InventedTemplateParameterInfo *Info = nullptr;
+ if (D.getContext() == DeclaratorContext::PrototypeContext) {
+ // With concepts we allow 'auto' in function parameters.
+ if (!SemaRef.getLangOpts().CPlusPlus2a || !Auto ||
+ Auto->getKeyword() != AutoTypeKeyword::Auto) {
+ Error = 0;
+ break;
+ } else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) {
+ Error = 21;
+ break;
+ } else if (D.hasTrailingReturnType()) {
+ // This might be OK, but we'll need to convert the trailing return
+ // type later.
+ break;
+ }
+
+ Info = &SemaRef.InventedParameterInfos.back();
+ } else {
+ // In C++14, generic lambdas allow 'auto' in their parameters.
+ if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto ||
+ Auto->getKeyword() != AutoTypeKeyword::Auto) {
+ Error = 16;
+ break;
+ }
+ Info = SemaRef.getCurLambda();
+ assert(Info && "No LambdaScopeInfo on the stack!");
}
+ T = InventTemplateParameter(state, T, nullptr, Auto, *Info);
break;
+ }
case DeclaratorContext::MemberContext: {
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
D.isFunctionDeclarator())
@@ -3221,6 +3335,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::ObjCParameterContext:
case DeclaratorContext::ObjCResultContext:
case DeclaratorContext::KNRTypeListContext:
+ case DeclaratorContext::RequiresExprContext:
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
DiagID = diag::err_type_defined_in_param_type;
@@ -4028,10 +4143,6 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,
return false;
}
-static TypeSourceInfo *
-GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
- QualType T, TypeSourceInfo *ReturnTypeInfo);
-
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@@ -4279,6 +4390,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TypeNameContext:
case DeclaratorContext::FunctionalCastContext:
+ case DeclaratorContext::RequiresExprContext:
// Don't infer in these contexts.
break;
}
@@ -4606,7 +4718,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else if (D.getContext() != DeclaratorContext::LambdaExprContext &&
(T.hasQualifiers() || !isa<AutoType>(T) ||
cast<AutoType>(T)->getKeyword() !=
- AutoTypeKeyword::Auto)) {
+ AutoTypeKeyword::Auto ||
+ cast<AutoType>(T)->isConstrained())) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
@@ -4617,7 +4730,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// An error occurred parsing the trailing return type.
T = Context.IntTy;
D.setInvalidType(true);
- }
+ } else if (S.getLangOpts().CPlusPlus2a)
+ // Handle cases like: `auto f() -> auto` or `auto f() -> C auto`.
+ if (AutoType *Auto = T->getContainedAutoType())
+ if (S.getCurScope()->isFunctionDeclarationScope())
+ T = InventTemplateParameter(state, T, TInfo, Auto,
+ S.InventedParameterInfos.back());
} else {
// This function type is not the type of the entity being declared,
// so checking the 'auto' is not the responsibility of this chunk.
@@ -5227,6 +5345,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
switch (D.getContext()) {
case DeclaratorContext::PrototypeContext:
case DeclaratorContext::LambdaExprParameterContext:
+ case DeclaratorContext::RequiresExprContext:
// C++0x [dcl.fct]p13:
// [...] When it is part of a parameter-declaration-clause, the
// parameter pack is a function parameter pack (14.5.3). The type T
@@ -5236,7 +5355,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
//
// We represent function parameter packs as function parameters whose
// type is a pack expansion.
- if (!T->containsUnexpandedParameterPack()) {
+ if (!T->containsUnexpandedParameterPack() &&
+ (!LangOpts.CPlusPlus2a || !T->getContainedAutoType())) {
S.Diag(D.getEllipsisLoc(),
diag::err_function_parameter_pack_without_parameter_packs)
<< T << D.getSourceRange();
@@ -5444,14 +5564,15 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
+ Sema &SemaRef;
ASTContext &Context;
TypeProcessingState &State;
const DeclSpec &DS;
public:
- TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State,
+ TypeSpecLocFiller(Sema &S, ASTContext &Context, TypeProcessingState &State,
const DeclSpec &DS)
- : Context(Context), State(State), DS(DS) {}
+ : SemaRef(S), Context(Context), State(State), DS(DS) {}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
Visit(TL.getModifiedLoc());
@@ -5579,6 +5700,34 @@ namespace {
TL.copy(
TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>());
}
+ void VisitAutoTypeLoc(AutoTypeLoc TL) {
+ assert(DS.getTypeSpecType() == TST_auto ||
+ DS.getTypeSpecType() == TST_decltype_auto ||
+ DS.getTypeSpecType() == TST_auto_type ||
+ DS.getTypeSpecType() == TST_unspecified);
+ TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ if (!DS.isConstrainedAuto())
+ return;
+ TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
+ if (DS.getTypeSpecScope().isNotEmpty())
+ TL.setNestedNameSpecifierLoc(
+ DS.getTypeSpecScope().getWithLocInContext(Context));
+ else
+ TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
+ TL.setTemplateKWLoc(TemplateId->TemplateKWLoc);
+ TL.setConceptNameLoc(TemplateId->TemplateNameLoc);
+ TL.setFoundDecl(nullptr);
+ TL.setLAngleLoc(TemplateId->LAngleLoc);
+ TL.setRAngleLoc(TemplateId->RAngleLoc);
+ if (TemplateId->NumArgs == 0)
+ return;
+ TemplateArgumentListInfo TemplateArgsInfo;
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ for (unsigned I = 0; I < TemplateId->NumArgs; ++I)
+ TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo());
+ }
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
@@ -5848,7 +5997,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
} else {
- TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL);
+ TypeSpecLocFiller(S, S.Context, State, D.getDeclSpec()).Visit(CurrTL);
}
return TInfo;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3b827fbc950b..d6105353bbdf 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -19,6 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
@@ -509,6 +510,15 @@ public:
DeclarationNameInfo
TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo);
+ bool TransformRequiresExprRequirements(ArrayRef<concepts::Requirement *> Reqs,
+ llvm::SmallVectorImpl<concepts::Requirement *> &Transformed);
+ concepts::TypeRequirement *
+ TransformTypeRequirement(concepts::TypeRequirement *Req);
+ concepts::ExprRequirement *
+ TransformExprRequirement(concepts::ExprRequirement *Req);
+ concepts::NestedRequirement *
+ TransformNestedRequirement(concepts::NestedRequirement *Req);
+
/// Transform the given template name.
///
/// \param SS The nested-name-specifier that qualifies the template
@@ -941,12 +951,16 @@ public:
/// Build a new C++11 auto type.
///
/// By default, builds a new AutoType with the given deduced type.
- QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) {
+ QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs) {
// Note, IsDependent is always false here: we implicitly convert an 'auto'
// which has been deduced to a dependent type into an undeduced 'auto', so
// that we'll retry deduction after the transformation.
return SemaRef.Context.getAutoType(Deduced, Keyword,
- /*IsDependent*/ false);
+ /*IsDependent*/ false, /*IsPack=*/false,
+ TypeConstraintConcept,
+ TypeConstraintArgs);
}
/// By default, builds a new DeducedTemplateSpecializationType with the given
@@ -1056,23 +1070,8 @@ public:
}
if (Keyword == ETK_None || Keyword == ETK_Typename) {
- QualType T = SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
- *Id, IdLoc);
- // If a dependent name resolves to a deduced template specialization type,
- // check that we're in one of the syntactic contexts permitting it.
- if (!DeducedTSTContext) {
- if (auto *Deduced = dyn_cast_or_null<DeducedTemplateSpecializationType>(
- T.isNull() ? nullptr : T->getContainedDeducedType())) {
- SemaRef.Diag(IdLoc, diag::err_dependent_deduced_tst)
- << (int)SemaRef.getTemplateNameKindForDiagnostics(
- Deduced->getTemplateName())
- << QualType(QualifierLoc.getNestedNameSpecifier()->getAsType(), 0);
- if (auto *TD = Deduced->getTemplateName().getAsTemplateDecl())
- SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here);
- return QualType();
- }
- }
- return T;
+ return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
+ *Id, IdLoc, DeducedTSTContext);
}
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
@@ -3078,7 +3077,56 @@ public:
return Result;
}
- /// \brief Build a new Objective-C boxed expression.
+ /// \brief Build a new requires expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation ClosingBraceLoc) {
+ return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body,
+ LocalParameters, Requirements, ClosingBraceLoc);
+ }
+
+ concepts::TypeRequirement *
+ RebuildTypeRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return SemaRef.BuildTypeRequirement(SubstDiag);
+ }
+
+ concepts::TypeRequirement *RebuildTypeRequirement(TypeSourceInfo *T) {
+ return SemaRef.BuildTypeRequirement(T);
+ }
+
+ concepts::ExprRequirement *
+ RebuildExprRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag, bool IsSimple,
+ SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement Ret) {
+ return SemaRef.BuildExprRequirement(SubstDiag, IsSimple, NoexceptLoc,
+ std::move(Ret));
+ }
+
+ concepts::ExprRequirement *
+ RebuildExprRequirement(Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement Ret) {
+ return SemaRef.BuildExprRequirement(E, IsSimple, NoexceptLoc,
+ std::move(Ret));
+ }
+
+ concepts::NestedRequirement *
+ RebuildNestedRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return SemaRef.BuildNestedRequirement(SubstDiag);
+ }
+
+ concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) {
+ return SemaRef.BuildNestedRequirement(Constraint);
+ }
+
+ /// \brief Build a new Objective-C boxed expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
@@ -4456,7 +4504,10 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
Deduced =
SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs);
T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(),
- AutoTy->isDependentType());
+ AutoTy->isDependentType(),
+ /*isPack=*/false,
+ AutoTy->getTypeConstraintConcept(),
+ AutoTy->getTypeConstraintArguments());
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
@@ -5189,21 +5240,29 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = ExpansionTL.getPatternLoc();
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- assert(Unexpanded.size() > 0 && "Could not find parameter packs!");
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions =
- ExpansionTL.getTypePtr()->getNumExpansions();
- NumExpansions = OrigNumExpansions;
- if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
- Pattern.getSourceRange(),
- Unexpanded,
- ShouldExpand,
- RetainExpansion,
- NumExpansions)) {
- return true;
+ Optional<unsigned> OrigNumExpansions;
+ if (Unexpanded.size() > 0) {
+ OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
+ NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
+ Pattern.getSourceRange(),
+ Unexpanded,
+ ShouldExpand,
+ RetainExpansion,
+ NumExpansions)) {
+ return true;
+ }
+ } else {
+#ifndef NDEBUG
+ const AutoType *AT =
+ Pattern.getType().getTypePtr()->getContainedAutoType();
+ assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) &&
+ "Could not find parameter packs or undeduced auto type!");
+#endif
}
if (ShouldExpand) {
@@ -5263,6 +5322,9 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
indexAdjustment,
NumExpansions,
/*ExpectParameterPack=*/true);
+ assert(NewParm->isParameterPack() &&
+ "Parameter pack no longer a parameter pack after "
+ "transformation.");
} else {
NewParm = getDerived().TransformFunctionTypeParam(
OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
@@ -5768,32 +5830,6 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
}
template<typename Derived>
-QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
- AutoTypeLoc TL) {
- const AutoType *T = TL.getTypePtr();
- QualType OldDeduced = T->getDeducedType();
- QualType NewDeduced;
- if (!OldDeduced.isNull()) {
- NewDeduced = getDerived().TransformType(OldDeduced);
- if (NewDeduced.isNull())
- return QualType();
- }
-
- QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
- T->isDependentType()) {
- Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword());
- if (Result.isNull())
- return QualType();
- }
-
- AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
- return Result;
-}
-
-template<typename Derived>
QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType(
TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
const DeducedTemplateSpecializationType *T = TL.getTypePtr();
@@ -6054,6 +6090,71 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
}
};
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
+ AutoTypeLoc TL) {
+ const AutoType *T = TL.getTypePtr();
+ QualType OldDeduced = T->getDeducedType();
+ QualType NewDeduced;
+ if (!OldDeduced.isNull()) {
+ NewDeduced = getDerived().TransformType(OldDeduced);
+ if (NewDeduced.isNull())
+ return QualType();
+ }
+
+ ConceptDecl *NewCD = nullptr;
+ TemplateArgumentListInfo NewTemplateArgs;
+ NestedNameSpecifierLoc NewNestedNameSpec;
+ if (TL.getTypePtr()->isConstrained()) {
+ NewCD = cast_or_null<ConceptDecl>(
+ getDerived().TransformDecl(
+ TL.getConceptNameLoc(),
+ TL.getTypePtr()->getTypeConstraintConcept()));
+
+ NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
+ NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
+ typedef TemplateArgumentLocContainerIterator<AutoTypeLoc> ArgIterator;
+ if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
+ ArgIterator(TL,
+ TL.getNumArgs()),
+ NewTemplateArgs))
+ return QualType();
+
+ if (TL.getNestedNameSpecifierLoc()) {
+ NewNestedNameSpec
+ = getDerived().TransformNestedNameSpecifierLoc(
+ TL.getNestedNameSpecifierLoc());
+ if (!NewNestedNameSpec)
+ return QualType();
+ }
+ }
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
+ T->isDependentType()) {
+ llvm::SmallVector<TemplateArgument, 4> NewArgList;
+ NewArgList.reserve(NewArgList.size());
+ for (const auto &ArgLoc : NewTemplateArgs.arguments())
+ NewArgList.push_back(ArgLoc.getArgument());
+ Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD,
+ NewArgList);
+ if (Result.isNull())
+ return QualType();
+ }
+
+ AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec);
+ NewTL.setTemplateKWLoc(TL.getTemplateKWLoc());
+ NewTL.setConceptNameLoc(TL.getConceptNameLoc());
+ NewTL.setFoundDecl(TL.getFoundDecl());
+ NewTL.setLAngleLoc(TL.getLAngleLoc());
+ NewTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned I = 0; I < TL.getNumArgs(); ++I)
+ NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo());
+
+ return Result;
+}
template <typename Derived>
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
@@ -11179,6 +11280,146 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr(
&TransArgs);
}
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
+ SmallVector<ParmVarDecl*, 4> TransParams;
+ SmallVector<QualType, 4> TransParamTypes;
+ Sema::ExtParameterInfoBuilder ExtParamInfos;
+
+ // C++2a [expr.prim.req]p2
+ // Expressions appearing within a requirement-body are unevaluated operands.
+ EnterExpressionEvaluationContext Ctx(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+
+ RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(
+ getSema().Context, E->getBody()->getDeclContext(),
+ E->getBody()->getBeginLoc());
+
+ Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false);
+
+ if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(),
+ E->getLocalParameters(),
+ /*ParamTypes=*/nullptr,
+ /*ParamInfos=*/nullptr,
+ TransParamTypes, &TransParams,
+ ExtParamInfos))
+ return ExprError();
+
+ for (ParmVarDecl *Param : TransParams)
+ Param->setDeclContext(Body);
+
+ SmallVector<concepts::Requirement *, 4> TransReqs;
+ if (getDerived().TransformRequiresExprRequirements(E->getRequirements(),
+ TransReqs))
+ return ExprError();
+
+ for (concepts::Requirement *Req : TransReqs) {
+ if (auto *ER = dyn_cast<concepts::ExprRequirement>(Req)) {
+ if (ER->getReturnTypeRequirement().isTypeConstraint()) {
+ ER->getReturnTypeRequirement()
+ .getTypeConstraintTemplateParameterList()->getParam(0)
+ ->setDeclContext(Body);
+ }
+ }
+ }
+
+ return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body,
+ TransParams, TransReqs,
+ E->getRBraceLoc());
+}
+
+template<typename Derived>
+bool TreeTransform<Derived>::TransformRequiresExprRequirements(
+ ArrayRef<concepts::Requirement *> Reqs,
+ SmallVectorImpl<concepts::Requirement *> &Transformed) {
+ for (concepts::Requirement *Req : Reqs) {
+ concepts::Requirement *TransReq = nullptr;
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
+ TransReq = getDerived().TransformTypeRequirement(TypeReq);
+ else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
+ TransReq = getDerived().TransformExprRequirement(ExprReq);
+ else
+ TransReq = getDerived().TransformNestedRequirement(
+ cast<concepts::NestedRequirement>(Req));
+ if (!TransReq)
+ return true;
+ Transformed.push_back(TransReq);
+ }
+ return false;
+}
+
+template<typename Derived>
+concepts::TypeRequirement *
+TreeTransform<Derived>::TransformTypeRequirement(
+ concepts::TypeRequirement *Req) {
+ if (Req->isSubstitutionFailure()) {
+ if (getDerived().AlwaysRebuild())
+ return getDerived().RebuildTypeRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+ TypeSourceInfo *TransType = getDerived().TransformType(Req->getType());
+ if (!TransType)
+ return nullptr;
+ return getDerived().RebuildTypeRequirement(TransType);
+}
+
+template<typename Derived>
+concepts::ExprRequirement *
+TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req) {
+ llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> TransExpr;
+ if (Req->isExprSubstitutionFailure())
+ TransExpr = Req->getExprSubstitutionDiagnostic();
+ else {
+ ExprResult TransExprRes = getDerived().TransformExpr(Req->getExpr());
+ if (TransExprRes.isInvalid())
+ return nullptr;
+ TransExpr = TransExprRes.get();
+ }
+
+ llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ const auto &RetReq = Req->getReturnTypeRequirement();
+ if (RetReq.isEmpty())
+ TransRetReq.emplace();
+ else if (RetReq.isSubstitutionFailure())
+ TransRetReq.emplace(RetReq.getSubstitutionDiagnostic());
+ else if (RetReq.isTypeConstraint()) {
+ TemplateParameterList *OrigTPL =
+ RetReq.getTypeConstraintTemplateParameterList();
+ TemplateParameterList *TPL =
+ getDerived().TransformTemplateParameterList(OrigTPL);
+ if (!TPL)
+ return nullptr;
+ TransRetReq.emplace(TPL);
+ }
+ assert(TransRetReq.hasValue() &&
+ "All code paths leading here must set TransRetReq");
+ if (Expr *E = TransExpr.dyn_cast<Expr *>())
+ return getDerived().RebuildExprRequirement(E, Req->isSimple(),
+ Req->getNoexceptLoc(),
+ std::move(*TransRetReq));
+ return getDerived().RebuildExprRequirement(
+ TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(),
+ Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq));
+}
+
+template<typename Derived>
+concepts::NestedRequirement *
+TreeTransform<Derived>::TransformNestedRequirement(
+ concepts::NestedRequirement *Req) {
+ if (Req->isSubstitutionFailure()) {
+ if (getDerived().AlwaysRebuild())
+ return getDerived().RebuildNestedRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+ ExprResult TransConstraint =
+ getDerived().TransformExpr(Req->getConstraintExpr());
+ if (TransConstraint.isInvalid())
+ return nullptr;
+ return getDerived().RebuildNestedRequirement(TransConstraint.get());
+}
template<typename Derived>
ExprResult
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index cdb5b17022c2..f93f1f77405d 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -402,6 +402,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Binding:
case Decl::Concept:
case Decl::LifetimeExtendedTemporary:
+ case Decl::RequiresExprBody:
return false;
// These indirectly derive from Redeclarable<T> but are not actually
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 19e7ebe03a1f..8e8b04451fb1 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -6576,6 +6576,17 @@ void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
TL.setNameLoc(readSourceLocation());
+ if (Reader.readBool()) {
+ TL.setNestedNameSpecifierLoc(ReadNestedNameSpecifierLoc());
+ TL.setTemplateKWLoc(readSourceLocation());
+ TL.setConceptNameLoc(readSourceLocation());
+ TL.setFoundDecl(Reader.readDeclAs<NamedDecl>());
+ TL.setLAngleLoc(readSourceLocation());
+ TL.setRAngleLoc(readSourceLocation());
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->getArg(i).getKind()));
+ }
}
void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc(
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 96a7d5ae0a31..093b69ab19d0 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -375,6 +375,7 @@ namespace clang {
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
DeclID VisitTemplateDecl(TemplateDecl *D);
void VisitConceptDecl(ConceptDecl *D);
+ void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D);
@@ -2037,6 +2038,9 @@ void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
mergeMergeable(D);
}
+void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
+}
+
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
@@ -2313,12 +2317,12 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt());
- if (Record.readInt()) {
+ if (Record.readBool()) {
NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc();
DeclarationNameInfo DN = Record.readDeclarationNameInfo();
- ConceptDecl *NamedConcept = cast<ConceptDecl>(Record.readDecl());
+ ConceptDecl *NamedConcept = Record.readDeclAs<ConceptDecl>();
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
- if (Record.readInt())
+ if (Record.readBool())
ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
Expr *ImmediatelyDeclaredConstraint = Record.readExpr();
D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept,
@@ -2336,6 +2340,8 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// TemplateParmPosition.
D->setDepth(Record.readInt());
D->setPosition(Record.readInt());
+ if (D->hasPlaceholderTypeConstraint())
+ D->setPlaceholderTypeConstraint(Record.readExpr());
if (D->isExpandedParameterPack()) {
auto TypesAndInfos =
D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
@@ -3819,13 +3825,19 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
HasTypeConstraint);
break;
}
- case DECL_NON_TYPE_TEMPLATE_PARM:
- D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID);
+ case DECL_NON_TYPE_TEMPLATE_PARM: {
+ bool HasTypeConstraint = Record.readInt();
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID,
+ HasTypeConstraint);
break;
- case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
+ }
+ case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: {
+ bool HasTypeConstraint = Record.readInt();
D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID,
- Record.readInt());
+ Record.readInt(),
+ HasTypeConstraint);
break;
+ }
case DECL_TEMPLATE_TEMPLATE_PARM:
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
break;
@@ -3839,6 +3851,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_CONCEPT:
D = ConceptDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_REQUIRES_EXPR_BODY:
+ D = RequiresExprBodyDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_STATIC_ASSERT:
D = StaticAssertDecl::CreateDeserialized(Context, ID);
break;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index f558c26b5f1e..5dd0ef9d43c3 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -724,27 +724,15 @@ void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
E->setRParenLoc(readSourceLocation());
}
-void ASTStmtReader::VisitConceptSpecializationExpr(
- ConceptSpecializationExpr *E) {
- VisitExpr(E);
- unsigned NumTemplateArgs = Record.readInt();
- E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
- E->TemplateKWLoc = Record.readSourceLocation();
- E->ConceptName = Record.readDeclarationNameInfo();
- E->NamedConcept = readDeclAs<ConceptDecl>();
- E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
- llvm::SmallVector<TemplateArgument, 4> Args;
- for (unsigned I = 0; I < NumTemplateArgs; ++I)
- Args.push_back(Record.readTemplateArgument());
- E->setTemplateArguments(Args);
+static ConstraintSatisfaction
+readConstraintSatisfaction(ASTRecordReader &Record) {
ConstraintSatisfaction Satisfaction;
Satisfaction.IsSatisfied = Record.readInt();
if (!Satisfaction.IsSatisfied) {
unsigned NumDetailRecords = Record.readInt();
for (unsigned i = 0; i != NumDetailRecords; ++i) {
Expr *ConstraintExpr = Record.readExpr();
- bool IsDiagnostic = Record.readInt();
- if (IsDiagnostic) {
+ if (bool IsDiagnostic = Record.readInt()) {
SourceLocation DiagLocation = Record.readSourceLocation();
std::string DiagMessage = Record.readString();
Satisfaction.Details.emplace_back(
@@ -755,8 +743,137 @@ void ASTStmtReader::VisitConceptSpecializationExpr(
Satisfaction.Details.emplace_back(ConstraintExpr, Record.readExpr());
}
}
- E->Satisfaction = ASTConstraintSatisfaction::Create(Record.getContext(),
- Satisfaction);
+ return Satisfaction;
+}
+
+void ASTStmtReader::VisitConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ VisitExpr(E);
+ unsigned NumTemplateArgs = Record.readInt();
+ E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
+ E->TemplateKWLoc = Record.readSourceLocation();
+ E->ConceptName = Record.readDeclarationNameInfo();
+ E->NamedConcept = readDeclAs<ConceptDecl>();
+ E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
+ llvm::SmallVector<TemplateArgument, 4> Args;
+ for (unsigned I = 0; I < NumTemplateArgs; ++I)
+ Args.push_back(Record.readTemplateArgument());
+ E->setTemplateArguments(Args);
+ E->Satisfaction = E->isValueDependent() ? nullptr :
+ ASTConstraintSatisfaction::Create(Record.getContext(),
+ readConstraintSatisfaction(Record));
+}
+
+static concepts::Requirement::SubstitutionDiagnostic *
+readSubstitutionDiagnostic(ASTRecordReader &Record) {
+ std::string SubstitutedEntity = Record.readString();
+ SourceLocation DiagLoc = Record.readSourceLocation();
+ std::string DiagMessage = Record.readString();
+ return new (Record.getContext())
+ concepts::Requirement::SubstitutionDiagnostic{SubstitutedEntity, DiagLoc,
+ DiagMessage};
+}
+
+void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) {
+ VisitExpr(E);
+ unsigned NumLocalParameters = Record.readInt();
+ unsigned NumRequirements = Record.readInt();
+ E->RequiresExprBits.RequiresKWLoc = Record.readSourceLocation();
+ E->RequiresExprBits.IsSatisfied = Record.readInt();
+ E->Body = Record.readDeclAs<RequiresExprBodyDecl>();
+ llvm::SmallVector<ParmVarDecl *, 4> LocalParameters;
+ for (unsigned i = 0; i < NumLocalParameters; ++i)
+ LocalParameters.push_back(cast<ParmVarDecl>(Record.readDecl()));
+ std::copy(LocalParameters.begin(), LocalParameters.end(),
+ E->getTrailingObjects<ParmVarDecl *>());
+ llvm::SmallVector<concepts::Requirement *, 4> Requirements;
+ for (unsigned i = 0; i < NumRequirements; ++i) {
+ auto RK =
+ static_cast<concepts::Requirement::RequirementKind>(Record.readInt());
+ concepts::Requirement *R = nullptr;
+ switch (RK) {
+ case concepts::Requirement::RK_Type: {
+ auto Status =
+ static_cast<concepts::TypeRequirement::SatisfactionStatus>(
+ Record.readInt());
+ if (Status == concepts::TypeRequirement::SS_SubstitutionFailure)
+ R = new (Record.getContext())
+ concepts::TypeRequirement(readSubstitutionDiagnostic(Record));
+ else
+ R = new (Record.getContext())
+ concepts::TypeRequirement(Record.readTypeSourceInfo());
+ } break;
+ case concepts::Requirement::RK_Simple:
+ case concepts::Requirement::RK_Compound: {
+ auto Status =
+ static_cast<concepts::ExprRequirement::SatisfactionStatus>(
+ Record.readInt());
+ llvm::PointerUnion<concepts::Requirement::SubstitutionDiagnostic *,
+ Expr *> E;
+ if (Status == concepts::ExprRequirement::SS_ExprSubstitutionFailure) {
+ E = readSubstitutionDiagnostic(Record);
+ } else
+ E = Record.readExpr();
+
+ llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> Req;
+ ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr;
+ SourceLocation NoexceptLoc;
+ if (RK == concepts::Requirement::RK_Simple) {
+ Req.emplace();
+ } else {
+ NoexceptLoc = Record.readSourceLocation();
+ switch (auto returnTypeRequirementKind = Record.readInt()) {
+ case 0:
+ // No return type requirement.
+ Req.emplace();
+ break;
+ case 1: {
+ // type-constraint
+ TemplateParameterList *TPL = Record.readTemplateParameterList();
+ if (Status >=
+ concepts::ExprRequirement::SS_ConstraintsNotSatisfied)
+ SubstitutedConstraintExpr =
+ cast<ConceptSpecializationExpr>(Record.readExpr());
+ Req.emplace(TPL);
+ } break;
+ case 2:
+ // Substitution failure
+ Req.emplace(readSubstitutionDiagnostic(Record));
+ break;
+ }
+ }
+ if (Expr *Ex = E.dyn_cast<Expr *>())
+ R = new (Record.getContext()) concepts::ExprRequirement(
+ Ex, RK == concepts::Requirement::RK_Simple, NoexceptLoc,
+ std::move(*Req), Status, SubstitutedConstraintExpr);
+ else
+ R = new (Record.getContext()) concepts::ExprRequirement(
+ E.get<concepts::Requirement::SubstitutionDiagnostic *>(),
+ RK == concepts::Requirement::RK_Simple, NoexceptLoc,
+ std::move(*Req));
+ } break;
+ case concepts::Requirement::RK_Nested: {
+ if (bool IsSubstitutionDiagnostic = Record.readInt()) {
+ R = new (Record.getContext()) concepts::NestedRequirement(
+ readSubstitutionDiagnostic(Record));
+ break;
+ }
+ Expr *E = Record.readExpr();
+ if (E->isInstantiationDependent())
+ R = new (Record.getContext()) concepts::NestedRequirement(E);
+ else
+ R = new (Record.getContext())
+ concepts::NestedRequirement(Record.getContext(), E,
+ readConstraintSatisfaction(Record));
+ } break;
+ }
+ if (!R)
+ continue;
+ Requirements.push_back(R);
+ }
+ std::copy(Requirements.begin(), Requirements.end(),
+ E->getTrailingObjects<concepts::Requirement *>());
+ E->RBraceLoc = Record.readSourceLocation();
}
void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
@@ -3566,11 +3683,18 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) DependentCoawaitExpr(Empty);
break;
- case EXPR_CONCEPT_SPECIALIZATION:
+ case EXPR_CONCEPT_SPECIALIZATION: {
unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields];
S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs);
break;
-
+ }
+
+ case EXPR_REQUIRES:
+ unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields];
+ unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1];
+ S = RequiresExpr::Create(Context, Empty, numLocalParameters,
+ numRequirement);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 6eba48a1abe9..252853aad1f8 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -349,6 +349,18 @@ void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
+ Record.push_back(TL.isConstrained());
+ if (TL.isConstrained()) {
+ Record.AddNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc());
+ Record.AddSourceLocation(TL.getTemplateKWLoc());
+ Record.AddSourceLocation(TL.getConceptNameLoc());
+ Record.AddDeclRef(TL.getFoundDecl());
+ Record.AddSourceLocation(TL.getLAngleLoc());
+ Record.AddSourceLocation(TL.getRAngleLoc());
+ for (unsigned I = 0; I < TL.getNumArgs(); ++I)
+ Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(),
+ TL.getArgLocInfo(I));
+ }
}
void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc(
@@ -885,6 +897,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
RECORD(DECL_TEMPLATE_TEMPLATE_PARM);
RECORD(DECL_CONCEPT);
+ RECORD(DECL_REQUIRES_EXPR_BODY);
RECORD(DECL_TYPE_ALIAS_TEMPLATE);
RECORD(DECL_STATIC_ASSERT);
RECORD(DECL_CXX_BASE_SPECIFIERS);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index b2a8c118d401..472136d99a13 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -104,6 +104,7 @@ namespace clang {
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
void VisitConceptDecl(ConceptDecl *D);
+ void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitVarTemplateDecl(VarTemplateDecl *D);
@@ -1481,6 +1482,10 @@ void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
Code = serialization::DECL_CONCEPT;
}
+void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
+ Code = serialization::DECL_REQUIRES_EXPR_BODY;
+}
+
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
VisitRedeclarable(D);
@@ -1670,6 +1675,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// For an expanded parameter pack, record the number of expansion types here
// so that it's easier for deserialization to allocate the right amount of
// memory.
+ Expr *TypeConstraint = D->getPlaceholderTypeConstraint();
+ Record.push_back(!!TypeConstraint);
if (D->isExpandedParameterPack())
Record.push_back(D->getNumExpansionTypes());
@@ -1677,6 +1684,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// TemplateParmPosition.
Record.push_back(D->getDepth());
Record.push_back(D->getPosition());
+ if (TypeConstraint)
+ Record.AddStmt(TypeConstraint);
if (D->isExpandedParameterPack()) {
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 9231f3b2b9ba..1b118c257a4c 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTRecordWriter.h"
+#include "clang/Sema/DeclSpec.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -388,19 +389,9 @@ void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
Code = serialization::EXPR_DEPENDENT_COAWAIT;
}
-void ASTStmtWriter::VisitConceptSpecializationExpr(
- ConceptSpecializationExpr *E) {
- VisitExpr(E);
- ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments();
- Record.push_back(TemplateArgs.size());
- Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc());
- Record.AddSourceLocation(E->getTemplateKWLoc());
- Record.AddDeclarationNameInfo(E->getConceptNameInfo());
- Record.AddDeclRef(E->getNamedConcept());
- Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
- for (const TemplateArgument &Arg : TemplateArgs)
- Record.AddTemplateArgument(Arg);
- const ASTConstraintSatisfaction &Satisfaction = E->getSatisfaction();
+static void
+addConstraintSatisfaction(ASTRecordWriter &Record,
+ const ASTConstraintSatisfaction &Satisfaction) {
Record.push_back(Satisfaction.IsSatisfied);
if (!Satisfaction.IsSatisfied) {
Record.push_back(Satisfaction.NumRecords);
@@ -418,10 +409,98 @@ void ASTStmtWriter::VisitConceptSpecializationExpr(
}
}
}
+}
+
+static void
+addSubstitutionDiagnostic(
+ ASTRecordWriter &Record,
+ const concepts::Requirement::SubstitutionDiagnostic *D) {
+ Record.AddString(D->SubstitutedEntity);
+ Record.AddSourceLocation(D->DiagLoc);
+ Record.AddString(D->DiagMessage);
+}
+
+void ASTStmtWriter::VisitConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ VisitExpr(E);
+ ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments();
+ Record.push_back(TemplateArgs.size());
+ Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc());
+ Record.AddSourceLocation(E->getTemplateKWLoc());
+ Record.AddDeclarationNameInfo(E->getConceptNameInfo());
+ Record.AddDeclRef(E->getNamedConcept());
+ Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
+ for (const TemplateArgument &Arg : TemplateArgs)
+ Record.AddTemplateArgument(Arg);
+ if (!E->isValueDependent())
+ addConstraintSatisfaction(Record, E->getSatisfaction());
Code = serialization::EXPR_CONCEPT_SPECIALIZATION;
}
+void ASTStmtWriter::VisitRequiresExpr(RequiresExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getLocalParameters().size());
+ Record.push_back(E->getRequirements().size());
+ Record.AddSourceLocation(E->RequiresExprBits.RequiresKWLoc);
+ Record.push_back(E->RequiresExprBits.IsSatisfied);
+ Record.AddDeclRef(E->getBody());
+ for (ParmVarDecl *P : E->getLocalParameters())
+ Record.AddDeclRef(P);
+ for (concepts::Requirement *R : E->getRequirements()) {
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(R)) {
+ Record.push_back(concepts::Requirement::RK_Type);
+ Record.push_back(TypeReq->Status);
+ if (TypeReq->Status == concepts::TypeRequirement::SS_SubstitutionFailure)
+ addSubstitutionDiagnostic(Record, TypeReq->getSubstitutionDiagnostic());
+ else
+ Record.AddTypeSourceInfo(TypeReq->getType());
+ } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R)) {
+ Record.push_back(ExprReq->getKind());
+ Record.push_back(ExprReq->Status);
+ if (ExprReq->isExprSubstitutionFailure()) {
+ addSubstitutionDiagnostic(Record,
+ ExprReq->Value.get<concepts::Requirement::SubstitutionDiagnostic *>());
+ } else
+ Record.AddStmt(ExprReq->Value.get<Expr *>());
+ if (ExprReq->getKind() == concepts::Requirement::RK_Compound) {
+ Record.AddSourceLocation(ExprReq->NoexceptLoc);
+ const auto &RetReq = ExprReq->getReturnTypeRequirement();
+ if (RetReq.isSubstitutionFailure()) {
+ Record.push_back(2);
+ addSubstitutionDiagnostic(Record, RetReq.getSubstitutionDiagnostic());
+ } else if (RetReq.isTypeConstraint()) {
+ Record.push_back(1);
+ Record.AddTemplateParameterList(
+ RetReq.getTypeConstraintTemplateParameterList());
+ if (ExprReq->Status >=
+ concepts::ExprRequirement::SS_ConstraintsNotSatisfied)
+ Record.AddStmt(
+ ExprReq->getReturnTypeRequirementSubstitutedConstraintExpr());
+ } else {
+ assert(RetReq.isEmpty());
+ Record.push_back(0);
+ }
+ }
+ } else {
+ auto *NestedReq = cast<concepts::NestedRequirement>(R);
+ Record.push_back(concepts::Requirement::RK_Nested);
+ Record.push_back(NestedReq->isSubstitutionFailure());
+ if (NestedReq->isSubstitutionFailure()){
+ addSubstitutionDiagnostic(Record,
+ NestedReq->getSubstitutionDiagnostic());
+ } else {
+ Record.AddStmt(NestedReq->Value.get<Expr *>());
+ if (!NestedReq->isDependent())
+ addConstraintSatisfaction(Record, *NestedReq->Satisfaction);
+ }
+ }
+ }
+ Record.AddSourceLocation(E->getEndLoc());
+
+ Code = serialization::EXPR_REQUIRES;
+}
+
void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
VisitStmt(S);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index f917a4c8637b..b542cf2c0303 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1386,6 +1386,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::AsTypeExprClass:
case Stmt::ConceptSpecializationExprClass:
case Stmt::CXXRewrittenBinaryOperatorClass:
+ case Stmt::RequiresExprClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 39f6c7f62be4..4457e40ff04b 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -241,8 +241,6 @@ static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
*NumberSignPtr = '=';
}
-static int ExecuteCC1Tool(ArrayRef<const char *> argv);
-
static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
// Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
@@ -313,21 +311,27 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv,
TheDriver.setInstalledDir(InstalledPathParent);
}
-static int ExecuteCC1Tool(ArrayRef<const char *> argv) {
+static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
// If we call the cc1 tool from the clangDriver library (through
// Driver::CC1Main), we need to clean up the options usage count. The options
// are currently global, and they might have been used previously by the
// driver.
llvm::cl::ResetAllOptionOccurrences();
- StringRef Tool = argv[1];
- void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
+
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver(A);
+ llvm::cl::ExpandResponseFiles(Saver, &llvm::cl::TokenizeGNUCommandLine, ArgV,
+ /*MarkEOLs=*/false);
+ StringRef Tool = ArgV[1];
+ void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
if (Tool == "-cc1")
- return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
+ return cc1_main(makeArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
if (Tool == "-cc1as")
- return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
+ return cc1as_main(makeArrayRef(ArgV).slice(2), ArgV[0],
+ GetExecutablePathVP);
if (Tool == "-cc1gen-reproducer")
- return cc1gen_reproducer_main(argv.slice(2), argv[0], GetExecutablePathVP);
-
+ return cc1gen_reproducer_main(makeArrayRef(ArgV).slice(2), ArgV[0],
+ GetExecutablePathVP);
// Reject unknown tools.
llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
<< "Valid tools include '-cc1' and '-cc1as'.\n";
diff --git a/libcxx/include/__config b/libcxx/include/__config
index ac4549802ef2..8f48f16c2364 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -1350,10 +1350,9 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
#define _LIBCPP_HAS_NO_COROUTINES
#endif
-// FIXME: Correct this macro when either (A) a feature test macro for the
-// spaceship operator is provided, or (B) a compiler provides a complete
-// implementation.
+#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201907L
#define _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
+#endif
// Decide whether to use availability macros.
#if !defined(_LIBCPP_BUILDING_LIBRARY) && \
diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support
index 026429f6a8ec..dbf313a1bf22 100644
--- a/libcxx/include/__threading_support
+++ b/libcxx/include/__threading_support
@@ -445,7 +445,7 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
{
- return mtx_init(__m, mtx_recursive) == thrd_success ? 0 : EINVAL;
+ return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
}
int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index d884201ba31b..272f9c0717c0 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -500,6 +500,17 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection,
leaderSelection = selection = IMAGE_COMDAT_SELECT_LARGEST;
}
+ // GCCs __declspec(selectany) doesn't actually pick "any" but "same size as".
+ // Clang on the other hand picks "any". To be able to link two object files
+ // with a __declspec(selectany) declaration, one compiled with gcc and the
+ // other with clang, we merge them as proper "same size as"
+ if (config->mingw && ((selection == IMAGE_COMDAT_SELECT_ANY &&
+ leaderSelection == IMAGE_COMDAT_SELECT_SAME_SIZE) ||
+ (selection == IMAGE_COMDAT_SELECT_SAME_SIZE &&
+ leaderSelection == IMAGE_COMDAT_SELECT_ANY))) {
+ leaderSelection = selection = IMAGE_COMDAT_SELECT_SAME_SIZE;
+ }
+
// Other than that, comdat selections must match. This is a bit more
// strict than link.exe which allows merging "any" and "largest" if "any"
// is the first symbol the linker sees, and it allows merging "largest"
diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp
index 3c0b0c290b58..1d4e80184dcd 100644
--- a/lld/ELF/Arch/PPC.cpp
+++ b/lld/ELF/Arch/PPC.cpp
@@ -136,6 +136,7 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
}
PPC::PPC() {
+ copyRel = R_PPC_COPY;
gotRel = R_PPC_GLOB_DAT;
noneRel = R_PPC_NONE;
pltRel = R_PPC_JMP_SLOT;
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index da77a4ddaddf..e48a184c9db2 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -293,6 +293,7 @@ static uint32_t readFromHalf16(const uint8_t *loc) {
}
PPC64::PPC64() {
+ copyRel = R_PPC64_COPY;
gotRel = R_PPC64_GLOB_DAT;
noneRel = R_PPC64_NONE;
pltRel = R_PPC64_JMP_SLOT;
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 42db8e08162d..527f9db0ef29 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -236,9 +236,15 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
case R_RISCV_TPREL_LO12_S:
return R_TLS;
case R_RISCV_RELAX:
- case R_RISCV_ALIGN:
case R_RISCV_TPREL_ADD:
return R_NONE;
+ case R_RISCV_ALIGN:
+ // Not just a hint; always padded to the worst-case number of NOPs, so may
+ // not currently be aligned, and without linker relaxation support we can't
+ // delete NOPs to realign.
+ errorOrWarn(getErrorLocation(loc) + "relocation R_RISCV_ALIGN requires "
+ "unimplemented linker relaxation; recompile with -mno-relax");
+ return R_NONE;
default:
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
") against symbol " + toString(s));
@@ -431,7 +437,6 @@ void RISCV::relocateOne(uint8_t *loc, const RelType type,
write64le(loc, val - dtpOffset);
break;
- case R_RISCV_ALIGN:
case R_RISCV_RELAX:
return; // Ignored (for now)
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 06ba88a83dd4..ef1edbcd1992 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -169,6 +169,7 @@ struct Configuration {
bool mipsN32Abi = false;
bool mmapOutputFile;
bool nmagic;
+ bool noDynamicLinker = false;
bool noinhibitExec;
bool nostdlib;
bool oFormatBinary;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 23da749d3078..25330832339c 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -602,8 +602,13 @@ static DiscardPolicy getDiscard(opt::InputArgList &args) {
static StringRef getDynamicLinker(opt::InputArgList &args) {
auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
- if (!arg || arg->getOption().getID() == OPT_no_dynamic_linker)
+ if (!arg)
+ return "";
+ if (arg->getOption().getID() == OPT_no_dynamic_linker) {
+ // --no-dynamic-linker suppresses undefined weak symbols in .dynsym
+ config->noDynamicLinker = true;
return "";
+ }
return arg->getValue();
}
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 4731554e0c0d..ced9991f2003 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -408,6 +408,14 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
assert(absVal && relE);
+ // Allow R_PLT_PC (optimized to R_PC here) to a hidden undefined weak symbol
+ // in PIC mode. This is a little strange, but it allows us to link function
+ // calls to such symbols (e.g. glibc/stdlib/exit.c:__run_exit_handlers).
+ // Normally such a call will be guarded with a comparison, which will load a
+ // zero from the GOT.
+ if (sym.isUndefWeak())
+ return true;
+
// We set the final symbols values for linker script defined symbols later.
// They always can be computed as a link time constant.
if (sym.scriptDefined)
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index f0f6121009a5..0dcf34722d33 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -278,7 +278,11 @@ bool Symbol::includeInDynsym() const {
if (computeBinding() == STB_LOCAL)
return false;
if (!isDefined() && !isCommon())
- return true;
+ // This should unconditionally return true, unfortunately glibc -static-pie
+ // expects undefined weak symbols not to exist in .dynsym, e.g.
+ // __pthread_mutex_lock reference in _dl_add_to_namespace_list,
+ // __pthread_initialize_minimal reference in csu/libc-start.c.
+ return !(config->noDynamicLinker && isUndefWeak());
return exportDynamic || inDynamicList;
}
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 70a68fd8db9e..d3899d0f18f1 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -95,7 +95,7 @@ template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *loc) {
assert(loc != nullptr);
for (InputSectionBase *d : inputSections) {
auto *isec = cast<InputSection>(d);
- if (!isec->getParent())
+ if (!isec->getParent() || (isec->type & SHT_NOBITS))
continue;
const uint8_t *isecLoc =
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 6373044d8804..ac332de2a057 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -135,8 +135,8 @@ StringRef getOutputSectionName(const InputSectionBase *s) {
}
static bool needsInterpSection() {
- return !config->shared && !config->dynamicLinker.empty() &&
- script->needsInterpSection();
+ return !config->relocatable && !config->shared &&
+ !config->dynamicLinker.empty() && script->needsInterpSection();
}
template <class ELFT> void writeResult() { Writer<ELFT>().run(); }
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
index 8c5b482f0511..719d0c9c36ac 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
@@ -26,6 +26,7 @@
#undef R_PPC64_GOT16_LO
#undef R_PPC64_GOT16_HI
#undef R_PPC64_GOT16_HA
+#undef R_PPC64_COPY
#undef R_PPC64_GLOB_DAT
#undef R_PPC64_JMP_SLOT
#undef R_PPC64_RELATIVE
@@ -119,6 +120,7 @@ ELF_RELOC(R_PPC64_GOT16, 14)
ELF_RELOC(R_PPC64_GOT16_LO, 15)
ELF_RELOC(R_PPC64_GOT16_HI, 16)
ELF_RELOC(R_PPC64_GOT16_HA, 17)
+ELF_RELOC(R_PPC64_COPY, 19)
ELF_RELOC(R_PPC64_GLOB_DAT, 20)
ELF_RELOC(R_PPC64_JMP_SLOT, 21)
ELF_RELOC(R_PPC64_RELATIVE, 22)
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index b374fd3d80af..a860ce2773e1 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -113,6 +113,9 @@ public:
ProfileSummaryInfo *PSI;
+ /// The symbol for the entry in __patchable_function_entires.
+ MCSymbol *CurrentPatchableFunctionEntrySym = nullptr;
+
/// The symbol for the current function. This is recalculated at the beginning
/// of each call to runOnMachineFunction().
MCSymbol *CurrentFnSym = nullptr;
@@ -449,6 +452,9 @@ public:
/// instructions in verbose mode.
virtual void emitImplicitDef(const MachineInstr *MI) const;
+ /// Emit N NOP instructions.
+ void emitNops(unsigned N);
+
//===------------------------------------------------------------------===//
// Symbol Lowering Routines.
//===------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h
index ed7d5c7f01f4..bf41420f2a5a 100644
--- a/llvm/include/llvm/MC/MCAsmBackend.h
+++ b/llvm/include/llvm/MC/MCAsmBackend.h
@@ -108,6 +108,14 @@ public:
return false;
}
+ virtual bool evaluateTargetFixup(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &WasForced) {
+ llvm_unreachable("Need to implement hook if target has custom fixups");
+ }
+
/// Apply the \p Value for given \p Fixup into the provided data fragment, at
/// the offset specified by the fixup and following the fixup kind as
/// appropriate. Errors (such as an out of range fixup value) should be
diff --git a/llvm/include/llvm/MC/MCFixupKindInfo.h b/llvm/include/llvm/MC/MCFixupKindInfo.h
index 0ea34866db6a..0d57441ce0dc 100644
--- a/llvm/include/llvm/MC/MCFixupKindInfo.h
+++ b/llvm/include/llvm/MC/MCFixupKindInfo.h
@@ -19,7 +19,10 @@ struct MCFixupKindInfo {
FKF_IsPCRel = (1 << 0),
/// Should this fixup kind force a 4-byte aligned effective PC value?
- FKF_IsAlignedDownTo32Bits = (1 << 1)
+ FKF_IsAlignedDownTo32Bits = (1 << 1),
+
+ /// Should this fixup be evaluated in a target dependent manner?
+ FKF_IsTarget = (1 << 2)
};
/// A target specific name for the fixup kind. The names will be unique for
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index b122b51bb169..cdc9b640e74e 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1182,7 +1182,7 @@ def PATCHABLE_FUNCTION_ENTER : StandardPseudoInstruction {
let InOperandList = (ins);
let AsmString = "# XRay Function Enter.";
let usesCustomInserter = 1;
- let hasSideEffects = 0;
+ let hasSideEffects = 1;
}
def PATCHABLE_RET : StandardPseudoInstruction {
let OutOperandList = (outs);
@@ -1198,7 +1198,7 @@ def PATCHABLE_FUNCTION_EXIT : StandardPseudoInstruction {
let InOperandList = (ins);
let AsmString = "# XRay Function Exit.";
let usesCustomInserter = 1;
- let hasSideEffects = 0; // FIXME: is this correct?
+ let hasSideEffects = 1;
let isReturn = 0; // Original return instruction will follow
}
def PATCHABLE_TAIL_CALL : StandardPseudoInstruction {
diff --git a/llvm/include/llvm/Transforms/Utils/SizeOpts.h b/llvm/include/llvm/Transforms/Utils/SizeOpts.h
index ba0f86c45263..1137c89195a6 100644
--- a/llvm/include/llvm/Transforms/Utils/SizeOpts.h
+++ b/llvm/include/llvm/Transforms/Utils/SizeOpts.h
@@ -17,15 +17,13 @@
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Support/CommandLine.h"
-using namespace llvm;
-
-extern cl::opt<bool> EnablePGSO;
-extern cl::opt<bool> PGSOLargeWorkingSetSizeOnly;
-extern cl::opt<bool> PGSOIRPassOrTestOnly;
-extern cl::opt<bool> PGSOColdCodeOnly;
-extern cl::opt<bool> ForcePGSO;
-extern cl::opt<int> PgsoCutoffInstrProf;
-extern cl::opt<int> PgsoCutoffSampleProf;
+extern llvm::cl::opt<bool> EnablePGSO;
+extern llvm::cl::opt<bool> PGSOLargeWorkingSetSizeOnly;
+extern llvm::cl::opt<bool> PGSOIRPassOrTestOnly;
+extern llvm::cl::opt<bool> PGSOColdCodeOnly;
+extern llvm::cl::opt<bool> ForcePGSO;
+extern llvm::cl::opt<int> PgsoCutoffInstrProf;
+extern llvm::cl::opt<int> PgsoCutoffSampleProf;
namespace llvm {
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 6f9aa4dd79fd..3516f4a7b370 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -706,6 +706,21 @@ void AsmPrinter::EmitFunctionHeader() {
}
}
+ // Emit M NOPs for -fpatchable-function-entry=N,M where M>0. We arbitrarily
+ // place prefix data before NOPs.
+ unsigned PatchableFunctionPrefix = 0;
+ (void)F.getFnAttribute("patchable-function-prefix")
+ .getValueAsString()
+ .getAsInteger(10, PatchableFunctionPrefix);
+ if (PatchableFunctionPrefix) {
+ CurrentPatchableFunctionEntrySym =
+ OutContext.createLinkerPrivateTempSymbol();
+ OutStreamer->EmitLabel(CurrentPatchableFunctionEntrySym);
+ emitNops(PatchableFunctionPrefix);
+ } else {
+ CurrentPatchableFunctionEntrySym = CurrentFnBegin;
+ }
+
// Emit the function descriptor. This is a virtual function to allow targets
// to emit their specific function descriptor.
if (MAI->needsFunctionDescriptors())
@@ -1167,7 +1182,7 @@ void AsmPrinter::EmitFunctionBody() {
// unspecified.
if (Noop.getOpcode()) {
OutStreamer->AddComment("avoids zero-length function");
- OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
+ emitNops(1);
}
}
@@ -2797,6 +2812,13 @@ void AsmPrinter::printOffset(int64_t Offset, raw_ostream &OS) const {
OS << Offset;
}
+void AsmPrinter::emitNops(unsigned N) {
+ MCInst Nop;
+ MF->getSubtarget().getInstrInfo()->getNoop(Nop);
+ for (; N; --N)
+ EmitToStreamer(*OutStreamer, Nop);
+}
+
//===----------------------------------------------------------------------===//
// Symbol Lowering Routines.
//===----------------------------------------------------------------------===//
@@ -3199,7 +3221,14 @@ void AsmPrinter::recordSled(MCSymbol *Sled, const MachineInstr &MI,
void AsmPrinter::emitPatchableFunctionEntries() {
const Function &F = MF->getFunction();
- if (!F.hasFnAttribute("patchable-function-entry"))
+ unsigned PatchableFunctionPrefix = 0, PatchableFunctionEntry = 0;
+ (void)F.getFnAttribute("patchable-function-prefix")
+ .getValueAsString()
+ .getAsInteger(10, PatchableFunctionPrefix);
+ (void)F.getFnAttribute("patchable-function-entry")
+ .getValueAsString()
+ .getAsInteger(10, PatchableFunctionEntry);
+ if (!PatchableFunctionPrefix && !PatchableFunctionEntry)
return;
const unsigned PointerSize = getPointerSize();
if (TM.getTargetTriple().isOSBinFormatELF()) {
@@ -3228,7 +3257,7 @@ void AsmPrinter::emitPatchableFunctionEntries() {
"__patchable_function_entries", ELF::SHT_PROGBITS, Flags));
}
EmitAlignment(Align(PointerSize));
- OutStreamer->EmitSymbolValue(CurrentFnBegin, PointerSize);
+ OutStreamer->EmitSymbolValue(CurrentPatchableFunctionEntrySym, PointerSize);
}
}
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index f05afd058746..003db39fe5f9 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -6122,6 +6122,7 @@ bool CodeGenPrepare::optimizeSelectInst(SelectInst *SI) {
BasicBlock *StartBlock = SI->getParent();
BasicBlock::iterator SplitPt = ++(BasicBlock::iterator(LastSI));
BasicBlock *EndBlock = StartBlock->splitBasicBlock(SplitPt, "select.end");
+ BFI->setBlockFreq(EndBlock, BFI->getBlockFreq(StartBlock).getFrequency());
// Delete the unconditional branch that was just created by the split.
StartBlock->getTerminator()->eraseFromParent();
diff --git a/llvm/lib/CodeGen/PatchableFunction.cpp b/llvm/lib/CodeGen/PatchableFunction.cpp
index 1d6069c50554..a8466396f9b8 100644
--- a/llvm/lib/CodeGen/PatchableFunction.cpp
+++ b/llvm/lib/CodeGen/PatchableFunction.cpp
@@ -57,10 +57,15 @@ static bool doesNotGeneratecode(const MachineInstr &MI) {
bool PatchableFunction::runOnMachineFunction(MachineFunction &MF) {
if (MF.getFunction().hasFnAttribute("patchable-function-entry")) {
MachineBasicBlock &FirstMBB = *MF.begin();
- MachineInstr &FirstMI = *FirstMBB.begin();
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
- BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
- TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
+ if (FirstMBB.empty()) {
+ BuildMI(&FirstMBB, DebugLoc(),
+ TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
+ } else {
+ MachineInstr &FirstMI = *FirstMBB.begin();
+ BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(),
+ TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER));
+ }
return true;
}
diff --git a/llvm/lib/CodeGen/StackColoring.cpp b/llvm/lib/CodeGen/StackColoring.cpp
index b6e81116286f..40bc36c3030b 100644
--- a/llvm/lib/CodeGen/StackColoring.cpp
+++ b/llvm/lib/CodeGen/StackColoring.cpp
@@ -960,6 +960,7 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) {
}
// Remap all instructions to the new stack slots.
+ std::vector<std::vector<MachineMemOperand *>> SSRefs(MFI->getObjectIndexEnd());
for (MachineBasicBlock &BB : *MF)
for (MachineInstr &I : BB) {
// Skip lifetime markers. We'll remove them soon.
@@ -1025,6 +1026,16 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) {
SmallVector<MachineMemOperand *, 2> NewMMOs;
bool ReplaceMemOps = false;
for (MachineMemOperand *MMO : I.memoperands()) {
+ // Collect MachineMemOperands which reference
+ // FixedStackPseudoSourceValues with old frame indices.
+ if (const auto *FSV = dyn_cast_or_null<FixedStackPseudoSourceValue>(
+ MMO->getPseudoValue())) {
+ int FI = FSV->getFrameIndex();
+ auto To = SlotRemap.find(FI);
+ if (To != SlotRemap.end())
+ SSRefs[FI].push_back(MMO);
+ }
+
// If this memory location can be a slot remapped here,
// we remove AA information.
bool MayHaveConflictingAAMD = false;
@@ -1062,6 +1073,14 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) {
I.setMemRefs(*MF, NewMMOs);
}
+ // Rewrite MachineMemOperands that reference old frame indices.
+ for (auto E : enumerate(SSRefs)) {
+ const PseudoSourceValue *NewSV =
+ MF->getPSVManager().getFixedStack(SlotRemap[E.index()]);
+ for (MachineMemOperand *Ref : E.value())
+ Ref->setValue(NewSV);
+ }
+
// Update the location of C++ catch objects for the MSVC personality routine.
if (WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo())
for (WinEHTryBlockMapEntry &TBME : EHInfo->TryBlockMap)
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 41cb511ad9b4..d08d05d4b2ed 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -956,6 +956,12 @@ void TargetPassConfig::addMachinePasses() {
if (getOptLevel() != CodeGenOpt::None)
addBlockPlacement();
+ // Insert before XRay Instrumentation.
+ addPass(&FEntryInserterID, false);
+
+ addPass(&XRayInstrumentationID, false);
+ addPass(&PatchableFunctionID, false);
+
addPreEmitPass();
if (TM->Options.EnableIPRA)
@@ -968,12 +974,6 @@ void TargetPassConfig::addMachinePasses() {
addPass(&StackMapLivenessID, false);
addPass(&LiveDebugValuesID, false);
- // Insert before XRay Instrumentation.
- addPass(&FEntryInserterID, false);
-
- addPass(&XRayInstrumentationID, false);
- addPass(&PatchableFunctionID, false);
-
if (TM->Options.EnableMachineOutliner && getOptLevel() != CodeGenOpt::None &&
EnableMachineOutliner != NeverOutline) {
bool RunOnAllFunctions = (EnableMachineOutliner == AlwaysOutline);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index d15b70d71b47..61707cc83504 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1852,16 +1852,25 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V);
}
+ if (Attrs.hasFnAttribute("patchable-function-prefix")) {
+ StringRef S = Attrs
+ .getAttribute(AttributeList::FunctionIndex,
+ "patchable-function-prefix")
+ .getValueAsString();
+ unsigned N;
+ if (S.getAsInteger(10, N))
+ CheckFailed(
+ "\"patchable-function-prefix\" takes an unsigned integer: " + S, V);
+ }
if (Attrs.hasFnAttribute("patchable-function-entry")) {
- StringRef S0 = Attrs
- .getAttribute(AttributeList::FunctionIndex,
- "patchable-function-entry")
- .getValueAsString();
- StringRef S = S0;
+ StringRef S = Attrs
+ .getAttribute(AttributeList::FunctionIndex,
+ "patchable-function-entry")
+ .getValueAsString();
unsigned N;
if (S.getAsInteger(10, N))
CheckFailed(
- "\"patchable-function-entry\" takes an unsigned integer: " + S0, V);
+ "\"patchable-function-entry\" takes an unsigned integer: " + S, V);
}
}
diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp
index b30137aafb8d..75ec27975564 100644
--- a/llvm/lib/MC/MCAssembler.cpp
+++ b/llvm/lib/MC/MCAssembler.cpp
@@ -217,6 +217,13 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout,
}
assert(getBackendPtr() && "Expected assembler backend");
+ bool IsTarget = getBackendPtr()->getFixupKindInfo(Fixup.getKind()).Flags &
+ MCFixupKindInfo::FKF_IsTarget;
+
+ if (IsTarget)
+ return getBackend().evaluateTargetFixup(*this, Layout, Fixup, DF, Target,
+ Value, WasForced);
+
bool IsPCRel = getBackendPtr()->getFixupKindInfo(Fixup.getKind()).Flags &
MCFixupKindInfo::FKF_IsPCRel;
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 00e321f9b850..b8953583a310 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -250,8 +250,7 @@ void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
.getValueAsString()
.getAsInteger(10, Num))
return;
- for (; Num; --Num)
- EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
+ emitNops(Num);
return;
}
diff --git a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
index 3156bb446963..bc91d628f0b4 100644
--- a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
@@ -1325,6 +1325,19 @@ canRenameUpToDef(MachineInstr &FirstMI, LiveRegUnits &UsedInBetween,
// For defs, check if we can rename the first def of RegToRename.
if (FoundDef) {
+ // For some pseudo instructions, we might not generate code in the end
+ // (e.g. KILL) and we would end up without a correct def for the rename
+ // register.
+ // TODO: This might be overly conservative and we could handle those cases
+ // in multiple ways:
+ // 1. Insert an extra copy, to materialize the def.
+ // 2. Skip pseudo-defs until we find an non-pseudo def.
+ if (MI.isPseudo()) {
+ LLVM_DEBUG(dbgs() << " Cannot rename pseudo instruction " << MI
+ << "\n");
+ return false;
+ }
+
for (auto &MOP : MI.operands()) {
if (!MOP.isReg() || !MOP.isDef() || MOP.isDebug() || !MOP.getReg() ||
!TRI->regsOverlap(MOP.getReg(), RegToRename))
diff --git a/llvm/lib/Target/ARM/ARMMCInstLower.cpp b/llvm/lib/Target/ARM/ARMMCInstLower.cpp
index c92689f4942e..8e01b998d900 100644
--- a/llvm/lib/Target/ARM/ARMMCInstLower.cpp
+++ b/llvm/lib/Target/ARM/ARMMCInstLower.cpp
@@ -207,10 +207,7 @@ void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)
.addImm(ARMCC::AL).addReg(0));
- MCInst Noop;
- Subtarget->getInstrInfo()->getNoop(Noop);
- for (int8_t I = 0; I < NoopsInSledCount; I++)
- OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
+ emitNops(NoopsInSledCount);
OutStreamer->EmitLabel(Target);
recordSled(CurSled, MI, Kind);
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 5881a0a86ef7..373d0ccb1857 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -9,6 +9,7 @@
#include "RISCVAsmBackend.h"
#include "RISCVMCExpr.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDirectives.h"
@@ -28,8 +29,6 @@ using namespace llvm;
bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target) {
- bool ShouldForce = false;
-
switch (Fixup.getTargetKind()) {
default:
break;
@@ -44,40 +43,9 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
case RISCV::fixup_riscv_tls_got_hi20:
case RISCV::fixup_riscv_tls_gd_hi20:
return true;
- case RISCV::fixup_riscv_pcrel_lo12_i:
- case RISCV::fixup_riscv_pcrel_lo12_s:
- // For pcrel_lo12, force a relocation if the target of the corresponding
- // pcrel_hi20 is not in the same fragment.
- const MCFixup *T = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup();
- if (!T) {
- Asm.getContext().reportError(Fixup.getLoc(),
- "could not find corresponding %pcrel_hi");
- return false;
- }
-
- switch (T->getTargetKind()) {
- default:
- llvm_unreachable("Unexpected fixup kind for pcrel_lo12");
- break;
- case RISCV::fixup_riscv_got_hi20:
- case RISCV::fixup_riscv_tls_got_hi20:
- case RISCV::fixup_riscv_tls_gd_hi20:
- ShouldForce = true;
- break;
- case RISCV::fixup_riscv_pcrel_hi20: {
- MCFragment *TFragment = T->getValue()->findAssociatedFragment();
- MCFragment *FixupFragment = Fixup.getValue()->findAssociatedFragment();
- assert(FixupFragment && "We should have a fragment for this fixup");
- ShouldForce =
- !TFragment || TFragment->getParent() != FixupFragment->getParent();
- break;
- }
- }
- break;
}
- return ShouldForce || STI.getFeatureBits()[RISCV::FeatureRelax] ||
- ForceRelocs;
+ return STI.getFeatureBits()[RISCV::FeatureRelax] || ForceRelocs;
}
bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
@@ -284,6 +252,67 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
}
}
+bool RISCVAsmBackend::evaluateTargetFixup(
+ const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup,
+ const MCFragment *DF, const MCValue &Target, uint64_t &Value,
+ bool &WasForced) {
+ const MCFixup *AUIPCFixup;
+ const MCFragment *AUIPCDF;
+ MCValue AUIPCTarget;
+ switch (Fixup.getTargetKind()) {
+ default:
+ llvm_unreachable("Unexpected fixup kind!");
+ case RISCV::fixup_riscv_pcrel_hi20:
+ AUIPCFixup = &Fixup;
+ AUIPCDF = DF;
+ AUIPCTarget = Target;
+ break;
+ case RISCV::fixup_riscv_pcrel_lo12_i:
+ case RISCV::fixup_riscv_pcrel_lo12_s: {
+ AUIPCFixup = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF);
+ if (!AUIPCFixup) {
+ Asm.getContext().reportError(Fixup.getLoc(),
+ "could not find corresponding %pcrel_hi");
+ return true;
+ }
+
+ // MCAssembler::evaluateFixup will emit an error for this case when it sees
+ // the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo.
+ const MCExpr *AUIPCExpr = AUIPCFixup->getValue();
+ if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, &Layout, AUIPCFixup))
+ return true;
+ break;
+ }
+ }
+
+ if (!AUIPCTarget.getSymA() || AUIPCTarget.getSymB())
+ return false;
+
+ const MCSymbolRefExpr *A = AUIPCTarget.getSymA();
+ const MCSymbol &SA = A->getSymbol();
+ if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined())
+ return false;
+
+ auto *Writer = Asm.getWriterPtr();
+ if (!Writer)
+ return false;
+
+ bool IsResolved = Writer->isSymbolRefDifferenceFullyResolvedImpl(
+ Asm, SA, *AUIPCDF, false, true);
+ if (!IsResolved)
+ return false;
+
+ Value = Layout.getSymbolOffset(SA) + AUIPCTarget.getConstant();
+ Value -= Layout.getFragmentOffset(AUIPCDF) + AUIPCFixup->getOffset();
+
+ if (shouldForceRelocation(Asm, *AUIPCFixup, AUIPCTarget)) {
+ WasForced = true;
+ return false;
+ }
+
+ return true;
+}
+
void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
index 254249c87dc8..1c3c587355a2 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
@@ -65,6 +65,11 @@ public:
const MCAsmLayout &Layout,
MCAlignFragment &AF) override;
+ bool evaluateTargetFixup(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &WasForced) override;
+
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved,
@@ -101,9 +106,12 @@ public:
{ "fixup_riscv_hi20", 12, 20, 0 },
{ "fixup_riscv_lo12_i", 20, 12, 0 },
{ "fixup_riscv_lo12_s", 0, 32, 0 },
- { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_riscv_pcrel_lo12_i", 20, 12, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_riscv_pcrel_lo12_s", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_riscv_pcrel_hi20", 12, 20,
+ MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget },
+ { "fixup_riscv_pcrel_lo12_i", 20, 12,
+ MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget },
+ { "fixup_riscv_pcrel_lo12_s", 0, 32,
+ MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget },
{ "fixup_riscv_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_riscv_tprel_hi20", 12, 20, 0 },
{ "fixup_riscv_tprel_lo12_i", 20, 12, 0 },
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
index 7aa9b5e7d683..2a6f372e50be 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -47,7 +47,7 @@ void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
OS << ')';
}
-const MCFixup *RISCVMCExpr::getPCRelHiFixup() const {
+const MCFixup *RISCVMCExpr::getPCRelHiFixup(const MCFragment **DFOut) const {
MCValue AUIPCLoc;
if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr))
return nullptr;
@@ -81,6 +81,8 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup() const {
case RISCV::fixup_riscv_tls_got_hi20:
case RISCV::fixup_riscv_tls_gd_hi20:
case RISCV::fixup_riscv_pcrel_hi20:
+ if (DFOut)
+ *DFOut = DF;
return &F;
}
}
@@ -88,74 +90,9 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup() const {
return nullptr;
}
-bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout,
- const MCFixup *Fixup) const {
- // VK_RISCV_PCREL_LO has to be handled specially. The MCExpr inside is
- // actually the location of a auipc instruction with a VK_RISCV_PCREL_HI fixup
- // pointing to the real target. We need to generate an MCValue in the form of
- // (<real target> + <offset from this fixup to the auipc fixup>). The Fixup
- // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the
- // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct.
-
- // Don't try to evaluate if the fixup will be forced as a relocation (e.g.
- // as linker relaxation is enabled). If we evaluated pcrel_lo in this case,
- // the modified fixup will be converted into a relocation that no longer
- // points to the pcrel_hi as the linker requires.
- auto &RAB =
- static_cast<RISCVAsmBackend &>(Layout->getAssembler().getBackend());
- if (RAB.willForceRelocations())
- return false;
-
- MCValue AUIPCLoc;
- if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout))
- return false;
-
- const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA();
- // Don't try to evaluate %pcrel_hi/%pcrel_lo pairs that cross fragment
- // boundries.
- if (!AUIPCSRE ||
- findAssociatedFragment() != AUIPCSRE->findAssociatedFragment())
- return false;
-
- const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol();
- if (!AUIPCSymbol)
- return false;
-
- const MCFixup *TargetFixup = getPCRelHiFixup();
- if (!TargetFixup)
- return false;
-
- if ((unsigned)TargetFixup->getKind() != RISCV::fixup_riscv_pcrel_hi20)
- return false;
-
- MCValue Target;
- if (!TargetFixup->getValue()->evaluateAsValue(Target, *Layout))
- return false;
-
- if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection())
- return false;
-
- if (&Target.getSymA()->getSymbol().getSection() !=
- findAssociatedFragment()->getParent())
- return false;
-
- // We must use TargetFixup rather than AUIPCSymbol here. They will almost
- // always have the same offset, except for the case when AUIPCSymbol is at
- // the end of a fragment and the fixup comes from offset 0 in the next
- // fragment.
- uint64_t AUIPCOffset = TargetFixup->getOffset();
-
- Res = MCValue::get(Target.getSymA(), nullptr,
- Target.getConstant() + (Fixup->getOffset() - AUIPCOffset));
- return true;
-}
-
bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout,
const MCFixup *Fixup) const {
- if (Kind == VK_RISCV_PCREL_LO && evaluatePCRelLo(Res, Layout, Fixup))
- return true;
-
if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
return false;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
index 921df376f3df..167e7d553e7d 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
@@ -46,9 +46,6 @@ private:
int64_t evaluateAsInt64(int64_t Value) const;
- bool evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout,
- const MCFixup *Fixup) const;
-
explicit RISCVMCExpr(const MCExpr *Expr, VariantKind Kind)
: Expr(Expr), Kind(Kind) {}
@@ -61,11 +58,11 @@ public:
const MCExpr *getSubExpr() const { return Expr; }
/// Get the corresponding PC-relative HI fixup that a VK_RISCV_PCREL_LO
- /// points to.
+ /// points to, and optionally the fragment containing it.
///
/// \returns nullptr if this isn't a VK_RISCV_PCREL_LO pointing to a
/// known PC-relative HI fixup.
- const MCFixup *getPCRelHiFixup() const;
+ const MCFixup *getPCRelHiFixup(const MCFragment **DFOut) const;
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 3b416ce3d3f4..f6bc52968a33 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -24,14 +24,14 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
+using namespace llvm;
+
#define GEN_CHECK_COMPRESS_INSTR
#include "RISCVGenCompressInstEmitter.inc"
#define GET_INSTRINFO_CTOR_DTOR
#include "RISCVGenInstrInfo.inc"
-using namespace llvm;
-
RISCVInstrInfo::RISCVInstrInfo(RISCVSubtarget &STI)
: RISCVGenInstrInfo(RISCV::ADJCALLSTACKDOWN, RISCV::ADJCALLSTACKUP),
STI(STI) {}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
index ebf9d24eecc4..c288a7d8d403 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -1439,9 +1439,12 @@ Instruction *InstCombiner::visitStoreInst(StoreInst &SI) {
if (PrevSI->isUnordered() && equivalentAddressValues(PrevSI->getOperand(1),
SI.getOperand(1))) {
++NumDeadStore;
- ++BBI;
+ // Manually add back the original store to the worklist now, so it will
+ // be processed after the operands of the removed store, as this may
+ // expose additional DSE opportunities.
+ Worklist.Add(&SI);
eraseInstFromFunction(*PrevSI);
- continue;
+ return nullptr;
}
break;
}
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index aabd974cd73e..479bca83b51e 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -377,6 +377,18 @@ static Value *isOneOf(const InstructionsState &S, Value *Op) {
return S.OpValue;
}
+/// \returns true if \p Opcode is allowed as part of of the main/alternate
+/// instruction for SLP vectorization.
+///
+/// Example of unsupported opcode is SDIV that can potentially cause UB if the
+/// "shuffled out" lane would result in division by zero.
+static bool isValidForAlternation(unsigned Opcode) {
+ if (Instruction::isIntDivRem(Opcode))
+ return false;
+
+ return true;
+}
+
/// \returns analysis of the Instructions in \p VL described in
/// InstructionsState, the Opcode that we suppose the whole list
/// could be vectorized even if its structure is diverse.
@@ -399,7 +411,8 @@ static InstructionsState getSameOpcode(ArrayRef<Value *> VL,
if (IsBinOp && isa<BinaryOperator>(VL[Cnt])) {
if (InstOpcode == Opcode || InstOpcode == AltOpcode)
continue;
- if (Opcode == AltOpcode) {
+ if (Opcode == AltOpcode && isValidForAlternation(InstOpcode) &&
+ isValidForAlternation(Opcode)) {
AltOpcode = InstOpcode;
AltIndex = Cnt;
continue;
@@ -411,6 +424,9 @@ static InstructionsState getSameOpcode(ArrayRef<Value *> VL,
if (InstOpcode == Opcode || InstOpcode == AltOpcode)
continue;
if (Opcode == AltOpcode) {
+ assert(isValidForAlternation(Opcode) &&
+ isValidForAlternation(InstOpcode) &&
+ "Cast isn't safe for alternation, logic needs to be updated!");
AltOpcode = InstOpcode;
AltIndex = Cnt;
continue;