diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 282 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr23xx.cpp | 35 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr4xx.cpp | 11 | ||||
-rw-r--r-- | clang/test/SemaCXX/ref-init-ambiguous.cpp | 24 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/arc-overloading.mm | 30 | ||||
-rw-r--r-- | clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl | 18 | ||||
-rwxr-xr-x | clang/www/cxx_dr_status.html | 4 | ||||
-rwxr-xr-x | clang/www/make_cxx_dr_status | 4 |
12 files changed, 280 insertions, 154 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 53d4571fa8a..b56bfa24ff0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1933,7 +1933,8 @@ def err_lvalue_reference_bind_to_unrelated : Error< "cannot bind to a value of unrelated type}1,2">; def err_reference_bind_drops_quals : Error< "binding reference %diff{of type $ to value of type $|to value}0,1 " - "%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address space}2">; + "%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address space|" + "not permitted due to incompatible qualifiers}2">; def err_reference_bind_failed : Error< "reference %diff{to %select{type|incomplete type}1 $ could not bind to an " "%select{rvalue|lvalue}2 of type $|could not bind to %select{rvalue|lvalue}2 of " diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9a1fd70b889..851b25922f5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10745,10 +10745,11 @@ public: /// whether T1 is reference-compatible with T2. enum ReferenceConversions { Qualification = 0x1, - Function = 0x2, - DerivedToBase = 0x4, - ObjC = 0x8, - ObjCLifetime = 0x10, + NestedQualification = 0x2, + Function = 0x4, + DerivedToBase = 0x8, + ObjC = 0x10, + ObjCLifetime = 0x20, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime) }; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index cfb3a05e9c1..17f2028ec5c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5864,6 +5864,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // one of the operands is reference-compatible with the other, in order // to support conditionals between functions differing in noexcept. This // will similarly cover difference in array bounds after P0388R4. + // FIXME: If LTy and RTy have a composite pointer type, should we convert to + // that instead? ExprValueKind LVK = LHS.get()->getValueKind(); ExprValueKind RVK = RHS.get()->getValueKind(); if (!Context.hasSameType(LTy, RTy) && @@ -5871,7 +5873,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // DerivedToBase was already handled by the class-specific case above. // FIXME: Should we allow ObjC conversions here? const ReferenceConversions AllowedConversions = - ReferenceConversions::Qualification | ReferenceConversions::Function; + ReferenceConversions::Qualification | + ReferenceConversions::NestedQualification | + ReferenceConversions::Function; ReferenceConversions RefConv; if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) == diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index d89d37d8499..163ad8dc54d 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8911,11 +8911,17 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << NonRefType << SourceType << 1 /*addr space*/ << Args[0]->getSourceRange(); - else + else if (DroppedQualifiers.hasQualifiers()) S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << NonRefType << SourceType << 0 /*cv quals*/ << Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers()) << DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange(); + else + // FIXME: Consider decomposing the type and explaining which qualifiers + // were dropped where, or on which level a 'const' is missing, etc. + S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) + << NonRefType << SourceType << 2 /*incompatible quals*/ + << Args[0]->getSourceRange(); break; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 69609986be4..be02a199a51 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3169,6 +3169,70 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals, return true; } +/// Perform a single iteration of the loop for checking if a qualification +/// conversion is valid. +/// +/// Specifically, check whether any change between the qualifiers of \p +/// FromType and \p ToType is permissible, given knowledge about whether every +/// outer layer is const-qualified. +static bool isQualificationConversionStep(QualType FromType, QualType ToType, + bool CStyle, + bool &PreviousToQualsIncludeConst, + bool &ObjCLifetimeConversion) { + Qualifiers FromQuals = FromType.getQualifiers(); + Qualifiers ToQuals = ToType.getQualifiers(); + + // Ignore __unaligned qualifier if this type is void. + if (ToType.getUnqualifiedType()->isVoidType()) + FromQuals.removeUnaligned(); + + // Objective-C ARC: + // Check Objective-C lifetime conversions. + if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime()) { + if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) { + if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals)) + ObjCLifetimeConversion = true; + FromQuals.removeObjCLifetime(); + ToQuals.removeObjCLifetime(); + } else { + // Qualification conversions cannot cast between different + // Objective-C lifetime qualifiers. + return false; + } + } + + // Allow addition/removal of GC attributes but not changing GC attributes. + if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() && + (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) { + FromQuals.removeObjCGCAttr(); + ToQuals.removeObjCGCAttr(); + } + + // -- for every j > 0, if const is in cv 1,j then const is in cv + // 2,j, and similarly for volatile. + if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) + return false; + + // For a C-style cast, just require the address spaces to overlap. + // FIXME: Does "superset" also imply the representation of a pointer is the + // same? We're assuming that it does here and in compatiblyIncludes. + if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) && + !FromQuals.isAddressSpaceSupersetOf(ToQuals)) + return false; + + // -- if the cv 1,j and cv 2,j are different, then const is in + // every cv for 0 < k < j. + if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() && + !PreviousToQualsIncludeConst) + return false; + + // Keep track of whether all prior cv-qualifiers in the "to" type + // include const. + PreviousToQualsIncludeConst = + PreviousToQualsIncludeConst && ToQuals.hasConst(); + return true; +} + /// IsQualificationConversion - Determines whether the conversion from /// an rvalue of type FromType to ToType is a qualification conversion /// (C++ 4.4). @@ -3194,73 +3258,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, bool PreviousToQualsIncludeConst = true; bool UnwrappedAnyPointer = false; while (Context.UnwrapSimilarTypes(FromType, ToType)) { - // Within each iteration of the loop, we check the qualifiers to - // determine if this still looks like a qualification - // conversion. Then, if all is well, we unwrap one more level of - // pointers or pointers-to-members and do it all again - // until there are no more pointers or pointers-to-members left to - // unwrap. - UnwrappedAnyPointer = true; - - Qualifiers FromQuals = FromType.getQualifiers(); - Qualifiers ToQuals = ToType.getQualifiers(); - - // Ignore __unaligned qualifier if this type is void. - if (ToType.getUnqualifiedType()->isVoidType()) - FromQuals.removeUnaligned(); - - // Objective-C ARC: - // Check Objective-C lifetime conversions. - if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() && - UnwrappedAnyPointer) { - if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) { - if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals)) - ObjCLifetimeConversion = true; - FromQuals.removeObjCLifetime(); - ToQuals.removeObjCLifetime(); - } else { - // Qualification conversions cannot cast between different - // Objective-C lifetime qualifiers. - return false; - } - } - - // Allow addition/removal of GC attributes but not changing GC attributes. - if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() && - (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) { - FromQuals.removeObjCGCAttr(); - ToQuals.removeObjCGCAttr(); - } - - // -- for every j > 0, if const is in cv 1,j then const is in cv - // 2,j, and similarly for volatile. - if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) - return false; - - // -- if the cv 1,j and cv 2,j are different, then const is in - // every cv for 0 < k < j. - if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() - && !PreviousToQualsIncludeConst) + if (!isQualificationConversionStep(FromType, ToType, CStyle, + PreviousToQualsIncludeConst, + ObjCLifetimeConversion)) return false; - - // Keep track of whether all prior cv-qualifiers in the "to" type - // include const. - PreviousToQualsIncludeConst - = PreviousToQualsIncludeConst && ToQuals.hasConst(); - } - - // Allows address space promotion by language rules implemented in - // Type::Qualifiers::isAddressSpaceSupersetOf. - Qualifiers FromQuals = FromType.getQualifiers(); - Qualifiers ToQuals = ToType.getQualifiers(); - if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) && - !FromQuals.isAddressSpaceSupersetOf(ToQuals)) { - return false; + UnwrappedAnyPointer = true; } // We are left with FromType and ToType being the pointee types // after unwrapping the original FromType and ToType the same number - // of types. If we unwrapped any pointers, and if FromType and + // of times. If we unwrapped any pointers, and if FromType and // ToType have the same unqualified type (since we checked // qualifiers above), then this is a qualification conversion. return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType); @@ -3982,19 +3989,21 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, } } - // Compare based on qualification conversions (C++ 13.3.3.2p3, - // bullet 3). - if (ImplicitConversionSequence::CompareKind QualCK - = CompareQualificationConversions(S, SCS1, SCS2)) - return QualCK; - if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { // Check for a better reference binding based on the kind of bindings. if (isBetterReferenceBindingKind(SCS1, SCS2)) return ImplicitConversionSequence::Better; else if (isBetterReferenceBindingKind(SCS2, SCS1)) return ImplicitConversionSequence::Worse; + } + // Compare based on qualification conversions (C++ 13.3.3.2p3, + // bullet 3). + if (ImplicitConversionSequence::CompareKind QualCK + = CompareQualificationConversions(S, SCS1, SCS2)) + return QualCK; + + if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to // which the references refer are the same type except for @@ -4026,7 +4035,7 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); if (T2.isMoreQualifiedThan(T1)) return ImplicitConversionSequence::Better; - else if (T1.isMoreQualifiedThan(T2)) + if (T1.isMoreQualifiedThan(T2)) return ImplicitConversionSequence::Worse; } } @@ -4100,22 +4109,16 @@ CompareQualificationConversions(Sema &S, QualType T2 = SCS2.getToType(2); T1 = S.Context.getCanonicalType(T1); T2 = S.Context.getCanonicalType(T2); + assert(!T1->isReferenceType() && !T2->isReferenceType()); Qualifiers T1Quals, T2Quals; QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals); QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals); - // If the types are the same, we won't learn anything by unwrapped + // If the types are the same, we won't learn anything by unwrapping // them. if (UnqualT1 == UnqualT2) return ImplicitConversionSequence::Indistinguishable; - // If the type is an array type, promote the element qualifiers to the type - // for comparison. - if (isa<ArrayType>(T1) && T1Quals) - T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); - if (isa<ArrayType>(T2) && T2Quals) - T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); - ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; @@ -4413,10 +4416,19 @@ static bool isTypeValid(QualType T) { return true; } +static QualType withoutUnaligned(ASTContext &Ctx, QualType T) { + if (!T.getQualifiers().hasUnaligned()) + return T; + + Qualifiers Q; + T = Ctx.getUnqualifiedArrayType(T, Q); + Q.removeUnaligned(); + return Ctx.getQualifiedType(T, Q); +} + /// CompareReferenceRelationship - Compare the two types T1 and T2 to -/// determine whether they are reference-related, -/// reference-compatible, reference-compatible with added -/// qualification, or incompatible, for use in C++ initialization by +/// determine whether they are reference-compatible, +/// reference-related, or incompatible, for use in C++ initialization by /// reference (C++ [dcl.ref.init]p4). Neither type can be a reference /// type, and the first type (T1) is the pointee type of the reference /// type being initialized. @@ -4438,10 +4450,17 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp; Conv = ReferenceConversions(); - // C++ [dcl.init.ref]p4: + // C++2a [dcl.init.ref]p4: // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is - // reference-related to "cv2 T2" if T1 is the same type as T2, or + // reference-related to "cv2 T2" if T1 is similar to T2, or // T1 is a base class of T2. + // "cv1 T1" is reference-compatible with "cv2 T2" if + // a prvalue of type "pointer to cv2 T2" can be converted to the type + // "pointer to cv1 T1" via a standard conversion sequence. + + // Check for standard conversions we can apply to pointers: derived-to-base + // conversions, ObjC pointer conversions, and function pointer conversions. + // (Qualification conversions are checked last.) QualType ConvertedT2; if (UnqualT1 == UnqualT2) { // Nothing to do. @@ -4455,59 +4474,56 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, Conv |= ReferenceConversions::ObjC; else if (UnqualT2->isFunctionType() && IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) { - // C++1z [dcl.init.ref]p4: - // cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept - // function" and T1 is "function" - // - // We extend this to also apply to 'noreturn', so allow any function - // conversion between function types. Conv |= ReferenceConversions::Function; + // No need to check qualifiers; function types don't have them. return Ref_Compatible; - } else - return Ref_Incompatible; - - // At this point, we know that T1 and T2 are reference-related (at - // least). - - // If the type is an array type, promote the element qualifiers to the type - // for comparison. - if (isa<ArrayType>(T1) && T1Quals) - T1 = Context.getQualifiedType(UnqualT1, T1Quals); - if (isa<ArrayType>(T2) && T2Quals) - T2 = Context.getQualifiedType(UnqualT2, T2Quals); - - // C++ [dcl.init.ref]p4: - // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is - // reference-related to T2 and cv1 is the same cv-qualification - // as, or greater cv-qualification than, cv2. For purposes of - // overload resolution, cases for which cv1 is greater - // cv-qualification than cv2 are identified as - // reference-compatible with added qualification (see 13.3.3.2). - // - // Note that we also require equivalence of Objective-C GC and address-space - // qualifiers when performing these computations, so that e.g., an int in - // address space 1 is not reference-compatible with an int in address - // space 2. - if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() && - T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) { - if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals)) - Conv |= ReferenceConversions::ObjCLifetime; - - T1Quals.removeObjCLifetime(); - T2Quals.removeObjCLifetime(); } + bool ConvertedReferent = Conv != 0; - // MS compiler ignores __unaligned qualifier for references; do the same. - T1Quals.removeUnaligned(); - T2Quals.removeUnaligned(); + // We can have a qualification conversion. Compute whether the types are + // similar at the same time. + bool PreviousToQualsIncludeConst = true; + bool TopLevel = true; + do { + if (T1 == T2) + break; - if (T1Quals != T2Quals) + // We will need a qualification conversion. Conv |= ReferenceConversions::Qualification; - if (T1Quals.compatiblyIncludes(T2Quals)) - return Ref_Compatible; - else - return Ref_Related; + // Track whether we performed a qualification conversion anywhere other + // than the top level. This matters for ranking reference bindings in + // overload resolution. + if (!TopLevel) + Conv |= ReferenceConversions::NestedQualification; + + // MS compiler ignores __unaligned qualifier for references; do the same. + T1 = withoutUnaligned(Context, T1); + T2 = withoutUnaligned(Context, T2); + + // If we find a qualifier mismatch, the types are not reference-compatible, + // but are still be reference-related if they're similar. + bool ObjCLifetimeConversion = false; + if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, + PreviousToQualsIncludeConst, + ObjCLifetimeConversion)) + return (ConvertedReferent || Context.hasSimilarType(T1, T2)) + ? Ref_Related + : Ref_Incompatible; + + // FIXME: Should we track this for any level other than the first? + if (ObjCLifetimeConversion) + Conv |= ReferenceConversions::ObjCLifetime; + + TopLevel = false; + } while (Context.UnwrapSimilarTypes(T1, T2)); + + // At this point, if the types are reference-related, we must either have the + // same inner type (ignoring qualifiers), or must have already worked out how + // to convert the referent. + return (ConvertedReferent || Context.hasSameUnqualifiedType(T1, T2)) + ? Ref_Compatible + : Ref_Incompatible; } /// Look for a user-defined conversion to a value reference-compatible @@ -4665,12 +4681,20 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, auto SetAsReferenceBinding = [&](bool BindsDirectly) { ICS.setStandard(); ICS.Standard.First = ICK_Identity; + // FIXME: A reference binding can be a function conversion too. We should + // consider that when ordering reference-to-function bindings. ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase) ? ICK_Derived_To_Base : (RefConv & Sema::ReferenceConversions::ObjC) ? ICK_Compatible_Conversion : ICK_Identity; - ICS.Standard.Third = ICK_Identity; + // FIXME: As a speculative fix to a defect introduced by CWG2352, we rank + // a reference binding that performs a non-top-level qualification + // conversion as a qualification conversion, not as an identity conversion. + ICS.Standard.Third = (RefConv & + Sema::ReferenceConversions::NestedQualification) + ? ICK_Qualification + : ICK_Identity; ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); ICS.Standard.setToType(0, T2); ICS.Standard.setToType(1, T1); diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp index 763abd5368e..85f59207460 100644 --- a/clang/test/CXX/drs/dr23xx.cpp +++ b/clang/test/CXX/drs/dr23xx.cpp @@ -1,12 +1,41 @@ -// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s // RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s -#if __cplusplus <= 201103L -// expected-no-diagnostics +namespace dr2352 { // dr2352: 10 + int **p; + const int *const *const &f1() { return p; } + int *const *const &f2() { return p; } + int **const &f3() { return p; } + + const int **const &f4() { return p; } // expected-error {{reference to type 'const int **const' could not bind to an lvalue of type 'int **'}} + const int *const *&f5() { return p; } // expected-error {{binding reference of type 'const int *const *' to value of type 'int **' not permitted due to incompatible qualifiers}} + + // FIXME: We permit this as a speculative defect resolution, allowing + // qualification conversions when forming a glvalue conditional expression. + const int * const * const q = 0; + __typeof(&(true ? p : q)) x = &(true ? p : q); + + // FIXME: Should we compute the composite pointer type here and produce an + // lvalue of type 'const int *const * const'? + const int * const * r; + void *y = &(true ? p : r); // expected-error {{rvalue of type 'const int *const *'}} + + // FIXME: We order these as a speculative defect resolution. + void f(const int * const * const &r); +#if __cplusplus >= 201103L + constexpr #endif + int *const *const &f(int * const * const &r) { return r; } + + // No temporary is created here. + int *const *const &check_f = f(p); +#if __cplusplus >= 201103L + static_assert(&p == &check_f, ""); +#endif +} namespace dr2353 { // dr2353: 9 struct X { diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index 8eeb7715cad..d37ece6cb88 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -486,14 +486,21 @@ namespace dr433 { // dr433: yes S<int> s; } -namespace dr434 { // dr434: yes +namespace dr434 { // dr434: sup 2352 void f() { const int ci = 0; int *pi = 0; - const int *&rpci = pi; // expected-error {{cannot bind}} + const int *&rpci = pi; // expected-error {{incompatible qualifiers}} + const int * const &rcpci = pi; // OK rpci = &ci; *pi = 1; } + +#if __cplusplus >= 201103L + int *pi = 0; + const int * const &rcpci = pi; + static_assert(&rcpci == &pi, ""); +#endif } // dr435: na diff --git a/clang/test/SemaCXX/ref-init-ambiguous.cpp b/clang/test/SemaCXX/ref-init-ambiguous.cpp index ce47e10c9ae..7e1a3bc5794 100644 --- a/clang/test/SemaCXX/ref-init-ambiguous.cpp +++ b/clang/test/SemaCXX/ref-init-ambiguous.cpp @@ -25,4 +25,26 @@ const E2 & re(C c) { return c; // expected-error {{reference initialization of type 'const E2 &' with initializer of type 'C' is ambiguous}} } - +namespace CWG2352 { + void f(const int * const &) = delete; + void f(int *); + + void g(int * &); + void g(const int *) = delete; + + void h1(int *const * const &); + void h1(const int *const *) = delete; + void h2(const int *const * const &) = delete; + void h2(int *const *); + + void test() { + int *x; + // Under CWG2352, this became ambiguous. We order by qualification + // conversion even when comparing a reference binding to a + // non-reference-binding. + f(x); + g(x); + h1(&x); + h2(&x); + } +} diff --git a/clang/test/SemaObjCXX/arc-overloading.mm b/clang/test/SemaObjCXX/arc-overloading.mm index 3ac9c51293b..910b5c7be97 100644 --- a/clang/test/SemaObjCXX/arc-overloading.mm +++ b/clang/test/SemaObjCXX/arc-overloading.mm @@ -174,6 +174,36 @@ void test_f9() { const __autoreleasing id& ar4 = weak_a; } +int &f10(__strong id *&); // expected-note 2{{not viable: no known conversion}} +float &f10(__autoreleasing id *&); // expected-note 2{{not viable: no known conversion}} + +void test_f10() { + __strong id *strong_id; + __weak id *weak_id; + __autoreleasing id *autoreleasing_id; + __unsafe_unretained id *unsafe_id; + + int &ir1 = f10(strong_id); + float &fr1 = f10(autoreleasing_id); + float &fr2 = f10(unsafe_id); // expected-error {{no match}} + float &fr2a = f10(weak_id); // expected-error {{no match}} +} + +int &f11(__strong id *const &); // expected-note {{not viable: 1st argument ('__weak id *') has __weak ownership, but parameter has __strong ownership}} +float &f11(const __autoreleasing id *const &); // expected-note {{not viable: 1st argument ('__weak id *') has __weak ownership, but parameter has __autoreleasing ownership}} + +void test_f11() { + __strong id *strong_id; + __weak id *weak_id; + __autoreleasing id *autoreleasing_id; + __unsafe_unretained id *unsafe_id; + + int &ir1 = f11(strong_id); + float &fr1 = f11(autoreleasing_id); + float &fr2 = f11(unsafe_id); + float &fr2a = f11(weak_id); // expected-error {{no match}} +} + // rdar://9790531 void f9790531(void *inClientData); // expected-note {{candidate function not viable: cannot implicitly convert argument of type 'MixerEQGraphTestDelegate *const __strong' to 'void *' for 1st argument under ARC}} void f9790531_1(struct S*inClientData); // expected-note {{candidate function not viable}} diff --git a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl index c46e4e08a2c..14f7cf3a0e7 100644 --- a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl +++ b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl @@ -501,12 +501,9 @@ void test_pointer_chains() { // Case 1: // * address spaces of corresponded most outer pointees overlaps, their canonical types are equal // * CVR, address spaces and canonical types of the rest of pointees are equivalent. + var_as_as_int = var_asc_as_int; var_as_as_int = 0 ? var_as_as_int : var_asc_as_int; -#if __OPENCL_CPP_VERSION__ -#ifdef GENERIC -// expected-error@-3{{incompatible operand types ('__generic int *__generic *' and '__generic int *__local *')}} -#endif -#endif + // Case 2: Corresponded inner pointees has non-overlapping address spaces. var_as_as_int = 0 ? var_as_as_int : var_asc_asn_int; #if !__OPENCL_CPP_VERSION__ @@ -516,12 +513,17 @@ void test_pointer_chains() { #endif // Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces. + // FIXME: Should this really be allowed in C++ mode? + var_as_as_int = var_asc_asc_int; +#if !__OPENCL_CPP_VERSION__ #ifdef GENERIC +// expected-error@-3 {{assigning '__local int *__local *__private' to '__generic int *__generic *__private' changes address space of nested pointer}} +#endif +#endif var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int; #if !__OPENCL_CPP_VERSION__ -// expected-warning-re@-2{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(local|global|constant)}} *')}} -#else -// expected-error-re@-4{{incompatible operand types ('__{{generic|global|constant}} int *__{{generic|global|constant}} *' and '__{{local|global|constant}} int *__{{local|global|constant}} *')}} +#ifdef GENERIC +// expected-warning@-3{{pointer type mismatch ('__generic int *__generic *' and '__local int *__local *')}} #endif #endif } diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 23a7218e897..c4ec4573652 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -2645,7 +2645,7 @@ of class templates</td> <td><a href="https://wg21.link/cwg434">434</a></td> <td>NAD</td> <td>Unclear suppression of standard conversions while binding reference to lvalue</td> - <td class="full" align="center">Yes</td> + <td class="svn" align="center">Superseded by <a href="#2352">2352</a></td> </tr> <tr id="435"> <td><a href="https://wg21.link/cwg435">435</a></td> @@ -13927,7 +13927,7 @@ and <I>POD class</I></td> <td><a href="https://wg21.link/cwg2352">2352</a></td> <td>DR</td> <td>Similar types and reference binding</td> - <td class="none" align="center">Unknown</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="2353"> <td><a href="https://wg21.link/cwg2353">2353</a></td> diff --git a/clang/www/make_cxx_dr_status b/clang/www/make_cxx_dr_status index 4351d659e41..fd5eb7fbabb 100755 --- a/clang/www/make_cxx_dr_status +++ b/clang/www/make_cxx_dr_status @@ -28,7 +28,7 @@ def parse(dr): _, url, issue = issue_link.split('"', 2) url = url.strip() issue = int(issue.split('>', 1)[1].split('<', 1)[0]) - title = title.replace('<issue_title>', '').replace('</issue_title>', '').strip() + title = title.replace('<issue_title>', '').replace('</issue_title>', '').replace('\r\n', '\n').strip() return DR(section, issue, url, status, title) status_re = re.compile(r'\bdr([0-9]+): (.*)') @@ -171,7 +171,7 @@ for dr in drs: print >> out_file, '''\ <tr%s id="%s"> - <td><a href="http://wg21.link/cwg%s">%s</a></td> + <td><a href="https://wg21.link/cwg%s">%s</a></td> <td>%s</td> <td>%s</td> <td%s align="center">%s</td> |