summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--clang/include/clang/Sema/Sema.h9
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp6
-rw-r--r--clang/lib/Sema/SemaInit.cpp8
-rw-r--r--clang/lib/Sema/SemaOverload.cpp282
-rw-r--r--clang/test/CXX/drs/dr23xx.cpp35
-rw-r--r--clang/test/CXX/drs/dr4xx.cpp11
-rw-r--r--clang/test/SemaCXX/ref-init-ambiguous.cpp24
-rw-r--r--clang/test/SemaObjCXX/arc-overloading.mm30
-rw-r--r--clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl18
-rwxr-xr-xclang/www/cxx_dr_status.html4
-rwxr-xr-xclang/www/make_cxx_dr_status4
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>
OpenPOWER on IntegriCloud