Support for merging UsingPackDecls across modules.

Fixes a false-positive error if the same std::variant<...> type is
instantiated across multiple modules.
This commit is contained in:
Richard Smith 2021-07-01 18:43:01 -07:00
parent f6b6e72143
commit 9ab5f76117
4 changed files with 50 additions and 2 deletions

View File

@ -3067,7 +3067,7 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
return true; return true;
} }
/// Determine whether the two declarations refer to the same entity.pr /// Determine whether the two declarations refer to the same entity.
static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!"); assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
@ -3261,10 +3261,19 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
UX->isAccessDeclaration() == UY->isAccessDeclaration(); UX->isAccessDeclaration() == UY->isAccessDeclaration();
} }
if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) {
return isSameQualifier( return isSameQualifier(
UX->getQualifier(), UX->getQualifier(),
cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier()); cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier());
}
// Using-pack declarations are only created by instantiation, and match if
// they're instantiated from matching UnresolvedUsing...Decls.
if (const auto *UX = dyn_cast<UsingPackDecl>(X)) {
return declaresSameEntity(
UX->getInstantiatedFromUsingDecl(),
cast<UsingPackDecl>(Y)->getInstantiatedFromUsingDecl());
}
// Namespace alias definitions with the same target match. // Namespace alias definitions with the same target match.
if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) { if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {

View File

@ -1,6 +1,7 @@
struct X { struct X {
int v; int v;
typedef int t; typedef int t;
void f(X);
}; };
struct YA { struct YA {
@ -8,6 +9,10 @@ struct YA {
typedef int type; typedef int type;
}; };
struct Z {
void f(Z);
};
template<typename T> struct C : X, T { template<typename T> struct C : X, T {
using T::value; using T::value;
using typename T::type; using typename T::type;
@ -41,3 +46,10 @@ typedef C<YA>::type I;
typedef D<YA>::type I; typedef D<YA>::type I;
typedef E<YA>::type I; typedef E<YA>::type I;
typedef F<YA>::type I; typedef F<YA>::type I;
#if __cplusplus >= 201702L
template<typename ...T> struct G : T... {
using T::f...;
};
using Q = decltype(G<X, Z>());
#endif

View File

@ -1,6 +1,7 @@
struct X { struct X {
int v; int v;
typedef int t; typedef int t;
void f(X);
}; };
struct YB { struct YB {
@ -14,6 +15,10 @@ struct YBRev {
int type; int type;
}; };
struct Z {
void f(Z);
};
template<typename T> struct C : X, T { template<typename T> struct C : X, T {
using T::value; using T::value;
using typename T::type; using typename T::type;
@ -54,3 +59,10 @@ typedef E<YB>::type I;
#endif #endif
typedef F<YB>::type I; typedef F<YB>::type I;
#if __cplusplus >= 201702L
template<typename ...T> struct G : T... {
using T::f...;
};
using Q = decltype(G<X, Z>());
#endif

View File

@ -2,9 +2,11 @@
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=1 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=1
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++98 %s -DORDER=1 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++98 %s -DORDER=1
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++11 %s -DORDER=1 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++11 %s -DORDER=1
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++17 %s -DORDER=1
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=2 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=2
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++98 %s -DORDER=2 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++98 %s -DORDER=2
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++11 %s -DORDER=2 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++11 %s -DORDER=2
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++17 %s -DORDER=2
#if ORDER == 1 #if ORDER == 1
#include "a.h" #include "a.h"
@ -39,6 +41,19 @@ template int UseAll<YA>();
template int UseAll<YB>(); template int UseAll<YB>();
template int UseAll<Y>(); template int UseAll<Y>();
#if __cplusplus >= 201702L
void use_g(Q q) {
q.f(q); // expected-error {{ambiguous}}
#if ORDER == 1
// expected-note@a.h:* {{candidate function}}
// expected-note@a.h:* {{candidate function}}
#else
// expected-note@b.h:* {{candidate function}}
// expected-note@b.h:* {{candidate function}}
#endif
}
#endif
// Which of these two sets of diagnostics is chosen is not important. It's OK // Which of these two sets of diagnostics is chosen is not important. It's OK
// if this varies with ORDER, but it must be consistent across runs. // if this varies with ORDER, but it must be consistent across runs.
#if ORDER == 1 #if ORDER == 1