Merge ^/vendor/lvm-project/release-10.x up to its last change (upstream

commit llvmorg-10-init-17538-gd11abddb32f).
This commit is contained in:
Dimitry Andric 2020-01-24 22:15:36 +00:00
commit 55e4f9d541
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/clang1000-import/; revision=357099
145 changed files with 4904 additions and 1099 deletions

View File

@ -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

View File

@ -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;

View File

@ -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(),

View File

@ -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

View File

@ -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.

View File

@ -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

View 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

View File

@ -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 :

View File

@ -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, {})

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}]>;
}

View File

@ -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.
}];
}

View File

@ -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)

View File

@ -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.

View File

@ -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>;

View File

@ -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'">,

View File

@ -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">,

View File

@ -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

View File

@ -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<

View File

@ -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")

View File

@ -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>;

View File

@ -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)

View File

@ -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 {

View File

@ -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:

View File

@ -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>;

View File

@ -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();

View File

@ -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

View File

@ -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(),

View File

@ -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;

View File

@ -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).

View File

@ -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();

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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(

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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:

View 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);
}

View File

@ -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
};
@ -12531,6 +12532,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()) {
@ -14189,6 +14193,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:

View File

@ -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:

View File

@ -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);
}

View File

@ -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"

View File

@ -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) {

View File

@ -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,

View File

@ -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));

View File

@ -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(

View File

@ -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);
}

View File

@ -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>();
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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());
}

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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()) {

View File

@ -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));
}

View File

@ -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,

View File

@ -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);

View File

@ -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 "";
}

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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.

View File

@ -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();

View File

@ -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;

View File

@ -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");

View File

@ -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

View File

@ -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;
}

View File

@ -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))

View File

@ -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,

View File

@ -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 &&

View File

@ -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) {}

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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));

View File

@ -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);
}

View File

@ -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");

View File

@ -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);

View File

@ -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());

View File

@ -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();
}

View File

@ -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;

View File

@ -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.
///

View File

@ -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;
}

View File

@ -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