forked from OSchip/llvm-project
[NFC] [AST] Move isSameEntity into ASTContext
Currently we are trying to implement the semantics of C++ Modules. A big challenge would be the ODR checking. Previously we did this in ASTReader, it would handle the cases like: ``` module; export module a_module; import another_module; // check the ODR consistency here ``` or ``` export module m; import a_module; import another_module; // check the ODR consistency here ``` However, it wouldn't handle the case: ``` import another_module; // When we check ODR here, everything looks fine. ``` In the case, the read process is ended. But we need to check the ODR still. To reuse the facility we do in ASTReader, this patch moves the corresponding codes into ASTContext. This should be good since there were facilities like `hasSameTemplateName` and `hasSameType`. Although the patch is a little bit big, all of the change should be trivial. Reviewed By: erichkeane Differential Revision: https://reviews.llvm.org/D118223
This commit is contained in:
parent
1510668fb0
commit
f85ee6d56a
|
@ -2622,6 +2622,18 @@ public:
|
|||
/// template.
|
||||
bool hasSameTemplateName(TemplateName X, TemplateName Y);
|
||||
|
||||
/// Determine whether the two declarations refer to the same entity.
|
||||
bool isSameEntity(NamedDecl *X, NamedDecl *Y);
|
||||
|
||||
/// Determine whether two template parameter lists are similar enough
|
||||
/// that they may be used in declarations of the same template.
|
||||
bool isSameTemplateParameterList(TemplateParameterList *X,
|
||||
TemplateParameterList *Y);
|
||||
|
||||
/// Determine whether two template parameters are similar enough
|
||||
/// that they may be used in declarations of the same template.
|
||||
bool isSameTemplateParameter(NamedDecl *X, NamedDecl *Y);
|
||||
|
||||
/// Retrieve the "canonical" template argument.
|
||||
///
|
||||
/// The canonical template argument is the simplest template argument
|
||||
|
|
|
@ -6147,6 +6147,376 @@ bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) {
|
|||
return X.getAsVoidPointer() == Y.getAsVoidPointer();
|
||||
}
|
||||
|
||||
bool ASTContext::isSameTemplateParameter(NamedDecl *X, NamedDecl *Y) {
|
||||
if (X->getKind() != Y->getKind())
|
||||
return false;
|
||||
|
||||
if (auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) {
|
||||
auto *TY = cast<TemplateTypeParmDecl>(Y);
|
||||
if (TX->isParameterPack() != TY->isParameterPack())
|
||||
return false;
|
||||
if (TX->hasTypeConstraint() != TY->hasTypeConstraint())
|
||||
return false;
|
||||
const TypeConstraint *TXTC = TX->getTypeConstraint();
|
||||
const TypeConstraint *TYTC = TY->getTypeConstraint();
|
||||
if (!TXTC != !TYTC)
|
||||
return false;
|
||||
if (TXTC && TYTC) {
|
||||
auto *NCX = TXTC->getNamedConcept();
|
||||
auto *NCY = TYTC->getNamedConcept();
|
||||
if (!NCX || !NCY || !isSameEntity(NCX, NCY))
|
||||
return false;
|
||||
if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs())
|
||||
return false;
|
||||
if (TXTC->hasExplicitTemplateArgs()) {
|
||||
auto *TXTCArgs = TXTC->getTemplateArgsAsWritten();
|
||||
auto *TYTCArgs = TYTC->getTemplateArgsAsWritten();
|
||||
if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs)
|
||||
return false;
|
||||
llvm::FoldingSetNodeID XID, YID;
|
||||
for (auto &ArgLoc : TXTCArgs->arguments())
|
||||
ArgLoc.getArgument().Profile(XID, X->getASTContext());
|
||||
for (auto &ArgLoc : TYTCArgs->arguments())
|
||||
ArgLoc.getArgument().Profile(YID, Y->getASTContext());
|
||||
if (XID != YID)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
|
||||
auto *TY = cast<NonTypeTemplateParmDecl>(Y);
|
||||
return TX->isParameterPack() == TY->isParameterPack() &&
|
||||
TX->getASTContext().hasSameType(TX->getType(), TY->getType());
|
||||
}
|
||||
|
||||
auto *TX = cast<TemplateTemplateParmDecl>(X);
|
||||
auto *TY = cast<TemplateTemplateParmDecl>(Y);
|
||||
return TX->isParameterPack() == TY->isParameterPack() &&
|
||||
isSameTemplateParameterList(TX->getTemplateParameters(),
|
||||
TY->getTemplateParameters());
|
||||
}
|
||||
|
||||
bool ASTContext::isSameTemplateParameterList(TemplateParameterList *X,
|
||||
TemplateParameterList *Y) {
|
||||
if (X->size() != Y->size())
|
||||
return false;
|
||||
|
||||
for (unsigned I = 0, N = X->size(); I != N; ++I)
|
||||
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, *this, /*Canonical=*/true);
|
||||
YRC->Profile(YRCID, *this, /*Canonical=*/true);
|
||||
if (XRCID != YRCID)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
|
||||
if (auto *NS = X->getAsNamespace())
|
||||
return NS;
|
||||
if (auto *NAS = X->getAsNamespaceAlias())
|
||||
return NAS->getNamespace();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool isSameQualifier(const NestedNameSpecifier *X,
|
||||
const NestedNameSpecifier *Y) {
|
||||
if (auto *NSX = getNamespace(X)) {
|
||||
auto *NSY = getNamespace(Y);
|
||||
if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl())
|
||||
return false;
|
||||
} else if (X->getKind() != Y->getKind())
|
||||
return false;
|
||||
|
||||
// FIXME: For namespaces and types, we're permitted to check that the entity
|
||||
// is named via the same tokens. We should probably do so.
|
||||
switch (X->getKind()) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
if (X->getAsIdentifier() != Y->getAsIdentifier())
|
||||
return false;
|
||||
break;
|
||||
case NestedNameSpecifier::Namespace:
|
||||
case NestedNameSpecifier::NamespaceAlias:
|
||||
// We've already checked that we named the same namespace.
|
||||
break;
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
case NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
if (X->getAsType()->getCanonicalTypeInternal() !=
|
||||
Y->getAsType()->getCanonicalTypeInternal())
|
||||
return false;
|
||||
break;
|
||||
case NestedNameSpecifier::Global:
|
||||
case NestedNameSpecifier::Super:
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recurse into earlier portion of NNS, if any.
|
||||
auto *PX = X->getPrefix();
|
||||
auto *PY = Y->getPrefix();
|
||||
if (PX && PY)
|
||||
return isSameQualifier(PX, PY);
|
||||
return !PX && !PY;
|
||||
}
|
||||
|
||||
/// Determine whether the attributes we can overload on are identical for A and
|
||||
/// B. Will ignore any overloadable attrs represented in the type of A and B.
|
||||
static bool hasSameOverloadableAttrs(const FunctionDecl *A,
|
||||
const FunctionDecl *B) {
|
||||
// Note that pass_object_size attributes are represented in the function's
|
||||
// ExtParameterInfo, so we don't need to check them here.
|
||||
|
||||
llvm::FoldingSetNodeID Cand1ID, Cand2ID;
|
||||
auto AEnableIfAttrs = A->specific_attrs<EnableIfAttr>();
|
||||
auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>();
|
||||
|
||||
for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) {
|
||||
Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
|
||||
Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
|
||||
|
||||
// Return false if the number of enable_if attributes is different.
|
||||
if (!Cand1A || !Cand2A)
|
||||
return false;
|
||||
|
||||
Cand1ID.clear();
|
||||
Cand2ID.clear();
|
||||
|
||||
(*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true);
|
||||
(*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true);
|
||||
|
||||
// Return false if any of the enable_if expressions of A and B are
|
||||
// different.
|
||||
if (Cand1ID != Cand2ID)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTContext::isSameEntity(NamedDecl *X, NamedDecl *Y) {
|
||||
if (X == Y)
|
||||
return true;
|
||||
|
||||
if (X->getDeclName() != Y->getDeclName())
|
||||
return false;
|
||||
|
||||
// Must be in the same context.
|
||||
//
|
||||
// Note that we can't use DeclContext::Equals here, because the DeclContexts
|
||||
// could be two different declarations of the same function. (We will fix the
|
||||
// semantic DC to refer to the primary definition after merging.)
|
||||
if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()),
|
||||
cast<Decl>(Y->getDeclContext()->getRedeclContext())))
|
||||
return false;
|
||||
|
||||
// Two typedefs refer to the same entity if they have the same underlying
|
||||
// type.
|
||||
if (const auto *TypedefX = dyn_cast<TypedefNameDecl>(X))
|
||||
if (const auto *TypedefY = dyn_cast<TypedefNameDecl>(Y))
|
||||
return hasSameType(TypedefX->getUnderlyingType(),
|
||||
TypedefY->getUnderlyingType());
|
||||
|
||||
// Must have the same kind.
|
||||
if (X->getKind() != Y->getKind())
|
||||
return false;
|
||||
|
||||
// Objective-C classes and protocols with the same name always match.
|
||||
if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
|
||||
return true;
|
||||
|
||||
if (isa<ClassTemplateSpecializationDecl>(X)) {
|
||||
// No need to handle these here: we merge them when adding them to the
|
||||
// template.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compatible tags match.
|
||||
if (const auto *TagX = dyn_cast<TagDecl>(X)) {
|
||||
const auto *TagY = cast<TagDecl>(Y);
|
||||
return (TagX->getTagKind() == TagY->getTagKind()) ||
|
||||
((TagX->getTagKind() == TTK_Struct ||
|
||||
TagX->getTagKind() == TTK_Class ||
|
||||
TagX->getTagKind() == TTK_Interface) &&
|
||||
(TagY->getTagKind() == TTK_Struct ||
|
||||
TagY->getTagKind() == TTK_Class ||
|
||||
TagY->getTagKind() == TTK_Interface));
|
||||
}
|
||||
|
||||
// Functions with the same type and linkage match.
|
||||
// FIXME: This needs to cope with merging of prototyped/non-prototyped
|
||||
// functions, etc.
|
||||
if (const auto *FuncX = dyn_cast<FunctionDecl>(X)) {
|
||||
const auto *FuncY = cast<FunctionDecl>(Y);
|
||||
if (const auto *CtorX = dyn_cast<CXXConstructorDecl>(X)) {
|
||||
const auto *CtorY = cast<CXXConstructorDecl>(Y);
|
||||
if (CtorX->getInheritedConstructor() &&
|
||||
!isSameEntity(CtorX->getInheritedConstructor().getConstructor(),
|
||||
CtorY->getInheritedConstructor().getConstructor()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FuncX->isMultiVersion() != FuncY->isMultiVersion())
|
||||
return false;
|
||||
|
||||
// Multiversioned functions with different feature strings are represented
|
||||
// as separate declarations.
|
||||
if (FuncX->isMultiVersion()) {
|
||||
const auto *TAX = FuncX->getAttr<TargetAttr>();
|
||||
const auto *TAY = FuncY->getAttr<TargetAttr>();
|
||||
assert(TAX && TAY && "Multiversion Function without target attribute");
|
||||
|
||||
if (TAX->getFeaturesStr() != TAY->getFeaturesStr())
|
||||
return false;
|
||||
}
|
||||
|
||||
const Expr *XRC = FuncX->getTrailingRequiresClause();
|
||||
const Expr *YRC = FuncY->getTrailingRequiresClause();
|
||||
if (!XRC != !YRC)
|
||||
return false;
|
||||
if (XRC) {
|
||||
llvm::FoldingSetNodeID XRCID, YRCID;
|
||||
XRC->Profile(XRCID, *this, /*Canonical=*/true);
|
||||
YRC->Profile(YRCID, *this, /*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
|
||||
// being inherited onto the type but not the TSI), but the TSI type of
|
||||
// the first declaration of the function should match across modules.
|
||||
FD = FD->getCanonicalDecl();
|
||||
return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType()
|
||||
: FD->getType();
|
||||
};
|
||||
QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY);
|
||||
if (!hasSameType(XT, YT)) {
|
||||
// We can get functions with different types on the redecl chain in C++17
|
||||
// if they have differing exception specifications and at least one of
|
||||
// the excpetion specs is unresolved.
|
||||
auto *XFPT = XT->getAs<FunctionProtoType>();
|
||||
auto *YFPT = YT->getAs<FunctionProtoType>();
|
||||
if (getLangOpts().CPlusPlus17 && XFPT && YFPT &&
|
||||
(isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
|
||||
isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
|
||||
hasSameFunctionTypeIgnoringExceptionSpec(XT, YT))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() &&
|
||||
hasSameOverloadableAttrs(FuncX, FuncY);
|
||||
}
|
||||
|
||||
// Variables with the same type and linkage match.
|
||||
if (const auto *VarX = dyn_cast<VarDecl>(X)) {
|
||||
const auto *VarY = cast<VarDecl>(Y);
|
||||
if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) {
|
||||
if (hasSameType(VarX->getType(), VarY->getType()))
|
||||
return true;
|
||||
|
||||
// We can get decls with different types on the redecl chain. Eg.
|
||||
// template <typename T> struct S { static T Var[]; }; // #1
|
||||
// template <typename T> T S<T>::Var[sizeof(T)]; // #2
|
||||
// Only? happens when completing an incomplete array type. In this case
|
||||
// when comparing #1 and #2 we should go through their element type.
|
||||
const ArrayType *VarXTy = getAsArrayType(VarX->getType());
|
||||
const ArrayType *VarYTy = getAsArrayType(VarY->getType());
|
||||
if (!VarXTy || !VarYTy)
|
||||
return false;
|
||||
if (VarXTy->isIncompleteArrayType() || VarYTy->isIncompleteArrayType())
|
||||
return hasSameType(VarXTy->getElementType(), VarYTy->getElementType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Namespaces with the same name and inlinedness match.
|
||||
if (const auto *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
|
||||
const auto *NamespaceY = cast<NamespaceDecl>(Y);
|
||||
return NamespaceX->isInline() == NamespaceY->isInline();
|
||||
}
|
||||
|
||||
// Identical template names and kinds match if their template parameter lists
|
||||
// and patterns match.
|
||||
if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) {
|
||||
const auto *TemplateY = cast<TemplateDecl>(Y);
|
||||
return isSameEntity(TemplateX->getTemplatedDecl(),
|
||||
TemplateY->getTemplatedDecl()) &&
|
||||
isSameTemplateParameterList(TemplateX->getTemplateParameters(),
|
||||
TemplateY->getTemplateParameters());
|
||||
}
|
||||
|
||||
// Fields with the same name and the same type match.
|
||||
if (const auto *FDX = dyn_cast<FieldDecl>(X)) {
|
||||
const auto *FDY = cast<FieldDecl>(Y);
|
||||
// FIXME: Also check the bitwidth is odr-equivalent, if any.
|
||||
return hasSameType(FDX->getType(), FDY->getType());
|
||||
}
|
||||
|
||||
// Indirect fields with the same target field match.
|
||||
if (const auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) {
|
||||
const auto *IFDY = cast<IndirectFieldDecl>(Y);
|
||||
return IFDX->getAnonField()->getCanonicalDecl() ==
|
||||
IFDY->getAnonField()->getCanonicalDecl();
|
||||
}
|
||||
|
||||
// Enumerators with the same name match.
|
||||
if (isa<EnumConstantDecl>(X))
|
||||
// FIXME: Also check the value is odr-equivalent.
|
||||
return true;
|
||||
|
||||
// Using shadow declarations with the same target match.
|
||||
if (const auto *USX = dyn_cast<UsingShadowDecl>(X)) {
|
||||
const auto *USY = cast<UsingShadowDecl>(Y);
|
||||
return USX->getTargetDecl() == USY->getTargetDecl();
|
||||
}
|
||||
|
||||
// Using declarations with the same qualifier match. (We already know that
|
||||
// the name matches.)
|
||||
if (const auto *UX = dyn_cast<UsingDecl>(X)) {
|
||||
const auto *UY = cast<UsingDecl>(Y);
|
||||
return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
|
||||
UX->hasTypename() == UY->hasTypename() &&
|
||||
UX->isAccessDeclaration() == UY->isAccessDeclaration();
|
||||
}
|
||||
if (const auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) {
|
||||
const auto *UY = cast<UnresolvedUsingValueDecl>(Y);
|
||||
return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
|
||||
UX->isAccessDeclaration() == UY->isAccessDeclaration();
|
||||
}
|
||||
if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) {
|
||||
return isSameQualifier(
|
||||
UX->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.
|
||||
if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
|
||||
const auto *NAY = cast<NamespaceAliasDecl>(Y);
|
||||
return NAX->getNamespace()->Equals(NAY->getNamespace());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TemplateArgument
|
||||
ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
|
||||
switch (Arg.getKind()) {
|
||||
|
|
|
@ -2945,391 +2945,6 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint64_t LocalOffset) {
|
|||
return LocalOffset + M.GlobalBitOffset;
|
||||
}
|
||||
|
||||
static bool isSameTemplateParameterList(const ASTContext &C,
|
||||
const TemplateParameterList *X,
|
||||
const TemplateParameterList *Y);
|
||||
static bool isSameEntity(NamedDecl *X, NamedDecl *Y);
|
||||
|
||||
/// Determine whether two template parameters are similar enough
|
||||
/// that they may be used in declarations of the same template.
|
||||
static bool isSameTemplateParameter(const NamedDecl *X,
|
||||
const NamedDecl *Y) {
|
||||
if (X->getKind() != Y->getKind())
|
||||
return false;
|
||||
|
||||
if (const auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) {
|
||||
const auto *TY = cast<TemplateTypeParmDecl>(Y);
|
||||
if (TX->isParameterPack() != TY->isParameterPack())
|
||||
return false;
|
||||
if (TX->hasTypeConstraint() != TY->hasTypeConstraint())
|
||||
return false;
|
||||
const TypeConstraint *TXTC = TX->getTypeConstraint();
|
||||
const TypeConstraint *TYTC = TY->getTypeConstraint();
|
||||
if (!TXTC != !TYTC)
|
||||
return false;
|
||||
if (TXTC && TYTC) {
|
||||
auto *NCX = TXTC->getNamedConcept();
|
||||
auto *NCY = TYTC->getNamedConcept();
|
||||
if (!NCX || !NCY || !isSameEntity(NCX, NCY))
|
||||
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)) {
|
||||
const auto *TY = cast<NonTypeTemplateParmDecl>(Y);
|
||||
return TX->isParameterPack() == TY->isParameterPack() &&
|
||||
TX->getASTContext().hasSameType(TX->getType(), TY->getType());
|
||||
}
|
||||
|
||||
const auto *TX = cast<TemplateTemplateParmDecl>(X);
|
||||
const auto *TY = cast<TemplateTemplateParmDecl>(Y);
|
||||
return TX->isParameterPack() == TY->isParameterPack() &&
|
||||
isSameTemplateParameterList(TX->getASTContext(),
|
||||
TX->getTemplateParameters(),
|
||||
TY->getTemplateParameters());
|
||||
}
|
||||
|
||||
static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
|
||||
if (auto *NS = X->getAsNamespace())
|
||||
return NS;
|
||||
if (auto *NAS = X->getAsNamespaceAlias())
|
||||
return NAS->getNamespace();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool isSameQualifier(const NestedNameSpecifier *X,
|
||||
const NestedNameSpecifier *Y) {
|
||||
if (auto *NSX = getNamespace(X)) {
|
||||
auto *NSY = getNamespace(Y);
|
||||
if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl())
|
||||
return false;
|
||||
} else if (X->getKind() != Y->getKind())
|
||||
return false;
|
||||
|
||||
// FIXME: For namespaces and types, we're permitted to check that the entity
|
||||
// is named via the same tokens. We should probably do so.
|
||||
switch (X->getKind()) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
if (X->getAsIdentifier() != Y->getAsIdentifier())
|
||||
return false;
|
||||
break;
|
||||
case NestedNameSpecifier::Namespace:
|
||||
case NestedNameSpecifier::NamespaceAlias:
|
||||
// We've already checked that we named the same namespace.
|
||||
break;
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
case NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
if (X->getAsType()->getCanonicalTypeInternal() !=
|
||||
Y->getAsType()->getCanonicalTypeInternal())
|
||||
return false;
|
||||
break;
|
||||
case NestedNameSpecifier::Global:
|
||||
case NestedNameSpecifier::Super:
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recurse into earlier portion of NNS, if any.
|
||||
auto *PX = X->getPrefix();
|
||||
auto *PY = Y->getPrefix();
|
||||
if (PX && PY)
|
||||
return isSameQualifier(PX, PY);
|
||||
return !PX && !PY;
|
||||
}
|
||||
|
||||
/// Determine whether two template parameter lists are similar enough
|
||||
/// that they may be used in declarations of the same template.
|
||||
static bool isSameTemplateParameterList(const ASTContext &C,
|
||||
const TemplateParameterList *X,
|
||||
const TemplateParameterList *Y) {
|
||||
if (X->size() != Y->size())
|
||||
return false;
|
||||
|
||||
for (unsigned I = 0, N = X->size(); I != N; ++I)
|
||||
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;
|
||||
}
|
||||
|
||||
/// Determine whether the attributes we can overload on are identical for A and
|
||||
/// B. Will ignore any overloadable attrs represented in the type of A and B.
|
||||
static bool hasSameOverloadableAttrs(const FunctionDecl *A,
|
||||
const FunctionDecl *B) {
|
||||
// Note that pass_object_size attributes are represented in the function's
|
||||
// ExtParameterInfo, so we don't need to check them here.
|
||||
|
||||
llvm::FoldingSetNodeID Cand1ID, Cand2ID;
|
||||
auto AEnableIfAttrs = A->specific_attrs<EnableIfAttr>();
|
||||
auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>();
|
||||
|
||||
for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) {
|
||||
Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
|
||||
Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
|
||||
|
||||
// Return false if the number of enable_if attributes is different.
|
||||
if (!Cand1A || !Cand2A)
|
||||
return false;
|
||||
|
||||
Cand1ID.clear();
|
||||
Cand2ID.clear();
|
||||
|
||||
(*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true);
|
||||
(*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true);
|
||||
|
||||
// Return false if any of the enable_if expressions of A and B are
|
||||
// different.
|
||||
if (Cand1ID != Cand2ID)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Determine whether the two declarations refer to the same entity.
|
||||
static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
|
||||
if (X == Y)
|
||||
return true;
|
||||
|
||||
if (X->getDeclName() != Y->getDeclName())
|
||||
return false;
|
||||
|
||||
// Must be in the same context.
|
||||
//
|
||||
// Note that we can't use DeclContext::Equals here, because the DeclContexts
|
||||
// could be two different declarations of the same function. (We will fix the
|
||||
// semantic DC to refer to the primary definition after merging.)
|
||||
if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()),
|
||||
cast<Decl>(Y->getDeclContext()->getRedeclContext())))
|
||||
return false;
|
||||
|
||||
// Two typedefs refer to the same entity if they have the same underlying
|
||||
// type.
|
||||
if (const auto *TypedefX = dyn_cast<TypedefNameDecl>(X))
|
||||
if (const auto *TypedefY = dyn_cast<TypedefNameDecl>(Y))
|
||||
return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(),
|
||||
TypedefY->getUnderlyingType());
|
||||
|
||||
// Must have the same kind.
|
||||
if (X->getKind() != Y->getKind())
|
||||
return false;
|
||||
|
||||
// Objective-C classes and protocols with the same name always match.
|
||||
if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
|
||||
return true;
|
||||
|
||||
if (isa<ClassTemplateSpecializationDecl>(X)) {
|
||||
// No need to handle these here: we merge them when adding them to the
|
||||
// template.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compatible tags match.
|
||||
if (const auto *TagX = dyn_cast<TagDecl>(X)) {
|
||||
const auto *TagY = cast<TagDecl>(Y);
|
||||
return (TagX->getTagKind() == TagY->getTagKind()) ||
|
||||
((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class ||
|
||||
TagX->getTagKind() == TTK_Interface) &&
|
||||
(TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
|
||||
TagY->getTagKind() == TTK_Interface));
|
||||
}
|
||||
|
||||
// Functions with the same type and linkage match.
|
||||
// FIXME: This needs to cope with merging of prototyped/non-prototyped
|
||||
// functions, etc.
|
||||
if (const auto *FuncX = dyn_cast<FunctionDecl>(X)) {
|
||||
const auto *FuncY = cast<FunctionDecl>(Y);
|
||||
if (const auto *CtorX = dyn_cast<CXXConstructorDecl>(X)) {
|
||||
const auto *CtorY = cast<CXXConstructorDecl>(Y);
|
||||
if (CtorX->getInheritedConstructor() &&
|
||||
!isSameEntity(CtorX->getInheritedConstructor().getConstructor(),
|
||||
CtorY->getInheritedConstructor().getConstructor()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FuncX->isMultiVersion() != FuncY->isMultiVersion())
|
||||
return false;
|
||||
|
||||
// Multiversioned functions with different feature strings are represented
|
||||
// as separate declarations.
|
||||
if (FuncX->isMultiVersion()) {
|
||||
const auto *TAX = FuncX->getAttr<TargetAttr>();
|
||||
const auto *TAY = FuncY->getAttr<TargetAttr>();
|
||||
assert(TAX && TAY && "Multiversion Function without target attribute");
|
||||
|
||||
if (TAX->getFeaturesStr() != TAY->getFeaturesStr())
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
// being inherited onto the type but not the TSI), but the TSI type of
|
||||
// the first declaration of the function should match across modules.
|
||||
FD = FD->getCanonicalDecl();
|
||||
return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType()
|
||||
: FD->getType();
|
||||
};
|
||||
QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY);
|
||||
if (!C.hasSameType(XT, YT)) {
|
||||
// We can get functions with different types on the redecl chain in C++17
|
||||
// if they have differing exception specifications and at least one of
|
||||
// the excpetion specs is unresolved.
|
||||
auto *XFPT = XT->getAs<FunctionProtoType>();
|
||||
auto *YFPT = YT->getAs<FunctionProtoType>();
|
||||
if (C.getLangOpts().CPlusPlus17 && XFPT && YFPT &&
|
||||
(isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
|
||||
isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
|
||||
C.hasSameFunctionTypeIgnoringExceptionSpec(XT, YT))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() &&
|
||||
hasSameOverloadableAttrs(FuncX, FuncY);
|
||||
}
|
||||
|
||||
// Variables with the same type and linkage match.
|
||||
if (const auto *VarX = dyn_cast<VarDecl>(X)) {
|
||||
const auto *VarY = cast<VarDecl>(Y);
|
||||
if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) {
|
||||
ASTContext &C = VarX->getASTContext();
|
||||
if (C.hasSameType(VarX->getType(), VarY->getType()))
|
||||
return true;
|
||||
|
||||
// We can get decls with different types on the redecl chain. Eg.
|
||||
// template <typename T> struct S { static T Var[]; }; // #1
|
||||
// template <typename T> T S<T>::Var[sizeof(T)]; // #2
|
||||
// Only? happens when completing an incomplete array type. In this case
|
||||
// when comparing #1 and #2 we should go through their element type.
|
||||
const ArrayType *VarXTy = C.getAsArrayType(VarX->getType());
|
||||
const ArrayType *VarYTy = C.getAsArrayType(VarY->getType());
|
||||
if (!VarXTy || !VarYTy)
|
||||
return false;
|
||||
if (VarXTy->isIncompleteArrayType() || VarYTy->isIncompleteArrayType())
|
||||
return C.hasSameType(VarXTy->getElementType(), VarYTy->getElementType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Namespaces with the same name and inlinedness match.
|
||||
if (const auto *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
|
||||
const auto *NamespaceY = cast<NamespaceDecl>(Y);
|
||||
return NamespaceX->isInline() == NamespaceY->isInline();
|
||||
}
|
||||
|
||||
// Identical template names and kinds match if their template parameter lists
|
||||
// and patterns match.
|
||||
if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) {
|
||||
const auto *TemplateY = cast<TemplateDecl>(Y);
|
||||
return isSameEntity(TemplateX->getTemplatedDecl(),
|
||||
TemplateY->getTemplatedDecl()) &&
|
||||
isSameTemplateParameterList(TemplateX->getASTContext(),
|
||||
TemplateX->getTemplateParameters(),
|
||||
TemplateY->getTemplateParameters());
|
||||
}
|
||||
|
||||
// Fields with the same name and the same type match.
|
||||
if (const auto *FDX = dyn_cast<FieldDecl>(X)) {
|
||||
const auto *FDY = cast<FieldDecl>(Y);
|
||||
// FIXME: Also check the bitwidth is odr-equivalent, if any.
|
||||
return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
|
||||
}
|
||||
|
||||
// Indirect fields with the same target field match.
|
||||
if (const auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) {
|
||||
const auto *IFDY = cast<IndirectFieldDecl>(Y);
|
||||
return IFDX->getAnonField()->getCanonicalDecl() ==
|
||||
IFDY->getAnonField()->getCanonicalDecl();
|
||||
}
|
||||
|
||||
// Enumerators with the same name match.
|
||||
if (isa<EnumConstantDecl>(X))
|
||||
// FIXME: Also check the value is odr-equivalent.
|
||||
return true;
|
||||
|
||||
// Using shadow declarations with the same target match.
|
||||
if (const auto *USX = dyn_cast<UsingShadowDecl>(X)) {
|
||||
const auto *USY = cast<UsingShadowDecl>(Y);
|
||||
return USX->getTargetDecl() == USY->getTargetDecl();
|
||||
}
|
||||
|
||||
// Using declarations with the same qualifier match. (We already know that
|
||||
// the name matches.)
|
||||
if (const auto *UX = dyn_cast<UsingDecl>(X)) {
|
||||
const auto *UY = cast<UsingDecl>(Y);
|
||||
return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
|
||||
UX->hasTypename() == UY->hasTypename() &&
|
||||
UX->isAccessDeclaration() == UY->isAccessDeclaration();
|
||||
}
|
||||
if (const auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) {
|
||||
const auto *UY = cast<UnresolvedUsingValueDecl>(Y);
|
||||
return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
|
||||
UX->isAccessDeclaration() == UY->isAccessDeclaration();
|
||||
}
|
||||
if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) {
|
||||
return isSameQualifier(
|
||||
UX->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.
|
||||
if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
|
||||
const auto *NAY = cast<NamespaceAliasDecl>(Y);
|
||||
return NAX->getNamespace()->Equals(NAY->getNamespace());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Find the context in which we should search for previous declarations when
|
||||
/// looking for declarations to merge.
|
||||
DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
|
||||
|
@ -3511,12 +3126,13 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
|
|||
return Result;
|
||||
}
|
||||
|
||||
ASTContext &C = Reader.getContext();
|
||||
DeclContext *DC = D->getDeclContext()->getRedeclContext();
|
||||
if (TypedefNameForLinkage) {
|
||||
auto It = Reader.ImportedTypedefNamesForLinkage.find(
|
||||
std::make_pair(DC, TypedefNameForLinkage));
|
||||
if (It != Reader.ImportedTypedefNamesForLinkage.end())
|
||||
if (isSameEntity(It->second, D))
|
||||
if (C.isSameEntity(It->second, D))
|
||||
return FindExistingResult(Reader, D, It->second, AnonymousDeclNumber,
|
||||
TypedefNameForLinkage);
|
||||
// Go on to check in other places in case an existing typedef name
|
||||
|
@ -3528,7 +3144,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
|
|||
// in its context by number.
|
||||
if (auto *Existing = getAnonymousDeclForMerging(
|
||||
Reader, D->getLexicalDeclContext(), AnonymousDeclNumber))
|
||||
if (isSameEntity(Existing, D))
|
||||
if (C.isSameEntity(Existing, D))
|
||||
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
|
||||
TypedefNameForLinkage);
|
||||
} else if (DC->isTranslationUnit() &&
|
||||
|
@ -3560,7 +3176,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
|
|||
IEnd = IdResolver.end();
|
||||
I != IEnd; ++I) {
|
||||
if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
|
||||
if (isSameEntity(Existing, D))
|
||||
if (C.isSameEntity(Existing, D))
|
||||
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
|
||||
TypedefNameForLinkage);
|
||||
}
|
||||
|
@ -3568,7 +3184,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
|
|||
DeclContext::lookup_result R = MergeDC->noload_lookup(Name);
|
||||
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
|
||||
if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
|
||||
if (isSameEntity(Existing, D))
|
||||
if (C.isSameEntity(Existing, D))
|
||||
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
|
||||
TypedefNameForLinkage);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue