diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 9fa301e4aa..edbdaa1848 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -299,8 +299,6 @@ public: (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)); } - bool isSupersetOf(Qualifiers Other) const; - bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } @@ -606,8 +604,14 @@ public: /// ASTContext::getUnqualifiedArrayType. inline SplitQualType getSplitUnqualifiedType() const; + /// \brief Determine whether this type is more qualified than the other + /// given type, requiring exact equality for non-CVR qualifiers. bool isMoreQualifiedThan(QualType Other) const; + + /// \brief Determine whether this type is at least as qualified as the other + /// given type, requiring exact equality for non-CVR qualifiers. bool isAtLeastAsQualifiedAs(QualType Other) const; + QualType getNonReferenceType() const; /// \brief Determine the type of a (typically non-lvalue) expression with the @@ -4154,12 +4158,6 @@ inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { return getFunctionExtInfo(*t); } -/// \brief Determine whether this set of qualifiers is a superset of the given -/// set of qualifiers. -inline bool Qualifiers::isSupersetOf(Qualifiers Other) const { - return Mask != Other.Mask && (Mask | Other.Mask) == Mask; -} - /// isMoreQualifiedThan - Determine whether this type is more /// qualified than the Other type. For example, "const volatile int" /// is more qualified than "const int", "volatile int", and diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 7ab60303ad..566e2b936c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -270,11 +270,11 @@ GetBestOverloadCandidateSimple( unsigned Best = 0, N = Cands.size(); for (unsigned I = 1; I != N; ++I) - if (Cands[Best].second.isSupersetOf(Cands[I].second)) + if (Cands[Best].second.compatiblyIncludes(Cands[I].second)) Best = I; for (unsigned I = 1; I != N; ++I) - if (Cands[Best].second.isSupersetOf(Cands[I].second)) + if (Cands[Best].second.compatiblyIncludes(Cands[I].second)) return 0; return Cands[Best].first; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b395fcd33d..73d523f8bb 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -800,6 +800,32 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_Success; } +/// \brief Determine whether the parameter has qualifiers that are either +/// inconsistent with or a superset of the argument's qualifiers. +static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, + QualType ArgType) { + Qualifiers ParamQs = ParamType.getQualifiers(); + Qualifiers ArgQs = ArgType.getQualifiers(); + + if (ParamQs == ArgQs) + return false; + + // Mismatched (but not missing) Objective-C GC attributes. + if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() && + ParamQs.hasObjCGCAttr()) + return true; + + // Mismatched (but not missing) address spaces. + if (ParamQs.getAddressSpace() != ArgQs.getAddressSpace() && + ParamQs.hasAddressSpace()) + return true; + + // CVR qualifier superset. + return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) && + ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers()) + == ParamQs.getCVRQualifiers()); +} + /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -960,7 +986,8 @@ DeduceTemplateArguments(Sema &S, // The argument type can not be less qualified than the parameter // type. - if (Param.isMoreQualifiedThan(Arg) && !(TDF & TDF_IgnoreQualifiers)) { + if (!(TDF & TDF_IgnoreQualifiers) && + hasInconsistentOrSupersetQualifiersOf(Param, Arg)) { Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); @@ -971,8 +998,18 @@ DeduceTemplateArguments(Sema &S, assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); QualType DeducedType = Arg; - // local manipulation is okay because it's canonical - DeducedType.removeLocalCVRQualifiers(Param.getCVRQualifiers()); + // Remove any qualifiers on the parameter from the deduced type. + // We checked the qualifiers for consistency above. + Qualifiers DeducedQs = DeducedType.getQualifiers(); + Qualifiers ParamQs = Param.getQualifiers(); + DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers()); + if (ParamQs.hasObjCGCAttr()) + DeducedQs.removeObjCGCAttr(); + if (ParamQs.hasAddressSpace()) + DeducedQs.removeAddressSpace(); + DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), + DeducedQs); + if (RecanonicalizeArg) DeducedType = S.Context.getCanonicalType(DeducedType); @@ -1005,7 +1042,7 @@ DeduceTemplateArguments(Sema &S, // Check the cv-qualifiers on the parameter and argument types. if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { - if (Param.isMoreQualifiedThan(Arg)) + if (hasInconsistentOrSupersetQualifiersOf(Param, Arg)) return Sema::TDK_NonDeducedMismatch; } else if (!IsPossiblyOpaquelyQualifiedType(Param)) { if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) diff --git a/test/SemaTemplate/address-spaces.cpp b/test/SemaTemplate/address-spaces.cpp index 26e7224184..df262e1dc6 100644 --- a/test/SemaTemplate/address-spaces.cpp +++ b/test/SemaTemplate/address-spaces.cpp @@ -31,7 +31,21 @@ int check_remove0[is_same::type, int_1>::value? 1 : -1 int check_remove1[is_same::type, int_2>::value? 1 : -1]; int check_remove2[is_same::type, int>::value? -1 : 1]; int check_remove3[is_same::type, int_1>::value? -1 : 1]; + +template +struct is_pointer_in_address_space_1 { + static const bool value = false; +}; + +template +struct is_pointer_in_address_space_1 { + static const bool value = true; +}; +int check_ptr_in_as1[is_pointer_in_address_space_1::value? 1 : -1]; +int check_ptr_in_as2[is_pointer_in_address_space_1::value? -1 : 1]; +int check_ptr_in_as3[is_pointer_in_address_space_1::value? -1 : 1]; + // Check that we maintain address spaces through template argument // deduction for a call. template @@ -46,3 +60,16 @@ void test_accept_any_pointer(int_1_ptr ip1, int_2_ptr ip2) { accept_any_pointer(array); // expected-note{{in instantiation of}} } +template struct identity {}; + +template +identity accept_arg_in_address_space_1(__attribute__((address_space(1))) T &ir1); + +template +identity accept_any_arg(T &ir1); + +void test_arg_in_address_space_1() { + static int __attribute__((address_space(1))) int_1; + identity ii = accept_arg_in_address_space_1(int_1); + identity ii2 = accept_any_arg(int_1); +}