diff options
Diffstat (limited to 'clang/lib')
71 files changed, 3325 insertions, 700 deletions
| diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index fc32e768d92f8..c28a06bdf0b24 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -14,6 +14,10 @@  #include "clang/AST/ASTConcept.h"  #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/TemplateBase.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h"  using namespace clang;  ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C, @@ -53,3 +57,12 @@ ASTConstraintSatisfaction::Create(const ASTContext &C,    void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));    return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);  } + +void ConstraintSatisfaction::Profile( +    llvm::FoldingSetNodeID &ID, const ASTContext &C, NamedDecl *ConstraintOwner, +    ArrayRef<TemplateArgument> TemplateArgs) { +  ID.AddPointer(ConstraintOwner); +  ID.AddInteger(TemplateArgs.size()); +  for (auto &Arg : TemplateArgs) +    Arg.Profile(ID, C); +} diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a51429264dbee..6d1db38e36ccd 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -716,6 +716,61 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,      RequiresClause->Profile(ID, C, /*Canonical=*/true);  } +static Expr * +canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC, +                                          QualType ConstrainedType) { +  // This is a bit ugly - we need to form a new immediately-declared +  // constraint that references the new parameter; this would ideally +  // require semantic analysis (e.g. template<C T> struct S {}; - the +  // converted arguments of C<T> could be an argument pack if C is +  // declared as template<typename... T> concept C = ...). +  // We don't have semantic analysis here so we dig deep into the +  // ready-made constraint expr and change the thing manually. +  ConceptSpecializationExpr *CSE; +  if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC)) +    CSE = cast<ConceptSpecializationExpr>(Fold->getLHS()); +  else +    CSE = cast<ConceptSpecializationExpr>(IDC); +  ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments(); +  SmallVector<TemplateArgument, 3> NewConverted; +  NewConverted.reserve(OldConverted.size()); +  if (OldConverted.front().getKind() == TemplateArgument::Pack) { +    // The case: +    // template<typename... T> concept C = true; +    // template<C<int> T> struct S; -> constraint is C<{T, int}> +    NewConverted.push_back(ConstrainedType); +    for (auto &Arg : OldConverted.front().pack_elements().drop_front(1)) +      NewConverted.push_back(Arg); +    TemplateArgument NewPack(NewConverted); + +    NewConverted.clear(); +    NewConverted.push_back(NewPack); +    assert(OldConverted.size() == 1 && +           "Template parameter pack should be the last parameter"); +  } else { +    assert(OldConverted.front().getKind() == TemplateArgument::Type && +           "Unexpected first argument kind for immediately-declared " +           "constraint"); +    NewConverted.push_back(ConstrainedType); +    for (auto &Arg : OldConverted.drop_front(1)) +      NewConverted.push_back(Arg); +  } +  Expr *NewIDC = ConceptSpecializationExpr::Create( +      C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(), +      CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(), +      CSE->getNamedConcept(), +      // Actually canonicalizing a TemplateArgumentLoc is difficult so we +      // simply omit the ArgsAsWritten +      /*ArgsAsWritten=*/nullptr, NewConverted, nullptr); + +  if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC)) +    NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC, +                                 BinaryOperatorKind::BO_LAnd, +                                 SourceLocation(), /*RHS=*/nullptr, +                                 SourceLocation(), /*NumExpansions=*/None); +  return NewIDC; +} +  TemplateTemplateParmDecl *  ASTContext::getCanonicalTemplateTemplateParmDecl(                                            TemplateTemplateParmDecl *TTP) const { @@ -743,68 +798,23 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(            TTP->isExpandedParameterPack() ?            llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);        if (const auto *TC = TTP->getTypeConstraint()) { -        // This is a bit ugly - we need to form a new immediately-declared -        // constraint that references the new parameter; this would ideally -        // require semantic analysis (e.g. template<C T> struct S {}; - the -        // converted arguments of C<T> could be an argument pack if C is -        // declared as template<typename... T> concept C = ...). -        // We don't have semantic analysis here so we dig deep into the -        // ready-made constraint expr and change the thing manually. -        Expr *IDC = TC->getImmediatelyDeclaredConstraint(); -        ConceptSpecializationExpr *CSE; -        if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC)) -          CSE = cast<ConceptSpecializationExpr>(Fold->getLHS()); -        else -          CSE = cast<ConceptSpecializationExpr>(IDC); -        ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments(); -        SmallVector<TemplateArgument, 3> NewConverted; -        NewConverted.reserve(OldConverted.size()); -          QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0); -        if (OldConverted.front().getKind() == TemplateArgument::Pack) { -          // The case: -          // template<typename... T> concept C = true; -          // template<C<int> T> struct S; -> constraint is C<{T, int}> -          NewConverted.push_back(ParamAsArgument); -          for (auto &Arg : OldConverted.front().pack_elements().drop_front(1)) -            NewConverted.push_back(Arg); -          TemplateArgument NewPack(NewConverted); - -          NewConverted.clear(); -          NewConverted.push_back(NewPack); -          assert(OldConverted.size() == 1 && -                 "Template parameter pack should be the last parameter"); -        } else { -          assert(OldConverted.front().getKind() == TemplateArgument::Type && -                 "Unexpected first argument kind for immediately-declared " -                 "constraint"); -          NewConverted.push_back(ParamAsArgument); -          for (auto &Arg : OldConverted.drop_front(1)) -            NewConverted.push_back(Arg); -        } -        Expr *NewIDC = ConceptSpecializationExpr::Create(*this, -            NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(), -            CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(), -            CSE->getNamedConcept(), -            // Actually canonicalizing a TemplateArgumentLoc is difficult so we -            // simply omit the ArgsAsWritten -            /*ArgsAsWritten=*/nullptr, NewConverted, nullptr); - -        if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC)) -          NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(), -                                           SourceLocation(), NewIDC, -                                           BinaryOperatorKind::BO_LAnd, -                                           SourceLocation(), /*RHS=*/nullptr, -                                           SourceLocation(), -                                           /*NumExpansions=*/None); - +        Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint( +                *this, TC->getImmediatelyDeclaredConstraint(), +                ParamAsArgument); +        TemplateArgumentListInfo CanonArgsAsWritten; +        if (auto *Args = TC->getTemplateArgsAsWritten()) +          for (const auto &ArgLoc : Args->arguments()) +            CanonArgsAsWritten.addArgument( +                TemplateArgumentLoc(ArgLoc.getArgument(), +                                    TemplateArgumentLocInfo()));          NewTTP->setTypeConstraint(              NestedNameSpecifierLoc(),              DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),                                  SourceLocation()), /*FoundDecl=*/nullptr,              // Actually canonicalizing a TemplateArgumentLoc is difficult so we              // simply omit the ArgsAsWritten -            CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC); +            TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);        }        CanonParams.push_back(NewTTP);      } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { @@ -839,6 +849,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(                                                  NTTP->isParameterPack(),                                                  TInfo);        } +      if (AutoType *AT = T->getContainedAutoType()) { +        if (AT->isConstrained()) { +          Param->setPlaceholderTypeConstraint( +              canonicalizeImmediatelyDeclaredConstraint( +                  *this, NTTP->getPlaceholderTypeConstraint(), T)); +        } +      }        CanonParams.push_back(Param);      } else @@ -943,7 +960,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,                         Builtin::Context &builtins)      : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),        TemplateSpecializationTypes(this_()), -      DependentTemplateSpecializationTypes(this_()), +      DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),        SubstTemplateTemplateParmPacks(this_()),        CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),        SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), @@ -5124,21 +5141,29 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,  /// getAutoType - Return the uniqued reference to the 'auto' type which has been  /// deduced to the given type, or to the canonical undeduced 'auto' type, or the  /// canonical deduced-but-dependent 'auto' type. -QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, -                                 bool IsDependent, bool IsPack) const { +QualType +ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, +                        bool IsDependent, bool IsPack, +                        ConceptDecl *TypeConstraintConcept, +                        ArrayRef<TemplateArgument> TypeConstraintArgs) const {    assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); -  if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) +  if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && +      !TypeConstraintConcept && !IsDependent)      return getAutoDeductType();    // Look in the folding set for an existing type.    void *InsertPos = nullptr;    llvm::FoldingSetNodeID ID; -  AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack); +  AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent, +                    TypeConstraintConcept, TypeConstraintArgs);    if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))      return QualType(AT, 0); -  auto *AT = new (*this, TypeAlignment) -      AutoType(DeducedType, Keyword, IsDependent, IsPack); +  void *Mem = Allocate(sizeof(AutoType) + +                       sizeof(TemplateArgument) * TypeConstraintArgs.size(), +                       TypeAlignment); +  auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack, +                                TypeConstraintConcept, TypeConstraintArgs);    Types.push_back(AT);    if (InsertPos)      AutoTypes.InsertNode(AT, InsertPos); @@ -5200,7 +5225,8 @@ QualType ASTContext::getAutoDeductType() const {    if (AutoDeductTy.isNull())      AutoDeductTy = QualType(        new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, -                                          /*dependent*/false, /*pack*/false), +                                          /*dependent*/false, /*pack*/false, +                                          /*concept*/nullptr, /*args*/{}),        0);    return AutoDeductTy;  } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 22fb67478c969..1f2ce30398c91 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1366,9 +1366,21 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) {    if (!ToDeducedTypeOrErr)      return ToDeducedTypeOrErr.takeError(); -  return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr, -                                             T->getKeyword(), -                                             /*IsDependent*/false); +  ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept()); +  if (!ToTypeConstraintConcept) +    return ToTypeConstraintConcept.takeError(); + +  SmallVector<TemplateArgument, 2> ToTemplateArgs; +  ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments(); +  if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(), +                                          FromTemplateArgs.size(), +                                          ToTemplateArgs)) +    return std::move(Err); + +  return Importer.getToContext().getAutoType( +      *ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false, +      /*IsPack=*/false, cast_or_null<ConceptDecl>(*ToTypeConstraintConcept), +      ToTemplateArgs);  }  ExpectedType ASTNodeImporter::VisitInjectedClassNameType( diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index db48405055cda..91a2f3a8391bb 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -729,11 +729,31 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,        return false;      break; -  case Type::Auto: -    if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(), -                                  cast<AutoType>(T2)->getDeducedType())) +  case Type::Auto: { +    auto *Auto1 = cast<AutoType>(T1); +    auto *Auto2 = cast<AutoType>(T2); +    if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(), +                                  Auto2->getDeducedType()))        return false; +    if (Auto1->isConstrained() != Auto2->isConstrained()) +      return false; +    if (Auto1->isConstrained()) { +      if (Auto1->getTypeConstraintConcept() != +          Auto2->getTypeConstraintConcept()) +        return false; +      ArrayRef<TemplateArgument> Auto1Args = +          Auto1->getTypeConstraintArguments(); +      ArrayRef<TemplateArgument> Auto2Args = +          Auto2->getTypeConstraintArguments(); +      if (Auto1Args.size() != Auto2Args.size()) +        return false; +      for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) { +        if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I])) +          return false; +      } +    }      break; +  }    case Type::DeducedTemplateSpecialization: {      const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 6ee767ccecf7d..cb4d61cac2c71 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -804,6 +804,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {      case OMPCapturedExpr:      case Empty:      case LifetimeExtendedTemporary: +    case RequiresExprBody:        // Never looked up by name.        return 0;    } @@ -1177,6 +1178,7 @@ DeclContext *DeclContext::getPrimaryContext() {    case Decl::Captured:    case Decl::OMPDeclareReduction:    case Decl::OMPDeclareMapper: +  case Decl::RequiresExprBody:      // There is only one DeclContext for these entities.      return this; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 2ead1e70ea0d6..48e310e858b26 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1968,6 +1968,16 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,        QualType(), nullptr, SourceLocation());  } +RequiresExprBodyDecl *RequiresExprBodyDecl::Create( +    ASTContext &C, DeclContext *DC, SourceLocation StartLoc) { +  return new (C, DC) RequiresExprBodyDecl(C, DC, StartLoc); +} + +RequiresExprBodyDecl *RequiresExprBodyDecl::CreateDeserialized(ASTContext &C, +                                                               unsigned ID) { +  return new (C, ID) RequiresExprBodyDecl(C, nullptr, SourceLocation()); +} +  void CXXMethodDecl::anchor() {}  bool CXXMethodDecl::isStatic() const { diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 95a2e26e0df84..b5e4ec2d7f43c 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -164,10 +164,15 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,  void TemplateParameterList::  getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {    if (HasConstrainedParameters) -    for (const NamedDecl *Param : *this) -      if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) +    for (const NamedDecl *Param : *this) { +      if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {          if (const auto *TC = TTP->getTypeConstraint())            AC.push_back(TC->getImmediatelyDeclaredConstraint()); +      } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { +        if (const Expr *E = NTTP->getPlaceholderTypeConstraint()) +          AC.push_back(E); +      } +    }    if (HasRequiresClause)      AC.push_back(getRequiresClause());  } @@ -483,7 +488,10 @@ static void ProfileTemplateParameterList(ASTContext &C,      if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {        ID.AddInteger(1);        ID.AddBoolean(TTP->isParameterPack()); -      // TODO: Concepts: profile type-constraints. +      ID.AddBoolean(TTP->hasTypeConstraint()); +      if (const TypeConstraint *TC = TTP->getTypeConstraint()) +        TC->getImmediatelyDeclaredConstraint()->Profile(ID, C, +                                                        /*Canonical=*/true);        continue;      }      const auto *TTP = cast<TemplateTemplateParmDecl>(D); @@ -684,8 +692,14 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,                                  unsigned D, unsigned P, IdentifierInfo *Id,                                  QualType T, bool ParameterPack,                                  TypeSourceInfo *TInfo) { -  return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, -                                             T, ParameterPack, TInfo); +  AutoType *AT = +      C.getLangOpts().CPlusPlus2a ? T->getContainedAutoType() : nullptr; +  return new (C, DC, +              additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, +                                    Expr *>(0, +                                            AT && AT->isConstrained() ? 1 : 0)) +      NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack, +                              TInfo);  }  NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( @@ -693,26 +707,34 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(      SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,      QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,      ArrayRef<TypeSourceInfo *> ExpandedTInfos) { +  AutoType *AT = TInfo->getType()->getContainedAutoType();    return new (C, DC, -              additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>( -                  ExpandedTypes.size())) +              additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, +                                    Expr *>( +                  ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0))        NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,                                ExpandedTypes, ExpandedTInfos);  }  NonTypeTemplateParmDecl * -NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { -  return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(), -                                             SourceLocation(), 0, 0, nullptr, -                                             QualType(), false, nullptr); +NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, +                                            bool HasTypeConstraint) { +  return new (C, ID, additionalSizeToAlloc<std::pair<QualType, +                                                     TypeSourceInfo *>, +                                           Expr *>(0, +                                                   HasTypeConstraint ? 1 : 0)) +          NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), +                                  0, 0, nullptr, QualType(), false, nullptr);  }  NonTypeTemplateParmDecl *  NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, -                                            unsigned NumExpandedTypes) { +                                            unsigned NumExpandedTypes, +                                            bool HasTypeConstraint) {    auto *NTTP = -      new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>( -                      NumExpandedTypes)) +      new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, +                                        Expr *>( +                      NumExpandedTypes, HasTypeConstraint ? 1 : 0))            NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),                                    0, 0, nullptr, QualType(), nullptr, None,                                    None); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 73ddbc62482dd..8351989587662 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3457,6 +3457,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,    case OpaqueValueExprClass:    case SourceLocExprClass:    case ConceptSpecializationExprClass: +  case RequiresExprClass:      // These never have a side-effect.      return false; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 422227d787b10..e4bd218ae2d36 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -17,6 +17,7 @@  #include "clang/AST/DeclAccessPair.h"  #include "clang/AST/DeclBase.h"  #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h"  #include "clang/AST/DeclarationName.h"  #include "clang/AST/Expr.h"  #include "clang/AST/LambdaCapture.h" @@ -1764,81 +1765,3 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx,                             alignof(CUDAKernelCallExpr));    return new (Mem) CUDAKernelCallExpr(NumArgs, Empty);  } - -ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C, -    NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, -    DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, -    ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, -    ArrayRef<TemplateArgument> ConvertedArgs, -    const ConstraintSatisfaction *Satisfaction) -    : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, -           /*TypeDependent=*/false, -           // All the flags below are set in setTemplateArguments. -           /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false, -           /*ContainsUnexpandedParameterPacks=*/false), -      ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, -                       NamedConcept, ArgsAsWritten), -      NumTemplateArgs(ConvertedArgs.size()), -      Satisfaction(Satisfaction ? -                   ASTConstraintSatisfaction::Create(C, *Satisfaction) : -                   nullptr) { -  setTemplateArguments(ConvertedArgs); -} - -ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, -    unsigned NumTemplateArgs) -    : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), -      NumTemplateArgs(NumTemplateArgs) { } - -void ConceptSpecializationExpr::setTemplateArguments( -    ArrayRef<TemplateArgument> Converted) { -  assert(Converted.size() == NumTemplateArgs); -  std::uninitialized_copy(Converted.begin(), Converted.end(), -                          getTrailingObjects<TemplateArgument>()); -  bool IsInstantiationDependent = false; -  bool ContainsUnexpandedParameterPack = false; -  for (const TemplateArgument& Arg : Converted) { -    if (Arg.isInstantiationDependent()) -      IsInstantiationDependent = true; -    if (Arg.containsUnexpandedParameterPack()) -      ContainsUnexpandedParameterPack = true; -    if (ContainsUnexpandedParameterPack && IsInstantiationDependent) -      break; -  } - -  // Currently guaranteed by the fact concepts can only be at namespace-scope. -  assert(!NestedNameSpec || -         (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() && -          !NestedNameSpec.getNestedNameSpecifier() -              ->containsUnexpandedParameterPack())); -  setInstantiationDependent(IsInstantiationDependent); -  setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); -  assert((!isValueDependent() || isInstantiationDependent()) && -         "should not be value-dependent"); -} - -ConceptSpecializationExpr * -ConceptSpecializationExpr::Create(const ASTContext &C, -                                  NestedNameSpecifierLoc NNS, -                                  SourceLocation TemplateKWLoc, -                                  DeclarationNameInfo ConceptNameInfo, -                                  NamedDecl *FoundDecl, -                                  ConceptDecl *NamedConcept, -                               const ASTTemplateArgumentListInfo *ArgsAsWritten, -                                  ArrayRef<TemplateArgument> ConvertedArgs, -                                  const ConstraintSatisfaction *Satisfaction) { -  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( -                                ConvertedArgs.size())); -  return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, -                                                ConceptNameInfo, FoundDecl, -                                                NamedConcept, ArgsAsWritten, -                                                ConvertedArgs, Satisfaction); -} - -ConceptSpecializationExpr * -ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty, -                                  unsigned NumTemplateArgs) { -  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( -                                NumTemplateArgs)); -  return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs); -} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 9dbf6fe9e0f06..d201af31f521e 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -193,6 +193,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {    case Expr::DesignatedInitUpdateExprClass:    case Expr::SourceLocExprClass:    case Expr::ConceptSpecializationExprClass: +  case Expr::RequiresExprClass:      return Cl::CL_PRValue;    case Expr::ConstantExprClass: diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp new file mode 100644 index 0000000000000..76d57ed5d5b1f --- /dev/null +++ b/clang/lib/AST/ExprConcepts.cpp @@ -0,0 +1,185 @@ +//===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the subclesses of Expr class declared in ExprCXX.h +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExprConcepts.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConcept.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/TrailingObjects.h" +#include <algorithm> +#include <utility> +#include <string> + +using namespace clang; + +ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C, +    NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, +    DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, +    ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, +    ArrayRef<TemplateArgument> ConvertedArgs, +    const ConstraintSatisfaction *Satisfaction) +    : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, +           /*TypeDependent=*/false, +           // All the flags below are set in setTemplateArguments. +           /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false, +           /*ContainsUnexpandedParameterPacks=*/false), +      ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, +                       NamedConcept, ArgsAsWritten), +      NumTemplateArgs(ConvertedArgs.size()), +      Satisfaction(Satisfaction ? +                   ASTConstraintSatisfaction::Create(C, *Satisfaction) : +                   nullptr) { +  setTemplateArguments(ConvertedArgs); +} + +ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, +    unsigned NumTemplateArgs) +    : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), +      NumTemplateArgs(NumTemplateArgs) { } + +void ConceptSpecializationExpr::setTemplateArguments( +    ArrayRef<TemplateArgument> Converted) { +  assert(Converted.size() == NumTemplateArgs); +  std::uninitialized_copy(Converted.begin(), Converted.end(), +                          getTrailingObjects<TemplateArgument>()); +  bool IsInstantiationDependent = false; +  bool ContainsUnexpandedParameterPack = false; +  for (const TemplateArgument& Arg : Converted) { +    if (Arg.isInstantiationDependent()) +      IsInstantiationDependent = true; +    if (Arg.containsUnexpandedParameterPack()) +      ContainsUnexpandedParameterPack = true; +    if (ContainsUnexpandedParameterPack && IsInstantiationDependent) +      break; +  } + +  // Currently guaranteed by the fact concepts can only be at namespace-scope. +  assert(!NestedNameSpec || +         (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() && +          !NestedNameSpec.getNestedNameSpecifier() +              ->containsUnexpandedParameterPack())); +  setInstantiationDependent(IsInstantiationDependent); +  setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); +  assert((!isValueDependent() || isInstantiationDependent()) && +         "should not be value-dependent"); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(const ASTContext &C, +                                  NestedNameSpecifierLoc NNS, +                                  SourceLocation TemplateKWLoc, +                                  DeclarationNameInfo ConceptNameInfo, +                                  NamedDecl *FoundDecl, +                                  ConceptDecl *NamedConcept, +                               const ASTTemplateArgumentListInfo *ArgsAsWritten, +                                  ArrayRef<TemplateArgument> ConvertedArgs, +                                  const ConstraintSatisfaction *Satisfaction) { +  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( +                                ConvertedArgs.size())); +  return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, +                                                ConceptNameInfo, FoundDecl, +                                                NamedConcept, ArgsAsWritten, +                                                ConvertedArgs, Satisfaction); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty, +                                  unsigned NumTemplateArgs) { +  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( +                                NumTemplateArgs)); +  return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs); +} + +const TypeConstraint * +concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const { +  assert(isTypeConstraint()); +  auto TPL = +      TypeConstraintInfo.getPointer().get<TemplateParameterList *>(); +  return cast<TemplateTypeParmDecl>(TPL->getParam(0)) +      ->getTypeConstraint(); +} + +RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, +                           RequiresExprBodyDecl *Body, +                           ArrayRef<ParmVarDecl *> LocalParameters, +                           ArrayRef<concepts::Requirement *> Requirements, +                           SourceLocation RBraceLoc) +  : Expr(RequiresExprClass, C.BoolTy, VK_RValue, OK_Ordinary, +         /*TD=*/false, /*VD=*/false, /*ID=*/false, +         /*ContainsUnexpandedParameterPack=*/false), +    NumLocalParameters(LocalParameters.size()), +    NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) { +  RequiresExprBits.IsSatisfied = false; +  RequiresExprBits.RequiresKWLoc = RequiresKWLoc; +  bool Dependent = false; +  bool ContainsUnexpandedParameterPack = false; +  for (ParmVarDecl *P : LocalParameters) { +    Dependent |= P->getType()->isInstantiationDependentType(); +    ContainsUnexpandedParameterPack |= +        P->getType()->containsUnexpandedParameterPack(); +  } +  RequiresExprBits.IsSatisfied = true; +  for (concepts::Requirement *R : Requirements) { +    Dependent |= R->isDependent(); +    ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack(); +    if (!Dependent) { +      RequiresExprBits.IsSatisfied = R->isSatisfied(); +      if (!RequiresExprBits.IsSatisfied) +        break; +    } +  } +  std::copy(LocalParameters.begin(), LocalParameters.end(), +            getTrailingObjects<ParmVarDecl *>()); +  std::copy(Requirements.begin(), Requirements.end(), +            getTrailingObjects<concepts::Requirement *>()); +  RequiresExprBits.IsSatisfied |= Dependent; +  setValueDependent(Dependent); +  setInstantiationDependent(Dependent); +  setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); +} + +RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty, +                           unsigned NumLocalParameters, +                           unsigned NumRequirements) +  : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters), +    NumRequirements(NumRequirements) { } + +RequiresExpr * +RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc, +                     RequiresExprBodyDecl *Body, +                     ArrayRef<ParmVarDecl *> LocalParameters, +                     ArrayRef<concepts::Requirement *> Requirements, +                     SourceLocation RBraceLoc) { +  void *Mem = +      C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( +                     LocalParameters.size(), Requirements.size()), +                 alignof(RequiresExpr)); +  return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters, +                                Requirements, RBraceLoc); +} + +RequiresExpr * +RequiresExpr::Create(ASTContext &C, EmptyShell Empty, +                     unsigned NumLocalParameters, unsigned NumRequirements) { +  void *Mem = +      C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( +                     NumLocalParameters, NumRequirements), +                 alignof(RequiresExpr)); +  return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements); +} diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index c4b27b5d1daa2..c79973507323d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9912,6 +9912,7 @@ public:    bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);    bool VisitSourceLocExpr(const SourceLocExpr *E);    bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E); +  bool VisitRequiresExpr(const RequiresExpr *E);    // FIXME: Missing: array subscript of vector, member of vector  }; @@ -12524,6 +12525,9 @@ bool IntExprEvaluator::VisitConceptSpecializationExpr(    return Success(E->isSatisfied(), E);  } +bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) { +  return Success(E->isSatisfied(), E); +}  bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {    switch (E->getOpcode()) { @@ -14182,6 +14186,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {    case Expr::CXXScalarValueInitExprClass:    case Expr::TypeTraitExprClass:    case Expr::ConceptSpecializationExprClass: +  case Expr::RequiresExprClass:    case Expr::ArrayTypeTraitExprClass:    case Expr::ExpressionTraitExprClass:    case Expr::CXXNoexceptExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 0d567edac5216..5d485e000750b 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -22,6 +22,7 @@  #include "clang/AST/DeclOpenMP.h"  #include "clang/AST/DeclTemplate.h"  #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h"  #include "clang/AST/ExprCXX.h"  #include "clang/AST/ExprObjC.h"  #include "clang/AST/TypeLoc.h" @@ -3668,6 +3669,7 @@ recurse:    case Expr::ConvertVectorExprClass:    case Expr::StmtExprClass:    case Expr::TypeTraitExprClass: +  case Expr::RequiresExprClass:    case Expr::ArrayTypeTraitExprClass:    case Expr::ExpressionTraitExprClass:    case Expr::VAArgExprClass: diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 27fdca1c4b9cf..1f9ff9e407dc2 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -857,6 +857,13 @@ public:    void VisitAutoType(const AutoType *T) {      ID.AddInteger((unsigned)T->getKeyword()); +    ID.AddInteger(T->isConstrained()); +    if (T->isConstrained()) { +      AddDecl(T->getTypeConstraintConcept()); +      ID.AddInteger(T->getNumArgs()); +      for (const auto &TA : T->getTypeConstraintArguments()) +        Hash.AddTemplateArgument(TA); +    }      VisitDeducedType(T);    } diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index b6e4d8aff21e9..7409ae7ddc9e7 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -16,6 +16,7 @@  #include "clang/AST/Decl.h"  #include "clang/AST/DeclGroup.h"  #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h"  #include "clang/AST/ExprCXX.h"  #include "clang/AST/ExprObjC.h"  #include "clang/AST/ExprOpenMP.h" diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index c14bb886bb11a..45fd8ceae8d36 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2269,6 +2269,60 @@ void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {                              Policy);  } +void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) { +  OS << "requires "; +  auto LocalParameters = E->getLocalParameters(); +  if (!LocalParameters.empty()) { +    OS << "("; +    for (ParmVarDecl *LocalParam : LocalParameters) { +      PrintRawDecl(LocalParam); +      if (LocalParam != LocalParameters.back()) +        OS << ", "; +    } + +    OS << ") "; +  } +  OS << "{ "; +  auto Requirements = E->getRequirements(); +  for (concepts::Requirement *Req : Requirements) { +    if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) { +      if (TypeReq->isSubstitutionFailure()) +        OS << "<<error-type>>"; +      else +        TypeReq->getType()->getType().print(OS, Policy); +    } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) { +      if (ExprReq->isCompound()) +        OS << "{ "; +      if (ExprReq->isExprSubstitutionFailure()) +        OS << "<<error-expression>>"; +      else +        PrintExpr(ExprReq->getExpr()); +      if (ExprReq->isCompound()) { +        OS << " }"; +        if (ExprReq->getNoexceptLoc().isValid()) +          OS << " noexcept"; +        const auto &RetReq = ExprReq->getReturnTypeRequirement(); +        if (!RetReq.isEmpty()) { +          OS << " -> "; +          if (RetReq.isSubstitutionFailure()) +            OS << "<<error-type>>"; +          else if (RetReq.isTypeConstraint()) +            RetReq.getTypeConstraint()->print(OS, Policy); +        } +      } +    } else { +      auto *NestedReq = cast<concepts::NestedRequirement>(Req); +      OS << "requires "; +      if (NestedReq->isSubstitutionFailure()) +        OS << "<<error-expression>>"; +      else +        PrintExpr(NestedReq->getConstraintExpr()); +    } +    OS << "; "; +  } +  OS << "}"; +} +  // C++ Coroutines TS  void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 2aa5106e90fae..382ea5c8d7ef0 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1335,9 +1335,52 @@ void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {  void StmtProfiler::VisitConceptSpecializationExpr(                                             const ConceptSpecializationExpr *S) {    VisitExpr(S); -  VisitDecl(S->getFoundDecl()); -  VisitTemplateArguments(S->getTemplateArgsAsWritten()->getTemplateArgs(), -                         S->getTemplateArgsAsWritten()->NumTemplateArgs); +  VisitDecl(S->getNamedConcept()); +  for (const TemplateArgument &Arg : S->getTemplateArguments()) +    VisitTemplateArgument(Arg); +} + +void StmtProfiler::VisitRequiresExpr(const RequiresExpr *S) { +  VisitExpr(S); +  ID.AddInteger(S->getLocalParameters().size()); +  for (ParmVarDecl *LocalParam : S->getLocalParameters()) +    VisitDecl(LocalParam); +  ID.AddInteger(S->getRequirements().size()); +  for (concepts::Requirement *Req : S->getRequirements()) { +    if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) { +      ID.AddInteger(concepts::Requirement::RK_Type); +      ID.AddBoolean(TypeReq->isSubstitutionFailure()); +      if (!TypeReq->isSubstitutionFailure()) +        VisitType(TypeReq->getType()->getType()); +    } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) { +      ID.AddInteger(concepts::Requirement::RK_Compound); +      ID.AddBoolean(ExprReq->isExprSubstitutionFailure()); +      if (!ExprReq->isExprSubstitutionFailure()) +        Visit(ExprReq->getExpr()); +      // C++2a [expr.prim.req.compound]p1 Example: +      //    [...] The compound-requirement in C1 requires that x++ is a valid +      //    expression. It is equivalent to the simple-requirement x++; [...] +      // We therefore do not profile isSimple() here. +      ID.AddBoolean(ExprReq->getNoexceptLoc().isValid()); +      const concepts::ExprRequirement::ReturnTypeRequirement &RetReq = +          ExprReq->getReturnTypeRequirement(); +      if (RetReq.isEmpty()) { +        ID.AddInteger(0); +      } else if (RetReq.isTypeConstraint()) { +        ID.AddInteger(1); +        Visit(RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint()); +      } else { +        assert(RetReq.isSubstitutionFailure()); +        ID.AddInteger(2); +      } +    } else { +      ID.AddInteger(concepts::Requirement::RK_Nested); +      auto *NestedReq = cast<concepts::NestedRequirement>(Req); +      ID.AddBoolean(NestedReq->isSubstitutionFailure()); +      if (!NestedReq->isSubstitutionFailure())   +        Visit(NestedReq->getConstraintExpr()); +    } +  }  }  static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index db16c2a06b64f..6f0ebf232e77c 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -561,7 +561,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,  }  const ASTTemplateArgumentListInfo * -ASTTemplateArgumentListInfo::Create(ASTContext &C, +ASTTemplateArgumentListInfo::Create(const ASTContext &C,                                      const TemplateArgumentListInfo &List) {    std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());    void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo)); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 965ad17fcfa5b..c9b571862c199 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1201,6 +1201,11 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {      OS << " decltype(auto)";    if (!T->isDeduced())      OS << " undeduced"; +  if (T->isConstrained()) { +    dumpDeclRef(T->getTypeConstraintConcept()); +    for (const auto &Arg : T->getTypeConstraintArguments()) +      VisitTemplateArgument(Arg); +  }  }  void TextNodeDumper::VisitTemplateSpecializationType( diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index c5ad711d872e0..5099494da5fd6 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1114,7 +1114,9 @@ public:        return QualType(T, 0);      return Ctx.getAutoType(deducedType, T->getKeyword(), -                           T->isDependentType()); +                           T->isDependentType(), /*IsPack=*/false, +                           T->getTypeConstraintConcept(), +                           T->getTypeConstraintArguments());    }    // FIXME: Non-trivial to implement, but important for C++ @@ -4158,3 +4160,35 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,                               /*HasUnsignedPadding=*/false);    APFixedPoint(Val, FXSema).toString(Str);  } + +AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, +                   bool IsDeducedAsDependent, bool IsDeducedAsPack, +                   ConceptDecl *TypeConstraintConcept, +                   ArrayRef<TemplateArgument> TypeConstraintArgs) +    : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, +                  IsDeducedAsDependent, IsDeducedAsPack) { +  AutoTypeBits.Keyword = (unsigned)Keyword; +  AutoTypeBits.NumArgs = TypeConstraintArgs.size(); +  this->TypeConstraintConcept = TypeConstraintConcept; +  if (TypeConstraintConcept) { +    TemplateArgument *ArgBuffer = getArgBuffer(); +    for (const TemplateArgument &Arg : TypeConstraintArgs) { +      if (Arg.containsUnexpandedParameterPack()) +        setContainsUnexpandedParameterPack(); + +      new (ArgBuffer++) TemplateArgument(Arg); +    } +  } +} + +void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, +                      QualType Deduced, AutoTypeKeyword Keyword, +                      bool IsDependent, ConceptDecl *CD, +                      ArrayRef<TemplateArgument> Arguments) { +  ID.AddPointer(Deduced.getAsOpaquePtr()); +  ID.AddInteger((unsigned)Keyword); +  ID.AddBoolean(IsDependent); +  ID.AddPointer(CD); +  for (const TemplateArgument &Arg : Arguments) +    Arg.Profile(ID, Context); +} diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 6e67ca8e0af72..665a86f2c1432 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -11,6 +11,7 @@  //===----------------------------------------------------------------------===//  #include "clang/AST/TypeLoc.h" +#include "clang/AST/DeclTemplate.h"  #include "clang/AST/ASTContext.h"  #include "clang/AST/Attr.h"  #include "clang/AST/Expr.h" @@ -589,3 +590,97 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,      }    }  } + +DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const { +  return DeclarationNameInfo(getNamedConcept()->getDeclName(), +                             getLocalData()->ConceptNameLoc); +} + +void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { +  setNestedNameSpecifierLoc(NestedNameSpecifierLoc()); +  setTemplateKWLoc(Loc); +  setConceptNameLoc(Loc); +  setFoundDecl(nullptr); +  setRAngleLoc(Loc); +  setLAngleLoc(Loc); +  TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), +                                                   getTypePtr()->getArgs(), +                                                   getArgInfos(), Loc); +  setNameLoc(Loc); +} + + +namespace { + +  class GetContainedAutoTypeLocVisitor : +    public TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc> { +  public: +    using TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc>::Visit; + +    TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) { +      return TL; +    } + +    // Only these types can contain the desired 'auto' type. + +    TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) { +      return Visit(T.getNamedTypeLoc()); +    } + +    TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) { +      return Visit(T.getUnqualifiedLoc()); +    } + +    TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) { +      return Visit(T.getPointeeLoc()); +    } + +    TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) { +      return Visit(T.getPointeeLoc()); +    } + +    TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) { +      return Visit(T.getPointeeLoc()); +    } + +    TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) { +      return Visit(T.getPointeeLoc()); +    } + +    TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) { +      return Visit(T.getElementLoc()); +    } + +    TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) { +      return Visit(T.getReturnLoc()); +    } + +    TypeLoc VisitParenTypeLoc(ParenTypeLoc T) { +      return Visit(T.getInnerLoc()); +    } + +    TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) { +      return Visit(T.getModifiedLoc()); +    } + +    TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) { +      return Visit(T.getInnerLoc()); +    } + +    TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) { +      return Visit(T.getOriginalLoc()); +    } + +    TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) { +      return Visit(T.getPatternLoc()); +    } +  }; + +} // namespace + +AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const { +  TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this); +  if (Res.isNull()) +    return AutoTypeLoc(); +  return Res.getAs<AutoTypeLoc>(); +} diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index c2f4baec989ee..4a7e765a2bd82 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1046,6 +1046,13 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {    if (!T->getDeducedType().isNull()) {      printBefore(T->getDeducedType(), OS);    } else { +    if (T->isConstrained()) { +      OS << T->getTypeConstraintConcept()->getName(); +      auto Args = T->getTypeConstraintArguments(); +      if (!Args.empty()) +        printTemplateArgumentList(OS, Args, Policy); +      OS << ' '; +    }      switch (T->getKeyword()) {      case AutoTypeKeyword::Auto: OS << "auto"; break;      case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break; @@ -1234,20 +1241,18 @@ void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {}  void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,                                                raw_ostream &OS) { -  if (IdentifierInfo *Id = T->getIdentifier()) -    OS << Id->getName(); -  else { -    bool IsLambdaAutoParam = false; -    if (auto D = T->getDecl()) { -      if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext())) -        IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda(); +  TemplateTypeParmDecl *D = T->getDecl(); +  if (D && D->isImplicit()) { +    if (auto *TC = D->getTypeConstraint()) { +      TC->print(OS, Policy); +      OS << ' ';      } +    OS << "auto"; +  } else if (IdentifierInfo *Id = T->getIdentifier()) +    OS << Id->getName(); +  else +    OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); -    if (IsLambdaAutoParam) -      OS << "auto"; -    else -      OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); -  }    spaceBeforePlaceHolder(OS);  } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 4aebea19924f7..ee25bd883caf6 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -142,7 +142,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,    // We treat bridge casts as objective-C keywords so we can warn on them    // in non-arc mode.    if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled; -  if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled; +  if (LangOpts.CPlusPlus2a && (Flags & KEYCONCEPTS)) return KS_Enabled;    if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled;    if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled;    if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 09fd3087b494a..2d20f92fbb3d2 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3222,6 +3222,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,          Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))),                             ConvertType(E->getType())));    } +  case Builtin::BI__warn_memset_zero_len: +    return RValue::getIgnored();    case Builtin::BI__annotation: {      // Re-encode each wide string to UTF8 and make an MDString.      SmallVector<Metadata *, 1> Strings; diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 5aac7a8d54c77..60f1dba7c768a 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -111,6 +111,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {    case Decl::Empty:    case Decl::Concept:    case Decl::LifetimeExtendedTemporary: +  case Decl::RequiresExprBody:      // None of these decls require codegen support.      return; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 3f23fe11e4f58..de5c3a03fb68d 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -680,6 +680,10 @@ public:      return Builder.getInt1(E->isSatisfied());    } +  Value *VisitRequiresExpr(const RequiresExpr *E) { +    return Builder.getInt1(E->isSatisfied()); +  } +    Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {      return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue());    } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 2bf94f697e01c..648e6d9c214a8 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -820,13 +820,18 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,              llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));      } +    unsigned Count, Offset;      if (const auto *Attr = D->getAttr<PatchableFunctionEntryAttr>()) { -      // Attr->getStart is currently ignored. -      Fn->addFnAttr("patchable-function-entry", -                    std::to_string(Attr->getCount())); -    } else if (unsigned Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount) { -      Fn->addFnAttr("patchable-function-entry", -                    std::to_string(Count)); +      Count = Attr->getCount(); +      Offset = Attr->getOffset(); +    } else { +      Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount; +      Offset = CGM.getCodeGenOpts().PatchableFunctionEntryOffset; +    } +    if (Count && Offset <= Count) { +      Fn->addFnAttr("patchable-function-entry", std::to_string(Count - Offset)); +      if (Offset) +        Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset));      }    } diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index ba188f5c4083c..25aec3690f210 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -172,7 +172,7 @@ int Compilation::ExecuteCommand(const Command &C,      }      if (getDriver().CCPrintOptions) -      *OS << "[Logging clang options]"; +      *OS << "[Logging clang options]\n";      C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);    } diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp index d57c3a1cdbb89..7dab2a022d929 100644 --- a/clang/lib/Driver/Job.cpp +++ b/clang/lib/Driver/Job.cpp @@ -373,7 +373,7 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,  void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,                         CrashReportInfo *CrashInfo) const { -  OS << " (in-process)"; +  OS << " (in-process)\n";    Command::Print(OS, Terminator, Quote, CrashInfo);  } diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 3ebbd30195b31..cab97b1a601a3 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -68,8 +68,7 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args,    }    // -frtti is default, except for the PS4 CPU. -  return (Triple.isPS4CPU() || Triple.isNVPTX()) ? ToolChain::RM_Disabled -                                                 : ToolChain::RM_Enabled; +  return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled;  }  ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 9b3055413e9e6..647465863d3e3 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5077,20 +5077,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,    if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) {      StringRef S0 = A->getValue(), S = S0; -    unsigned Size, Start = 0; +    unsigned Size, Offset = 0;      if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 &&          Triple.getArch() != llvm::Triple::x86_64)        D.Diag(diag::err_drv_unsupported_opt_for_target)            << A->getAsString(Args) << TripleStr;      else if (S.consumeInteger(10, Size) ||               (!S.empty() && (!S.consume_front(",") || -                             S.consumeInteger(10, Start) || !S.empty()))) +                             S.consumeInteger(10, Offset) || !S.empty())))        D.Diag(diag::err_drv_invalid_argument_to_option)            << S0 << A->getOption().getName(); -    else if (Start) +    else if (Size < Offset)        D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument); -    else +    else {        CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size))); +      CmdArgs.push_back(Args.MakeArgString( +          "-fpatchable-function-entry-offset=" + Twine(Offset))); +    }    }    if (TC.SupportsProfiling()) { diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index f89e648948aba..da7004cf283f2 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -105,9 +105,8 @@ const char *AMDGCN::Linker::constructLLVMLinkCommand(    CmdArgs.push_back("-o");    auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-linked", "bc");    CmdArgs.push_back(OutputFileName); -  SmallString<128> ExecPath(C.getDriver().Dir); -  llvm::sys::path::append(ExecPath, "llvm-link"); -  const char *Exec = Args.MakeArgString(ExecPath); +  const char *Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));    C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));    return OutputFileName;  } @@ -133,9 +132,8 @@ const char *AMDGCN::Linker::constructOptCommand(    auto OutputFileName =        getOutputFileName(C, OutputFilePrefix, "-optimized", "bc");    OptArgs.push_back(OutputFileName); -  SmallString<128> OptPath(C.getDriver().Dir); -  llvm::sys::path::append(OptPath, "opt"); -  const char *OptExec = Args.MakeArgString(OptPath); +  const char *OptExec = +      Args.MakeArgString(getToolChain().GetProgramPath("opt"));    C.addCommand(std::make_unique<Command>(JA, *this, OptExec, OptArgs, Inputs));    return OutputFileName;  } @@ -180,9 +178,7 @@ const char *AMDGCN::Linker::constructLlcCommand(    auto LlcOutputFile =        getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o");    LlcArgs.push_back(LlcOutputFile); -  SmallString<128> LlcPath(C.getDriver().Dir); -  llvm::sys::path::append(LlcPath, "llc"); -  const char *Llc = Args.MakeArgString(LlcPath); +  const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc"));    C.addCommand(std::make_unique<Command>(JA, *this, Llc, LlcArgs, Inputs));    return LlcOutputFile;  } @@ -196,9 +192,7 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,    // The output from ld.lld is an HSA code object file.    ArgStringList LldArgs{        "-flavor", "gnu", "-shared", "-o", Output.getFilename(), InputFileName}; -  SmallString<128> LldPath(C.getDriver().Dir); -  llvm::sys::path::append(LldPath, "lld"); -  const char *Lld = Args.MakeArgString(LldPath); +  const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));    C.addCommand(std::make_unique<Command>(JA, *this, Lld, LldArgs, Inputs));  } @@ -230,9 +224,8 @@ void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,        Args.MakeArgString(std::string("-outputs=").append(OutputFileName));    BundlerArgs.push_back(BundlerOutputArg); -  SmallString<128> BundlerPath(C.getDriver().Dir); -  llvm::sys::path::append(BundlerPath, "clang-offload-bundler"); -  const char *Bundler = Args.MakeArgString(BundlerPath); +  const char *Bundler = Args.MakeArgString( +      T.getToolChain().GetProgramPath("clang-offload-bundler"));    C.addCommand(std::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs));  } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index d5d394e61926a..88564e02f23ed 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2596,7 +2596,7 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const {  /// otherwise.  static bool isKeywordWithCondition(const FormatToken &Tok) {    return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, -                     tok::kw_constexpr); +                     tok::kw_constexpr, tok::kw_catch);  }  bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index e1e59565083b7..4e5babdbaa038 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1103,6 +1103,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,    Opts.PatchableFunctionEntryCount =        getLastArgIntValue(Args, OPT_fpatchable_function_entry_EQ, 0, Diags); +  Opts.PatchableFunctionEntryOffset = getLastArgIntValue( +      Args, OPT_fpatchable_function_entry_offset_EQ, 0, Diags);    Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);    Opts.CallFEntry = Args.hasArg(OPT_mfentry);    Opts.MNopMCount = Args.hasArg(OPT_mnop_mcount); @@ -2852,7 +2854,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,                                                   << A->getValue();      Opts.NewAlignOverride = 0;    } -  Opts.ConceptsTS = Args.hasArg(OPT_fconcepts_ts); +  Opts.ConceptSatisfactionCaching = +      !Args.hasArg(OPT_fno_concept_satisfaction_caching); +  if (Args.hasArg(OPT_fconcepts_ts)) +    Diags.Report(diag::warn_fe_concepts_ts_flag);    Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);    Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);    Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 8574d0a7e8132..935c64a0fa13f 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -429,6 +429,10 @@ private:        return "ConstraintNormalization";      case CodeSynthesisContext::ParameterMappingSubstitution:        return "ParameterMappingSubstitution"; +    case CodeSynthesisContext::RequirementInstantiation: +      return "RequirementInstantiation"; +    case CodeSynthesisContext::NestedRequirementConstraintsCheck: +      return "NestedRequirementConstraintsCheck";      }      return "";    } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 2c7e3a56c0436..8a0ff55e44fc6 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -548,7 +548,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,    // C++20 features.    if (LangOpts.CPlusPlus2a) {      //Builder.defineMacro("__cpp_aggregate_paren_init", "201902L"); -    //Builder.defineMacro("__cpp_concepts", "201907L"); +    Builder.defineMacro("__cpp_concepts", "201907L");      Builder.defineMacro("__cpp_conditional_explicit", "201806L");      //Builder.defineMacro("__cpp_consteval", "201811L");      Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); @@ -564,8 +564,6 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,    Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");    // TS features. -  if (LangOpts.ConceptsTS) -    Builder.defineMacro("__cpp_experimental_concepts", "1L");    if (LangOpts.Coroutines)      Builder.defineMacro("__cpp_coroutines", "201703L");  } diff --git a/clang/lib/Headers/ppc_wrappers/emmintrin.h b/clang/lib/Headers/ppc_wrappers/emmintrin.h index 293276cc9be05..4dcb8485e2e9b 100644 --- a/clang/lib/Headers/ppc_wrappers/emmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/emmintrin.h @@ -1749,7 +1749,7 @@ _mm_sll_epi64 (__m128i __A, __m128i __B)    lshift = vec_splat ((__v2du) __B, 0);    shmask = vec_cmplt (lshift, shmax);    result = vec_sl ((__v2du) __A, lshift); -  result = vec_sel ((__v2du) shmask, result, shmask); +  result = (__v2du)vec_sel ((__v2df) shmask, (__v2df)result, shmask);    return (__m128i) result;  } @@ -1843,7 +1843,7 @@ _mm_srl_epi64 (__m128i __A, __m128i __B)    rshift = vec_splat ((__v2du) __B, 0);    shmask = vec_cmplt (rshift, shmax);    result = vec_sr ((__v2du) __A, rshift); -  result = vec_sel ((__v2du) shmask, result, shmask); +  result = (__v2du)vec_sel ((__v2df) shmask, (__v2df)result, shmask);    return (__m128i) result;  } diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index f8b5fec438007..a75965784168c 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -133,7 +133,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(    LexedMethod* LM = new LexedMethod(this, FnD);    getCurrentClass().LateParsedDeclarations.push_back(LM); -  LM->TemplateScope = getCurScope()->isTemplateParamScope(); +  LM->TemplateScope = getCurScope()->isTemplateParamScope() || +      (FnD && isa<FunctionTemplateDecl>(FnD) && +       cast<FunctionTemplateDecl>(FnD)->isAbbreviated());    CachedTokens &Toks = LM->Toks;    tok::TokenKind kind = Tok.getKind(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 69a3ed9cbad77..4af993c4527ff 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2962,6 +2962,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,        case Sema::NC_ContextIndependentExpr:        case Sema::NC_VarTemplate:        case Sema::NC_FunctionTemplate: +      case Sema::NC_Concept:          // Might be a redeclaration of a prior entity.          break;        } @@ -3177,7 +3178,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,               DSContext == DeclSpecContext::DSC_class) &&              TemplateId->Name &&              Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) && -            isConstructorDeclarator(/*Unqualified*/ false)) { +            isConstructorDeclarator(/*Unqualified=*/false)) {            // The user meant this to be an out-of-line constructor            // definition, but template arguments are not allowed            // there.  Just allow this as a constructor; we'll @@ -3189,7 +3190,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,          ConsumeAnnotationToken(); // The C++ scope.          assert(Tok.is(tok::annot_template_id) &&                 "ParseOptionalCXXScopeSpecifier not working"); -        AnnotateTemplateIdTokenAsType(); +        AnnotateTemplateIdTokenAsType(SS); +        continue; +      } + +      if (Next.is(tok::annot_template_id) && +          static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) +            ->Kind == TNK_Concept_template && +          GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) { +        DS.getTypeSpecScope() = SS; +        // This is a qualified placeholder-specifier, e.g., ::C<int> auto ... +        // Consume the scope annotation and continue to consume the template-id +        // as a placeholder-specifier. +        ConsumeAnnotationToken();          continue;        } @@ -3235,6 +3248,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,        // C++ doesn't have implicit int.  Diagnose it as a typo w.r.t. to the        // typename.        if (!TypeRep) { +        if (TryAnnotateTypeConstraint()) +          goto DoneWithDeclSpec; +        if (isTypeConstraintAnnotation()) +          continue;          // Eat the scope spec so the identifier is current.          ConsumeAnnotationToken();          ParsedAttributesWithRange Attrs(AttrFactory); @@ -3384,6 +3401,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,        // If this is not a typedef name, don't parse it as part of the declspec,        // it must be an implicit int or an error.        if (!TypeRep) { +        if (TryAnnotateTypeConstraint()) +          goto DoneWithDeclSpec; +        if (isTypeConstraintAnnotation()) +          continue;          ParsedAttributesWithRange Attrs(AttrFactory);          if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {            if (!Attrs.empty()) { @@ -3433,9 +3454,51 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,        continue;      } -      // type-name +      // type-name or placeholder-specifier      case tok::annot_template_id: {        TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); +      if (TemplateId->Kind == TNK_Concept_template) { +        if (NextToken().is(tok::identifier)) { +          Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto) +              << FixItHint::CreateInsertion(NextToken().getLocation(), "auto"); +          // Attempt to continue as if 'auto' was placed here. +          isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, +                                         TemplateId, Policy); +          break; +        } +        if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) +            goto DoneWithDeclSpec; +        ConsumeAnnotationToken(); +        SourceLocation AutoLoc = Tok.getLocation(); +        if (TryConsumeToken(tok::kw_decltype)) { +          BalancedDelimiterTracker Tracker(*this, tok::l_paren); +          if (Tracker.consumeOpen()) { +            // Something like `void foo(Iterator decltype i)` +            Diag(Tok, diag::err_expected) << tok::l_paren; +          } else { +            if (!TryConsumeToken(tok::kw_auto)) { +              // Something like `void foo(Iterator decltype(int) i)` +              Tracker.skipToEnd(); +              Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto) +                << FixItHint::CreateReplacement(SourceRange(AutoLoc, +                                                            Tok.getLocation()), +                                                "auto"); +            } else { +              Tracker.consumeClose(); +            } +          } +          ConsumedEnd = Tok.getLocation(); +          // Even if something went wrong above, continue as if we've seen +          // `decltype(auto)`. +          isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec, +                                         DiagID, TemplateId, Policy); +        } else { +          isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, +                                         TemplateId, Policy); +        } +        break; +      } +        if (TemplateId->Kind != TNK_Type_template &&            TemplateId->Kind != TNK_Undeclared_template) {          // This template-id does not refer to a type name, so we're @@ -3448,12 +3511,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,        // constructor declaration.        if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&            Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && -          isConstructorDeclarator(TemplateId->SS.isEmpty())) +          isConstructorDeclarator(/*Unqualified=*/true))          goto DoneWithDeclSpec;        // Turn the template-id annotation token into a type annotation        // token, then try again to parse it as a type-specifier. -      AnnotateTemplateIdTokenAsType(); +      CXXScopeSpec SS; +      AnnotateTemplateIdTokenAsType(SS);        continue;      } @@ -3617,7 +3681,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,        ConsumedEnd = ExplicitLoc;        ConsumeToken(); // kw_explicit        if (Tok.is(tok::l_paren)) { -        if (getLangOpts().CPlusPlus2a) { +        if (getLangOpts().CPlusPlus2a || isExplicitBool() == TPResult::True) { +          Diag(Tok.getLocation(), getLangOpts().CPlusPlus2a +                                      ? diag::warn_cxx17_compat_explicit_bool +                                      : diag::ext_explicit_bool); +            ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));            BalancedDelimiterTracker Tracker(*this, tok::l_paren);            Tracker.consumeOpen(); @@ -3630,8 +3698,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,                  Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());            } else              Tracker.skipToEnd(); -        } else +        } else {            Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool); +        }        }        isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,                                               ExplicitSpec, CloseParenLoc); @@ -6021,11 +6090,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {    while (1) {      if (Tok.is(tok::l_paren)) { +      bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration();        // Enter function-declaration scope, limiting any declarators to the        // function prototype scope, including parameter declarators.        ParseScope PrototypeScope(this,                                  Scope::FunctionPrototypeScope|Scope::DeclScope| -                                (D.isFunctionDeclaratorAFunctionDeclaration() +                                (IsFunctionDeclaration                                     ? Scope::FunctionDeclarationScope : 0));        // The paren may be part of a C++ direct initializer, eg. "int x(1);". @@ -6044,7 +6114,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {        ParsedAttributes attrs(AttrFactory);        BalancedDelimiterTracker T(*this, tok::l_paren);        T.consumeOpen(); +      if (IsFunctionDeclaration) +        Actions.ActOnStartFunctionDeclarationDeclarator(D, +                                                        TemplateParameterDepth);        ParseFunctionDeclarator(D, attrs, T, IsAmbiguous); +      if (IsFunctionDeclaration) +        Actions.ActOnFinishFunctionDeclarationDeclarator(D);        PrototypeScope.Exit();      } else if (Tok.is(tok::l_square)) {        ParseBracketDeclarator(D); @@ -6360,7 +6435,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,      ProhibitAttributes(FnAttrs);    } else {      if (Tok.isNot(tok::r_paren)) -      ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, +      ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo,                                        EllipsisLoc);      else if (RequiresArg)        Diag(Tok, diag::err_argument_required_after_attribute); @@ -6578,9 +6653,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList(  /// after the opening parenthesis. This function will not parse a K&R-style  /// identifier list.  /// -/// D is the declarator being parsed.  If FirstArgAttrs is non-null, then the -/// caller parsed those arguments immediately after the open paren - they should -/// be considered to be part of the first parameter. +/// DeclContext is the context of the declarator being parsed.  If FirstArgAttrs +/// is non-null, then the caller parsed those attributes immediately after the +/// open paren - they should be considered to be part of the first parameter.  ///  /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will  /// be the location of the ellipsis, if any was parsed. @@ -6606,7 +6681,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(  /// [C++11] attribute-specifier-seq parameter-declaration  ///  void Parser::ParseParameterDeclarationClause( -       Declarator &D, +       DeclaratorContext DeclaratorCtx,         ParsedAttributes &FirstArgAttrs,         SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,         SourceLocation &EllipsisLoc) { @@ -6655,9 +6730,11 @@ void Parser::ParseParameterDeclarationClause(      // "LambdaExprParameterContext", because we must accept either      // 'declarator' or 'abstract-declarator' here.      Declarator ParmDeclarator( -        DS, D.getContext() == DeclaratorContext::LambdaExprContext -                ? DeclaratorContext::LambdaExprParameterContext -                : DeclaratorContext::PrototypeContext); +        DS, DeclaratorCtx == DeclaratorContext::RequiresExprContext +                ? DeclaratorContext::RequiresExprContext +                : DeclaratorCtx == DeclaratorContext::LambdaExprContext +                      ? DeclaratorContext::LambdaExprParameterContext +                      : DeclaratorContext::PrototypeContext);      ParseDeclarator(ParmDeclarator);      // Parse GNU attributes, if present. @@ -6711,7 +6788,7 @@ void Parser::ParseParameterDeclarationClause(          SourceLocation EqualLoc = Tok.getLocation();          // Parse the default argument -        if (D.getContext() == DeclaratorContext::MemberContext) { +        if (DeclaratorCtx == DeclaratorContext::MemberContext) {            // If we're inside a class definition, cache the tokens            // corresponding to the default argument. We'll actually parse            // them when we see the end of the class definition. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 081d4d8b12092..f872aa3a950c9 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1142,7 +1142,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,      if (TemplateId->Kind == TNK_Type_template ||          TemplateId->Kind == TNK_Dependent_template_name ||          TemplateId->Kind == TNK_Undeclared_template) { -      AnnotateTemplateIdTokenAsType(/*IsClassName*/true); +      AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);        assert(Tok.is(tok::annot_typename) && "template-id -> type failed");        ParsedType Type = getTypeAnnotation(Tok); @@ -1193,7 +1193,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,                                  TemplateName))        return true;      if (TNK == TNK_Type_template || TNK == TNK_Dependent_template_name) -      AnnotateTemplateIdTokenAsType(/*IsClassName*/true); +      AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);      // If we didn't end up with a typename token, there's nothing more we      // can do. @@ -1826,7 +1826,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,                  TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {        ProhibitAttributes(attrs);        TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, -                                                  TemplateId->SS, +                                                  SS,                                                    TemplateId->TemplateKWLoc,                                                    TemplateId->Template,                                                    TemplateId->TemplateNameLoc, @@ -1876,7 +1876,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,        // Build the class template specialization.        TagOrTempResult = Actions.ActOnClassTemplateSpecialization(            getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(), -          *TemplateId, attrs, +          SS, *TemplateId, attrs,            MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]                                                  : nullptr,                                   TemplateParams ? TemplateParams->size() : 0), @@ -2642,6 +2642,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,    }    ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::MemberContext); +  if (TemplateInfo.TemplateParams) +    DeclaratorInfo.setTemplateParameterLists(TemplateParams);    VirtSpecifiers VS;    // Hold late-parsed attributes so we can attach a Decl to them later. @@ -3520,7 +3522,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {      if (TemplateId && (TemplateId->Kind == TNK_Type_template ||                         TemplateId->Kind == TNK_Dependent_template_name ||                         TemplateId->Kind == TNK_Undeclared_template)) { -      AnnotateTemplateIdTokenAsType(/*IsClassName*/true); +      AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);        assert(Tok.is(tok::annot_typename) && "template-id -> type failed");        TemplateTypeTy = getTypeAnnotation(Tok);        ConsumeAnnotationToken(); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 1442df046bb93..1eb3ad6afd1cb 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -234,7 +234,7 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {  /// \endverbatim  ExprResult Parser::ParseConstraintExpression() {    EnterExpressionEvaluationContext ConstantEvaluated( -      Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); +      Actions, Sema::ExpressionEvaluationContext::Unevaluated);    ExprResult LHS(ParseCastExpression(AnyCastExpr));    ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));    if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { @@ -256,7 +256,7 @@ ExprResult Parser::ParseConstraintExpression() {  ExprResult  Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) {    EnterExpressionEvaluationContext ConstantEvaluated( -      Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); +      Actions, Sema::ExpressionEvaluationContext::Unevaluated);    bool NotPrimaryExpression = false;    auto ParsePrimary = [&] () {      ExprResult E = ParseCastExpression(PrimaryExprOnly, @@ -756,6 +756,7 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {  /// [C++11] user-defined-literal  ///         '(' expression ')'  /// [C11]   generic-selection +/// [C++2a] requires-expression  ///         '__func__'        [C99 6.4.2.2]  /// [GNU]   '__FUNCTION__'  /// [MS]    '__FUNCDNAME__' @@ -1530,7 +1531,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,          CXXScopeSpec SS;          ParseOptionalCXXScopeSpecifier(SS, nullptr,                                         /*EnteringContext=*/false); -        AnnotateTemplateIdTokenAsType(); +        AnnotateTemplateIdTokenAsType(SS);          return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,                                     isTypeCast, isVectorLiteral,                                     NotPrimaryExpression); @@ -1548,7 +1549,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,        // We have a template-id that we know refers to a type,        // translate it into a type and continue parsing as a cast        // expression. -      AnnotateTemplateIdTokenAsType(); +      CXXScopeSpec SS; +      AnnotateTemplateIdTokenAsType(SS);        return ParseCastExpression(ParseKind, isAddressOfOperand,                                   NotCastExpr, isTypeCast, isVectorLiteral,                                   NotPrimaryExpression); @@ -1600,6 +1602,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,        *NotPrimaryExpression = true;      return ParseCXXDeleteExpression(false, Tok.getLocation()); +  case tok::kw_requires: // [C++2a] requires-expression +    return ParseRequiresExpression(); +    case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'      if (NotPrimaryExpression)        *NotPrimaryExpression = true; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index e685d5ea8a9cc..036eabb94dd7e 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -11,7 +11,9 @@  //===----------------------------------------------------------------------===//  #include "clang/Parse/Parser.h"  #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h"  #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h"  #include "clang/Basic/PrettyStackTrace.h"  #include "clang/Lex/LiteralSupport.h"  #include "clang/Parse/ParseDiagnostic.h" @@ -165,13 +167,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,      return false;    } -  if (Tok.is(tok::annot_template_id)) { -    // If the current token is an annotated template id, it may already have -    // a scope specifier. Restore it. -    TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); -    SS = TemplateId->SS; -  } -    // Has to happen before any "return false"s in this function.    bool CheckForDestructor = false;    if (MayBePseudoDestructor && *MayBePseudoDestructor) { @@ -1306,9 +1301,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(        Actions.RecordParsingTemplateParameterDepth(            CurTemplateDepthTracker.getOriginalDepth()); -      ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); - -      // For a generic lambda, each 'auto' within the parameter declaration +      ParseParameterDeclarationClause(D.getContext(), Attr, ParamInfo, +                                      EllipsisLoc); +      // For a generic lambda, each 'auto' within the parameter declaration         // clause creates a template type parameter, so increment the depth.        // If we've parsed any explicit template parameters, then the depth will        // have already been incremented. So we make sure that at most a single @@ -2405,7 +2400,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,              : Id.OperatorFunctionId.Operator;      TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( -        SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK, +        TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,          LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);      Id.setTemplateId(TemplateId); @@ -3262,6 +3257,324 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {    return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get());  } +/// ParseRequiresExpression - Parse a C++2a requires-expression. +/// C++2a [expr.prim.req]p1 +///     A requires-expression provides a concise way to express requirements on +///     template arguments. A requirement is one that can be checked by name +///     lookup (6.4) or by checking properties of types and expressions. +/// +///     requires-expression: +///         'requires' requirement-parameter-list[opt] requirement-body +/// +///     requirement-parameter-list: +///         '(' parameter-declaration-clause[opt] ')' +/// +///     requirement-body: +///         '{' requirement-seq '}' +/// +///     requirement-seq: +///         requirement +///         requirement-seq requirement +/// +///     requirement: +///         simple-requirement +///         type-requirement +///         compound-requirement +///         nested-requirement +ExprResult Parser::ParseRequiresExpression() { +  assert(Tok.is(tok::kw_requires) && "Expected 'requires' keyword"); +  SourceLocation RequiresKWLoc = ConsumeToken(); // Consume 'requires' + +  llvm::SmallVector<ParmVarDecl *, 2> LocalParameterDecls; +  if (Tok.is(tok::l_paren)) { +    // requirement parameter list is present. +    ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope | +                                    Scope::DeclScope); +    BalancedDelimiterTracker Parens(*this, tok::l_paren); +    Parens.consumeOpen(); +    if (!Tok.is(tok::r_paren)) { +      ParsedAttributes FirstArgAttrs(getAttrFactory()); +      SourceLocation EllipsisLoc; +      llvm::SmallVector<DeclaratorChunk::ParamInfo, 2> LocalParameters; +      DiagnosticErrorTrap Trap(Diags); +      ParseParameterDeclarationClause(DeclaratorContext::RequiresExprContext, +                                      FirstArgAttrs, LocalParameters, +                                      EllipsisLoc); +      if (EllipsisLoc.isValid()) +        Diag(EllipsisLoc, diag::err_requires_expr_parameter_list_ellipsis); +      for (auto &ParamInfo : LocalParameters) +        LocalParameterDecls.push_back(cast<ParmVarDecl>(ParamInfo.Param)); +      if (Trap.hasErrorOccurred()) +        SkipUntil(tok::r_paren, StopBeforeMatch); +    } +    Parens.consumeClose(); +  } + +  BalancedDelimiterTracker Braces(*this, tok::l_brace); +  if (Braces.expectAndConsume()) +    return ExprError(); + +  // Start of requirement list +  llvm::SmallVector<concepts::Requirement *, 2> Requirements; + +  // C++2a [expr.prim.req]p2 +  //   Expressions appearing within a requirement-body are unevaluated operands. +  EnterExpressionEvaluationContext Ctx( +      Actions, Sema::ExpressionEvaluationContext::Unevaluated); + +  ParseScope BodyScope(this, Scope::DeclScope); +  RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr( +      RequiresKWLoc, LocalParameterDecls, getCurScope()); + +  if (Tok.is(tok::r_brace)) { +    // Grammar does not allow an empty body. +    // requirement-body: +    //   { requirement-seq } +    // requirement-seq: +    //   requirement +    //   requirement-seq requirement +    Diag(Tok, diag::err_empty_requires_expr); +    // Continue anyway and produce a requires expr with no requirements. +  } else { +    while (!Tok.is(tok::r_brace)) { +      switch (Tok.getKind()) { +      case tok::l_brace: { +        // Compound requirement +        // C++ [expr.prim.req.compound] +        //     compound-requirement: +        //         '{' expression '}' 'noexcept'[opt] +        //             return-type-requirement[opt] ';' +        //     return-type-requirement: +        //         trailing-return-type +        //         '->' cv-qualifier-seq[opt] constrained-parameter +        //             cv-qualifier-seq[opt] abstract-declarator[opt] +        BalancedDelimiterTracker ExprBraces(*this, tok::l_brace); +        ExprBraces.consumeOpen(); +        ExprResult Expression = +            Actions.CorrectDelayedTyposInExpr(ParseExpression()); +        if (!Expression.isUsable()) { +          ExprBraces.skipToEnd(); +          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +          break; +        } +        if (ExprBraces.consumeClose()) +          ExprBraces.skipToEnd(); + +        concepts::Requirement *Req = nullptr; +        SourceLocation NoexceptLoc; +        TryConsumeToken(tok::kw_noexcept, NoexceptLoc); +        if (Tok.is(tok::semi)) { +          Req = Actions.ActOnCompoundRequirement(Expression.get(), NoexceptLoc); +          if (Req) +            Requirements.push_back(Req); +          break; +        } +        if (!TryConsumeToken(tok::arrow)) +          // User probably forgot the arrow, remind them and try to continue. +          Diag(Tok, diag::err_requires_expr_missing_arrow) +              << FixItHint::CreateInsertion(Tok.getLocation(), "->"); +        // Try to parse a 'type-constraint' +        CXXScopeSpec SS; +        if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), +                                           /*EnteringContext=*/false, +                                           /*MayBePseudoDestructor=*/nullptr, +                                           // If this is not a type-constraint, +                                           // then this scope-spec is part of +                                           // the typename of a non-type +                                           // template parameter +                                           /*IsTypename=*/true, +                                           /*LastII=*/nullptr, +                                           // We won't find concepts in +                                           // non-namespaces anyway, so might as +                                           // well parse this correctly for +                                           // possible type names. +                                           /*OnlyNamespace=*/false, +                                           /*SuppressDiagnostic=*/true)) { +          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +          break; +        } +        if (TryAnnotateTypeConstraint()) { +          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +          break; +        } +        if (!isTypeConstraintAnnotation()) { +          Diag(Tok, diag::err_requires_expr_expected_type_constraint); +          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +          break; +        } +        if (Tok.is(tok::annot_cxxscope)) +          ConsumeAnnotationToken(); + +        Req = Actions.ActOnCompoundRequirement( +            Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok), +            TemplateParameterDepth); +        ConsumeAnnotationToken(); +        if (Req) +          Requirements.push_back(Req); +        break; +      } +      default: { +        bool PossibleRequiresExprInSimpleRequirement = false; +        if (Tok.is(tok::kw_requires)) { +          auto IsNestedRequirement = [&] { +            RevertingTentativeParsingAction TPA(*this); +            ConsumeToken(); // 'requires' +            if (Tok.is(tok::l_brace)) +              // This is a requires expression +              // requires (T t) { +              //   requires { t++; }; +              //   ...      ^ +              // } +              return false; +            if (Tok.is(tok::l_paren)) { +              // This might be the parameter list of a requires expression +              ConsumeParen(); +              auto Res = TryParseParameterDeclarationClause(); +              if (Res != TPResult::False) { +                // Skip to the closing parenthesis +                // FIXME: Don't traverse these tokens twice (here and in +                //  TryParseParameterDeclarationClause). +                unsigned Depth = 1; +                while (Depth != 0) { +                  if (Tok.is(tok::l_paren)) +                    Depth++; +                  else if (Tok.is(tok::r_paren)) +                    Depth--; +                  ConsumeAnyToken(); +                } +                // requires (T t) { +                //   requires () ? +                //   ...         ^ +                //   - OR - +                //   requires (int x) ? +                //   ...              ^ +                // } +                if (Tok.is(tok::l_brace)) +                  // requires (...) { +                  //                ^ - a requires expression as a +                  //                    simple-requirement. +                  return false; +              } +            } +            return true; +          }; +          if (IsNestedRequirement()) { +            ConsumeToken(); +            // Nested requirement +            // C++ [expr.prim.req.nested] +            //     nested-requirement: +            //         'requires' constraint-expression ';' +            ExprResult ConstraintExpr = +                Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); +            if (ConstraintExpr.isInvalid() || !ConstraintExpr.isUsable()) { +              SkipUntil(tok::semi, tok::r_brace, +                        SkipUntilFlags::StopBeforeMatch); +              break; +            } +            if (auto *Req = +                    Actions.ActOnNestedRequirement(ConstraintExpr.get())) +              Requirements.push_back(Req); +            else { +              SkipUntil(tok::semi, tok::r_brace, +                        SkipUntilFlags::StopBeforeMatch); +              break; +            } +            break; +          } else +            PossibleRequiresExprInSimpleRequirement = true; +        } else if (Tok.is(tok::kw_typename)) { +          // This might be 'typename T::value_type;' (a type requirement) or +          // 'typename T::value_type{};' (a simple requirement). +          TentativeParsingAction TPA(*this); + +          // We need to consume the typename to allow 'requires { typename a; }' +          SourceLocation TypenameKWLoc = ConsumeToken(); +          if (TryAnnotateCXXScopeToken()) { +            SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +            break; +          } +          CXXScopeSpec SS; +          if (Tok.is(tok::annot_cxxscope)) { +            Actions.RestoreNestedNameSpecifierAnnotation( +                Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); +            ConsumeAnnotationToken(); +          } + +          if (Tok.isOneOf(tok::identifier, tok::annot_template_id) && +              !NextToken().isOneOf(tok::l_brace, tok::l_paren)) { +            TPA.Commit(); +            SourceLocation NameLoc = Tok.getLocation(); +            IdentifierInfo *II = nullptr; +            TemplateIdAnnotation *TemplateId = nullptr; +            if (Tok.is(tok::identifier)) { +              II = Tok.getIdentifierInfo(); +              ConsumeToken(); +            } else { +              TemplateId = takeTemplateIdAnnotation(Tok); +              ConsumeAnnotationToken(); +            } + +            if (auto *Req = Actions.ActOnTypeRequirement(TypenameKWLoc, SS, +                                                         NameLoc, II, +                                                         TemplateId)) { +              Requirements.push_back(Req); +            } +            break; +          } +          TPA.Revert(); +        } +        // Simple requirement +        // C++ [expr.prim.req.simple] +        //     simple-requirement: +        //         expression ';' +        SourceLocation StartLoc = Tok.getLocation(); +        ExprResult Expression = +            Actions.CorrectDelayedTyposInExpr(ParseExpression()); +        if (!Expression.isUsable()) { +          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +          break; +        } +        if (!Expression.isInvalid() && PossibleRequiresExprInSimpleRequirement) +          Diag(StartLoc, diag::warn_requires_expr_in_simple_requirement) +              << FixItHint::CreateInsertion(StartLoc, "requires"); +        if (auto *Req = Actions.ActOnSimpleRequirement(Expression.get())) +          Requirements.push_back(Req); +        else { +          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +          break; +        } +        // User may have tried to put some compound requirement stuff here +        if (Tok.is(tok::kw_noexcept)) { +          Diag(Tok, diag::err_requires_expr_simple_requirement_noexcept) +              << FixItHint::CreateInsertion(StartLoc, "{") +              << FixItHint::CreateInsertion(Tok.getLocation(), "}"); +          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +          break; +        } +        break; +      } +      } +      if (ExpectAndConsumeSemi(diag::err_expected_semi_requirement)) { +        SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); +        TryConsumeToken(tok::semi); +        break; +      } +    } +    if (Requirements.empty()) { +      // Don't emit an empty requires expr here to avoid confusing the user with +      // other diagnostics quoting an empty requires expression they never +      // wrote. +      Braces.consumeClose(); +      Actions.ActOnFinishRequiresExpr(); +      return ExprError(); +    } +  } +  Braces.consumeClose(); +  Actions.ActOnFinishRequiresExpr(); +  return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls, +                                   Requirements, Braces.getCloseLocation()); +} +  static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) {    switch (kind) {    default: llvm_unreachable("Not a known type trait"); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 1b9301b6591dc..3bc4e3596f120 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -240,6 +240,8 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(    // Parse the declarator.    ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); +  if (TemplateInfo.TemplateParams) +    DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);    ParseDeclarator(DeclaratorInfo);    // Error parsing the declarator?    if (!DeclaratorInfo.hasName()) { @@ -499,10 +501,7 @@ Parser::ParseTemplateParameterList(const unsigned Depth,  /// Determine whether the parser is at the start of a template  /// type parameter. -/// \param ScopeError will receive true if there was an error parsing a -/// scope specifier at the current location. -bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { -  ScopeError = false; +Parser::TPResult Parser::isStartOfTemplateTypeParameter() {    if (Tok.is(tok::kw_class)) {      // "class" may be the start of an elaborated-type-specifier or a      // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter. @@ -512,7 +511,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {      case tok::greater:      case tok::greatergreater:      case tok::ellipsis: -      return true; +      return TPResult::True;      case tok::identifier:        // This may be either a type-parameter or an elaborated-type-specifier. @@ -520,7 +519,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {        break;      default: -      return false; +      return TPResult::False;      }      switch (GetLookAheadToken(2).getKind()) { @@ -528,51 +527,28 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {      case tok::comma:      case tok::greater:      case tok::greatergreater: -      return true; +      return TPResult::True;      default: -      return false; +      return TPResult::False;      }    } -  bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); -  CXXScopeSpec SS; -  ScopeError = -      ParseOptionalCXXScopeSpecifier(SS, ParsedType(), -                                     /*EnteringContext=*/false, -                                     /*MayBePseudoDestructor=*/nullptr, -                                     // If this is not a type-constraint, then -                                     // this scope-spec is part of the typename -                                     // of a non-type template parameter -                                     /*IsTypename=*/true, /*LastII=*/nullptr, -                                     // We won't find concepts in -                                     // non-namespaces anyway, so might as well -                                     // parse this correctly for possible type -                                     // names. -                                     /*OnlyNamespace=*/false); -  if (ScopeError) -    return false; -  if (TryAnnotateTypeConstraint(SS)) -    return false; -  bool IsTypeConstraint = isTypeConstraintAnnotation(); -  if (!IsTypeConstraint && SS.isNotEmpty()) { -    // This isn't a type-constraint but we've already parsed this scope -    // specifier - annotate it. -    AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation); -    return false; -  } +  if (TryAnnotateTypeConstraint()) +    return TPResult::Error; -  if (IsTypeConstraint && +  if (isTypeConstraintAnnotation() &&        // Next token might be 'auto' or 'decltype', indicating that this        // type-constraint is in fact part of a placeholder-type-specifier of a        // non-type template parameter. -      !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) -    return true; +      !GetLookAheadToken(Tok.is(tok::annot_cxxscope) ? 2 : 1) +           .isOneOf(tok::kw_auto, tok::kw_decltype)) +    return TPResult::True;    // 'typedef' is a reasonably-common typo/thinko for 'typename', and is    // ill-formed otherwise.    if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef)) -    return false; +    return TPResult::False;    // C++ [temp.param]p2:    //   There is no semantic difference between class and typename in a @@ -592,17 +568,17 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {    case tok::greater:    case tok::greatergreater:    case tok::ellipsis: -    return true; +    return TPResult::True;    case tok::kw_typename:    case tok::kw_typedef:    case tok::kw_class:      // These indicate that a comma was missed after a type parameter, not that      // we have found a non-type parameter. -    return true; +    return TPResult::True;    default: -    return false; +    return TPResult::False;    }  } @@ -627,13 +603,9 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {  ///         typename  ///  NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { -  // We could be facing a type-constraint, which (could) start a type parameter. -  // Annotate it now (we might end up not using it if we determine this -  // type-constraint is in fact part of a placeholder-type-specifier of a -  // non-type template parameter. -  bool ScopeError; -  if (isStartOfTemplateTypeParameter(ScopeError)) { +  switch (isStartOfTemplateTypeParameter()) { +  case TPResult::True:      // Is there just a typo in the input code? ('typedef' instead of      // 'typename')      if (Tok.is(tok::kw_typedef)) { @@ -649,8 +621,10 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {      }      return ParseTypeParameter(Depth, Position); -  } -  if (ScopeError) { +  case TPResult::False: +    break; + +  case TPResult::Error: {      // We return an invalid parameter as opposed to null to avoid having bogus      // diagnostics about an empty template parameter list.      // FIXME: Fix ParseTemplateParameterList to better handle nullptr results @@ -670,6 +644,11 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {                StopAtSemi | StopBeforeMatch);      return ErrorParam;    } + +  case TPResult::Ambiguous: +    llvm_unreachable("template param classification can't be ambiguous"); +  } +    if (Tok.is(tok::kw_template))      return ParseTemplateTemplateParameter(Depth, Position); @@ -682,15 +661,15 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {  /// Check whether the current token is a template-id annotation denoting a  /// type-constraint.  bool Parser::isTypeConstraintAnnotation() { -  if (Tok.isNot(tok::annot_template_id)) +  const Token &T = Tok.is(tok::annot_cxxscope) ? NextToken() : Tok; +  if (T.isNot(tok::annot_template_id))      return false;    const auto *ExistingAnnot = -      static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); +      static_cast<TemplateIdAnnotation *>(T.getAnnotationValue());    return ExistingAnnot->Kind == TNK_Concept_template;  } -/// Try parsing a type-constraint construct at the current location, after the -/// optional scope specifier. +/// Try parsing a type-constraint at the current location.  ///  ///     type-constraint:  ///       nested-name-specifier[opt] concept-name @@ -698,35 +677,61 @@ bool Parser::isTypeConstraintAnnotation() {  ///           '<' template-argument-list[opt] '>'[opt]  ///  /// \returns true if an error occurred, and false otherwise. -bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) { -  if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier)) +bool Parser::TryAnnotateTypeConstraint() { +  if (!getLangOpts().CPlusPlus2a)      return false; +  CXXScopeSpec SS; +  bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); +  if (ParseOptionalCXXScopeSpecifier( +          SS, ParsedType(), +          /*EnteringContext=*/false, +          /*MayBePseudoDestructor=*/nullptr, +          // If this is not a type-constraint, then +          // this scope-spec is part of the typename +          // of a non-type template parameter +          /*IsTypename=*/true, /*LastII=*/nullptr, +          // We won't find concepts in +          // non-namespaces anyway, so might as well +          // parse this correctly for possible type +          // names. +          /*OnlyNamespace=*/false)) +    return true; -  UnqualifiedId PossibleConceptName; -  PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(), -                                    Tok.getLocation()); - -  TemplateTy PossibleConcept; -  bool MemberOfUnknownSpecialization = false; -  auto TNK = Actions.isTemplateName(getCurScope(), SS, -                                    /*hasTemplateKeyword=*/false, -                                    PossibleConceptName, -                                    /*ObjectType=*/ParsedType(), -                                    /*EnteringContext=*/false, -                                    PossibleConcept, -                                    MemberOfUnknownSpecialization); -  assert(!MemberOfUnknownSpecialization -         && "Member when we only allowed namespace scope qualifiers??"); -  if (!PossibleConcept || TNK != TNK_Concept_template) -    return false; +  if (Tok.is(tok::identifier)) { +    UnqualifiedId PossibleConceptName; +    PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(), +                                      Tok.getLocation()); + +    TemplateTy PossibleConcept; +    bool MemberOfUnknownSpecialization = false; +    auto TNK = Actions.isTemplateName(getCurScope(), SS, +                                      /*hasTemplateKeyword=*/false, +                                      PossibleConceptName, +                                      /*ObjectType=*/ParsedType(), +                                      /*EnteringContext=*/false, +                                      PossibleConcept, +                                      MemberOfUnknownSpecialization); +    if (MemberOfUnknownSpecialization || !PossibleConcept || +        TNK != TNK_Concept_template) { +      if (SS.isNotEmpty()) +        AnnotateScopeToken(SS, !WasScopeAnnotation); +      return false; +    } -  // At this point we're sure we're dealing with a constrained parameter. It -  // may or may not have a template parameter list following the concept name. -  return AnnotateTemplateIdToken(PossibleConcept, TNK, SS, -                                 /*TemplateKWLoc=*/SourceLocation(), -                                 PossibleConceptName, -                                 /*AllowTypeAnnotation=*/false, -                                 /*TypeConstraint=*/true); +    // At this point we're sure we're dealing with a constrained parameter. It +    // may or may not have a template parameter list following the concept +    // name. +    if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS, +                                   /*TemplateKWLoc=*/SourceLocation(), +                                   PossibleConceptName, +                                   /*AllowTypeAnnotation=*/false, +                                   /*TypeConstraint=*/true)) +      return true; +  } + +  if (SS.isNotEmpty()) +    AnnotateScopeToken(SS, !WasScopeAnnotation); +  return false;  }  /// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]). @@ -739,13 +744,17 @@ bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {  ///         'typename' ...[opt][C++0x] identifier[opt]  ///         'typename' identifier[opt] '=' type-id  NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { -  assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) && +  assert((Tok.isOneOf(tok::kw_class, tok::kw_typename) || +          isTypeConstraintAnnotation()) &&           "A type-parameter starts with 'class', 'typename' or a "           "type-constraint"); +  CXXScopeSpec TypeConstraintSS;    TemplateIdAnnotation *TypeConstraint = nullptr;    bool TypenameKeyword = false;    SourceLocation KeyLoc; +  ParseOptionalCXXScopeSpecifier(TypeConstraintSS, nullptr, +                                 /*EnteringContext*/ false);    if (Tok.is(tok::annot_template_id)) {      // Consume the 'type-constraint'.      TypeConstraint = @@ -754,6 +763,9 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {             "stray non-concept template-id annotation");      KeyLoc = ConsumeAnnotationToken();    } else { +    assert(TypeConstraintSS.isEmpty() && +           "expected type constraint after scope specifier"); +      // Consume the 'class' or 'typename' keyword.      TypenameKeyword = Tok.is(tok::kw_typename);      KeyLoc = ConsumeToken(); @@ -795,7 +807,8 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {    ParsedType DefaultArg;    if (TryConsumeToken(tok::equal, EqualLoc))      DefaultArg = ParseTypeName(/*Range=*/nullptr, -                               DeclaratorContext::TemplateTypeArgContext).get(); +                               DeclaratorContext::TemplateTypeArgContext) +                     .get();    NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(),                                                    TypenameKeyword, EllipsisLoc, @@ -804,10 +817,11 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {                                                    DefaultArg,                                                    TypeConstraint != nullptr); -  if (TypeConstraint) -    Actions.ActOnTypeConstraint(TypeConstraint, +  if (TypeConstraint) { +    Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint,                                  cast<TemplateTypeParmDecl>(NewDecl),                                  EllipsisLoc); +  }    return NewDecl;  } @@ -1331,8 +1345,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,              : TemplateName.OperatorFunctionId.Operator;      TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( -      SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, -      LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); +        TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, +        LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);      Tok.setAnnotationValue(TemplateId);      if (TemplateKWLoc.isValid()) @@ -1357,11 +1371,14 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,  /// a type annotation token will still be created, but will have a  /// NULL type pointer to signify an error.  /// +/// \param SS The scope specifier appearing before the template-id, if any. +///  /// \param IsClassName Is this template-id appearing in a context where we  /// know it names a class, such as in an elaborated-type-specifier or  /// base-specifier? ('typename' and 'template' are unneeded and disallowed  /// in those contexts.) -void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) { +void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS, +                                           bool IsClassName) {    assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");    TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); @@ -1375,7 +1392,7 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {    TypeResult Type      = Actions.ActOnTemplateIdType(getCurScope(), -                                  TemplateId->SS, +                                  SS,                                    TemplateId->TemplateKWLoc,                                    TemplateId->Template,                                    TemplateId->Name, @@ -1388,8 +1405,8 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {    // Create the new "type" annotation token.    Tok.setKind(tok::annot_typename);    setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get()); -  if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name. -    Tok.setLocation(TemplateId->SS.getBeginLoc()); +  if (SS.isNotEmpty()) // it was a C++ qualified type name. +    Tok.setLocation(SS.getBeginLoc());    // End location stays the same    // Replace the template-id annotation token, and possible the scope-specifier diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 4d69fb4693fb8..ad0a15b0c8a6d 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -202,9 +202,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {        }      } -    if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype, -                    tok::annot_template_id) && -        TryAnnotateCXXScopeToken()) +    if (TryAnnotateOptionalCXXScopeToken())        return TPResult::Error;      if (Tok.is(tok::annot_cxxscope))        ConsumeAnnotationToken(); @@ -785,9 +783,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,  Parser::TPResult Parser::TryParsePtrOperatorSeq() {    while (true) { -    if (Tok.isOneOf(tok::coloncolon, tok::identifier)) -      if (TryAnnotateCXXScopeToken(true)) -        return TPResult::Error; +    if (TryAnnotateOptionalCXXScopeToken(true)) +      return TPResult::Error;      if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) ||          (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { @@ -1316,6 +1313,18 @@ public:  Parser::TPResult  Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,                                    bool *InvalidAsDeclSpec) { +  auto IsPlaceholderSpecifier = [&] (TemplateIdAnnotation *TemplateId, +                                     int Lookahead) { +    // We have a placeholder-constraint (we check for 'auto' or 'decltype' to +    // distinguish 'C<int>;' from 'C<int> auto c = 1;') +    return TemplateId->Kind == TNK_Concept_template && +        GetLookAheadToken(Lookahead + 1).isOneOf(tok::kw_auto, tok::kw_decltype, +            // If we have an identifier here, the user probably forgot the +            // 'auto' in the placeholder constraint, e.g. 'C<int> x = 2;' +            // This will be diagnosed nicely later, so disambiguate as a +            // declaration. +            tok::identifier); +  };    switch (Tok.getKind()) {    case tok::identifier: {      // Check for need to substitute AltiVec __vector keyword @@ -1519,10 +1528,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,        *InvalidAsDeclSpec = NextToken().is(tok::l_paren);        return TPResult::Ambiguous;      } +    if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/0)) +      return TPResult::True;      if (TemplateId->Kind != TNK_Type_template)        return TPResult::False;      CXXScopeSpec SS; -    AnnotateTemplateIdTokenAsType(); +    AnnotateTemplateIdTokenAsType(SS);      assert(Tok.is(tok::annot_typename));      goto case_typename;    } @@ -1532,6 +1543,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,      if (TryAnnotateTypeOrScopeToken())        return TPResult::Error;      if (!Tok.is(tok::annot_typename)) { +      if (Tok.is(tok::annot_cxxscope) && +          NextToken().is(tok::annot_template_id)) { +        TemplateIdAnnotation *TemplateId = +            takeTemplateIdAnnotation(NextToken()); +        if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1)) +          return TPResult::True; +      }        // If the next token is an identifier or a type qualifier, then this        // can't possibly be a valid expression either.        if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { @@ -2137,3 +2155,58 @@ Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) {      return TPResult::Ambiguous;    return TPResult::False;  } + +/// Determine whether we might be looking at the '(' of a C++20 explicit(bool) +/// in an earlier language mode. +Parser::TPResult Parser::isExplicitBool() { +  assert(Tok.is(tok::l_paren) && "expected to be looking at a '(' token"); + +  RevertingTentativeParsingAction PA(*this); +  ConsumeParen(); + +  // We can only have 'explicit' on a constructor, conversion function, or +  // deduction guide. The declarator of a deduction guide cannot be +  // parenthesized, so we know this isn't a deduction guide. So the only +  // thing we need to check for is some number of parens followed by either +  // the current class name or 'operator'. +  while (Tok.is(tok::l_paren)) +    ConsumeParen(); + +  if (TryAnnotateOptionalCXXScopeToken()) +    return TPResult::Error; + +  // Class-scope constructor and conversion function names can't really be +  // qualified, but we get better diagnostics if we assume they can be. +  CXXScopeSpec SS; +  if (Tok.is(tok::annot_cxxscope)) { +    Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), +                                                 Tok.getAnnotationRange(), +                                                 SS); +    ConsumeAnnotationToken(); +  } + +  // 'explicit(operator' might be explicit(bool) or the declaration of a +  // conversion function, but it's probably a conversion function. +  if (Tok.is(tok::kw_operator)) +    return TPResult::Ambiguous; + +  // If this can't be a constructor name, it can only be explicit(bool). +  if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) +    return TPResult::True; +  if (!Actions.isCurrentClassName(Tok.is(tok::identifier) +                                      ? *Tok.getIdentifierInfo() +                                      : *takeTemplateIdAnnotation(Tok)->Name, +                                  getCurScope(), &SS)) +    return TPResult::True; +  // Formally, we must have a right-paren after the constructor name to match +  // the grammar for a constructor. But clang permits a parenthesized +  // constructor declarator, so also allow a constructor declarator to follow +  // with no ')' token after the constructor name. +  if (!NextToken().is(tok::r_paren) && +      !isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(), +                               /*DeductionGuide=*/false)) +    return TPResult::True; + +  // Might be explicit(bool) or a parenthesized constructor name. +  return TPResult::Ambiguous; +} diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 4249de361b89e..0b778bd242776 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1136,6 +1136,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,    // Poison SEH identifiers so they are flagged as illegal in function bodies.    PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);    const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); +  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);    // If this is C90 and the declspecs were completely missing, fudge in an    // implicit int.  We do this here because this is the only place where @@ -1262,6 +1263,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,    // safe because we're always the sole owner.    D.getMutableDeclSpec().abort(); +  // With abbreviated function templates - we need to explicitly add depth to +  // account for the implicit template parameter list induced by the template. +  if (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res)) +    if (Template->isAbbreviated() && +        Template->getTemplateParameters()->getParam(0)->isImplicit()) +      // First template parameter is implicit - meaning no explicit template +      // parameter list was specified. +      CurTemplateDepthTracker.addDepth(1); +    if (TryConsumeToken(tok::equal)) {      assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); @@ -1732,6 +1742,20 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {        return ANK_Error;      return ANK_Success;    } +  case Sema::NC_Concept: { +    UnqualifiedId Id; +    Id.setIdentifier(Name, NameLoc); +    if (Next.is(tok::less)) +      // We have a concept name followed by '<'. Consume the identifier token so +      // we reach the '<' and annotate it. +      ConsumeToken(); +    if (AnnotateTemplateIdToken( +            TemplateTy::make(Classification.getTemplateName()), +            Classification.getTemplateNameKind(), SS, SourceLocation(), Id, +            /*AllowTypeAnnotation=*/false, /*TypeConstraint=*/true)) +      return ANK_Error; +    return ANK_Success; +  }    }    // Unable to classify the name, but maybe we can annotate a scope specifier. @@ -1810,7 +1834,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {                                         /*EnteringContext=*/false, nullptr,                                         /*IsTypename*/ true))        return true; -    if (!SS.isSet()) { +    if (SS.isEmpty()) {        if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) ||            Tok.is(tok::annot_decltype)) {          // Attempt to recover by skipping the invalid 'typename' @@ -1983,7 +2007,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,        // template-id annotation in a context where we weren't allowed        // to produce a type annotation token. Update the template-id        // annotation token to a type annotation token now. -      AnnotateTemplateIdTokenAsType(); +      AnnotateTemplateIdTokenAsType(SS);        return false;      }    } @@ -2005,10 +2029,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,  bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {    assert(getLangOpts().CPlusPlus &&           "Call sites of this function should be guarded by checking for C++"); -  assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || -          (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) || -          Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)) && -         "Cannot be a type or scope token!"); +  assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!");    CXXScopeSpec SS;    if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext)) diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 639231c87232a..94d87974624e1 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -784,6 +784,15 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,    return false;  } +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, +                               unsigned &DiagID, TemplateIdAnnotation *Rep, +                               const PrintingPolicy &Policy) { +  assert(T == TST_auto || T == TST_decltype_auto); +  ConstrainedAuto = true; +  TemplateIdRep = Rep; +  return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Policy); +} +  bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,                                 const char *&PrevSpec,                                 unsigned &DiagID, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 2cd158a8b43c1..9cfce5a63b1df 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -52,6 +52,21 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {  ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } +IdentifierInfo * +Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, +                                                 unsigned int Index) { +  std::string InventedName; +  llvm::raw_string_ostream OS(InventedName); + +  if (!ParamName) +    OS << "auto:" << Index + 1; +  else +    OS << ParamName->getName() << ":auto"; + +  OS.flush(); +  return &Context.Idents.get(OS.str()); +} +  PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,                                         const Preprocessor &PP) {    PrintingPolicy Policy = Context.getPrintingPolicy(); @@ -153,10 +168,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,        TUKind(TUKind), NumSFINAEErrors(0),        FullyCheckedComparisonCategories(            static_cast<unsigned>(ComparisonCategoryType::Last) + 1), -      AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), -      NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), -      CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), -      TyposCorrected(0), AnalysisWarnings(*this), +      SatisfactionCache(Context), AccessCheckingSFINAE(false), +      InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), +      ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr), +      DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),        ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),        CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {    TUScope = nullptr; @@ -379,6 +394,14 @@ Sema::~Sema() {    if (isMultiplexExternalSource)      delete ExternalSource; +  // Delete cached satisfactions. +  std::vector<ConstraintSatisfaction *> Satisfactions; +  Satisfactions.reserve(Satisfactions.size()); +  for (auto &Node : SatisfactionCache) +    Satisfactions.push_back(&Node); +  for (auto *Node : Satisfactions) +    delete Node; +    threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);    // Destroys data sharing attributes stack for OpenMP @@ -1261,7 +1284,8 @@ DeclContext *Sema::getFunctionLevelDeclContext() {    DeclContext *DC = CurContext;    while (true) { -    if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) { +    if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC) || +        isa<RequiresExprBodyDecl>(DC)) {        DC = DC->getParent();      } else if (isa<CXXMethodDecl>(DC) &&                 cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 018ac2d7dc9d1..81601b09ce0d6 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -17,7 +17,10 @@  #include "clang/Sema/SemaDiagnostic.h"  #include "clang/Sema/TemplateDeduction.h"  #include "clang/Sema/Template.h" -#include "clang/AST/ExprCXX.h" +#include "clang/Sema/Overload.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/AST/ExprConcepts.h"  #include "clang/AST/RecursiveASTVisitor.h"  #include "clang/Basic/OperatorPrecedence.h"  #include "llvm/ADT/DenseMap.h" @@ -269,36 +272,56 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,    return false;  } -bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template, -                                       ArrayRef<const Expr *> ConstraintExprs, -                                       ArrayRef<TemplateArgument> TemplateArgs, -                                       SourceRange TemplateIDRange, -                                       ConstraintSatisfaction &Satisfaction) { -  return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, -                                       TemplateArgs, TemplateIDRange, -                                       Satisfaction); -} +bool Sema::CheckConstraintSatisfaction( +    NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, +    ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange, +    ConstraintSatisfaction &OutSatisfaction) { +  if (ConstraintExprs.empty()) { +    OutSatisfaction.IsSatisfied = true; +    return false; +  } -bool -Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part, -                                  ArrayRef<const Expr *> ConstraintExprs, -                                  ArrayRef<TemplateArgument> TemplateArgs, -                                  SourceRange TemplateIDRange, -                                  ConstraintSatisfaction &Satisfaction) { -  return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs, -                                       TemplateArgs, TemplateIDRange, -                                       Satisfaction); -} +  llvm::FoldingSetNodeID ID; +  void *InsertPos; +  ConstraintSatisfaction *Satisfaction = nullptr; +  if (LangOpts.ConceptSatisfactionCaching) { +    ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs); +    Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos); +    if (Satisfaction) { +      OutSatisfaction = *Satisfaction; +      return false; +    } +    Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs); +  } else { +    Satisfaction = &OutSatisfaction; +  } +  bool Failed; +  if (auto *T = dyn_cast<TemplateDecl>(Template)) +    Failed = ::CheckConstraintSatisfaction(*this, T, ConstraintExprs, +                                           TemplateArgs, TemplateIDRange, +                                           *Satisfaction); +  else if (auto *P = +               dyn_cast<ClassTemplatePartialSpecializationDecl>(Template)) +    Failed = ::CheckConstraintSatisfaction(*this, P, ConstraintExprs, +                                           TemplateArgs, TemplateIDRange, +                                           *Satisfaction); +  else +    Failed = ::CheckConstraintSatisfaction( +        *this, cast<VarTemplatePartialSpecializationDecl>(Template), +        ConstraintExprs, TemplateArgs, TemplateIDRange, *Satisfaction); +  if (Failed) { +    if (LangOpts.ConceptSatisfactionCaching) +      delete Satisfaction; +    return true; +  } -bool -Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial, -                                  ArrayRef<const Expr *> ConstraintExprs, -                                  ArrayRef<TemplateArgument> TemplateArgs, -                                  SourceRange TemplateIDRange, -                                  ConstraintSatisfaction &Satisfaction) { -  return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs, -                                       TemplateArgs, TemplateIDRange, -                                       Satisfaction); +  if (LangOpts.ConceptSatisfactionCaching) { +    // We cannot use InsertNode here because CheckConstraintSatisfaction might +    // have invalidated it. +    SatisfactionCache.InsertNode(Satisfaction); +    OutSatisfaction = *Satisfaction; +  } +  return false;  }  bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, @@ -336,6 +359,118 @@ bool Sema::EnsureTemplateArgumentListConstraints(    return false;  } +static void diagnoseUnsatisfiedRequirement(Sema &S, +                                           concepts::ExprRequirement *Req, +                                           bool First) { +  assert(!Req->isSatisfied() +         && "Diagnose() can only be used on an unsatisfied requirement"); +  switch (Req->getSatisfactionStatus()) { +    case concepts::ExprRequirement::SS_Dependent: +      llvm_unreachable("Diagnosing a dependent requirement"); +      break; +    case concepts::ExprRequirement::SS_ExprSubstitutionFailure: { +      auto *SubstDiag = Req->getExprSubstitutionDiagnostic(); +      if (!SubstDiag->DiagMessage.empty()) +        S.Diag(SubstDiag->DiagLoc, +               diag::note_expr_requirement_expr_substitution_error) +               << (int)First << SubstDiag->SubstitutedEntity +               << SubstDiag->DiagMessage; +      else +        S.Diag(SubstDiag->DiagLoc, +               diag::note_expr_requirement_expr_unknown_substitution_error) +            << (int)First << SubstDiag->SubstitutedEntity; +      break; +    } +    case concepts::ExprRequirement::SS_NoexceptNotMet: +      S.Diag(Req->getNoexceptLoc(), +             diag::note_expr_requirement_noexcept_not_met) +          << (int)First << Req->getExpr(); +      break; +    case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: { +      auto *SubstDiag = +          Req->getReturnTypeRequirement().getSubstitutionDiagnostic(); +      if (!SubstDiag->DiagMessage.empty()) +        S.Diag(SubstDiag->DiagLoc, +               diag::note_expr_requirement_type_requirement_substitution_error) +            << (int)First << SubstDiag->SubstitutedEntity +            << SubstDiag->DiagMessage; +      else +        S.Diag(SubstDiag->DiagLoc, +               diag::note_expr_requirement_type_requirement_unknown_substitution_error) +            << (int)First << SubstDiag->SubstitutedEntity; +      break; +    } +    case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: { +      ConceptSpecializationExpr *ConstraintExpr = +          Req->getReturnTypeRequirementSubstitutedConstraintExpr(); +      if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1) +        // A simple case - expr type is the type being constrained and the concept +        // was not provided arguments. +        S.Diag(ConstraintExpr->getBeginLoc(), +               diag::note_expr_requirement_constraints_not_satisfied_simple) +            << (int)First << S.BuildDecltypeType(Req->getExpr(), +                                                 Req->getExpr()->getBeginLoc()) +            << ConstraintExpr->getNamedConcept(); +      else +        S.Diag(ConstraintExpr->getBeginLoc(), +               diag::note_expr_requirement_constraints_not_satisfied) +            << (int)First << ConstraintExpr; +      S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction()); +      break; +    } +    case concepts::ExprRequirement::SS_Satisfied: +      llvm_unreachable("We checked this above"); +  } +} + +static void diagnoseUnsatisfiedRequirement(Sema &S, +                                           concepts::TypeRequirement *Req, +                                           bool First) { +  assert(!Req->isSatisfied() +         && "Diagnose() can only be used on an unsatisfied requirement"); +  switch (Req->getSatisfactionStatus()) { +  case concepts::TypeRequirement::SS_Dependent: +    llvm_unreachable("Diagnosing a dependent requirement"); +    return; +  case concepts::TypeRequirement::SS_SubstitutionFailure: { +    auto *SubstDiag = Req->getSubstitutionDiagnostic(); +    if (!SubstDiag->DiagMessage.empty()) +      S.Diag(SubstDiag->DiagLoc, +             diag::note_type_requirement_substitution_error) << (int)First +          << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage; +    else +      S.Diag(SubstDiag->DiagLoc, +             diag::note_type_requirement_unknown_substitution_error) +          << (int)First << SubstDiag->SubstitutedEntity; +    return; +  } +  default: +    llvm_unreachable("Unknown satisfaction status"); +    return; +  } +} + +static void diagnoseUnsatisfiedRequirement(Sema &S, +                                           concepts::NestedRequirement *Req, +                                           bool First) { +  if (Req->isSubstitutionFailure()) { +    concepts::Requirement::SubstitutionDiagnostic *SubstDiag = +        Req->getSubstitutionDiagnostic(); +    if (!SubstDiag->DiagMessage.empty()) +      S.Diag(SubstDiag->DiagLoc, +             diag::note_nested_requirement_substitution_error) +             << (int)First << SubstDiag->SubstitutedEntity +             << SubstDiag->DiagMessage; +    else +      S.Diag(SubstDiag->DiagLoc, +             diag::note_nested_requirement_unknown_substitution_error) +          << (int)First << SubstDiag->SubstitutedEntity; +    return; +  } +  S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First); +} + +  static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,                                                          Expr *SubstExpr,                                                          bool First = true) { @@ -412,6 +547,19 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,      }      S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());      return; +  } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) { +    for (concepts::Requirement *Req : RE->getRequirements()) +      if (!Req->isDependent() && !Req->isSatisfied()) { +        if (auto *E = dyn_cast<concepts::ExprRequirement>(Req)) +          diagnoseUnsatisfiedRequirement(S, E, First); +        else if (auto *T = dyn_cast<concepts::TypeRequirement>(Req)) +          diagnoseUnsatisfiedRequirement(S, T, First); +        else +          diagnoseUnsatisfiedRequirement( +              S, cast<concepts::NestedRequirement>(Req), First); +        break; +      } +    return;    }    S.Diag(SubstExpr->getSourceRange().getBegin(), @@ -434,11 +582,11 @@ static void diagnoseUnsatisfiedConstraintExpr(        Record.template get<Expr *>(), First);  } -void Sema::DiagnoseUnsatisfiedConstraint( -    const ConstraintSatisfaction& Satisfaction) { +void +Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction, +                                    bool First) {    assert(!Satisfaction.IsSatisfied &&           "Attempted to diagnose a satisfied constraint"); -  bool First = true;    for (auto &Pair : Satisfaction.Details) {      diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);      First = false; @@ -446,10 +594,10 @@ void Sema::DiagnoseUnsatisfiedConstraint(  }  void Sema::DiagnoseUnsatisfiedConstraint( -    const ASTConstraintSatisfaction &Satisfaction) { +    const ASTConstraintSatisfaction &Satisfaction, +    bool First) {    assert(!Satisfaction.IsSatisfied &&           "Attempted to diagnose a satisfied constraint"); -  bool First = true;    for (auto &Pair : Satisfaction) {      diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);      First = false; @@ -826,3 +974,67 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1,        << AmbiguousAtomic2->getSourceRange();    return true;  } + +concepts::ExprRequirement::ExprRequirement( +    Expr *E, bool IsSimple, SourceLocation NoexceptLoc, +    ReturnTypeRequirement Req, SatisfactionStatus Status, +    ConceptSpecializationExpr *SubstitutedConstraintExpr) : +    Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent, +                Status == SS_Dependent && +                (E->containsUnexpandedParameterPack() || +                 Req.containsUnexpandedParameterPack()), +                Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc), +    TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr), +    Status(Status) { +  assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && +         "Simple requirement must not have a return type requirement or a " +         "noexcept specification"); +  assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) == +         (SubstitutedConstraintExpr != nullptr)); +} + +concepts::ExprRequirement::ExprRequirement( +    SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple, +    SourceLocation NoexceptLoc, ReturnTypeRequirement Req) : +    Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(), +                Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false), +    Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req), +    Status(SS_ExprSubstitutionFailure) { +  assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && +         "Simple requirement must not have a return type requirement or a " +         "noexcept specification"); +} + +concepts::ExprRequirement::ReturnTypeRequirement:: +ReturnTypeRequirement(TemplateParameterList *TPL) : +    TypeConstraintInfo(TPL, 0) { +  assert(TPL->size() == 1); +  const TypeConstraint *TC = +      cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint(); +  assert(TC && +         "TPL must have a template type parameter with a type constraint"); +  auto *Constraint = +      cast_or_null<ConceptSpecializationExpr>( +          TC->getImmediatelyDeclaredConstraint()); +  bool Dependent = false; +  if (Constraint->getTemplateArgsAsWritten()) { +    for (auto &ArgLoc : +         Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)) { +      if (ArgLoc.getArgument().isDependent()) { +        Dependent = true; +        break; +      } +    } +  } +  TypeConstraintInfo.setInt(Dependent ? 1 : 0); +} + +concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) : +    Requirement(RK_Type, T->getType()->isDependentType(), +                T->getType()->containsUnexpandedParameterPack(), +                // We reach this ctor with either dependent types (in which +                // IsSatisfied doesn't matter) or with non-dependent type in +                // which the existence of the type indicates satisfaction. +                /*IsSatisfied=*/true +                ), Value(T), +    Status(T->getType()->isDependentType() ? SS_Dependent : SS_Satisfied) {} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 507e4a6cd4365..0bf4903365370 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10,6 +10,7 @@  //  //===----------------------------------------------------------------------===// +#include "TreeTransform.h"  #include "TypeLocBuilder.h"  #include "clang/AST/ASTConsumer.h"  #include "clang/AST/ASTContext.h" @@ -1153,6 +1154,10 @@ Corrected:      return ParsedType::make(T);    } +  if (isa<ConceptDecl>(FirstDecl)) +    return NameClassification::Concept( +        TemplateName(cast<TemplateDecl>(FirstDecl))); +    // We can have a type template here if we're classifying a template argument.    if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl) &&        !isa<VarTemplateDecl>(FirstDecl)) @@ -6468,6 +6473,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {      return true;    if (DC->isRecord())      return false; +  if (isa<RequiresExprBodyDecl>(DC)) +    return false;    llvm_unreachable("Unexpected context");  } @@ -8654,11 +8661,21 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {  NamedDecl*  Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,                                TypeSourceInfo *TInfo, LookupResult &Previous, -                              MultiTemplateParamsArg TemplateParamLists, +                              MultiTemplateParamsArg TemplateParamListsRef,                                bool &AddToScope) {    QualType R = TInfo->getType();    assert(R->isFunctionType()); +  SmallVector<TemplateParameterList *, 4> TemplateParamLists; +  for (TemplateParameterList *TPL : TemplateParamListsRef) +    TemplateParamLists.push_back(TPL); +  if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) { +    if (!TemplateParamLists.empty() && +        Invented->getDepth() == TemplateParamLists.back()->getDepth()) +      TemplateParamLists.back() = Invented; +    else +      TemplateParamLists.push_back(Invented); +  }    // TODO: consider using NameInfo for diagnostic.    DeclarationNameInfo NameInfo = GetNameForDeclarator(D); @@ -8738,15 +8755,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,      // Match up the template parameter lists with the scope specifier, then      // determine whether we have a template or a template specialization.      bool Invalid = false; -    if (TemplateParameterList *TemplateParams = -            MatchTemplateParametersToScopeSpecifier( -                D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), -                D.getCXXScopeSpec(), -                D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId -                    ? D.getName().TemplateId -                    : nullptr, -                TemplateParamLists, isFriend, isMemberSpecialization, -                Invalid)) { +    TemplateParameterList *TemplateParams = +        MatchTemplateParametersToScopeSpecifier( +            D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), +            D.getCXXScopeSpec(), +            D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId +                ? D.getName().TemplateId +                : nullptr, +            TemplateParamLists, isFriend, isMemberSpecialization, +            Invalid); +    if (TemplateParams) {        if (TemplateParams->size() > 0) {          // This is a function template @@ -8779,7 +8797,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,          // For source fidelity, store the other template param lists.          if (TemplateParamLists.size() > 1) {            NewFD->setTemplateParameterListsInfo(Context, -                                               TemplateParamLists.drop_back(1)); +              ArrayRef<TemplateParameterList *>(TemplateParamLists) +                  .drop_back(1));          }        } else {          // This is a function template specialization. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5c51b0f9b8cb7..849bc09063b37 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4924,9 +4924,9 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,      Expr *Arg = AL.getArgAsExpr(1);      if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true))        return; -    if (Offset) { +    if (Count < Offset) {        S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range) -          << &AL << 0 << 0 << Arg->getBeginLoc(); +          << &AL << 0 << Count << Arg->getBeginLoc();        return;      }    } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9916d3be77e10..9fa5691983a17 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17386,3 +17386,50 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,    return NewPD;  } + +void Sema::ActOnStartFunctionDeclarationDeclarator( +    Declarator &Declarator, unsigned TemplateParameterDepth) { +  auto &Info = InventedParameterInfos.emplace_back(); +  TemplateParameterList *ExplicitParams = nullptr; +  ArrayRef<TemplateParameterList *> ExplicitLists = +      Declarator.getTemplateParameterLists(); +  if (!ExplicitLists.empty()) { +    bool IsMemberSpecialization, IsInvalid; +    ExplicitParams = MatchTemplateParametersToScopeSpecifier( +        Declarator.getBeginLoc(), Declarator.getIdentifierLoc(), +        Declarator.getCXXScopeSpec(), /*TemplateId=*/nullptr, +        ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid, +        /*SuppressDiagnostic=*/true); +  } +  if (ExplicitParams) { +    Info.AutoTemplateParameterDepth = ExplicitParams->getDepth(); +    for (NamedDecl *Param : *ExplicitParams) +      Info.TemplateParams.push_back(Param); +    Info.NumExplicitTemplateParams = ExplicitParams->size(); +  } else { +    Info.AutoTemplateParameterDepth = TemplateParameterDepth; +    Info.NumExplicitTemplateParams = 0; +  } +} + +void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { +  auto &FSI = InventedParameterInfos.back(); +  if (FSI.TemplateParams.size() > FSI.NumExplicitTemplateParams) { +    if (FSI.NumExplicitTemplateParams != 0) { +      TemplateParameterList *ExplicitParams = +          Declarator.getTemplateParameterLists().back(); +      Declarator.setInventedTemplateParameterList( +          TemplateParameterList::Create( +              Context, ExplicitParams->getTemplateLoc(), +              ExplicitParams->getLAngleLoc(), FSI.TemplateParams, +              ExplicitParams->getRAngleLoc(), +              ExplicitParams->getRequiresClause())); +    } else { +      Declarator.setInventedTemplateParameterList( +          TemplateParameterList::Create( +              Context, SourceLocation(), SourceLocation(), FSI.TemplateParams, +              SourceLocation(), /*RequiresClause=*/nullptr)); +    } +  } +  InventedParameterInfos.pop_back(); +} diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 5aedbe7644e4b..193eaa3e01f93 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1386,6 +1386,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {    case Expr::StringLiteralClass:    case Expr::SourceLocExprClass:    case Expr::ConceptSpecializationExprClass: +  case Expr::RequiresExprClass:      // These expressions can never throw.      return CT_Cannot; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5f4071924d3f1..ea4b93ee6a5a4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -350,6 +350,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,      }    } +  if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) && +      !isUnevaluatedContext()) { +    // C++ [expr.prim.req.nested] p3 +    //   A local parameter shall only appear as an unevaluated operand +    //   (Clause 8) within the constraint-expression. +    Diag(Loc, diag::err_requires_expr_parameter_referenced_in_evaluated_context) +        << D; +    Diag(D->getLocation(), diag::note_entity_declared_at) << D; +    return true; +  } +    return false;  } @@ -1904,7 +1915,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,    bool RefersToCapturedVariable =        isa<VarDecl>(D) &&        NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc()); - +      DeclRefExpr *E = DeclRefExpr::Create(        Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,        VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D)); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a73e6906fceb9..192c237b6c1ce 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -11,6 +11,7 @@  ///  //===----------------------------------------------------------------------===// +#include "clang/Sema/Template.h"  #include "clang/Sema/SemaInternal.h"  #include "TreeTransform.h"  #include "TypeLocBuilder.h" @@ -7317,7 +7318,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,      ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),                                         TemplateId->NumArgs);      TypeResult T = ActOnTemplateIdType(S, -                                       TemplateId->SS, +                                       SS,                                         TemplateId->TemplateKWLoc,                                         TemplateId->Template,                                         TemplateId->Name, @@ -7370,7 +7371,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,        ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),                                           TemplateId->NumArgs);        TypeResult T = ActOnTemplateIdType(S, -                                         TemplateId->SS, +                                         SS,                                           TemplateId->TemplateKWLoc,                                           TemplateId->Template,                                           TemplateId->Name, @@ -8331,3 +8332,215 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,    return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);  } + +concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) { +  return BuildExprRequirement(E, /*IsSimple=*/true, +                              /*NoexceptLoc=*/SourceLocation(), +                              /*ReturnTypeRequirement=*/{}); +} + +concepts::Requirement * +Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, +                           SourceLocation NameLoc, IdentifierInfo *TypeName, +                           TemplateIdAnnotation *TemplateId) { +  assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) && +         "Exactly one of TypeName and TemplateId must be specified."); +  TypeSourceInfo *TSI = nullptr; +  if (TypeName) { +    QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc, +                                   SS.getWithLocInContext(Context), *TypeName, +                                   NameLoc, &TSI, /*DeducedTypeContext=*/false); +    if (T.isNull()) +      return nullptr; +  } else { +    ASTTemplateArgsPtr ArgsPtr(TemplateId->getTemplateArgs(), +                               TemplateId->NumArgs); +    TypeResult T = ActOnTypenameType(CurScope, TypenameKWLoc, SS, +                                     TemplateId->TemplateKWLoc, +                                     TemplateId->Template, TemplateId->Name, +                                     TemplateId->TemplateNameLoc, +                                     TemplateId->LAngleLoc, ArgsPtr, +                                     TemplateId->RAngleLoc); +    if (T.isInvalid()) +      return nullptr; +    if (GetTypeFromParser(T.get(), &TSI).isNull()) +      return nullptr; +  } +  return BuildTypeRequirement(TSI); +} + +concepts::Requirement * +Sema::ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc) { +  return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, +                              /*ReturnTypeRequirement=*/{}); +} + +concepts::Requirement * +Sema::ActOnCompoundRequirement( +    Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, +    TemplateIdAnnotation *TypeConstraint, unsigned Depth) { +  // C++2a [expr.prim.req.compound] p1.3.3 +  //   [..] the expression is deduced against an invented function template +  //   F [...] F is a void function template with a single type template +  //   parameter T declared with the constrained-parameter. Form a new +  //   cv-qualifier-seq cv by taking the union of const and volatile specifiers +  //   around the constrained-parameter. F has a single parameter whose +  //   type-specifier is cv T followed by the abstract-declarator. [...] +  // +  // The cv part is done in the calling function - we get the concept with +  // arguments and the abstract declarator with the correct CV qualification and +  // have to synthesize T and the single parameter of F. +  auto &II = Context.Idents.get("expr-type"); +  auto *TParam = TemplateTypeParmDecl::Create(Context, CurContext, +                                              SourceLocation(), +                                              SourceLocation(), Depth, +                                              /*Index=*/0, &II, +                                              /*Typename=*/true, +                                              /*ParameterPack=*/false, +                                              /*HasTypeConstraint=*/true); + +  if (ActOnTypeConstraint(SS, TypeConstraint, TParam, +                          /*EllpsisLoc=*/SourceLocation())) +    // Just produce a requirement with no type requirements. +    return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {}); + +  auto *TPL = TemplateParameterList::Create(Context, SourceLocation(), +                                            SourceLocation(), +                                            ArrayRef<NamedDecl *>(TParam), +                                            SourceLocation(), +                                            /*RequiresClause=*/nullptr); +  return BuildExprRequirement( +      E, /*IsSimple=*/false, NoexceptLoc, +      concepts::ExprRequirement::ReturnTypeRequirement(TPL)); +} + +concepts::ExprRequirement * +Sema::BuildExprRequirement( +    Expr *E, bool IsSimple, SourceLocation NoexceptLoc, +    concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { +  auto Status = concepts::ExprRequirement::SS_Satisfied; +  ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; +  if (E->isInstantiationDependent() || ReturnTypeRequirement.isDependent()) +    Status = concepts::ExprRequirement::SS_Dependent; +  else if (NoexceptLoc.isValid() && canThrow(E) == CanThrowResult::CT_Can) +    Status = concepts::ExprRequirement::SS_NoexceptNotMet; +  else if (ReturnTypeRequirement.isSubstitutionFailure()) +    Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure; +  else if (ReturnTypeRequirement.isTypeConstraint()) { +    // C++2a [expr.prim.req]p1.3.3 +    //     The immediately-declared constraint ([temp]) of decltype((E)) shall +    //     be satisfied. +    TemplateParameterList *TPL = +        ReturnTypeRequirement.getTypeConstraintTemplateParameterList(); +    QualType MatchedType = +        BuildDecltypeType(E, E->getBeginLoc()).getCanonicalType(); +    llvm::SmallVector<TemplateArgument, 1> Args; +    Args.push_back(TemplateArgument(MatchedType)); +    TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); +    MultiLevelTemplateArgumentList MLTAL(TAL); +    for (unsigned I = 0; I < TPL->getDepth(); ++I) +      MLTAL.addOuterRetainedLevel(); +    Expr *IDC = +        cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint() +            ->getImmediatelyDeclaredConstraint(); +    ExprResult Constraint = SubstExpr(IDC, MLTAL); +    assert(!Constraint.isInvalid() && +           "Substitution cannot fail as it is simply putting a type template " +           "argument into a concept specialization expression's parameter."); + +    SubstitutedConstraintExpr = +        cast<ConceptSpecializationExpr>(Constraint.get()); +    if (!SubstitutedConstraintExpr->isSatisfied()) +      Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied; +  } +  return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc, +                                                 ReturnTypeRequirement, Status, +                                                 SubstitutedConstraintExpr); +} + +concepts::ExprRequirement * +Sema::BuildExprRequirement( +    concepts::Requirement::SubstitutionDiagnostic *ExprSubstitutionDiagnostic, +    bool IsSimple, SourceLocation NoexceptLoc, +    concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { +  return new (Context) concepts::ExprRequirement(ExprSubstitutionDiagnostic, +                                                 IsSimple, NoexceptLoc, +                                                 ReturnTypeRequirement); +} + +concepts::TypeRequirement * +Sema::BuildTypeRequirement(TypeSourceInfo *Type) { +  return new (Context) concepts::TypeRequirement(Type); +} + +concepts::TypeRequirement * +Sema::BuildTypeRequirement( +    concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { +  return new (Context) concepts::TypeRequirement(SubstDiag); +} + +concepts::Requirement *Sema::ActOnNestedRequirement(Expr *Constraint) { +  return BuildNestedRequirement(Constraint); +} + +concepts::NestedRequirement * +Sema::BuildNestedRequirement(Expr *Constraint) { +  ConstraintSatisfaction Satisfaction; +  if (!Constraint->isInstantiationDependent() && +      CheckConstraintSatisfaction(Constraint, Satisfaction)) +    return nullptr; +  return new (Context) concepts::NestedRequirement(Context, Constraint, +                                                   Satisfaction); +} + +concepts::NestedRequirement * +Sema::BuildNestedRequirement( +    concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { +  return new (Context) concepts::NestedRequirement(SubstDiag); +} + +RequiresExprBodyDecl * +Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, +                             ArrayRef<ParmVarDecl *> LocalParameters, +                             Scope *BodyScope) { +  assert(BodyScope); + +  RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(Context, CurContext, +                                                            RequiresKWLoc); + +  PushDeclContext(BodyScope, Body); + +  for (ParmVarDecl *Param : LocalParameters) { +    if (Param->hasDefaultArg()) +      // C++2a [expr.prim.req] p4 +      //     [...] A local parameter of a requires-expression shall not have a +      //     default argument. [...] +      Diag(Param->getDefaultArgRange().getBegin(), +           diag::err_requires_expr_local_parameter_default_argument); +    // Ignore default argument and move on + +    Param->setDeclContext(Body); +    // If this has an identifier, add it to the scope stack. +    if (Param->getIdentifier()) { +      CheckShadow(BodyScope, Param); +      PushOnScopeChains(Param, BodyScope); +    } +  } +  return Body; +} + +void Sema::ActOnFinishRequiresExpr() { +  assert(CurContext && "DeclContext imbalance!"); +  CurContext = CurContext->getLexicalParent(); +  assert(CurContext && "Popped translation unit!"); +} + +ExprResult +Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc, +                        RequiresExprBodyDecl *Body, +                        ArrayRef<ParmVarDecl *> LocalParameters, +                        ArrayRef<concepts::Requirement *> Requirements, +                        SourceLocation ClosingBraceLoc) { +  return RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, +                              Requirements, ClosingBraceLoc); +} diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index c2d14a44f53d4..ae89b146c409b 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -791,7 +791,8 @@ QualType Sema::buildLambdaInitCaptureInitialization(    // deduce against.    QualType DeductType = Context.getAutoDeductType();    TypeLocBuilder TLB; -  TLB.pushTypeSpec(DeductType).setNameLoc(Loc); +  AutoTypeLoc TL = TLB.push<AutoTypeLoc>(DeductType); +  TL.setNameLoc(Loc);    if (ByRef) {      DeductType = BuildReferenceType(DeductType, true, Loc, Id);      assert(!DeductType.isNull() && "can't build reference to auto"); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 0ed51de0cc131..8d96404a5c27d 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1575,7 +1575,9 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {    unsigned N = CodeSynthesisContexts.size();    for (unsigned I = CodeSynthesisContextLookupModules.size();         I != N; ++I) { -    Module *M = getDefiningModule(*this, CodeSynthesisContexts[I].Entity); +    Module *M = CodeSynthesisContexts[I].Entity ? +                getDefiningModule(*this, CodeSynthesisContexts[I].Entity) : +                nullptr;      if (M && !LookupModulesCache.insert(M).second)        M = nullptr;      CodeSynthesisContextLookupModules.push_back(M); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d6c3af9e84c80..ff64810062801 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2838,6 +2838,9 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,  ///    Suggest "const foo &x" to prevent the copy.  static void DiagnoseForRangeVariableCopies(Sema &SemaRef,                                             const CXXForRangeStmt *ForStmt) { +  if (SemaRef.inTemplateInstantiation()) +    return; +    if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy,                                ForStmt->getBeginLoc()) &&        SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy, @@ -2860,6 +2863,9 @@ static void DiagnoseForRangeVariableCopies(Sema &SemaRef,    if (!InitExpr)      return; +  if (InitExpr->getExprLoc().isMacroID()) +    return; +    if (VariableType->isReferenceType()) {      DiagnoseForRangeReferenceVariableCopies(SemaRef, VD,                                              ForStmt->getRangeInit()->getType()); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1184446796eba..f961244da0726 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1050,7 +1050,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {    return TemplateArgs;  } -bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, +bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, +                               TemplateIdAnnotation *TypeConstr,                                 TemplateTypeParmDecl *ConstrainedParameter,                                 SourceLocation EllipsisLoc) {    ConceptDecl *CD = @@ -1080,14 +1081,57 @@ bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,          makeTemplateArgumentListInfo(*this, *TypeConstr);    }    return AttachTypeConstraint( -      TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) : -      NestedNameSpecifierLoc(), +      SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(),        DeclarationNameInfo(DeclarationName(TypeConstr->Name),                            TypeConstr->TemplateNameLoc), CD,        TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,        ConstrainedParameter, EllipsisLoc);  } +template<typename ArgumentLocAppender> +static ExprResult formImmediatelyDeclaredConstraint( +    Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, +    ConceptDecl *NamedConcept, SourceLocation LAngleLoc, +    SourceLocation RAngleLoc, QualType ConstrainedType, +    SourceLocation ParamNameLoc, ArgumentLocAppender Appender, +    SourceLocation EllipsisLoc) { + +  TemplateArgumentListInfo ConstraintArgs; +  ConstraintArgs.addArgument( +    S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType), +                                    /*NTTPType=*/QualType(), ParamNameLoc)); + +  ConstraintArgs.setRAngleLoc(RAngleLoc); +  ConstraintArgs.setLAngleLoc(LAngleLoc); +  Appender(ConstraintArgs); + +  // C++2a [temp.param]p4: +  //     [...] This constraint-expression E is called the immediately-declared +  //     constraint of T. [...] +  CXXScopeSpec SS; +  SS.Adopt(NS); +  ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( +      SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, +      /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs); +  if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) +    return ImmediatelyDeclaredConstraint; + +  // C++2a [temp.param]p4: +  //     [...] If T is not a pack, then E is E', otherwise E is (E' && ...). +  // +  // We have the following case: +  // +  // template<typename T> concept C1 = true; +  // template<C1... T> struct s1; +  // +  // The constraint: (C1<T> && ...) +  return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), +                            ImmediatelyDeclaredConstraint.get(), BO_LAnd, +                            EllipsisLoc, /*RHS=*/nullptr, +                            /*RParenLoc=*/SourceLocation(), +                            /*NumExpansions=*/None); +} +  /// Attach a type-constraint to a template parameter.  /// \returns true if an error occured. This can happen if the  /// immediately-declared constraint could not be formed (e.g. incorrect number @@ -1106,51 +1150,21 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,                                                         *TemplateArgs) : nullptr;    QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); -  TemplateArgumentListInfo ConstraintArgs; -  ConstraintArgs.addArgument( -    TemplateArgumentLoc( -        TemplateArgument(ParamAsArgument), -        TemplateArgumentLocInfo( -            Context.getTrivialTypeSourceInfo(ParamAsArgument, -                ConstrainedParameter->getLocation())))); -  if (TemplateArgs) { -    ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc()); -    ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc()); -    for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments()) -      ConstraintArgs.addArgument(ArgLoc); -  } -  // C++2a [temp.param]p4: -  //     [...] This constraint-expression E is called the immediately-declared -  //     constraint of T. [...] -  CXXScopeSpec SS; -  SS.Adopt(NS); -  ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS, -      /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, -      NamedConcept, &ConstraintArgs); +  ExprResult ImmediatelyDeclaredConstraint = +      formImmediatelyDeclaredConstraint( +          *this, NS, NameInfo, NamedConcept, +          TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), +          TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), +          ParamAsArgument, ConstrainedParameter->getLocation(), +          [&] (TemplateArgumentListInfo &ConstraintArgs) { +            if (TemplateArgs) +              for (const auto &ArgLoc : TemplateArgs->arguments()) +                ConstraintArgs.addArgument(ArgLoc); +          }, EllipsisLoc);    if (ImmediatelyDeclaredConstraint.isInvalid())      return true; -  if (ConstrainedParameter->isParameterPack()) { -    // C++2a [temp.param]p4: -    //     [...] If T is not a pack, then E is E', otherwise E is (E' && ...). -    // -    // We have the following case: -    // -    // template<typename T> concept C1 = true; -    // template<C1... T> struct s1; -    // -    // The constraint: (C1<T> && ...) -    ImmediatelyDeclaredConstraint = -        BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), -                         ImmediatelyDeclaredConstraint.get(), BO_LAnd, -                         EllipsisLoc, /*RHS=*/nullptr, -                         /*RParenLoc=*/SourceLocation(), -                         /*NumExpansions=*/None).get(); -    if (ImmediatelyDeclaredConstraint.isInvalid()) -      return true; -  } -    ConstrainedParameter->setTypeConstraint(NS, NameInfo,                                            /*FoundDecl=*/NamedConcept,                                            NamedConcept, ArgsAsWritten, @@ -1158,6 +1172,38 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,    return false;  } +bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, +                                SourceLocation EllipsisLoc) { +  if (NTTP->getType() != TL.getType() || +      TL.getAutoKeyword() != AutoTypeKeyword::Auto) { +    Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), +         diag::err_unsupported_placeholder_constraint) +       << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange(); +    return true; +  } +  // FIXME: Concepts: This should be the type of the placeholder, but this is +  // unclear in the wording right now. +  DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue, +                                      NTTP->getLocation()); +  if (!Ref) +    return true; +  ExprResult ImmediatelyDeclaredConstraint = +      formImmediatelyDeclaredConstraint( +          *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), +          TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), +          BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), +          [&] (TemplateArgumentListInfo &ConstraintArgs) { +            for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) +              ConstraintArgs.addArgument(TL.getArgLoc(I)); +          }, EllipsisLoc); +  if (ImmediatelyDeclaredConstraint.isInvalid() || +     !ImmediatelyDeclaredConstraint.isUsable()) +    return true; + +  NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); +  return false; +} +  /// Check that the type of a non-type template parameter is  /// well-formed.  /// @@ -1319,6 +1365,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,        TInfo);    Param->setAccess(AS_public); +  if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) +    if (TL.isConstrained()) +      if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) +        Invalid = true; +    if (Invalid)      Param->setInvalidDecl(); @@ -2762,7 +2813,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(      SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,      TemplateIdAnnotation *TemplateId,      ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend, -    bool &IsMemberSpecialization, bool &Invalid) { +    bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) {    IsMemberSpecialization = false;    Invalid = false; @@ -2870,8 +2921,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(    auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) {      if (SawNonEmptyTemplateParameterList) { -      Diag(DeclLoc, diag::err_specialize_member_of_template) -        << !Recovery << Range; +      if (!SuppressDiagnostic) +        Diag(DeclLoc, diag::err_specialize_member_of_template) +          << !Recovery << Range;        Invalid = true;        IsMemberSpecialization = false;        return true; @@ -2892,9 +2944,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(      else        ExpectedTemplateLoc = DeclStartLoc; -    Diag(DeclLoc, diag::err_template_spec_needs_header) -      << Range -      << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); +    if (!SuppressDiagnostic) +      Diag(DeclLoc, diag::err_template_spec_needs_header) +        << Range +        << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");      return false;    }; @@ -2984,12 +3037,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(        if (ParamIdx < ParamLists.size()) {          if (ParamLists[ParamIdx]->size() > 0) {            // The header has template parameters when it shouldn't. Complain. -          Diag(ParamLists[ParamIdx]->getTemplateLoc(), -               diag::err_template_param_list_matches_nontemplate) -            << T -            << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), -                           ParamLists[ParamIdx]->getRAngleLoc()) -            << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); +          if (!SuppressDiagnostic) +            Diag(ParamLists[ParamIdx]->getTemplateLoc(), +                 diag::err_template_param_list_matches_nontemplate) +              << T +              << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), +                             ParamLists[ParamIdx]->getRAngleLoc()) +              << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);            Invalid = true;            return nullptr;          } @@ -3025,7 +3079,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(          if (ExpectedTemplateParams &&              !TemplateParameterListsAreEqual(ParamLists[ParamIdx],                                              ExpectedTemplateParams, -                                            true, TPL_TemplateMatch)) +                                            !SuppressDiagnostic, TPL_TemplateMatch))            Invalid = true;          if (!Invalid && @@ -3037,9 +3091,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(          continue;        } -      Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) -        << T -        << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); +      if (!SuppressDiagnostic) +        Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) +          << T +          << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);        Invalid = true;        continue;      } @@ -3075,16 +3130,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(          AllExplicitSpecHeaders = false;      } -    Diag(ParamLists[ParamIdx]->getTemplateLoc(), -         AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers -                                : diag::err_template_spec_extra_headers) -        << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), -                       ParamLists[ParamLists.size() - 2]->getRAngleLoc()); +    if (!SuppressDiagnostic) +      Diag(ParamLists[ParamIdx]->getTemplateLoc(), +           AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers +                                  : diag::err_template_spec_extra_headers) +          << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), +                         ParamLists[ParamLists.size() - 2]->getRAngleLoc());      // If there was a specialization somewhere, such that 'template<>' is      // not required, and there were any 'template<>' headers, note where the      // specialization occurred. -    if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) +    if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader && +        !SuppressDiagnostic)        Diag(ExplicitSpecLoc,             diag::note_explicit_template_spec_does_not_need_header)          << NestedTypes.back(); @@ -4044,7 +4101,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(      if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),                                  Converted) && -        (!Context.getLangOpts().ConceptsTS || +        (!Context.getLangOpts().CPlusPlus2a ||           !TemplateParams->hasAssociatedConstraints())) {        // C++ [temp.class.spec]p9b3:        // @@ -6530,7 +6587,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,        DeductionArg = PE->getPattern();      if (DeduceAutoType(              Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), -            DeductionArg, ParamType, Depth) == DAR_Failed) { +            DeductionArg, ParamType, Depth, +            // We do not check constraints right now because the +            // immediately-declared constraint of the auto type is also an +            // associated constraint, and will be checked along with the other +            // associated constraints after checking the template argument list. +            /*IgnoreConstraints=*/true) == DAR_Failed) {        Diag(Arg->getExprLoc(),             diag::err_non_type_template_parm_type_deduction_failure)          << Param->getDeclName() << Param->getType() << Arg->getType() @@ -7102,6 +7164,11 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,        //   [temp.constr.order].        SmallVector<const Expr *, 3> ParamsAC, TemplateAC;        Params->getAssociatedConstraints(ParamsAC); +      // C++2a[temp.arg.template]p3 +      //   [...] In this comparison, if P is unconstrained, the constraints on A +      //   are not considered. +      if (ParamsAC.empty()) +        return false;        Template->getAssociatedConstraints(TemplateAC);        bool IsParamAtLeastAsConstrained;        if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, @@ -7872,13 +7939,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs(  DeclResult Sema::ActOnClassTemplateSpecialization(      Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, -    SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, -    const ParsedAttributesView &Attr, +    SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, +    TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,      MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) {    assert(TUK != TUK_Reference && "References are not specializations"); -  CXXScopeSpec &SS = TemplateId.SS; -    // NOTE: KWLoc is the location of the tag keyword. This will instead    // store the location of the outermost template keyword in the declaration.    SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 @@ -8048,7 +8113,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(      if (Context.hasSameType(CanonType,                          ClassTemplate->getInjectedClassNameSpecialization()) && -        (!Context.getLangOpts().ConceptsTS || +        (!Context.getLangOpts().CPlusPlus2a ||           !TemplateParams->hasAssociatedConstraints())) {        // C++ [temp.class.spec]p9b3:        // @@ -10012,24 +10077,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,        << FixItHint::CreateRemoval(TypenameLoc);    NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); +  TypeSourceInfo *TSI = nullptr;    QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, -                                 TypenameLoc, QualifierLoc, II, IdLoc); +                                 TypenameLoc, QualifierLoc, II, IdLoc, &TSI, +                                 /*DeducedTSTContext=*/true);    if (T.isNull())      return true; - -  TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); -  if (isa<DependentNameType>(T)) { -    DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>(); -    TL.setElaboratedKeywordLoc(TypenameLoc); -    TL.setQualifierLoc(QualifierLoc); -    TL.setNameLoc(IdLoc); -  } else { -    ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>(); -    TL.setElaboratedKeywordLoc(TypenameLoc); -    TL.setQualifierLoc(QualifierLoc); -    TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); -  } -    return CreateParsedType(T, TSI);  } @@ -10166,6 +10219,35 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,    return true;  } +QualType +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, +                        SourceLocation KeywordLoc, +                        NestedNameSpecifierLoc QualifierLoc, +                        const IdentifierInfo &II, +                        SourceLocation IILoc, +                        TypeSourceInfo **TSI, +                        bool DeducedTSTContext) { +  QualType T = CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, II, IILoc, +                                 DeducedTSTContext); +  if (T.isNull()) +    return QualType(); + +  *TSI = Context.CreateTypeSourceInfo(T); +  if (isa<DependentNameType>(T)) { +    DependentNameTypeLoc TL = +        (*TSI)->getTypeLoc().castAs<DependentNameTypeLoc>(); +    TL.setElaboratedKeywordLoc(KeywordLoc); +    TL.setQualifierLoc(QualifierLoc); +    TL.setNameLoc(IILoc); +  } else { +    ElaboratedTypeLoc TL = (*TSI)->getTypeLoc().castAs<ElaboratedTypeLoc>(); +    TL.setElaboratedKeywordLoc(KeywordLoc); +    TL.setQualifierLoc(QualifierLoc); +    TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IILoc); +  } +  return T; +} +  /// Build the type that describes a C++ typename specifier,  /// e.g., "typename T::type".  QualType @@ -10173,32 +10255,38 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,                          SourceLocation KeywordLoc,                          NestedNameSpecifierLoc QualifierLoc,                          const IdentifierInfo &II, -                        SourceLocation IILoc) { +                        SourceLocation IILoc, bool DeducedTSTContext) {    CXXScopeSpec SS;    SS.Adopt(QualifierLoc); -  DeclContext *Ctx = computeDeclContext(SS); -  if (!Ctx) { -    // If the nested-name-specifier is dependent and couldn't be -    // resolved to a type, build a typename type. -    assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); -    return Context.getDependentNameType(Keyword, -                                        QualifierLoc.getNestedNameSpecifier(), -                                        &II); +  DeclContext *Ctx = nullptr; +  if (QualifierLoc) { +    Ctx = computeDeclContext(SS); +    if (!Ctx) { +      // If the nested-name-specifier is dependent and couldn't be +      // resolved to a type, build a typename type. +      assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); +      return Context.getDependentNameType(Keyword, +                                          QualifierLoc.getNestedNameSpecifier(), +                                          &II); +    } + +    // If the nested-name-specifier refers to the current instantiation, +    // the "typename" keyword itself is superfluous. In C++03, the +    // program is actually ill-formed. However, DR 382 (in C++0x CD1) +    // allows such extraneous "typename" keywords, and we retroactively +    // apply this DR to C++03 code with only a warning. In any case we continue. + +    if (RequireCompleteDeclContext(SS, Ctx)) +      return QualType();    } -  // If the nested-name-specifier refers to the current instantiation, -  // the "typename" keyword itself is superfluous. In C++03, the -  // program is actually ill-formed. However, DR 382 (in C++0x CD1) -  // allows such extraneous "typename" keywords, and we retroactively -  // apply this DR to C++03 code with only a warning. In any case we continue. - -  if (RequireCompleteDeclContext(SS, Ctx)) -    return QualType(); -    DeclarationName Name(&II);    LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); -  LookupQualifiedName(Result, Ctx, SS); +  if (Ctx) +    LookupQualifiedName(Result, Ctx, SS); +  else +    LookupName(Result, CurScope);    unsigned DiagID = 0;    Decl *Referenced = nullptr;    switch (Result.getResultKind()) { @@ -10207,7 +10295,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,      // a more specific diagnostic.      SourceRange CondRange;      Expr *Cond = nullptr; -    if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { +    if (Ctx && isEnableIf(QualifierLoc, II, CondRange, Cond)) {        // If we have a condition, narrow it down to the specific failed        // condition.        if (Cond) { @@ -10223,12 +10311,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,          return QualType();        } -      Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) +      Diag(CondRange.getBegin(), +           diag::err_typename_nested_not_found_enable_if)            << Ctx << CondRange;        return QualType();      } -    DiagID = diag::err_typename_nested_not_found; +    DiagID = Ctx ? diag::err_typename_nested_not_found +                 : diag::err_unknown_typename;      break;    } @@ -10294,6 +10384,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,      //   is a placeholder for a deduced class type [...].      if (getLangOpts().CPlusPlus17) {        if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) { +        if (!DeducedTSTContext) { +          QualType T(QualifierLoc +                         ? QualifierLoc.getNestedNameSpecifier()->getAsType() +                         : nullptr, 0); +          if (!T.isNull()) +            Diag(IILoc, diag::err_dependent_deduced_tst) +              << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << T; +          else +            Diag(IILoc, diag::err_deduced_tst) +              << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)); +          Diag(TD->getLocation(), diag::note_template_decl_here); +          return QualType(); +        }          return Context.getElaboratedType(              Keyword, QualifierLoc.getNestedNameSpecifier(),              Context.getDeducedTemplateSpecializationType(TemplateName(TD), @@ -10301,12 +10404,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,        }      } -    DiagID = diag::err_typename_nested_not_type; +    DiagID = Ctx ? diag::err_typename_nested_not_type +                 : diag::err_typename_not_type;      Referenced = Result.getFoundDecl();      break;    case LookupResult::FoundOverloaded: -    DiagID = diag::err_typename_nested_not_type; +    DiagID = Ctx ? diag::err_typename_nested_not_type +                 : diag::err_typename_not_type;      Referenced = *Result.begin();      break; @@ -10318,9 +10423,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,    // type. Emit an appropriate diagnostic and return an error.    SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(),                          IILoc); -  Diag(IILoc, DiagID) << FullRange << Name << Ctx; +  if (Ctx) +    Diag(IILoc, DiagID) << FullRange << Name << Ctx; +  else +    Diag(IILoc, DiagID) << FullRange << Name;    if (Referenced) -    Diag(Referenced->getLocation(), diag::note_typename_refers_here) +    Diag(Referenced->getLocation(), +         Ctx ? diag::note_typename_member_refers_here +             : diag::note_typename_refers_here)        << Name;    return QualType();  } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 1b9f1b2144d1a..394c81c827946 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -724,38 +724,48 @@ private:      // Compute the set of template parameter indices that correspond to      // parameter packs expanded by the pack expansion.      llvm::SmallBitVector SawIndices(TemplateParams->size()); +    llvm::SmallVector<TemplateArgument, 4> ExtraDeductions;      auto AddPack = [&](unsigned Index) {        if (SawIndices[Index])          return;        SawIndices[Index] = true;        addPack(Index); + +      // Deducing a parameter pack that is a pack expansion also constrains the +      // packs appearing in that parameter to have the same deduced arity. Also, +      // in C++17 onwards, deducing a non-type template parameter deduces its +      // type, so we need to collect the pending deduced values for those packs. +      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>( +              TemplateParams->getParam(Index))) { +        if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType())) +          ExtraDeductions.push_back(Expansion->getPattern()); +      } +      // FIXME: Also collect the unexpanded packs in any type and template +      // parameter packs that are pack expansions.      }; -    // First look for unexpanded packs in the pattern. -    SmallVector<UnexpandedParameterPack, 2> Unexpanded; -    S.collectUnexpandedParameterPacks(Pattern, Unexpanded); -    for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { -      unsigned Depth, Index; -      std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); -      if (Depth == Info.getDeducedDepth()) -        AddPack(Index); -    } +    auto Collect = [&](TemplateArgument Pattern) { +      SmallVector<UnexpandedParameterPack, 2> Unexpanded; +      S.collectUnexpandedParameterPacks(Pattern, Unexpanded); +      for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { +        unsigned Depth, Index; +        std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); +        if (Depth == Info.getDeducedDepth()) +          AddPack(Index); +      } +    }; + +    // Look for unexpanded packs in the pattern. +    Collect(Pattern);      assert(!Packs.empty() && "Pack expansion without unexpanded packs?");      unsigned NumNamedPacks = Packs.size(); -    // We can also have deduced template parameters that do not actually -    // appear in the pattern, but can be deduced by it (the type of a non-type -    // template parameter pack, in particular). These won't have prevented us -    // from partially expanding the pack. -    llvm::SmallBitVector Used(TemplateParams->size()); -    MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true, -                               Info.getDeducedDepth(), Used); -    for (int Index = Used.find_first(); Index != -1; -         Index = Used.find_next(Index)) -      if (TemplateParams->getParam(Index)->isParameterPack()) -        AddPack(Index); +    // Also look for unexpanded packs that are indirectly deduced by deducing +    // the sizes of the packs in this pattern. +    while (!ExtraDeductions.empty()) +      Collect(ExtraDeductions.pop_back_val());      return NumNamedPacks;    } @@ -4404,9 +4414,10 @@ namespace {        QualType Result = SemaRef.Context.getAutoType(            Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(), -          ReplacementIsPack); +          ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(), +          TL.getTypePtr()->getTypeConstraintArguments());        auto NewTL = TLB.push<AutoTypeLoc>(Result); -      NewTL.setNameLoc(TL.getNameLoc()); +      NewTL.copy(TL);        return Result;      } @@ -4441,9 +4452,10 @@ namespace {  Sema::DeduceAutoResult  Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, -                     Optional<unsigned> DependentDeductionDepth) { +                     Optional<unsigned> DependentDeductionDepth, +                     bool IgnoreConstraints) {    return DeduceAutoType(Type->getTypeLoc(), Init, Result, -                        DependentDeductionDepth); +                        DependentDeductionDepth, IgnoreConstraints);  }  /// Attempt to produce an informative diagostic explaining why auto deduction @@ -4471,6 +4483,49 @@ static bool diagnoseAutoDeductionFailure(Sema &S,    }  } +static Sema::DeduceAutoResult +CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, +                                   AutoTypeLoc TypeLoc, QualType Deduced) { +  ConstraintSatisfaction Satisfaction; +  ConceptDecl *Concept = Type.getTypeConstraintConcept(); +  TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), +                                        TypeLoc.getRAngleLoc()); +  TemplateArgs.addArgument( +      TemplateArgumentLoc(TemplateArgument(Deduced), +                          S.Context.getTrivialTypeSourceInfo( +                              Deduced, TypeLoc.getNameLoc()))); +  for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I) +    TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); + +  llvm::SmallVector<TemplateArgument, 4> Converted; +  if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, +                                  /*PartialTemplateArgs=*/false, Converted)) +    return Sema::DAR_FailedAlreadyDiagnosed; +  if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, +                                    Converted, TypeLoc.getLocalSourceRange(), +                                    Satisfaction)) +    return Sema::DAR_FailedAlreadyDiagnosed; +  if (!Satisfaction.IsSatisfied) { +    std::string Buf; +    llvm::raw_string_ostream OS(Buf); +    OS << "'" << Concept->getName(); +    if (TypeLoc.hasExplicitTemplateArgs()) { +      OS << "<"; +      for (const auto &Arg : Type.getTypeConstraintArguments()) +        Arg.print(S.getPrintingPolicy(), OS); +      OS << ">"; +    } +    OS << "'"; +    OS.flush(); +    S.Diag(TypeLoc.getConceptNameLoc(), +           diag::err_placeholder_constraints_not_satisfied) +         << Deduced << Buf << TypeLoc.getLocalSourceRange(); +    S.DiagnoseUnsatisfiedConstraint(Satisfaction); +    return Sema::DAR_FailedAlreadyDiagnosed; +  } +  return Sema::DAR_Succeeded; +} +  /// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)  ///  /// Note that this is done even if the initializer is dependent. (This is @@ -4485,9 +4540,12 @@ static bool diagnoseAutoDeductionFailure(Sema &S,  ///        dependent cases. This is necessary for template partial ordering with  ///        'auto' template parameters. The value specified is the template  ///        parameter depth at which we should perform 'auto' deduction. +/// \param IgnoreConstraints Set if we should not fail if the deduced type does +///                          not satisfy the type-constraint in the auto type.  Sema::DeduceAutoResult  Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, -                     Optional<unsigned> DependentDeductionDepth) { +                     Optional<unsigned> DependentDeductionDepth, +                     bool IgnoreConstraints) {    if (Init->getType()->isNonOverloadPlaceholderType()) {      ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);      if (NonPlaceholder.isInvalid()) @@ -4528,6 +4586,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,          return DAR_FailedAlreadyDiagnosed;        // FIXME: Support a non-canonical deduced type for 'auto'.        Deduced = Context.getCanonicalType(Deduced); +      if (AT->isConstrained() && !IgnoreConstraints) { +        auto ConstraintsResult = +            CheckDeducedPlaceholderConstraints(*this, *AT, +                                               Type.getContainedAutoTypeLoc(), +                                               Deduced); +        if (ConstraintsResult != DAR_Succeeded) +          return ConstraintsResult; +      }        Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);        if (Result.isNull())          return DAR_FailedAlreadyDiagnosed; @@ -4635,6 +4701,17 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,        return DAR_FailedAlreadyDiagnosed;    } +  if (const auto *AT = Type.getType()->getAs<AutoType>()) { +    if (AT->isConstrained() && !IgnoreConstraints) { +      auto ConstraintsResult = +          CheckDeducedPlaceholderConstraints(*this, *AT, +                                             Type.getContainedAutoTypeLoc(), +                                             DeducedType); +      if (ConstraintsResult != DAR_Succeeded) +        return ConstraintsResult; +    } +  } +    Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);    if (Result.isNull())      return DAR_FailedAlreadyDiagnosed; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index af41e231134d0..39bc28d62305b 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -26,6 +26,7 @@  #include "clang/Sema/Template.h"  #include "clang/Sema/TemplateDeduction.h"  #include "clang/Sema/TemplateInstCallback.h" +#include "clang/Sema/SemaConcept.h"  #include "llvm/Support/TimeProfiler.h"  using namespace clang; @@ -199,8 +200,10 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {    case DeducedTemplateArgumentSubstitution:    case PriorTemplateArgumentSubstitution:    case ConstraintsCheck: +  case NestedRequirementConstraintsCheck:      return true; +  case RequirementInstantiation:    case DefaultTemplateArgumentChecking:    case DeclaringSpecialMember:    case DeclaringImplicitEqualityComparison: @@ -247,7 +250,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(      Inst.InstantiationRange = InstantiationRange;      SemaRef.pushCodeSynthesisContext(Inst); -    AlreadyInstantiating = +    AlreadyInstantiating = !Inst.Entity ? false :          !SemaRef.InstantiatingSpecializations               .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind))               .second; @@ -366,6 +369,26 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(  Sema::InstantiatingTemplate::InstantiatingTemplate(      Sema &SemaRef, SourceLocation PointOfInstantiation, +    concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo, +    SourceRange InstantiationRange) +    : InstantiatingTemplate( +          SemaRef, CodeSynthesisContext::RequirementInstantiation, +          PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, +          /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {} + + +Sema::InstantiatingTemplate::InstantiatingTemplate( +    Sema &SemaRef, SourceLocation PointOfInstantiation, +    concepts::NestedRequirement *Req, ConstraintsCheck, +    SourceRange InstantiationRange) +    : InstantiatingTemplate( +          SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck, +          PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, +          /*Template=*/nullptr, /*TemplateArgs=*/None) {} + + +Sema::InstantiatingTemplate::InstantiatingTemplate( +    Sema &SemaRef, SourceLocation PointOfInstantiation,      ConstraintsCheck, NamedDecl *Template,      ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)      : InstantiatingTemplate( @@ -446,8 +469,9 @@ void Sema::InstantiatingTemplate::Clear() {    if (!Invalid) {      if (!AlreadyInstantiating) {        auto &Active = SemaRef.CodeSynthesisContexts.back(); -      SemaRef.InstantiatingSpecializations.erase( -          std::make_pair(Active.Entity, Active.Kind)); +      if (Active.Entity) +        SemaRef.InstantiatingSpecializations.erase( +            std::make_pair(Active.Entity, Active.Kind));      }      atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, @@ -684,6 +708,18 @@ void Sema::PrintInstantiationStack() {          << Active->InstantiationRange;        break; +    case CodeSynthesisContext::RequirementInstantiation: +      Diags.Report(Active->PointOfInstantiation, +                   diag::note_template_requirement_instantiation_here) +        << Active->InstantiationRange; +      break; + +    case CodeSynthesisContext::NestedRequirementConstraintsCheck: +      Diags.Report(Active->PointOfInstantiation, +                   diag::note_nested_requirement_here) +        << Active->InstantiationRange; +      break; +      case CodeSynthesisContext::DeclaringSpecialMember:        Diags.Report(Active->PointOfInstantiation,                     diag::note_in_declaration_of_implicit_special_member) @@ -788,6 +824,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {      case CodeSynthesisContext::ConstraintsCheck:      case CodeSynthesisContext::ParameterMappingSubstitution:      case CodeSynthesisContext::ConstraintNormalization: +    case CodeSynthesisContext::NestedRequirementConstraintsCheck:        // This is a template instantiation, so there is no SFINAE.        return None; @@ -802,9 +839,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {      case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:      case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:      case CodeSynthesisContext::ConstraintSubstitution: -      // We're either substituting explicitly-specified template arguments -      // or deduced template arguments or a constraint expression, so SFINAE -      // applies. +    case CodeSynthesisContext::RequirementInstantiation: +      // We're either substituting explicitly-specified template arguments, +      // deduced template arguments, a constraint expression or a requirement +      // in a requires expression, so SFINAE applies.        assert(Active->DeductionInfo && "Missing deduction info pointer");        return Active->DeductionInfo; @@ -1056,6 +1094,41 @@ namespace {        return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);      } +    ExprResult TransformRequiresExpr(RequiresExpr *E) { +      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); +      return TreeTransform<TemplateInstantiator>::TransformRequiresExpr(E); +    } + +    bool TransformRequiresExprRequirements( +        ArrayRef<concepts::Requirement *> Reqs, +        SmallVectorImpl<concepts::Requirement *> &Transformed) { +      bool SatisfactionDetermined = false; +      for (concepts::Requirement *Req : Reqs) { +        concepts::Requirement *TransReq = nullptr; +        if (!SatisfactionDetermined) { +          if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) +            TransReq = TransformTypeRequirement(TypeReq); +          else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) +            TransReq = TransformExprRequirement(ExprReq); +          else +            TransReq = TransformNestedRequirement( +                cast<concepts::NestedRequirement>(Req)); +          if (!TransReq) +            return true; +          if (!TransReq->isDependent() && !TransReq->isSatisfied()) +            // [expr.prim.req]p6 +            //   [...]  The substitution and semantic constraint checking +            //   proceeds in lexical order and stops when a condition that +            //   determines the result of the requires-expression is +            //   encountered. [..] +            SatisfactionDetermined = true; +        } else +          TransReq = Req; +        Transformed.push_back(TransReq); +      } +      return false; +    } +      TemplateParameterList *TransformTemplateParameterList(                                TemplateParameterList *OrigTPL)  {        if (!OrigTPL || !OrigTPL->size()) return OrigTPL; @@ -1065,6 +1138,14 @@ namespace {                          /* DeclContext *Owner */ Owner, TemplateArgs);        return DeclInstantiator.SubstTemplateParams(OrigTPL);      } + +    concepts::TypeRequirement * +    TransformTypeRequirement(concepts::TypeRequirement *Req); +    concepts::ExprRequirement * +    TransformExprRequirement(concepts::ExprRequirement *Req); +    concepts::NestedRequirement * +    TransformNestedRequirement(concepts::NestedRequirement *Req); +    private:      ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,                                                 SourceLocation loc, @@ -1669,6 +1750,163 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(    return Result;  } +template<typename EntityPrinter> +static concepts::Requirement::SubstitutionDiagnostic * +createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) { +  SmallString<128> Message; +  SourceLocation ErrorLoc; +  if (Info.hasSFINAEDiagnostic()) { +    PartialDiagnosticAt PDA(SourceLocation(), +                            PartialDiagnostic::NullDiagnostic{}); +    Info.takeSFINAEDiagnostic(PDA); +    PDA.second.EmitToString(S.getDiagnostics(), Message); +    ErrorLoc = PDA.first; +  } else { +    ErrorLoc = Info.getLocation(); +  } +  char *MessageBuf = new (S.Context) char[Message.size()]; +  std::copy(Message.begin(), Message.end(), MessageBuf); +  SmallString<128> Entity; +  llvm::raw_svector_ostream OS(Entity); +  Printer(OS); +  char *EntityBuf = new (S.Context) char[Entity.size()]; +  std::copy(Entity.begin(), Entity.end(), EntityBuf); +  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{ +      StringRef(EntityBuf, Entity.size()), ErrorLoc, +      StringRef(MessageBuf, Message.size())}; +} + +concepts::TypeRequirement * +TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) { +  if (!Req->isDependent() && !AlwaysRebuild()) +    return Req; +  if (Req->isSubstitutionFailure()) { +    if (AlwaysRebuild()) +      return RebuildTypeRequirement( +              Req->getSubstitutionDiagnostic()); +    return Req; +  } + +  Sema::SFINAETrap Trap(SemaRef); +  TemplateDeductionInfo Info(Req->getType()->getTypeLoc().getBeginLoc()); +  Sema::InstantiatingTemplate TypeInst(SemaRef, +      Req->getType()->getTypeLoc().getBeginLoc(), Req, Info, +      Req->getType()->getTypeLoc().getSourceRange()); +  if (TypeInst.isInvalid()) +    return nullptr; +  TypeSourceInfo *TransType = TransformType(Req->getType()); +  if (!TransType || Trap.hasErrorOccurred()) +    return RebuildTypeRequirement(createSubstDiag(SemaRef, Info, +        [&] (llvm::raw_ostream& OS) { +            Req->getType()->getType().print(OS, SemaRef.getPrintingPolicy()); +        })); +  return RebuildTypeRequirement(TransType); +} + +concepts::ExprRequirement * +TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { +  if (!Req->isDependent() && !AlwaysRebuild()) +    return Req; + +  Sema::SFINAETrap Trap(SemaRef); +  TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc()); + +  llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> +      TransExpr; +  if (Req->isExprSubstitutionFailure()) +    TransExpr = Req->getExprSubstitutionDiagnostic(); +  else { +    Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(), +                                         Req, Info, +                                         Req->getExpr()->getSourceRange()); +    if (ExprInst.isInvalid()) +      return nullptr; +    ExprResult TransExprRes = TransformExpr(Req->getExpr()); +    if (TransExprRes.isInvalid() || Trap.hasErrorOccurred()) +      TransExpr = createSubstDiag(SemaRef, Info, +          [&] (llvm::raw_ostream& OS) { +              Req->getExpr()->printPretty(OS, nullptr, +                                          SemaRef.getPrintingPolicy()); +          }); +    else +      TransExpr = TransExprRes.get(); +  } + +  llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; +  const auto &RetReq = Req->getReturnTypeRequirement(); +  if (RetReq.isEmpty()) +    TransRetReq.emplace(); +  else if (RetReq.isSubstitutionFailure()) +    TransRetReq.emplace(RetReq.getSubstitutionDiagnostic()); +  else if (RetReq.isTypeConstraint()) { +    TemplateParameterList *OrigTPL = +        RetReq.getTypeConstraintTemplateParameterList(); +    Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(), +                                        Req, Info, OrigTPL->getSourceRange()); +    if (TPLInst.isInvalid()) +      return nullptr; +    TemplateParameterList *TPL = +        TransformTemplateParameterList(OrigTPL); +    if (!TPL) +      TransRetReq.emplace(createSubstDiag(SemaRef, Info, +          [&] (llvm::raw_ostream& OS) { +              RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint() +                  ->printPretty(OS, nullptr, SemaRef.getPrintingPolicy()); +          })); +    else { +      TPLInst.Clear(); +      TransRetReq.emplace(TPL); +    } +  } +  assert(TransRetReq.hasValue() && +         "All code paths leading here must set TransRetReq"); +  if (Expr *E = TransExpr.dyn_cast<Expr *>()) +    return RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(), +                                  std::move(*TransRetReq)); +  return RebuildExprRequirement( +      TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(), +      Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); +} + +concepts::NestedRequirement * +TemplateInstantiator::TransformNestedRequirement( +    concepts::NestedRequirement *Req) { +  if (!Req->isDependent() && !AlwaysRebuild()) +    return Req; +  if (Req->isSubstitutionFailure()) { +    if (AlwaysRebuild()) +      return RebuildNestedRequirement( +          Req->getSubstitutionDiagnostic()); +    return Req; +  } +  Sema::InstantiatingTemplate ReqInst(SemaRef, +      Req->getConstraintExpr()->getBeginLoc(), Req, +      Sema::InstantiatingTemplate::ConstraintsCheck{}, +      Req->getConstraintExpr()->getSourceRange()); + +  ExprResult TransConstraint; +  TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc()); +  { +    EnterExpressionEvaluationContext ContextRAII( +        SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); +    Sema::SFINAETrap Trap(SemaRef); +    Sema::InstantiatingTemplate ConstrInst(SemaRef, +        Req->getConstraintExpr()->getBeginLoc(), Req, Info, +        Req->getConstraintExpr()->getSourceRange()); +    if (ConstrInst.isInvalid()) +      return nullptr; +    TransConstraint = TransformExpr(Req->getConstraintExpr()); +    if (TransConstraint.isInvalid() || Trap.hasErrorOccurred()) +      return RebuildNestedRequirement(createSubstDiag(SemaRef, Info, +          [&] (llvm::raw_ostream& OS) { +              Req->getConstraintExpr()->printPretty(OS, nullptr, +                                                    SemaRef.getPrintingPolicy()); +          })); +  } +  return RebuildNestedRequirement(TransConstraint.get()); +} + +  /// Perform substitution on the type T with a given set of template  /// arguments.  /// diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 64500d0a26d54..fbbab8f007039 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1848,6 +1848,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(    // FIXME: Concepts: Do not substitute into constraint expressions    Expr *TrailingRequiresClause = D->getTrailingRequiresClause();    if (TrailingRequiresClause) { +    EnterExpressionEvaluationContext ConstantEvaluated( +        SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);      ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,                                             TemplateArgs);      if (SubstRC.isInvalid()) @@ -2186,6 +2188,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(    // FIXME: Concepts: Do not substitute into constraint expressions    Expr *TrailingRequiresClause = D->getTrailingRequiresClause();    if (TrailingRequiresClause) { +    EnterExpressionEvaluationContext ConstantEvaluated( +        SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);      ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,                                             TemplateArgs);      if (SubstRC.isInvalid()) @@ -2685,6 +2689,16 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(          D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),          D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); +  if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc()) +    if (AutoLoc.isConstrained()) +      if (SemaRef.AttachTypeConstraint( +              AutoLoc, Param, +              IsExpandedParameterPack +                ? DI->getTypeLoc().getAs<PackExpansionTypeLoc>() +                    .getEllipsisLoc() +                : SourceLocation())) +        Invalid = true; +    Param->setAccess(AS_public);    Param->setImplicit(D->isImplicit());    if (Invalid) @@ -3600,6 +3614,12 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {    llvm_unreachable("Concept definitions cannot reside inside a template");  } +Decl * +TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { +  return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(), +                                      D->getBeginLoc()); +} +  Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {    llvm_unreachable("Unexpected decl");  } @@ -3713,6 +3733,8 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {    // checking satisfaction.    Expr *InstRequiresClause = nullptr;    if (Expr *E = L->getRequiresClause()) { +    EnterExpressionEvaluationContext ConstantEvaluated( +        SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);      ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);      if (Res.isInvalid() || !Res.isUsable()) {        return nullptr; @@ -4236,9 +4258,9 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(          MLTAL.getInnermost(), SourceRange());      if (Inst.isInvalid())        return true; -    if (addInstantiatedParametersToScope(*this, Decl, -                                        Decl->getTemplateInstantiationPattern(), -                                         Scope, MLTAL)) +    if (addInstantiatedParametersToScope( +            *this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), +            Scope, MLTAL))        return true;    } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3884fdae8fe72..93ddd047e09be 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -11,6 +11,7 @@  //===----------------------------------------------------------------------===//  #include "TypeLocBuilder.h" +#include "TreeTransform.h"  #include "clang/AST/ASTConsumer.h"  #include "clang/AST/ASTContext.h"  #include "clang/AST/ASTMutationListener.h" @@ -27,6 +28,7 @@  #include "clang/Sema/DeclSpec.h"  #include "clang/Sema/DelayedDiagnostic.h"  #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h"  #include "clang/Sema/ScopeInfo.h"  #include "clang/Sema/SemaInternal.h"  #include "clang/Sema/Template.h" @@ -1251,6 +1253,26 @@ getImageAccess(const ParsedAttributesView &Attrs) {    return OpenCLAccessAttr::Keyword_read_only;  } +static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS, +                                                     AutoTypeKeyword AutoKW) { +  assert(DS.isConstrainedAuto()); +  TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); +  TemplateArgumentListInfo TemplateArgsInfo; +  TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc); +  TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc); +  ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), +                                     TemplateId->NumArgs); +  S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); +  llvm::SmallVector<TemplateArgument, 8> TemplateArgs; +  for (auto &ArgLoc : TemplateArgsInfo.arguments()) +    TemplateArgs.push_back(ArgLoc.getArgument()); +  return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false, +                               /*IsPack=*/false, +                               cast<ConceptDecl>(TemplateId->Template.get() +                                                 .getAsTemplateDecl()), +                               TemplateArgs); +} +  /// Convert the specified declspec to the appropriate type  /// object.  /// \param state Specifies the declarator containing the declaration specifier @@ -1595,6 +1617,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {      break;    case DeclSpec::TST_auto: +    if (DS.isConstrainedAuto()) { +      Result = ConvertConstrainedAutoDeclSpecToType(S, DS, +                                                    AutoTypeKeyword::Auto); +      break; +    }      Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);      break; @@ -1603,6 +1630,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {      break;    case DeclSpec::TST_decltype_auto: +    if (DS.isConstrainedAuto()) { +      Result = +          ConvertConstrainedAutoDeclSpecToType(S, DS, +                                               AutoTypeKeyword::DecltypeAuto); +      break; +    }      Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto,                                   /*IsDependent*/ false);      break; @@ -2921,6 +2954,87 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,                                D.getDeclSpec().getUnalignedSpecLoc());  } +static void CopyTypeConstraintFromAutoType(Sema &SemaRef, const AutoType *Auto, +                                           AutoTypeLoc AutoLoc, +                                           TemplateTypeParmDecl *TP, +                                           SourceLocation EllipsisLoc) { + +  TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc()); +  for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx) +    TAL.addArgument(AutoLoc.getArgLoc(Idx)); + +  SemaRef.AttachTypeConstraint( +      AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(), +      AutoLoc.getNamedConcept(), +      AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, TP, EllipsisLoc); +} + +static QualType InventTemplateParameter( +    TypeProcessingState &state, QualType T, TypeSourceInfo *TSI, AutoType *Auto, +    InventedTemplateParameterInfo &Info) { +  Sema &S = state.getSema(); +  Declarator &D = state.getDeclarator(); + +  const unsigned TemplateParameterDepth = Info.AutoTemplateParameterDepth; +  const unsigned AutoParameterPosition = Info.TemplateParams.size(); +  const bool IsParameterPack = D.hasEllipsis(); + +  // If auto is mentioned in a lambda parameter or abbreviated function +  // template context, convert it to a template parameter type. + +  // Create the TemplateTypeParmDecl here to retrieve the corresponding +  // template parameter type. Template parameters are temporarily added +  // to the TU until the associated TemplateDecl is created. +  TemplateTypeParmDecl *InventedTemplateParam = +      TemplateTypeParmDecl::Create( +          S.Context, S.Context.getTranslationUnitDecl(), +          /*KeyLoc=*/D.getDeclSpec().getTypeSpecTypeLoc(), +          /*NameLoc=*/D.getIdentifierLoc(), +          TemplateParameterDepth, AutoParameterPosition, +          S.InventAbbreviatedTemplateParameterTypeName( +              D.getIdentifier(), AutoParameterPosition), false, +          IsParameterPack, /*HasTypeConstraint=*/Auto->isConstrained()); +  InventedTemplateParam->setImplicit(); +  Info.TemplateParams.push_back(InventedTemplateParam); +  // Attach type constraints +  if (Auto->isConstrained()) { +    if (TSI) { +      CopyTypeConstraintFromAutoType( +          S, Auto, TSI->getTypeLoc().getContainedAutoTypeLoc(), +          InventedTemplateParam, D.getEllipsisLoc()); +    } else { +      TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId(); +      TemplateArgumentListInfo TemplateArgsInfo; +      if (TemplateId->LAngleLoc.isValid()) { +        ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), +                                           TemplateId->NumArgs); +        S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); +      } +      S.AttachTypeConstraint( +          D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context), +          DeclarationNameInfo(DeclarationName(TemplateId->Name), +                              TemplateId->TemplateNameLoc), +          cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()), +          TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, +          InventedTemplateParam, D.getEllipsisLoc()); +    } +  } + +  // If TSI is nullptr, this is a constrained declspec auto and the type +  // constraint will be attached later in TypeSpecLocFiller + +  // Replace the 'auto' in the function parameter with this invented +  // template type parameter. +  // FIXME: Retain some type sugar to indicate that this was written +  //  as 'auto'? +  return state.ReplaceAutoType( +      T, QualType(InventedTemplateParam->getTypeForDecl(), 0)); +} + +static TypeSourceInfo * +GetTypeSourceInfoForDeclarator(TypeProcessingState &State, +                               QualType T, TypeSourceInfo *ReturnTypeInfo); +  static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,                                               TypeSourceInfo *&ReturnTypeInfo) {    Sema &SemaRef = state.getSema(); @@ -2991,43 +3105,43 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,        break;      case DeclaratorContext::ObjCParameterContext:      case DeclaratorContext::ObjCResultContext: -    case DeclaratorContext::PrototypeContext:        Error = 0;        break; -    case DeclaratorContext::LambdaExprParameterContext: -      // In C++14, generic lambdas allow 'auto' in their parameters. -      if (!SemaRef.getLangOpts().CPlusPlus14 || -          !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto) -        Error = 16; -      else { -        // If auto is mentioned in a lambda parameter context, convert it to a -        // template parameter type. -        sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda(); -        assert(LSI && "No LambdaScopeInfo on the stack!"); -        const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth; -        const unsigned AutoParameterPosition = LSI->TemplateParams.size(); -        const bool IsParameterPack = D.hasEllipsis(); - -        // Create the TemplateTypeParmDecl here to retrieve the corresponding -        // template parameter type. Template parameters are temporarily added -        // to the TU until the associated TemplateDecl is created. -        TemplateTypeParmDecl *CorrespondingTemplateParam = -            TemplateTypeParmDecl::Create( -                SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(), -                /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(), -                TemplateParameterDepth, AutoParameterPosition, -                /*Identifier*/ nullptr, false, IsParameterPack, -                /*HasTypeConstraint=*/false); -        CorrespondingTemplateParam->setImplicit(); -        LSI->TemplateParams.push_back(CorrespondingTemplateParam); -        // Replace the 'auto' in the function parameter with this invented -        // template type parameter. -        // FIXME: Retain some type sugar to indicate that this was written -        // as 'auto'. -        T = state.ReplaceAutoType( -            T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0)); +    case DeclaratorContext::RequiresExprContext: +      Error = 22; +      break; +    case DeclaratorContext::PrototypeContext: +    case DeclaratorContext::LambdaExprParameterContext: { +      InventedTemplateParameterInfo *Info = nullptr; +      if (D.getContext() == DeclaratorContext::PrototypeContext) { +        // With concepts we allow 'auto' in function parameters. +        if (!SemaRef.getLangOpts().CPlusPlus2a || !Auto || +            Auto->getKeyword() != AutoTypeKeyword::Auto) { +          Error = 0; +          break; +        } else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) { +          Error = 21; +          break; +        } else if (D.hasTrailingReturnType()) { +          // This might be OK, but we'll need to convert the trailing return +          // type later. +          break; +        } + +        Info = &SemaRef.InventedParameterInfos.back(); +      } else { +        // In C++14, generic lambdas allow 'auto' in their parameters. +        if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto || +            Auto->getKeyword() != AutoTypeKeyword::Auto) { +          Error = 16; +          break; +        } +        Info = SemaRef.getCurLambda(); +        assert(Info && "No LambdaScopeInfo on the stack!");        } +      T = InventTemplateParameter(state, T, nullptr, Auto, *Info);        break; +    }      case DeclaratorContext::MemberContext: {        if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||            D.isFunctionDeclarator()) @@ -3221,6 +3335,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,      case DeclaratorContext::ObjCParameterContext:      case DeclaratorContext::ObjCResultContext:      case DeclaratorContext::KNRTypeListContext: +    case DeclaratorContext::RequiresExprContext:        // C++ [dcl.fct]p6:        //   Types shall not be defined in return or parameter types.        DiagID = diag::err_type_defined_in_param_type; @@ -4028,10 +4143,6 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,    return false;  } -static TypeSourceInfo * -GetTypeSourceInfoForDeclarator(TypeProcessingState &State, -                               QualType T, TypeSourceInfo *ReturnTypeInfo); -  static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,                                                  QualType declSpecType,                                                  TypeSourceInfo *TInfo) { @@ -4279,6 +4390,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,      case DeclaratorContext::TemplateTypeArgContext:      case DeclaratorContext::TypeNameContext:      case DeclaratorContext::FunctionalCastContext: +    case DeclaratorContext::RequiresExprContext:        // Don't infer in these contexts.        break;      } @@ -4606,7 +4718,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,            } else if (D.getContext() != DeclaratorContext::LambdaExprContext &&                       (T.hasQualifiers() || !isa<AutoType>(T) ||                        cast<AutoType>(T)->getKeyword() != -                          AutoTypeKeyword::Auto)) { +                          AutoTypeKeyword::Auto || +                      cast<AutoType>(T)->isConstrained())) {              S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),                     diag::err_trailing_return_without_auto)                  << T << D.getDeclSpec().getSourceRange(); @@ -4617,7 +4730,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,              // An error occurred parsing the trailing return type.              T = Context.IntTy;              D.setInvalidType(true); -          } +          } else if (S.getLangOpts().CPlusPlus2a) +            // Handle cases like: `auto f() -> auto` or `auto f() -> C auto`. +            if (AutoType *Auto = T->getContainedAutoType()) +              if (S.getCurScope()->isFunctionDeclarationScope()) +                T = InventTemplateParameter(state, T, TInfo, Auto, +                                            S.InventedParameterInfos.back());          } else {            // This function type is not the type of the entity being declared,            // so checking the 'auto' is not the responsibility of this chunk. @@ -5227,6 +5345,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,      switch (D.getContext()) {      case DeclaratorContext::PrototypeContext:      case DeclaratorContext::LambdaExprParameterContext: +    case DeclaratorContext::RequiresExprContext:        // C++0x [dcl.fct]p13:        //   [...] When it is part of a parameter-declaration-clause, the        //   parameter pack is a function parameter pack (14.5.3). The type T @@ -5236,7 +5355,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,        //        // We represent function parameter packs as function parameters whose        // type is a pack expansion. -      if (!T->containsUnexpandedParameterPack()) { +      if (!T->containsUnexpandedParameterPack() && +          (!LangOpts.CPlusPlus2a || !T->getContainedAutoType())) {          S.Diag(D.getEllipsisLoc(),               diag::err_function_parameter_pack_without_parameter_packs)            << T <<  D.getSourceRange(); @@ -5444,14 +5564,15 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,  namespace {    class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { +    Sema &SemaRef;      ASTContext &Context;      TypeProcessingState &State;      const DeclSpec &DS;    public: -    TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State, +    TypeSpecLocFiller(Sema &S, ASTContext &Context, TypeProcessingState &State,                        const DeclSpec &DS) -        : Context(Context), State(State), DS(DS) {} +        : SemaRef(S), Context(Context), State(State), DS(DS) {}      void VisitAttributedTypeLoc(AttributedTypeLoc TL) {        Visit(TL.getModifiedLoc()); @@ -5579,6 +5700,34 @@ namespace {        TL.copy(            TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>());      } +    void VisitAutoTypeLoc(AutoTypeLoc TL) { +      assert(DS.getTypeSpecType() == TST_auto || +             DS.getTypeSpecType() == TST_decltype_auto || +             DS.getTypeSpecType() == TST_auto_type || +             DS.getTypeSpecType() == TST_unspecified); +      TL.setNameLoc(DS.getTypeSpecTypeLoc()); +      if (!DS.isConstrainedAuto()) +        return; +      TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); +      if (DS.getTypeSpecScope().isNotEmpty()) +        TL.setNestedNameSpecifierLoc( +            DS.getTypeSpecScope().getWithLocInContext(Context)); +      else +        TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc()); +      TL.setTemplateKWLoc(TemplateId->TemplateKWLoc); +      TL.setConceptNameLoc(TemplateId->TemplateNameLoc); +      TL.setFoundDecl(nullptr); +      TL.setLAngleLoc(TemplateId->LAngleLoc); +      TL.setRAngleLoc(TemplateId->RAngleLoc); +      if (TemplateId->NumArgs == 0) +        return; +      TemplateArgumentListInfo TemplateArgsInfo; +      ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), +                                         TemplateId->NumArgs); +      SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); +      for (unsigned I = 0; I < TemplateId->NumArgs; ++I) +        TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo()); +    }      void VisitTagTypeLoc(TagTypeLoc TL) {        TL.setNameLoc(DS.getTypeSpecTypeNameLoc());      } @@ -5848,7 +5997,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,      assert(TL.getFullDataSize() == CurrTL.getFullDataSize());      memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());    } else { -    TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL); +    TypeSpecLocFiller(S, S.Context, State, D.getDeclSpec()).Visit(CurrTL);    }    return TInfo; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3b827fbc950b7..d6105353bbdf4 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -19,6 +19,7 @@  #include "clang/AST/DeclObjC.h"  #include "clang/AST/DeclTemplate.h"  #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h"  #include "clang/AST/ExprCXX.h"  #include "clang/AST/ExprObjC.h"  #include "clang/AST/ExprOpenMP.h" @@ -509,6 +510,15 @@ public:    DeclarationNameInfo    TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); +  bool TransformRequiresExprRequirements(ArrayRef<concepts::Requirement *> Reqs, +      llvm::SmallVectorImpl<concepts::Requirement *> &Transformed); +  concepts::TypeRequirement * +  TransformTypeRequirement(concepts::TypeRequirement *Req); +  concepts::ExprRequirement * +  TransformExprRequirement(concepts::ExprRequirement *Req); +  concepts::NestedRequirement * +  TransformNestedRequirement(concepts::NestedRequirement *Req); +    /// Transform the given template name.    ///    /// \param SS The nested-name-specifier that qualifies the template @@ -941,12 +951,16 @@ public:    /// Build a new C++11 auto type.    ///    /// By default, builds a new AutoType with the given deduced type. -  QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) { +  QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword, +                           ConceptDecl *TypeConstraintConcept, +                           ArrayRef<TemplateArgument> TypeConstraintArgs) {      // Note, IsDependent is always false here: we implicitly convert an 'auto'      // which has been deduced to a dependent type into an undeduced 'auto', so      // that we'll retry deduction after the transformation.      return SemaRef.Context.getAutoType(Deduced, Keyword, -                                       /*IsDependent*/ false); +                                       /*IsDependent*/ false, /*IsPack=*/false, +                                       TypeConstraintConcept, +                                       TypeConstraintArgs);    }    /// By default, builds a new DeducedTemplateSpecializationType with the given @@ -1056,23 +1070,8 @@ public:      }      if (Keyword == ETK_None || Keyword == ETK_Typename) { -      QualType T = SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, -                                             *Id, IdLoc); -      // If a dependent name resolves to a deduced template specialization type, -      // check that we're in one of the syntactic contexts permitting it. -      if (!DeducedTSTContext) { -        if (auto *Deduced = dyn_cast_or_null<DeducedTemplateSpecializationType>( -                T.isNull() ? nullptr : T->getContainedDeducedType())) { -          SemaRef.Diag(IdLoc, diag::err_dependent_deduced_tst) -            << (int)SemaRef.getTemplateNameKindForDiagnostics( -                   Deduced->getTemplateName()) -            << QualType(QualifierLoc.getNestedNameSpecifier()->getAsType(), 0); -          if (auto *TD = Deduced->getTemplateName().getAsTemplateDecl()) -            SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here); -          return QualType(); -        } -      } -      return T; +      return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, +                                       *Id, IdLoc, DeducedTSTContext);      }      TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); @@ -3078,7 +3077,56 @@ public:      return Result;    } -    /// \brief Build a new Objective-C boxed expression. +  /// \brief Build a new requires expression. +  /// +  /// By default, performs semantic analysis to build the new expression. +  /// Subclasses may override this routine to provide different behavior. +  ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc, +                                 RequiresExprBodyDecl *Body, +                                 ArrayRef<ParmVarDecl *> LocalParameters, +                                 ArrayRef<concepts::Requirement *> Requirements, +                                 SourceLocation ClosingBraceLoc) { +    return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body, +                                LocalParameters, Requirements, ClosingBraceLoc); +  } + +  concepts::TypeRequirement * +  RebuildTypeRequirement( +      concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { +    return SemaRef.BuildTypeRequirement(SubstDiag); +  } + +  concepts::TypeRequirement *RebuildTypeRequirement(TypeSourceInfo *T) { +    return SemaRef.BuildTypeRequirement(T); +  } + +  concepts::ExprRequirement * +  RebuildExprRequirement( +      concepts::Requirement::SubstitutionDiagnostic *SubstDiag, bool IsSimple, +      SourceLocation NoexceptLoc, +      concepts::ExprRequirement::ReturnTypeRequirement Ret) { +    return SemaRef.BuildExprRequirement(SubstDiag, IsSimple, NoexceptLoc, +                                        std::move(Ret)); +  } + +  concepts::ExprRequirement * +  RebuildExprRequirement(Expr *E, bool IsSimple, SourceLocation NoexceptLoc, +                         concepts::ExprRequirement::ReturnTypeRequirement Ret) { +    return SemaRef.BuildExprRequirement(E, IsSimple, NoexceptLoc, +                                        std::move(Ret)); +  } + +  concepts::NestedRequirement * +  RebuildNestedRequirement( +      concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { +    return SemaRef.BuildNestedRequirement(SubstDiag); +  } + +  concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) { +    return SemaRef.BuildNestedRequirement(Constraint); +  } + +  /// \brief Build a new Objective-C boxed expression.    ///    /// By default, performs semantic analysis to build the new expression.    /// Subclasses may override this routine to provide different behavior. @@ -4456,7 +4504,10 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,          Deduced =              SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs);          T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(), -                                        AutoTy->isDependentType()); +                                        AutoTy->isDependentType(), +                                        /*isPack=*/false, +                                        AutoTy->getTypeConstraintConcept(), +                                        AutoTy->getTypeConstraintArguments());        } else {          // Otherwise, complain about the addition of a qualifier to an          // already-qualified type. @@ -5189,21 +5240,29 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(          PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();          TypeLoc Pattern = ExpansionTL.getPatternLoc();          SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); -        assert(Unexpanded.size() > 0 && "Could not find parameter packs!");          // Determine whether we should expand the parameter packs.          bool ShouldExpand = false;          bool RetainExpansion = false; -        Optional<unsigned> OrigNumExpansions = -            ExpansionTL.getTypePtr()->getNumExpansions(); -        NumExpansions = OrigNumExpansions; -        if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), -                                                 Pattern.getSourceRange(), -                                                 Unexpanded, -                                                 ShouldExpand, -                                                 RetainExpansion, -                                                 NumExpansions)) { -          return true; +        Optional<unsigned> OrigNumExpansions; +        if (Unexpanded.size() > 0) { +          OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); +          NumExpansions = OrigNumExpansions; +          if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), +                                                   Pattern.getSourceRange(), +                                                   Unexpanded, +                                                   ShouldExpand, +                                                   RetainExpansion, +                                                   NumExpansions)) { +            return true; +          } +        } else { +#ifndef NDEBUG +          const AutoType *AT = +              Pattern.getType().getTypePtr()->getContainedAutoType(); +          assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) && +                 "Could not find parameter packs or undeduced auto type!"); +#endif          }          if (ShouldExpand) { @@ -5263,6 +5322,9 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(                                                            indexAdjustment,                                                            NumExpansions,                                                    /*ExpectParameterPack=*/true); +        assert(NewParm->isParameterPack() && +               "Parameter pack no longer a parameter pack after " +               "transformation.");        } else {          NewParm = getDerived().TransformFunctionTypeParam(              OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false); @@ -5768,32 +5830,6 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(  }  template<typename Derived> -QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, -                                                   AutoTypeLoc TL) { -  const AutoType *T = TL.getTypePtr(); -  QualType OldDeduced = T->getDeducedType(); -  QualType NewDeduced; -  if (!OldDeduced.isNull()) { -    NewDeduced = getDerived().TransformType(OldDeduced); -    if (NewDeduced.isNull()) -      return QualType(); -  } - -  QualType Result = TL.getType(); -  if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || -      T->isDependentType()) { -    Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword()); -    if (Result.isNull()) -      return QualType(); -  } - -  AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); -  NewTL.setNameLoc(TL.getNameLoc()); - -  return Result; -} - -template<typename Derived>  QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType(      TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {    const DeducedTemplateSpecializationType *T = TL.getTypePtr(); @@ -6054,6 +6090,71 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,      }    }; +template<typename Derived> +QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, +                                                   AutoTypeLoc TL) { +  const AutoType *T = TL.getTypePtr(); +  QualType OldDeduced = T->getDeducedType(); +  QualType NewDeduced; +  if (!OldDeduced.isNull()) { +    NewDeduced = getDerived().TransformType(OldDeduced); +    if (NewDeduced.isNull()) +      return QualType(); +  } + +  ConceptDecl *NewCD = nullptr; +  TemplateArgumentListInfo NewTemplateArgs; +  NestedNameSpecifierLoc NewNestedNameSpec; +  if (TL.getTypePtr()->isConstrained()) { +    NewCD = cast_or_null<ConceptDecl>( +        getDerived().TransformDecl( +            TL.getConceptNameLoc(), +            TL.getTypePtr()->getTypeConstraintConcept())); + +    NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); +    NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); +    typedef TemplateArgumentLocContainerIterator<AutoTypeLoc> ArgIterator; +    if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), +                                                ArgIterator(TL, +                                                            TL.getNumArgs()), +                                                NewTemplateArgs)) +      return QualType(); + +    if (TL.getNestedNameSpecifierLoc()) { +      NewNestedNameSpec +        = getDerived().TransformNestedNameSpecifierLoc( +            TL.getNestedNameSpecifierLoc()); +      if (!NewNestedNameSpec) +        return QualType(); +    } +  } + +  QualType Result = TL.getType(); +  if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || +      T->isDependentType()) { +    llvm::SmallVector<TemplateArgument, 4> NewArgList; +    NewArgList.reserve(NewArgList.size()); +    for (const auto &ArgLoc : NewTemplateArgs.arguments()) +      NewArgList.push_back(ArgLoc.getArgument()); +    Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, +                                          NewArgList); +    if (Result.isNull()) +      return QualType(); +  } + +  AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); +  NewTL.setNameLoc(TL.getNameLoc()); +  NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec); +  NewTL.setTemplateKWLoc(TL.getTemplateKWLoc()); +  NewTL.setConceptNameLoc(TL.getConceptNameLoc()); +  NewTL.setFoundDecl(TL.getFoundDecl()); +  NewTL.setLAngleLoc(TL.getLAngleLoc()); +  NewTL.setRAngleLoc(TL.getRAngleLoc()); +  for (unsigned I = 0; I < TL.getNumArgs(); ++I) +    NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo()); + +  return Result; +}  template <typename Derived>  QualType TreeTransform<Derived>::TransformTemplateSpecializationType( @@ -11179,6 +11280,146 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr(        &TransArgs);  } +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) { +  SmallVector<ParmVarDecl*, 4> TransParams; +  SmallVector<QualType, 4> TransParamTypes; +  Sema::ExtParameterInfoBuilder ExtParamInfos; + +  // C++2a [expr.prim.req]p2 +  // Expressions appearing within a requirement-body are unevaluated operands. +  EnterExpressionEvaluationContext Ctx( +      SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + +  RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create( +      getSema().Context, E->getBody()->getDeclContext(), +      E->getBody()->getBeginLoc()); + +  Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false); + +  if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(), +                                               E->getLocalParameters(), +                                               /*ParamTypes=*/nullptr, +                                               /*ParamInfos=*/nullptr, +                                               TransParamTypes, &TransParams, +                                               ExtParamInfos)) +    return ExprError(); + +  for (ParmVarDecl *Param : TransParams) +    Param->setDeclContext(Body); + +  SmallVector<concepts::Requirement *, 4> TransReqs; +  if (getDerived().TransformRequiresExprRequirements(E->getRequirements(), +                                                     TransReqs)) +    return ExprError(); + +  for (concepts::Requirement *Req : TransReqs) { +    if (auto *ER = dyn_cast<concepts::ExprRequirement>(Req)) { +      if (ER->getReturnTypeRequirement().isTypeConstraint()) { +        ER->getReturnTypeRequirement() +                .getTypeConstraintTemplateParameterList()->getParam(0) +                ->setDeclContext(Body); +      } +    } +  } + +  return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body, +                                          TransParams, TransReqs, +                                          E->getRBraceLoc()); +} + +template<typename Derived> +bool TreeTransform<Derived>::TransformRequiresExprRequirements( +    ArrayRef<concepts::Requirement *> Reqs, +    SmallVectorImpl<concepts::Requirement *> &Transformed) { +  for (concepts::Requirement *Req : Reqs) { +    concepts::Requirement *TransReq = nullptr; +    if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) +      TransReq = getDerived().TransformTypeRequirement(TypeReq); +    else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) +      TransReq = getDerived().TransformExprRequirement(ExprReq); +    else +      TransReq = getDerived().TransformNestedRequirement( +                     cast<concepts::NestedRequirement>(Req)); +    if (!TransReq) +      return true; +    Transformed.push_back(TransReq); +  } +  return false; +} + +template<typename Derived> +concepts::TypeRequirement * +TreeTransform<Derived>::TransformTypeRequirement( +    concepts::TypeRequirement *Req) { +  if (Req->isSubstitutionFailure()) { +    if (getDerived().AlwaysRebuild()) +      return getDerived().RebuildTypeRequirement( +              Req->getSubstitutionDiagnostic()); +    return Req; +  } +  TypeSourceInfo *TransType = getDerived().TransformType(Req->getType()); +  if (!TransType) +    return nullptr; +  return getDerived().RebuildTypeRequirement(TransType); +} + +template<typename Derived> +concepts::ExprRequirement * +TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req) { +  llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> TransExpr; +  if (Req->isExprSubstitutionFailure()) +    TransExpr = Req->getExprSubstitutionDiagnostic(); +  else { +    ExprResult TransExprRes = getDerived().TransformExpr(Req->getExpr()); +    if (TransExprRes.isInvalid()) +      return nullptr; +    TransExpr = TransExprRes.get(); +  } + +  llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; +  const auto &RetReq = Req->getReturnTypeRequirement(); +  if (RetReq.isEmpty()) +    TransRetReq.emplace(); +  else if (RetReq.isSubstitutionFailure()) +    TransRetReq.emplace(RetReq.getSubstitutionDiagnostic()); +  else if (RetReq.isTypeConstraint()) { +    TemplateParameterList *OrigTPL = +        RetReq.getTypeConstraintTemplateParameterList(); +    TemplateParameterList *TPL = +        getDerived().TransformTemplateParameterList(OrigTPL); +    if (!TPL) +      return nullptr; +    TransRetReq.emplace(TPL); +  } +  assert(TransRetReq.hasValue() && +         "All code paths leading here must set TransRetReq"); +  if (Expr *E = TransExpr.dyn_cast<Expr *>()) +    return getDerived().RebuildExprRequirement(E, Req->isSimple(), +                                               Req->getNoexceptLoc(), +                                               std::move(*TransRetReq)); +  return getDerived().RebuildExprRequirement( +      TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(), +      Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); +} + +template<typename Derived> +concepts::NestedRequirement * +TreeTransform<Derived>::TransformNestedRequirement( +    concepts::NestedRequirement *Req) { +  if (Req->isSubstitutionFailure()) { +    if (getDerived().AlwaysRebuild()) +      return getDerived().RebuildNestedRequirement( +          Req->getSubstitutionDiagnostic()); +    return Req; +  } +  ExprResult TransConstraint = +      getDerived().TransformExpr(Req->getConstraintExpr()); +  if (TransConstraint.isInvalid()) +    return nullptr; +  return getDerived().RebuildNestedRequirement(TransConstraint.get()); +}  template<typename Derived>  ExprResult diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index cdb5b17022c2f..f93f1f77405d3 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -402,6 +402,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {    case Decl::Binding:    case Decl::Concept:    case Decl::LifetimeExtendedTemporary: +  case Decl::RequiresExprBody:      return false;    // These indirectly derive from Redeclarable<T> but are not actually diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 19e7ebe03a1fd..8e8b04451fb15 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6576,6 +6576,17 @@ void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {  void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {    TL.setNameLoc(readSourceLocation()); +  if (Reader.readBool()) { +    TL.setNestedNameSpecifierLoc(ReadNestedNameSpecifierLoc()); +    TL.setTemplateKWLoc(readSourceLocation()); +    TL.setConceptNameLoc(readSourceLocation()); +    TL.setFoundDecl(Reader.readDeclAs<NamedDecl>()); +    TL.setLAngleLoc(readSourceLocation()); +    TL.setRAngleLoc(readSourceLocation()); +    for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) +      TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo( +                              TL.getTypePtr()->getArg(i).getKind())); +  }  }  void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 96a7d5ae0a31c..093b69ab19d03 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -375,6 +375,7 @@ namespace clang {      void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);      DeclID VisitTemplateDecl(TemplateDecl *D);      void VisitConceptDecl(ConceptDecl *D); +    void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);      RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);      void VisitClassTemplateDecl(ClassTemplateDecl *D);      void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D); @@ -2037,6 +2038,9 @@ void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {    mergeMergeable(D);  } +void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { +} +  ASTDeclReader::RedeclarableResult  ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {    RedeclarableResult Redecl = VisitRedeclarable(D); @@ -2313,12 +2317,12 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {    D->setDeclaredWithTypename(Record.readInt()); -  if (Record.readInt()) { +  if (Record.readBool()) {      NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc();      DeclarationNameInfo DN = Record.readDeclarationNameInfo(); -    ConceptDecl *NamedConcept = cast<ConceptDecl>(Record.readDecl()); +    ConceptDecl *NamedConcept = Record.readDeclAs<ConceptDecl>();      const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; -    if (Record.readInt()) +    if (Record.readBool())          ArgsAsWritten = Record.readASTTemplateArgumentListInfo();      Expr *ImmediatelyDeclaredConstraint = Record.readExpr();      D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept, @@ -2336,6 +2340,8 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {    // TemplateParmPosition.    D->setDepth(Record.readInt());    D->setPosition(Record.readInt()); +  if (D->hasPlaceholderTypeConstraint()) +    D->setPlaceholderTypeConstraint(Record.readExpr());    if (D->isExpandedParameterPack()) {      auto TypesAndInfos =          D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>(); @@ -3819,13 +3825,19 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {                                                   HasTypeConstraint);      break;    } -  case DECL_NON_TYPE_TEMPLATE_PARM: -    D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID); +  case DECL_NON_TYPE_TEMPLATE_PARM: { +    bool HasTypeConstraint = Record.readInt(); +    D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, +                                                    HasTypeConstraint);      break; -  case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: +  } +  case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: { +    bool HasTypeConstraint = Record.readInt();      D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, -                                                    Record.readInt()); +                                                    Record.readInt(), +                                                    HasTypeConstraint);      break; +  }    case DECL_TEMPLATE_TEMPLATE_PARM:      D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);      break; @@ -3839,6 +3851,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {    case DECL_CONCEPT:      D = ConceptDecl::CreateDeserialized(Context, ID);      break; +  case DECL_REQUIRES_EXPR_BODY: +    D = RequiresExprBodyDecl::CreateDeserialized(Context, ID); +    break;    case DECL_STATIC_ASSERT:      D = StaticAssertDecl::CreateDeserialized(Context, ID);      break; diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index f558c26b5f1e8..5dd0ef9d43c3e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -724,27 +724,15 @@ void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {    E->setRParenLoc(readSourceLocation());  } -void ASTStmtReader::VisitConceptSpecializationExpr( -        ConceptSpecializationExpr *E) { -  VisitExpr(E); -  unsigned NumTemplateArgs = Record.readInt(); -  E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); -  E->TemplateKWLoc = Record.readSourceLocation(); -  E->ConceptName = Record.readDeclarationNameInfo(); -  E->NamedConcept = readDeclAs<ConceptDecl>(); -  E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); -  llvm::SmallVector<TemplateArgument, 4> Args; -  for (unsigned I = 0; I < NumTemplateArgs; ++I) -    Args.push_back(Record.readTemplateArgument()); -  E->setTemplateArguments(Args); +static ConstraintSatisfaction +readConstraintSatisfaction(ASTRecordReader &Record) {    ConstraintSatisfaction Satisfaction;    Satisfaction.IsSatisfied = Record.readInt();    if (!Satisfaction.IsSatisfied) {      unsigned NumDetailRecords = Record.readInt();      for (unsigned i = 0; i != NumDetailRecords; ++i) {        Expr *ConstraintExpr = Record.readExpr(); -      bool IsDiagnostic = Record.readInt(); -      if (IsDiagnostic) { +      if (bool IsDiagnostic = Record.readInt()) {          SourceLocation DiagLocation = Record.readSourceLocation();          std::string DiagMessage = Record.readString();          Satisfaction.Details.emplace_back( @@ -755,8 +743,137 @@ void ASTStmtReader::VisitConceptSpecializationExpr(          Satisfaction.Details.emplace_back(ConstraintExpr, Record.readExpr());      }    } -  E->Satisfaction = ASTConstraintSatisfaction::Create(Record.getContext(), -                                                      Satisfaction); +  return Satisfaction; +} + +void ASTStmtReader::VisitConceptSpecializationExpr( +        ConceptSpecializationExpr *E) { +  VisitExpr(E); +  unsigned NumTemplateArgs = Record.readInt(); +  E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); +  E->TemplateKWLoc = Record.readSourceLocation(); +  E->ConceptName = Record.readDeclarationNameInfo(); +  E->NamedConcept = readDeclAs<ConceptDecl>(); +  E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); +  llvm::SmallVector<TemplateArgument, 4> Args; +  for (unsigned I = 0; I < NumTemplateArgs; ++I) +    Args.push_back(Record.readTemplateArgument()); +  E->setTemplateArguments(Args); +  E->Satisfaction = E->isValueDependent() ? nullptr : +      ASTConstraintSatisfaction::Create(Record.getContext(), +                                        readConstraintSatisfaction(Record)); +} + +static concepts::Requirement::SubstitutionDiagnostic * +readSubstitutionDiagnostic(ASTRecordReader &Record) { +  std::string SubstitutedEntity = Record.readString(); +  SourceLocation DiagLoc = Record.readSourceLocation(); +  std::string DiagMessage = Record.readString(); +  return new (Record.getContext()) +      concepts::Requirement::SubstitutionDiagnostic{SubstitutedEntity, DiagLoc, +                                                    DiagMessage}; +} + +void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) { +  VisitExpr(E); +  unsigned NumLocalParameters = Record.readInt(); +  unsigned NumRequirements = Record.readInt(); +  E->RequiresExprBits.RequiresKWLoc = Record.readSourceLocation(); +  E->RequiresExprBits.IsSatisfied = Record.readInt(); +  E->Body = Record.readDeclAs<RequiresExprBodyDecl>(); +  llvm::SmallVector<ParmVarDecl *, 4> LocalParameters; +  for (unsigned i = 0; i < NumLocalParameters; ++i) +    LocalParameters.push_back(cast<ParmVarDecl>(Record.readDecl())); +  std::copy(LocalParameters.begin(), LocalParameters.end(), +            E->getTrailingObjects<ParmVarDecl *>()); +  llvm::SmallVector<concepts::Requirement *, 4> Requirements; +  for (unsigned i = 0; i < NumRequirements; ++i) { +    auto RK = +        static_cast<concepts::Requirement::RequirementKind>(Record.readInt()); +    concepts::Requirement *R = nullptr; +    switch (RK) { +      case concepts::Requirement::RK_Type: { +        auto Status = +            static_cast<concepts::TypeRequirement::SatisfactionStatus>( +                Record.readInt()); +        if (Status == concepts::TypeRequirement::SS_SubstitutionFailure) +          R = new (Record.getContext()) +              concepts::TypeRequirement(readSubstitutionDiagnostic(Record)); +        else +          R = new (Record.getContext()) +              concepts::TypeRequirement(Record.readTypeSourceInfo()); +      } break; +      case concepts::Requirement::RK_Simple: +      case concepts::Requirement::RK_Compound: { +        auto Status = +            static_cast<concepts::ExprRequirement::SatisfactionStatus>( +                Record.readInt()); +        llvm::PointerUnion<concepts::Requirement::SubstitutionDiagnostic *, +                           Expr *> E; +        if (Status == concepts::ExprRequirement::SS_ExprSubstitutionFailure) { +          E = readSubstitutionDiagnostic(Record); +        } else +          E = Record.readExpr(); + +        llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> Req; +        ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; +        SourceLocation NoexceptLoc; +        if (RK == concepts::Requirement::RK_Simple) { +          Req.emplace(); +        } else { +          NoexceptLoc = Record.readSourceLocation(); +          switch (auto returnTypeRequirementKind = Record.readInt()) { +            case 0: +              // No return type requirement. +              Req.emplace(); +              break; +            case 1: { +              // type-constraint +              TemplateParameterList *TPL = Record.readTemplateParameterList(); +              if (Status >= +                  concepts::ExprRequirement::SS_ConstraintsNotSatisfied) +                SubstitutedConstraintExpr = +                    cast<ConceptSpecializationExpr>(Record.readExpr()); +              Req.emplace(TPL); +            } break; +            case 2: +              // Substitution failure +              Req.emplace(readSubstitutionDiagnostic(Record)); +              break; +          } +        } +        if (Expr *Ex = E.dyn_cast<Expr *>()) +          R = new (Record.getContext()) concepts::ExprRequirement( +                  Ex, RK == concepts::Requirement::RK_Simple, NoexceptLoc, +                  std::move(*Req), Status, SubstitutedConstraintExpr); +        else +          R = new (Record.getContext()) concepts::ExprRequirement( +                  E.get<concepts::Requirement::SubstitutionDiagnostic *>(), +                  RK == concepts::Requirement::RK_Simple, NoexceptLoc, +                  std::move(*Req)); +      } break; +      case concepts::Requirement::RK_Nested: { +        if (bool IsSubstitutionDiagnostic = Record.readInt()) { +          R = new (Record.getContext()) concepts::NestedRequirement( +              readSubstitutionDiagnostic(Record)); +          break; +        } +        Expr *E = Record.readExpr(); +        if (E->isInstantiationDependent()) +          R = new (Record.getContext()) concepts::NestedRequirement(E); +        else +          R = new (Record.getContext()) +              concepts::NestedRequirement(Record.getContext(), E, +                                          readConstraintSatisfaction(Record)); +      } break; +    } +    if (!R) +      continue; +    Requirements.push_back(R); +  } +  std::copy(Requirements.begin(), Requirements.end(), +            E->getTrailingObjects<concepts::Requirement *>()); +  E->RBraceLoc = Record.readSourceLocation();  }  void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { @@ -3566,11 +3683,18 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {        S = new (Context) DependentCoawaitExpr(Empty);        break; -    case EXPR_CONCEPT_SPECIALIZATION: +    case EXPR_CONCEPT_SPECIALIZATION: {        unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields];        S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs);        break; -       +    } + +    case EXPR_REQUIRES: +      unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields]; +      unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1]; +      S = RequiresExpr::Create(Context, Empty, numLocalParameters, +                               numRequirement); +      break;      }      // We hit a STMT_STOP, so we're done with this expression. diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 6eba48a1abe97..252853aad1f86 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -349,6 +349,18 @@ void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {  void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {    Record.AddSourceLocation(TL.getNameLoc()); +  Record.push_back(TL.isConstrained()); +  if (TL.isConstrained()) { +    Record.AddNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()); +    Record.AddSourceLocation(TL.getTemplateKWLoc()); +    Record.AddSourceLocation(TL.getConceptNameLoc()); +    Record.AddDeclRef(TL.getFoundDecl()); +    Record.AddSourceLocation(TL.getLAngleLoc()); +    Record.AddSourceLocation(TL.getRAngleLoc()); +    for (unsigned I = 0; I < TL.getNumArgs(); ++I) +      Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(), +                                        TL.getArgLocInfo(I)); +  }  }  void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc( @@ -885,6 +897,7 @@ void ASTWriter::WriteBlockInfoBlock() {    RECORD(DECL_NON_TYPE_TEMPLATE_PARM);    RECORD(DECL_TEMPLATE_TEMPLATE_PARM);    RECORD(DECL_CONCEPT); +  RECORD(DECL_REQUIRES_EXPR_BODY);    RECORD(DECL_TYPE_ALIAS_TEMPLATE);    RECORD(DECL_STATIC_ASSERT);    RECORD(DECL_CXX_BASE_SPECIFIERS); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index b2a8c118d4011..472136d99a131 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -104,6 +104,7 @@ namespace clang {      void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);      void VisitTemplateDecl(TemplateDecl *D);      void VisitConceptDecl(ConceptDecl *D); +    void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);      void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);      void VisitClassTemplateDecl(ClassTemplateDecl *D);      void VisitVarTemplateDecl(VarTemplateDecl *D); @@ -1481,6 +1482,10 @@ void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {    Code = serialization::DECL_CONCEPT;  } +void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { +  Code = serialization::DECL_REQUIRES_EXPR_BODY; +} +  void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {    VisitRedeclarable(D); @@ -1670,6 +1675,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {    // For an expanded parameter pack, record the number of expansion types here    // so that it's easier for deserialization to allocate the right amount of    // memory. +  Expr *TypeConstraint = D->getPlaceholderTypeConstraint(); +  Record.push_back(!!TypeConstraint);    if (D->isExpandedParameterPack())      Record.push_back(D->getNumExpansionTypes()); @@ -1677,6 +1684,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {    // TemplateParmPosition.    Record.push_back(D->getDepth());    Record.push_back(D->getPosition()); +  if (TypeConstraint) +    Record.AddStmt(TypeConstraint);    if (D->isExpandedParameterPack()) {      for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 9231f3b2b9ba2..1b118c257a4cc 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "clang/Serialization/ASTRecordWriter.h" +#include "clang/Sema/DeclSpec.h"  #include "clang/AST/ASTContext.h"  #include "clang/AST/DeclCXX.h"  #include "clang/AST/DeclObjC.h" @@ -388,19 +389,9 @@ void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {    Code = serialization::EXPR_DEPENDENT_COAWAIT;  } -void ASTStmtWriter::VisitConceptSpecializationExpr( -        ConceptSpecializationExpr *E) { -  VisitExpr(E); -  ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments(); -  Record.push_back(TemplateArgs.size()); -  Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc()); -  Record.AddSourceLocation(E->getTemplateKWLoc()); -  Record.AddDeclarationNameInfo(E->getConceptNameInfo()); -  Record.AddDeclRef(E->getNamedConcept()); -  Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); -  for (const TemplateArgument &Arg : TemplateArgs) -    Record.AddTemplateArgument(Arg); -  const ASTConstraintSatisfaction &Satisfaction = E->getSatisfaction(); +static void +addConstraintSatisfaction(ASTRecordWriter &Record, +                          const ASTConstraintSatisfaction &Satisfaction) {    Record.push_back(Satisfaction.IsSatisfied);    if (!Satisfaction.IsSatisfied) {      Record.push_back(Satisfaction.NumRecords); @@ -418,10 +409,98 @@ void ASTStmtWriter::VisitConceptSpecializationExpr(        }      }    } +} + +static void +addSubstitutionDiagnostic( +    ASTRecordWriter &Record, +    const concepts::Requirement::SubstitutionDiagnostic *D) { +  Record.AddString(D->SubstitutedEntity); +  Record.AddSourceLocation(D->DiagLoc); +  Record.AddString(D->DiagMessage); +} + +void ASTStmtWriter::VisitConceptSpecializationExpr( +        ConceptSpecializationExpr *E) { +  VisitExpr(E); +  ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments(); +  Record.push_back(TemplateArgs.size()); +  Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc()); +  Record.AddSourceLocation(E->getTemplateKWLoc()); +  Record.AddDeclarationNameInfo(E->getConceptNameInfo()); +  Record.AddDeclRef(E->getNamedConcept()); +  Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); +  for (const TemplateArgument &Arg : TemplateArgs) +    Record.AddTemplateArgument(Arg); +  if (!E->isValueDependent()) +    addConstraintSatisfaction(Record, E->getSatisfaction());    Code = serialization::EXPR_CONCEPT_SPECIALIZATION;  } +void ASTStmtWriter::VisitRequiresExpr(RequiresExpr *E) { +  VisitExpr(E); +  Record.push_back(E->getLocalParameters().size()); +  Record.push_back(E->getRequirements().size()); +  Record.AddSourceLocation(E->RequiresExprBits.RequiresKWLoc); +  Record.push_back(E->RequiresExprBits.IsSatisfied); +  Record.AddDeclRef(E->getBody()); +  for (ParmVarDecl *P : E->getLocalParameters()) +    Record.AddDeclRef(P); +  for (concepts::Requirement *R : E->getRequirements()) { +    if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(R)) { +      Record.push_back(concepts::Requirement::RK_Type); +      Record.push_back(TypeReq->Status); +      if (TypeReq->Status == concepts::TypeRequirement::SS_SubstitutionFailure) +        addSubstitutionDiagnostic(Record, TypeReq->getSubstitutionDiagnostic()); +      else +        Record.AddTypeSourceInfo(TypeReq->getType()); +    } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R)) { +      Record.push_back(ExprReq->getKind()); +      Record.push_back(ExprReq->Status); +      if (ExprReq->isExprSubstitutionFailure()) { +        addSubstitutionDiagnostic(Record, +         ExprReq->Value.get<concepts::Requirement::SubstitutionDiagnostic *>()); +      } else +        Record.AddStmt(ExprReq->Value.get<Expr *>()); +      if (ExprReq->getKind() == concepts::Requirement::RK_Compound) { +        Record.AddSourceLocation(ExprReq->NoexceptLoc); +        const auto &RetReq = ExprReq->getReturnTypeRequirement(); +        if (RetReq.isSubstitutionFailure()) { +          Record.push_back(2); +          addSubstitutionDiagnostic(Record, RetReq.getSubstitutionDiagnostic()); +        } else if (RetReq.isTypeConstraint()) { +          Record.push_back(1); +          Record.AddTemplateParameterList( +              RetReq.getTypeConstraintTemplateParameterList()); +          if (ExprReq->Status >= +              concepts::ExprRequirement::SS_ConstraintsNotSatisfied) +            Record.AddStmt( +                ExprReq->getReturnTypeRequirementSubstitutedConstraintExpr()); +        } else { +          assert(RetReq.isEmpty()); +          Record.push_back(0); +        } +      } +    } else { +      auto *NestedReq = cast<concepts::NestedRequirement>(R); +      Record.push_back(concepts::Requirement::RK_Nested); +      Record.push_back(NestedReq->isSubstitutionFailure()); +      if (NestedReq->isSubstitutionFailure()){ +        addSubstitutionDiagnostic(Record, +                                  NestedReq->getSubstitutionDiagnostic()); +      } else { +        Record.AddStmt(NestedReq->Value.get<Expr *>()); +        if (!NestedReq->isDependent()) +          addConstraintSatisfaction(Record, *NestedReq->Satisfaction); +      } +    } +  } +  Record.AddSourceLocation(E->getEndLoc()); + +  Code = serialization::EXPR_REQUIRES; +} +  void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {    VisitStmt(S); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index f917a4c8637b6..b542cf2c03038 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1386,6 +1386,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,      case Stmt::AsTypeExprClass:      case Stmt::ConceptSpecializationExprClass:      case Stmt::CXXRewrittenBinaryOperatorClass: +    case Stmt::RequiresExprClass:        // Fall through.      // Cases we intentionally don't evaluate, since they don't need | 
