diff options
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 44 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/overloadable-attrs/a.h | 16 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/overloadable-attrs/module.modulemap | 3 | ||||
-rw-r--r-- | clang/test/Modules/overloadable-attrs.cpp | 19 |
4 files changed, 80 insertions, 2 deletions
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 8b14c2d8254..9be3981329a 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2656,6 +2656,44 @@ static bool isSameTemplateParameterList(const TemplateParameterList *X, return true; } +/// Determine whether the attributes we can overload on are identical for A and +/// B. Expects A and B to (otherwise) have the same type. +static bool hasSameOverloadableAttrs(const FunctionDecl *A, + const FunctionDecl *B) { + SmallVector<const EnableIfAttr *, 4> AEnableIfs; + // Since this is an equality check, we can ignore that enable_if attrs show up + // in reverse order. + for (const auto *EIA : A->specific_attrs<EnableIfAttr>()) + AEnableIfs.push_back(EIA); + + SmallVector<const EnableIfAttr *, 4> BEnableIfs; + for (const auto *EIA : B->specific_attrs<EnableIfAttr>()) + BEnableIfs.push_back(EIA); + + // Two very common cases: either we have 0 enable_if attrs, or we have an + // unequal number of enable_if attrs. + if (AEnableIfs.empty() && BEnableIfs.empty()) + return true; + + if (AEnableIfs.size() != BEnableIfs.size()) + return false; + + llvm::FoldingSetNodeID Cand1ID, Cand2ID; + for (unsigned I = 0, E = AEnableIfs.size(); I != E; ++I) { + Cand1ID.clear(); + Cand2ID.clear(); + + AEnableIfs[I]->getCond()->Profile(Cand1ID, A->getASTContext(), true); + BEnableIfs[I]->getCond()->Profile(Cand2ID, B->getASTContext(), true); + if (Cand1ID != Cand2ID) + return false; + } + + // FIXME: This doesn't currently consider pass_object_size attributes, since + // we aren't guaranteed that A and B have valid parameter lists yet. + return true; +} + /// \brief Determine whether the two declarations refer to the same entity. static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!"); @@ -2711,8 +2749,10 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { CtorY->getInheritedConstructor().getConstructor())) return false; } - return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) && - FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType()); + return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() && + FuncX->getASTContext().hasSameType(FuncX->getType(), + FuncY->getType()) && + hasSameOverloadableAttrs(FuncX, FuncY); } // Variables with the same type and linkage match. diff --git a/clang/test/Modules/Inputs/overloadable-attrs/a.h b/clang/test/Modules/Inputs/overloadable-attrs/a.h new file mode 100644 index 00000000000..e7dabfbe586 --- /dev/null +++ b/clang/test/Modules/Inputs/overloadable-attrs/a.h @@ -0,0 +1,16 @@ +namespace enable_if_attrs { +constexpr int fn1() __attribute__((enable_if(0, ""))) { return 0; } +constexpr int fn1() { return 1; } + +constexpr int fn2() { return 1; } +constexpr int fn2() __attribute__((enable_if(0, ""))) { return 0; } + +constexpr int fn3(int i) __attribute__((enable_if(!i, ""))) { return 0; } +constexpr int fn3(int i) __attribute__((enable_if(i, ""))) { return 1; } + +constexpr int fn4(int i) { return 0; } +constexpr int fn4(int i) __attribute__((enable_if(i, ""))) { return 1; } + +constexpr int fn5(int i) __attribute__((enable_if(i, ""))) { return 1; } +constexpr int fn5(int i) { return 0; } +} diff --git a/clang/test/Modules/Inputs/overloadable-attrs/module.modulemap b/clang/test/Modules/Inputs/overloadable-attrs/module.modulemap new file mode 100644 index 00000000000..514d745d146 --- /dev/null +++ b/clang/test/Modules/Inputs/overloadable-attrs/module.modulemap @@ -0,0 +1,3 @@ +module a { + header "a.h" +} diff --git a/clang/test/Modules/overloadable-attrs.cpp b/clang/test/Modules/overloadable-attrs.cpp new file mode 100644 index 00000000000..ae9bd73f99f --- /dev/null +++ b/clang/test/Modules/overloadable-attrs.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -I%S/Inputs/overloadable-attrs -fmodules \ +// RUN: -fmodule-map-file=%S/Inputs/overloadable-attrs/module.modulemap \ +// RUN: -fmodules-cache-path=%t -verify %s -std=c++11 +// +// Ensures that we don't merge decls with attrs that we allow overloading on. +// +// expected-no-diagnostics + +#include "a.h" + +static_assert(enable_if_attrs::fn1() == 1, ""); +static_assert(enable_if_attrs::fn2() == 1, ""); +static_assert(enable_if_attrs::fn3(0) == 0, ""); +static_assert(enable_if_attrs::fn3(1) == 1, ""); +static_assert(enable_if_attrs::fn4(0) == 0, ""); +static_assert(enable_if_attrs::fn4(1) == 1, ""); +static_assert(enable_if_attrs::fn5(0) == 0, ""); +static_assert(enable_if_attrs::fn5(1) == 1, ""); |