Commit 7fb562c1 authored by Saar Raz's avatar Saar Raz
Browse files

[Concepts] Add constraints checks to isSameEntity

isSameEntity was missing constraints checking, causing constrained overloads
to not travel well accross serialization. (bug #45115)

Add constraints checking to isSameEntity.
parent f9e63891
Loading
Loading
Loading
Loading
+61 −6
Original line number Diff line number Diff line
@@ -2870,7 +2870,8 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset) {
  return LocalOffset + M.GlobalBitOffset;
}

static bool isSameTemplateParameterList(const TemplateParameterList *X,
static bool isSameTemplateParameterList(const ASTContext &C,
                                        const TemplateParameterList *X,
                                        const TemplateParameterList *Y);

/// Determine whether two template parameters are similar enough
@@ -2882,7 +2883,32 @@ static bool isSameTemplateParameter(const NamedDecl *X,

  if (const auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) {
    const auto *TY = cast<TemplateTypeParmDecl>(Y);
    return TX->isParameterPack() == TY->isParameterPack();
    if (TX->isParameterPack() != TY->isParameterPack())
      return false;
    if (TX->hasTypeConstraint() != TY->hasTypeConstraint())
      return false;
    if (TX->hasTypeConstraint()) {
      const TypeConstraint *TXTC = TX->getTypeConstraint();
      const TypeConstraint *TYTC = TY->getTypeConstraint();
      if (TXTC->getNamedConcept() != TYTC->getNamedConcept())
        return false;
      if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs())
        return false;
      if (TXTC->hasExplicitTemplateArgs()) {
        const auto *TXTCArgs = TXTC->getTemplateArgsAsWritten();
        const auto *TYTCArgs = TYTC->getTemplateArgsAsWritten();
        if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs)
          return false;
        llvm::FoldingSetNodeID XID, YID;
        for (const auto &ArgLoc : TXTCArgs->arguments())
          ArgLoc.getArgument().Profile(XID, X->getASTContext());
        for (const auto &ArgLoc : TYTCArgs->arguments())
          ArgLoc.getArgument().Profile(YID, Y->getASTContext());
        if (XID != YID)
          return false;
      }
    }
    return true;
  }

  if (const auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
@@ -2894,7 +2920,8 @@ static bool isSameTemplateParameter(const NamedDecl *X,
  const auto *TX = cast<TemplateTemplateParmDecl>(X);
  const auto *TY = cast<TemplateTemplateParmDecl>(Y);
  return TX->isParameterPack() == TY->isParameterPack() &&
         isSameTemplateParameterList(TX->getTemplateParameters(),
         isSameTemplateParameterList(TX->getASTContext(),
                                     TX->getTemplateParameters(),
                                     TY->getTemplateParameters());
}

@@ -2947,7 +2974,8 @@ static bool isSameQualifier(const NestedNameSpecifier *X,

/// Determine whether two template parameter lists are similar enough
/// that they may be used in declarations of the same template.
static bool isSameTemplateParameterList(const TemplateParameterList *X,
static bool isSameTemplateParameterList(const ASTContext &C,
                                        const TemplateParameterList *X,
                                        const TemplateParameterList *Y) {
  if (X->size() != Y->size())
    return false;
@@ -2956,6 +2984,18 @@ static bool isSameTemplateParameterList(const TemplateParameterList *X,
    if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I)))
      return false;

  const Expr *XRC = X->getRequiresClause();
  const Expr *YRC = Y->getRequiresClause();
  if (!XRC != !YRC)
    return false;
  if (XRC) {
    llvm::FoldingSetNodeID XRCID, YRCID;
    XRC->Profile(XRCID, C, /*Canonical=*/true);
    YRC->Profile(YRCID, C, /*Canonical=*/true);
    if (XRCID != YRCID)
      return false;
  }

  return true;
}

@@ -2992,7 +3032,7 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
  return true;
}

/// Determine whether the two declarations refer to the same entity.
/// Determine whether the two declarations refer to the same entity.pr
static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
  assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");

@@ -3067,6 +3107,19 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
    }

    ASTContext &C = FuncX->getASTContext();

    const Expr *XRC = FuncX->getTrailingRequiresClause();
    const Expr *YRC = FuncY->getTrailingRequiresClause();
    if (!XRC != !YRC)
      return false;
    if (XRC) {
      llvm::FoldingSetNodeID XRCID, YRCID;
      XRC->Profile(XRCID, C, /*Canonical=*/true);
      YRC->Profile(YRCID, C, /*Canonical=*/true);
      if (XRCID != YRCID)
        return false;
    }

    auto GetTypeAsWritten = [](const FunctionDecl *FD) {
      // Map to the first declaration that we've already merged into this one.
      // The TSI of redeclarations might not match (due to calling conventions
@@ -3090,6 +3143,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
        return true;
      return false;
    }

    return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() &&
           hasSameOverloadableAttrs(FuncX, FuncY);
  }
@@ -3129,7 +3183,8 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
    const auto *TemplateY = cast<TemplateDecl>(Y);
    return isSameEntity(TemplateX->getTemplatedDecl(),
                        TemplateY->getTemplatedDecl()) &&
           isSameTemplateParameterList(TemplateX->getTemplateParameters(),
           isSameTemplateParameterList(TemplateX->getASTContext(),
                                       TemplateX->getTemplateParameters(),
                                       TemplateY->getTemplateParameters());
  }

+37 −0
Original line number Diff line number Diff line
// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s

// expected-no-diagnostics

#ifndef HEADER
#define HEADER

template<typename T, typename U = char>
concept SizedLike = sizeof(T) == sizeof(U);

template <class T> void f(T) requires (sizeof(int) == sizeof(T)) {}
template <class T> void f(T) requires (sizeof(char) == sizeof(T)) {}

template <class T> requires (sizeof(int) == sizeof(T)) void g(T) {}
template <class T> requires (sizeof(char) == sizeof(T)) void g(T) {}

template <SizedLike<int> T> void h(T) {}
template <SizedLike<char> T> void h(T) {}

template <SizedLike<int> T> void i(T) {}
template <SizedLike T> void i(T) {}

#else /*included pch*/

int main() {
  (void)f('1');
  (void)f(1);
  (void)g('1');
  (void)g(1);
  (void)h('1');
  (void)h(1);
  (void)i('1');
  (void)i(1);
}

#endif // HEADER
 No newline at end of file