From 7fb562c1ab373a3d4e14003e40556791ec032bab Mon Sep 17 00:00:00 2001 From: Saar Raz Date: Tue, 10 Mar 2020 22:05:36 +0200 Subject: [PATCH] [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. --- clang/lib/Serialization/ASTReaderDecl.cpp | 67 ++++++++++++++++++++++++++++--- clang/test/PCH/cxx2a-constraints.cpp | 37 +++++++++++++++++ 2 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 clang/test/PCH/cxx2a-constraints.cpp diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 362d3ea..828f4a1 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -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(X)) { const auto *TY = cast(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(X)) { @@ -2894,7 +2920,8 @@ static bool isSameTemplateParameter(const NamedDecl *X, const auto *TX = cast(X); const auto *TY = cast(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(Y); return isSameEntity(TemplateX->getTemplatedDecl(), TemplateY->getTemplatedDecl()) && - isSameTemplateParameterList(TemplateX->getTemplateParameters(), + isSameTemplateParameterList(TemplateX->getASTContext(), + TemplateX->getTemplateParameters(), TemplateY->getTemplateParameters()); } diff --git a/clang/test/PCH/cxx2a-constraints.cpp b/clang/test/PCH/cxx2a-constraints.cpp new file mode 100644 index 0000000..593d962 --- /dev/null +++ b/clang/test/PCH/cxx2a-constraints.cpp @@ -0,0 +1,37 @@ +// 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 +concept SizedLike = sizeof(T) == sizeof(U); + +template void f(T) requires (sizeof(int) == sizeof(T)) {} +template void f(T) requires (sizeof(char) == sizeof(T)) {} + +template requires (sizeof(int) == sizeof(T)) void g(T) {} +template requires (sizeof(char) == sizeof(T)) void g(T) {} + +template T> void h(T) {} +template T> void h(T) {} + +template T> void i(T) {} +template 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 -- 2.7.4