summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp565
1 files changed, 403 insertions, 162 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 9aae9289b514..a73e6906fceb 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -921,7 +921,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
// cannot be a simple walk of the class's decls. Instead, we must perform
// lookup and overload resolution.
CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0);
- if (!CD)
+ if (!CD || CD->isDeleted())
continue;
// Mark the constructor referenced as it is used by this throw expression.
@@ -2323,7 +2323,7 @@ static bool resolveAllocationOverload(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
}
return true;
@@ -3513,7 +3513,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
return true;
case OR_Deleted: {
@@ -4095,9 +4095,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
<< From->getSourceRange();
}
+ // Defer address space conversion to the third conversion.
+ QualType FromPteeType = From->getType()->getPointeeType();
+ QualType ToPteeType = ToType->getPointeeType();
+ QualType NewToType = ToType;
+ if (!FromPteeType.isNull() && !ToPteeType.isNull() &&
+ FromPteeType.getAddressSpace() != ToPteeType.getAddressSpace()) {
+ NewToType = Context.removeAddrSpaceQualType(ToPteeType);
+ NewToType = Context.getAddrSpaceQualType(NewToType,
+ FromPteeType.getAddressSpace());
+ if (ToType->isObjCObjectPointerType())
+ NewToType = Context.getObjCObjectPointerType(NewToType);
+ else if (ToType->isBlockPointerType())
+ NewToType = Context.getBlockPointerType(NewToType);
+ else
+ NewToType = Context.getPointerType(NewToType);
+ }
+
CastKind Kind;
CXXCastPath BasePath;
- if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
+ if (CheckPointerConversion(From, NewToType, Kind, BasePath, CStyle))
return ExprError();
// Make sure we extend blocks if necessary.
@@ -4108,8 +4125,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = E.get();
}
if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
- CheckObjCConversion(SourceRange(), ToType, From, CCK);
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ CheckObjCConversion(SourceRange(), NewToType, From, CCK);
+ From = ImpCastExprToType(From, NewToType, Kind, VK_RValue, &BasePath, CCK)
.get();
break;
}
@@ -5730,38 +5747,157 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
return false;
}
+// Check the condition operand of ?: to see if it is valid for the GCC
+// extension.
+static bool isValidVectorForConditionalCondition(ASTContext &Ctx,
+ QualType CondTy) {
+ if (!CondTy->isVectorType() || CondTy->isExtVectorType())
+ return false;
+ const QualType EltTy =
+ cast<VectorType>(CondTy.getCanonicalType())->getElementType();
+
+ assert(!EltTy->isBooleanType() && !EltTy->isEnumeralType() &&
+ "Vectors cant be boolean or enum types");
+ return EltTy->isIntegralType(Ctx);
+}
+
+QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation QuestionLoc) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+
+ QualType CondType = Cond.get()->getType();
+ const auto *CondVT = CondType->getAs<VectorType>();
+ QualType CondElementTy = CondVT->getElementType();
+ unsigned CondElementCount = CondVT->getNumElements();
+ QualType LHSType = LHS.get()->getType();
+ const auto *LHSVT = LHSType->getAs<VectorType>();
+ QualType RHSType = RHS.get()->getType();
+ const auto *RHSVT = RHSType->getAs<VectorType>();
+
+ QualType ResultType;
+
+ // FIXME: In the future we should define what the Extvector conditional
+ // operator looks like.
+ if (LHSVT && isa<ExtVectorType>(LHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << LHSType;
+ return {};
+ }
+
+ if (RHSVT && isa<ExtVectorType>(RHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << RHSType;
+ return {};
+ }
+
+ if (LHSVT && RHSVT) {
+ // If both are vector types, they must be the same type.
+ if (!Context.hasSameType(LHSType, RHSType)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_mismatched_vectors)
+ << LHSType << RHSType;
+ return {};
+ }
+ ResultType = LHSType;
+ } else if (LHSVT || RHSVT) {
+ ResultType = CheckVectorOperands(
+ LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false);
+ if (ResultType.isNull())
+ return {};
+ } else {
+ // Both are scalar.
+ QualType ResultElementTy;
+ LHSType = LHSType.getCanonicalType().getUnqualifiedType();
+ RHSType = RHSType.getCanonicalType().getUnqualifiedType();
+
+ if (Context.hasSameType(LHSType, RHSType))
+ ResultElementTy = LHSType;
+ else
+ ResultElementTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
+
+ if (ResultElementTy->isEnumeralType()) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ false << ResultElementTy;
+ return {};
+ }
+ ResultType = Context.getVectorType(
+ ResultElementTy, CondType->getAs<VectorType>()->getNumElements(),
+ VectorType::GenericVector);
+
+ LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat);
+ RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat);
+ }
+
+ assert(!ResultType.isNull() && ResultType->isVectorType() &&
+ "Result should have been a vector type");
+ QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType();
+ unsigned ResultElementCount =
+ ResultType->getAs<VectorType>()->getNumElements();
+
+ if (ResultElementCount != CondElementCount) {
+ Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ if (Context.getTypeSize(ResultElementTy) !=
+ Context.getTypeSize(CondElementTy)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ return ResultType;
+}
+
/// Check the operands of ?: under C++ semantics.
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
/// extension. In this case, LHS == Cond. (But they're not aliases.)
+///
+/// This function also implements GCC's vector extension for conditionals.
+/// GCC's vector extension permits the use of a?b:c where the type of
+/// a is that of a integer vector with the same number of elements and
+/// size as the vectors of b and c. If one of either b or c is a scalar
+/// it is implicitly converted to match the type of the vector.
+/// Otherwise the expression is ill-formed. If both b and c are scalars,
+/// then b and c are checked and converted to the type of a if possible.
+/// Unlike the OpenCL ?: operator, the expression is evaluated as
+/// (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult &RHS, ExprValueKind &VK,
ExprObjectKind &OK,
SourceLocation QuestionLoc) {
- // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
- // interface pointers.
+ // FIXME: Handle C99's complex types, block pointers and Obj-C++ interface
+ // pointers.
+
+ // Assume r-value.
+ VK = VK_RValue;
+ OK = OK_Ordinary;
+ bool IsVectorConditional =
+ isValidVectorForConditionalCondition(Context, Cond.get()->getType());
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
- //
- // FIXME; GCC's vector extension permits the use of a?b:c where the type of
- // a is that of a integer vector with the same number of elements and
- // size as the vectors of b and c. If one of either b or c is a scalar
- // it is implicitly converted to match the type of the vector.
- // Otherwise the expression is ill-formed. If both b and c are scalars,
- // then b and c are checked and converted to the type of a if possible.
- // Unlike the OpenCL ?: operator, the expression is evaluated as
- // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
if (!Cond.get()->isTypeDependent()) {
- ExprResult CondRes = CheckCXXBooleanCondition(Cond.get());
+ ExprResult CondRes = IsVectorConditional
+ ? DefaultFunctionArrayLvalueConversion(Cond.get())
+ : CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
return QualType();
Cond = CondRes;
+ } else {
+ // To implement C++, the first expression typically doesn't alter the result
+ // type of the conditional, however the GCC compatible vector extension
+ // changes the result type to be that of the conditional. Since we cannot
+ // know if this is a vector extension here, delay the conversion of the
+ // LHS/RHS below until later.
+ return Context.DependentTy;
}
- // Assume r-value.
- VK = VK_RValue;
- OK = OK_Ordinary;
// Either of the arguments dependent?
if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent())
@@ -5780,6 +5916,17 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// and value category of the other.
bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenImpCasts());
bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenImpCasts());
+
+ // Void expressions aren't legal in the vector-conditional expressions.
+ if (IsVectorConditional) {
+ SourceRange DiagLoc =
+ LVoid ? LHS.get()->getSourceRange() : RHS.get()->getSourceRange();
+ bool IsThrow = LVoid ? LThrow : RThrow;
+ Diag(DiagLoc.getBegin(), diag::err_conditional_vector_has_void)
+ << DiagLoc << IsThrow;
+ return QualType();
+ }
+
if (LThrow != RThrow) {
Expr *NonThrow = LThrow ? RHS.get() : LHS.get();
VK = NonThrow->getValueKind();
@@ -5802,6 +5949,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
}
// Neither is void.
+ if (IsVectorConditional)
+ return CheckGNUVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
// C++11 [expr.cond]p3
// Otherwise, if the second and third operand have different types, and
@@ -5845,29 +5994,33 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// FIXME:
// Resolving a defect in P0012R1: we extend this to cover all cases where
// one of the operands is reference-compatible with the other, in order
- // to support conditionals between functions differing in noexcept.
+ // 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) &&
LVK == RVK && LVK != VK_RValue) {
// DerivedToBase was already handled by the class-specific case above.
// FIXME: Should we allow ObjC conversions here?
- bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion;
- if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion) == Ref_Compatible &&
- !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+ const ReferenceConversions AllowedConversions =
+ ReferenceConversions::Qualification |
+ ReferenceConversions::NestedQualification |
+ ReferenceConversions::Function;
+
+ ReferenceConversions RefConv;
+ if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) ==
+ Ref_Compatible &&
+ !(RefConv & ~AllowedConversions) &&
// [...] subject to the constraint that the reference must bind
// directly [...]
!RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) {
RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
RTy = RHS.get()->getType();
- } else if (CompareReferenceRelationship(
- QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion,
- FunctionConversion) == Ref_Compatible &&
- !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+ } else if (CompareReferenceRelationship(QuestionLoc, RTy, LTy, &RefConv) ==
+ Ref_Compatible &&
+ !(RefConv & ~AllowedConversions) &&
!LHS.get()->refersToBitField() &&
!LHS.get()->refersToVectorElement()) {
LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
@@ -5976,7 +6129,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// the usual arithmetic conversions are performed to bring them to a
// common type, and the result is of that type.
if (LTy->isArithmeticType() && RTy->isArithmeticType()) {
- QualType ResTy = UsualArithmeticConversions(LHS, RHS);
+ QualType ResTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (ResTy.isNull()) {
@@ -6098,10 +6252,10 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
/// Find a merged pointer type and convert the two expressions to it.
///
-/// This finds the composite pointer type (or member pointer type) for @p E1
-/// and @p E2 according to C++1z 5p14. It converts both expressions to this
-/// type and returns it.
-/// It does not emit diagnostics.
+/// This finds the composite pointer type for \p E1 and \p E2 according to
+/// C++2a [expr.type]p3. It converts both expressions to this type and returns
+/// it. It does not emit diagnostics (FIXME: that's not true if \p ConvertArgs
+/// is \c true).
///
/// \param Loc The location of the operator requiring these two expressions to
/// be converted to the composite pointer type.
@@ -6154,60 +6308,117 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
assert(!T1->isNullPtrType() && !T2->isNullPtrType() &&
"nullptr_t should be a null pointer constant");
- // - if T1 or T2 is "pointer to cv1 void" and the other type is
- // "pointer to cv2 T", "pointer to cv12 void", where cv12 is
- // the union of cv1 and cv2;
- // - if T1 or T2 is "pointer to noexcept function" and the other type is
- // "pointer to function", where the function types are otherwise the same,
- // "pointer to function";
- // FIXME: This rule is defective: it should also permit removing noexcept
- // from a pointer to member function. As a Clang extension, we also
- // permit removing 'noreturn', so we generalize this rule to;
- // - [Clang] If T1 and T2 are both of type "pointer to function" or
- // "pointer to member function" and the pointee types can be unified
- // by a function pointer conversion, that conversion is applied
- // before checking the following rules.
+ struct Step {
+ enum Kind { Pointer, ObjCPointer, MemberPointer, Array } K;
+ // Qualifiers to apply under the step kind.
+ Qualifiers Quals;
+ /// The class for a pointer-to-member; a constant array type with a bound
+ /// (if any) for an array.
+ const Type *ClassOrBound;
+
+ Step(Kind K, const Type *ClassOrBound = nullptr)
+ : K(K), Quals(), ClassOrBound(ClassOrBound) {}
+ QualType rebuild(ASTContext &Ctx, QualType T) const {
+ T = Ctx.getQualifiedType(T, Quals);
+ switch (K) {
+ case Pointer:
+ return Ctx.getPointerType(T);
+ case MemberPointer:
+ return Ctx.getMemberPointerType(T, ClassOrBound);
+ case ObjCPointer:
+ return Ctx.getObjCObjectPointerType(T);
+ case Array:
+ if (auto *CAT = cast_or_null<ConstantArrayType>(ClassOrBound))
+ return Ctx.getConstantArrayType(T, CAT->getSize(), nullptr,
+ ArrayType::Normal, 0);
+ else
+ return Ctx.getIncompleteArrayType(T, ArrayType::Normal, 0);
+ }
+ llvm_unreachable("unknown step kind");
+ }
+ };
+
+ SmallVector<Step, 8> Steps;
+
// - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1
// is reference-related to C2 or C2 is reference-related to C1 (8.6.3),
// the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1,
// respectively;
// - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer
- // to member of C2 of type cv2 U2" where C1 is reference-related to C2 or
- // C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and
- // T1 or the cv-combined type of T1 and T2, respectively;
+ // to member of C2 of type cv2 U2" for some non-function type U, where
+ // C1 is reference-related to C2 or C2 is reference-related to C1, the
+ // cv-combined type of T2 and T1 or the cv-combined type of T1 and T2,
+ // respectively;
// - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and
// T2;
//
- // If looked at in the right way, these bullets all do the same thing.
- // What we do here is, we build the two possible cv-combined types, and try
- // the conversions in both directions. If only one works, or if the two
- // composite types are the same, we have succeeded.
- // FIXME: extended qualifiers?
- //
- // Note that this will fail to find a composite pointer type for "pointer
- // to void" and "pointer to function". We can't actually perform the final
- // conversion in this case, even though a composite pointer type formally
- // exists.
- SmallVector<unsigned, 4> QualifierUnion;
- SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
+ // Dismantle T1 and T2 to simultaneously determine whether they are similar
+ // and to prepare to form the cv-combined type if so.
QualType Composite1 = T1;
QualType Composite2 = T2;
unsigned NeedConstBefore = 0;
while (true) {
+ assert(!Composite1.isNull() && !Composite2.isNull());
+
+ Qualifiers Q1, Q2;
+ Composite1 = Context.getUnqualifiedArrayType(Composite1, Q1);
+ Composite2 = Context.getUnqualifiedArrayType(Composite2, Q2);
+
+ // Top-level qualifiers are ignored. Merge at all lower levels.
+ if (!Steps.empty()) {
+ // Find the qualifier union: (approximately) the unique minimal set of
+ // qualifiers that is compatible with both types.
+ Qualifiers Quals = Qualifiers::fromCVRUMask(Q1.getCVRUQualifiers() |
+ Q2.getCVRUQualifiers());
+
+ // Under one level of pointer or pointer-to-member, we can change to an
+ // unambiguous compatible address space.
+ if (Q1.getAddressSpace() == Q2.getAddressSpace()) {
+ Quals.setAddressSpace(Q1.getAddressSpace());
+ } else if (Steps.size() == 1) {
+ bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2);
+ bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1);
+ if (MaybeQ1 == MaybeQ2)
+ return QualType(); // No unique best address space.
+ Quals.setAddressSpace(MaybeQ1 ? Q1.getAddressSpace()
+ : Q2.getAddressSpace());
+ } else {
+ return QualType();
+ }
+
+ // FIXME: In C, we merge __strong and none to __strong at the top level.
+ if (Q1.getObjCGCAttr() == Q2.getObjCGCAttr())
+ Quals.setObjCGCAttr(Q1.getObjCGCAttr());
+ else
+ return QualType();
+
+ // Mismatched lifetime qualifiers never compatibly include each other.
+ if (Q1.getObjCLifetime() == Q2.getObjCLifetime())
+ Quals.setObjCLifetime(Q1.getObjCLifetime());
+ else
+ return QualType();
+
+ Steps.back().Quals = Quals;
+ if (Q1 != Quals || Q2 != Quals)
+ NeedConstBefore = Steps.size() - 1;
+ }
+
+ // FIXME: Can we unify the following with UnwrapSimilarTypes?
const PointerType *Ptr1, *Ptr2;
if ((Ptr1 = Composite1->getAs<PointerType>()) &&
(Ptr2 = Composite2->getAs<PointerType>())) {
Composite1 = Ptr1->getPointeeType();
Composite2 = Ptr2->getPointeeType();
+ Steps.emplace_back(Step::Pointer);
+ continue;
+ }
- // If we're allowed to create a non-standard composite type, keep track
- // of where we need to fill in additional 'const' qualifiers.
- if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
- NeedConstBefore = QualifierUnion.size();
-
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- MemberOfClass.push_back(std::make_pair(nullptr, nullptr));
+ const ObjCObjectPointerType *ObjPtr1, *ObjPtr2;
+ if ((ObjPtr1 = Composite1->getAs<ObjCObjectPointerType>()) &&
+ (ObjPtr2 = Composite2->getAs<ObjCObjectPointerType>())) {
+ Composite1 = ObjPtr1->getPointeeType();
+ Composite2 = ObjPtr2->getPointeeType();
+ Steps.emplace_back(Step::ObjCPointer);
continue;
}
@@ -6217,34 +6428,79 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
Composite1 = MemPtr1->getPointeeType();
Composite2 = MemPtr2->getPointeeType();
- // If we're allowed to create a non-standard composite type, keep track
- // of where we need to fill in additional 'const' qualifiers.
- if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
- NeedConstBefore = QualifierUnion.size();
+ // At the top level, we can perform a base-to-derived pointer-to-member
+ // conversion:
+ //
+ // - [...] where C1 is reference-related to C2 or C2 is
+ // reference-related to C1
+ //
+ // (Note that the only kinds of reference-relatedness in scope here are
+ // "same type or derived from".) At any other level, the class must
+ // exactly match.
+ const Type *Class = nullptr;
+ QualType Cls1(MemPtr1->getClass(), 0);
+ QualType Cls2(MemPtr2->getClass(), 0);
+ if (Context.hasSameType(Cls1, Cls2))
+ Class = MemPtr1->getClass();
+ else if (Steps.empty())
+ Class = IsDerivedFrom(Loc, Cls1, Cls2) ? MemPtr1->getClass() :
+ IsDerivedFrom(Loc, Cls2, Cls1) ? MemPtr2->getClass() : nullptr;
+ if (!Class)
+ return QualType();
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
- MemPtr2->getClass()));
+ Steps.emplace_back(Step::MemberPointer, Class);
continue;
}
+ // Special case: at the top level, we can decompose an Objective-C pointer
+ // and a 'cv void *'. Unify the qualifiers.
+ if (Steps.empty() && ((Composite1->isVoidPointerType() &&
+ Composite2->isObjCObjectPointerType()) ||
+ (Composite1->isObjCObjectPointerType() &&
+ Composite2->isVoidPointerType()))) {
+ Composite1 = Composite1->getPointeeType();
+ Composite2 = Composite2->getPointeeType();
+ Steps.emplace_back(Step::Pointer);
+ continue;
+ }
+
+ // FIXME: arrays
+
// FIXME: block pointer types?
// Cannot unwrap any more types.
break;
}
- // Apply the function pointer conversion to unify the types. We've already
- // unwrapped down to the function types, and we want to merge rather than
- // just convert, so do this ourselves rather than calling
+ // - if T1 or T2 is "pointer to noexcept function" and the other type is
+ // "pointer to function", where the function types are otherwise the same,
+ // "pointer to function";
+ // - if T1 or T2 is "pointer to member of C1 of type function", the other
+ // type is "pointer to member of C2 of type noexcept function", and C1
+ // is reference-related to C2 or C2 is reference-related to C1, where
+ // the function types are otherwise the same, "pointer to member of C2 of
+ // type function" or "pointer to member of C1 of type function",
+ // respectively;
+ //
+ // We also support 'noreturn' here, so as a Clang extension we generalize the
+ // above to:
+ //
+ // - [Clang] If T1 and T2 are both of type "pointer to function" or
+ // "pointer to member function" and the pointee types can be unified
+ // by a function pointer conversion, that conversion is applied
+ // before checking the following rules.
+ //
+ // We've already unwrapped down to the function types, and we want to merge
+ // rather than just convert, so do this ourselves rather than calling
// IsFunctionConversion.
//
// FIXME: In order to match the standard wording as closely as possible, we
// currently only do this under a single level of pointers. Ideally, we would
// allow this in general, and set NeedConstBefore to the relevant depth on
- // the side(s) where we changed anything.
- if (QualifierUnion.size() == 1) {
+ // the side(s) where we changed anything. If we permit that, we should also
+ // consider this conversion when determining type similarity and model it as
+ // a qualification conversion.
+ if (Steps.size() == 1) {
if (auto *FPT1 = Composite1->getAs<FunctionProtoType>()) {
if (auto *FPT2 = Composite2->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo();
@@ -6270,88 +6526,72 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
}
}
- if (NeedConstBefore) {
- // Extension: Add 'const' to qualifiers that come before the first qualifier
- // mismatch, so that our (non-standard!) composite type meets the
- // requirements of C++ [conv.qual]p4 bullet 3.
- for (unsigned I = 0; I != NeedConstBefore; ++I)
- if ((QualifierUnion[I] & Qualifiers::Const) == 0)
- QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const;
+ // There are some more conversions we can perform under exactly one pointer.
+ if (Steps.size() == 1 && Steps.front().K == Step::Pointer &&
+ !Context.hasSameType(Composite1, Composite2)) {
+ // - if T1 or T2 is "pointer to cv1 void" and the other type is
+ // "pointer to cv2 T", where T is an object type or void,
+ // "pointer to cv12 void", where cv12 is the union of cv1 and cv2;
+ if (Composite1->isVoidType() && Composite2->isObjectType())
+ Composite2 = Composite1;
+ else if (Composite2->isVoidType() && Composite1->isObjectType())
+ Composite1 = Composite2;
+ // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1
+ // is reference-related to C2 or C2 is reference-related to C1 (8.6.3),
+ // the cv-combined type of T1 and T2 or the cv-combined type of T2 and
+ // T1, respectively;
+ //
+ // The "similar type" handling covers all of this except for the "T1 is a
+ // base class of T2" case in the definition of reference-related.
+ else if (IsDerivedFrom(Loc, Composite1, Composite2))
+ Composite1 = Composite2;
+ else if (IsDerivedFrom(Loc, Composite2, Composite1))
+ Composite2 = Composite1;
}
- // Rewrap the composites as pointers or member pointers with the union CVRs.
- auto MOC = MemberOfClass.rbegin();
- for (unsigned CVR : llvm::reverse(QualifierUnion)) {
- Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
- auto Classes = *MOC++;
- if (Classes.first && Classes.second) {
- // Rebuild member pointer type
- Composite1 = Context.getMemberPointerType(
- Context.getQualifiedType(Composite1, Quals), Classes.first);
- Composite2 = Context.getMemberPointerType(
- Context.getQualifiedType(Composite2, Quals), Classes.second);
- } else {
- // Rebuild pointer type
- Composite1 =
- Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
- Composite2 =
- Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
- }
- }
-
- struct Conversion {
- Sema &S;
- Expr *&E1, *&E2;
- QualType Composite;
- InitializedEntity Entity;
- InitializationKind Kind;
- InitializationSequence E1ToC, E2ToC;
- bool Viable;
-
- Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2,
- QualType Composite)
- : S(S), E1(E1), E2(E2), Composite(Composite),
- Entity(InitializedEntity::InitializeTemporary(Composite)),
- Kind(InitializationKind::CreateCopy(Loc, SourceLocation())),
- E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2),
- Viable(E1ToC && E2ToC) {}
-
- bool perform() {
- ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1);
- if (E1Result.isInvalid())
- return true;
- E1 = E1Result.getAs<Expr>();
+ // At this point, either the inner types are the same or we have failed to
+ // find a composite pointer type.
+ if (!Context.hasSameType(Composite1, Composite2))
+ return QualType();
- ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2);
- if (E2Result.isInvalid())
- return true;
- E2 = E2Result.getAs<Expr>();
+ // Per C++ [conv.qual]p3, add 'const' to every level before the last
+ // differing qualifier.
+ for (unsigned I = 0; I != NeedConstBefore; ++I)
+ Steps[I].Quals.addConst();
- return false;
- }
- };
+ // Rebuild the composite type.
+ QualType Composite = Composite1;
+ for (auto &S : llvm::reverse(Steps))
+ Composite = S.rebuild(Context, Composite);
- // Try to convert to each composite pointer type.
- Conversion C1(*this, Loc, E1, E2, Composite1);
- if (C1.Viable && Context.hasSameType(Composite1, Composite2)) {
- if (ConvertArgs && C1.perform())
+ if (ConvertArgs) {
+ // Convert the expressions to the composite pointer type.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(Composite);
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(Loc, SourceLocation());
+
+ InitializationSequence E1ToC(*this, Entity, Kind, E1);
+ if (!E1ToC)
return QualType();
- return C1.Composite;
- }
- Conversion C2(*this, Loc, E1, E2, Composite2);
- if (C1.Viable == C2.Viable) {
- // Either Composite1 and Composite2 are viable and are different, or
- // neither is viable.
- // FIXME: How both be viable and different?
- return QualType();
- }
+ InitializationSequence E2ToC(*this, Entity, Kind, E2);
+ if (!E2ToC)
+ return QualType();
- // Convert to the chosen type.
- if (ConvertArgs && (C1.Viable ? C1 : C2).perform())
- return QualType();
+ // FIXME: Let the caller know if these fail to avoid duplicate diagnostics.
+ ExprResult E1Result = E1ToC.Perform(*this, Entity, Kind, E1);
+ if (E1Result.isInvalid())
+ return QualType();
+ E1 = E1Result.get();
+
+ ExprResult E2Result = E2ToC.Perform(*this, Entity, Kind, E2);
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.get();
+ }
- return C1.Viable ? C1.Composite : C2.Composite;
+ return Composite;
}
ExprResult Sema::MaybeBindToTemporary(Expr *E) {
@@ -7780,8 +8020,9 @@ class TransformTypos : public TreeTransform<TransformTypos> {
// If we found a valid result, double check to make sure it's not ambiguous.
if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) {
- auto SavedTransformCache = std::move(TransformCache);
- TransformCache.clear();
+ auto SavedTransformCache =
+ llvm::SmallDenseMap<TypoExpr *, ExprResult, 2>(TransformCache);
+
// Ensure none of the TypoExprs have multiple typo correction candidates
// with the same edit length that pass all the checks and filters.
while (!AmbiguousTypoExprs.empty()) {