Vendor import of llvm-project release/10.x
llvmorg-10-init-17538-gd11abddb32f.
This commit is contained in:
parent
d225fe9c67
commit
8b67a9f01d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/llvm-project/release-10.x/; revision=357097 svn path=/vendor/llvm-project/llvmorg-10-init-17538-gd11abddb32f/; revision=357098; tag=vendor/llvm-project/llvmorg-10-init-17538-gd11abddb32f
@ -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
|
||||
|
@ -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 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
/// 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;
|
||||
|
@ -548,8 +548,8 @@ class ASTNodeTraverser
|
||||
}
|
||||
|
||||
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(),
|
||||
|
@ -1893,6 +1893,37 @@ class CXXDeductionGuideDecl : public FunctionDecl {
|
||||
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
|
||||
|
@ -1102,6 +1102,17 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// 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 @@ class TemplateTypeParmDecl final : public TypeDecl,
|
||||
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 @@ class NonTypeTemplateParmDecl final
|
||||
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 @@ class NonTypeTemplateParmDecl final
|
||||
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 @@ class NonTypeTemplateParmDecl final
|
||||
/// 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.
|
||||
|
@ -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 @@ class BuiltinBitCastExpr final
|
||||
}
|
||||
};
|
||||
|
||||
/// \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
|
||||
|
540
clang/include/clang/AST/ExprConcepts.h
Normal file
540
clang/include/clang/AST/ExprConcepts.h
Normal file
@ -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
|
@ -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 :
|
||||
|
@ -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, {})
|
||||
|
@ -910,6 +910,17 @@ class alignas(void *) Stmt {
|
||||
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 @@ class alignas(void *) Stmt {
|
||||
UnresolvedMemberExprBitfields UnresolvedMemberExprBits;
|
||||
CXXNoexceptExprBitfields CXXNoexceptExprBits;
|
||||
SubstNonTypeTemplateParmExprBitfields SubstNonTypeTemplateParmExprBits;
|
||||
RequiresExprBitfields RequiresExprBits;
|
||||
|
||||
// C++ Coroutines TS expressions
|
||||
CoawaitExprBitfields CoawaitBits;
|
||||
|
@ -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"
|
||||
|
@ -637,7 +637,7 @@ struct ASTTemplateArgumentListInfo final
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -58,6 +58,7 @@ namespace clang {
|
||||
|
||||
class ExtQuals;
|
||||
class QualType;
|
||||
class ConceptDecl;
|
||||
class TagDecl;
|
||||
class Type;
|
||||
|
||||
@ -1683,6 +1684,15 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
|
||||
/// 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 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
|
||||
|
||||
/// 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 @@ class DeducedType : public Type {
|
||||
}
|
||||
};
|
||||
|
||||
/// 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 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode {
|
||||
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;
|
||||
|
@ -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 @@ class TypeLoc {
|
||||
/// 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
|
||||
|
@ -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);
|
||||
}]>;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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>;
|
||||
|
||||
|
@ -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'">,
|
||||
|
@ -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">,
|
||||
|
@ -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
|
||||
|
@ -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<
|
||||
|
@ -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")
|
||||
|
@ -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>;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -208,7 +208,7 @@ class Driver {
|
||||
/// 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:
|
||||
|
@ -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>;
|
||||
|
@ -806,6 +806,16 @@ class Parser : public CodeCompletionHandler {
|
||||
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 @@ class Parser : public CodeCompletionHandler {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Concepts
|
||||
|
||||
ExprResult ParseRequiresExpression();
|
||||
void ParseTrailingRequiresClause(Declarator &D);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -2395,6 +2406,11 @@ class Parser : public CodeCompletionHandler {
|
||||
/// 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 @@ class Parser : public CodeCompletionHandler {
|
||||
Declarator &D,
|
||||
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo);
|
||||
void ParseParameterDeclarationClause(
|
||||
Declarator &D,
|
||||
DeclaratorContext DeclaratorContext,
|
||||
ParsedAttributes &attrs,
|
||||
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
|
||||
SourceLocation &EllipsisLoc);
|
||||
@ -3064,13 +3080,13 @@ class Parser : public CodeCompletionHandler {
|
||||
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 @@ class Parser : public CodeCompletionHandler {
|
||||
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();
|
||||
|
@ -349,6 +349,7 @@ class DeclSpec {
|
||||
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 @@ class DeclSpec {
|
||||
UnionParsedType TypeRep;
|
||||
Decl *DeclRep;
|
||||
Expr *ExprRep;
|
||||
TemplateIdAnnotation *TemplateIdRep;
|
||||
};
|
||||
|
||||
/// ExplicitSpecifier - Store information about explicit spicifer.
|
||||
@ -413,6 +415,9 @@ class DeclSpec {
|
||||
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 @@ class DeclSpec {
|
||||
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 @@ class DeclSpec {
|
||||
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 @@ class DeclSpec {
|
||||
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 @@ class DeclSpec {
|
||||
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 @@ class Declarator {
|
||||
/// 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 @@ class Declarator {
|
||||
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 @@ class Declarator {
|
||||
case DeclaratorContext::TemplateTypeArgContext:
|
||||
case DeclaratorContext::TrailingReturnContext:
|
||||
case DeclaratorContext::TrailingReturnVarContext:
|
||||
case DeclaratorContext::RequiresExprContext:
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("unknown context kind!");
|
||||
@ -2003,6 +2029,7 @@ class Declarator {
|
||||
case DeclaratorContext::TemplateParamContext:
|
||||
case DeclaratorContext::CXXCatchContext:
|
||||
case DeclaratorContext::ObjCCatchContext:
|
||||
case DeclaratorContext::RequiresExprContext:
|
||||
return true;
|
||||
|
||||
case DeclaratorContext::TypeNameContext:
|
||||
@ -2039,6 +2066,7 @@ class Declarator {
|
||||
case DeclaratorContext::MemberContext:
|
||||
case DeclaratorContext::PrototypeContext:
|
||||
case DeclaratorContext::TemplateParamContext:
|
||||
case DeclaratorContext::RequiresExprContext:
|
||||
// Maybe one day...
|
||||
return false;
|
||||
|
||||
@ -2116,6 +2144,7 @@ class Declarator {
|
||||
case DeclaratorContext::TemplateArgContext:
|
||||
case DeclaratorContext::TemplateTypeArgContext:
|
||||
case DeclaratorContext::TrailingReturnContext:
|
||||
case DeclaratorContext::RequiresExprContext:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("unknown context kind!");
|
||||
@ -2337,6 +2366,7 @@ class Declarator {
|
||||
case DeclaratorContext::TemplateTypeArgContext:
|
||||
case DeclaratorContext::TrailingReturnContext:
|
||||
case DeclaratorContext::TrailingReturnVarContext:
|
||||
case DeclaratorContext::RequiresExprContext:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("unknown context kind!");
|
||||
@ -2370,6 +2400,7 @@ class Declarator {
|
||||
case DeclaratorContext::TrailingReturnContext:
|
||||
case DeclaratorContext::TrailingReturnVarContext:
|
||||
case DeclaratorContext::TemplateTypeArgContext:
|
||||
case DeclaratorContext::RequiresExprContext:
|
||||
return false;
|
||||
|
||||
case DeclaratorContext::BlockContext:
|
||||
@ -2422,6 +2453,30 @@ class Declarator {
|
||||
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
|
||||
|
@ -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(),
|
||||
|
@ -385,6 +385,12 @@ class Scope {
|
||||
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;
|
||||
|
@ -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 @@ class CapturedRegionScopeInfo final : public CapturingScopeInfo {
|
||||
}
|
||||
};
|
||||
|
||||
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 @@ class LambdaScopeInfo final : public CapturingScopeInfo {
|
||||
/// 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).
|
||||
|
@ -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 @@ class Sema final {
|
||||
/// 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 @@ class Sema final {
|
||||
/// 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 @@ class Sema final {
|
||||
/// 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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
|
||||
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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
llvm::DenseMap<NamedDecl *, NormalizedConstraint *>
|
||||
NormalizationCache;
|
||||
|
||||
llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
|
||||
SatisfactionCache;
|
||||
|
||||
public:
|
||||
const NormalizedConstraint *
|
||||
getNormalizedAssociatedConstraints(
|
||||
@ -6225,6 +6261,8 @@ class Sema final {
|
||||
|
||||
/// \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 @@ class Sema final {
|
||||
/// 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 @@ class Sema final {
|
||||
|
||||
/// \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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
|
||||
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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
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 @@ class Sema final {
|
||||
|
||||
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 @@ class Sema final {
|
||||
/// 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 @@ class Sema final {
|
||||
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();
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
185
clang/lib/AST/ExprConcepts.cpp
Normal file
185
clang/lib/AST/ExprConcepts.cpp
Normal file
@ -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);
|
||||
}
|
@ -9912,6 +9912,7 @@ class IntExprEvaluator
|
||||
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:
|
||||
|
@ -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 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
|
||||
case Expr::ConvertVectorExprClass:
|
||||
case Expr::StmtExprClass:
|
||||
case Expr::TypeTraitExprClass:
|
||||
case Expr::RequiresExprClass:
|
||||
case Expr::ArrayTypeTraitExprClass:
|
||||
case Expr::ExpressionTraitExprClass:
|
||||
case Expr::VAArgExprClass:
|
||||
|
@ -857,6 +857,13 @@ class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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(
|
||||
|
@ -1114,7 +1114,9 @@ struct SimpleTransformVisitor : public TypeVisitor<Derived, QualType> {
|
||||
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);
|
||||
}
|
||||
|
@ -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>();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -680,6 +680,10 @@ class ScalarExprEmitter
|
||||
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());
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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()) {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -429,6 +429,10 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
|
||||
return "ConstraintNormalization";
|
||||
case CodeSynthesisContext::ParameterMappingSubstitution:
|
||||
return "ParameterMappingSubstitution";
|
||||
case CodeSynthesisContext::RequirementInstantiation:
|
||||
return "RequirementInstantiation";
|
||||
case CodeSynthesisContext::NestedRequirementConstraintsCheck:
|
||||
return "NestedRequirementConstraintsCheck";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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());
|
||||
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);
|
||||
assert(!MemberOfUnknownSpecialization
|
||||
&& "Member when we only allowed namespace scope qualifiers??");
|
||||
if (!PossibleConcept || TNK != TNK_Concept_template)
|
||||
return false;
|
||||
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
|
||||
|
@ -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 @@ class TentativeParseCCC final : public CorrectionCandidateCallback {
|
||||
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;
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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 &&
|
||||
|
@ -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) {}
|
||||
|
@ -10,6 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TreeTransform.h"
|
||||
#include "TypeLocBuilder.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
@ -1153,6 +1154,10 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
|
||||
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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -724,38 +724,48 @@ class PackDeductionScope {
|
||||
// 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;
|
||||
|
@ -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;
|
||||
@ -364,6 +367,26 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
|
||||
PointOfInstantiation, InstantiationRange, Param, Template,
|
||||
TemplateArgs) {}
|
||||
|
||||
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,
|
||||
@ -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.
|
||||
///
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user