summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r--clang/lib/Sema/SemaExpr.cpp193
1 files changed, 82 insertions, 111 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index eddc4207dfc..15564918b37 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8929,21 +8929,35 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
// C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
+ // C++ [expr.eq]p2:
+ // In addition, pointers to members can be compared, or a pointer to
+ // member and a null pointer constant. Pointer to member conversions
+ // (4.11) and qualification conversions (4.4) are performed to bring
+ // them to a common type. If one operand is a null pointer constant,
+ // the common type is the type of the other operand. Otherwise, the
+ // common type is a pointer to member type similar (4.4) to the type
+ // of one of the operands, with a cv-qualification signature (4.4)
+ // that is the union of the cv-qualification signatures of the operand
+ // types.
+
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
- assert(LHSType->isPointerType() || RHSType->isPointerType() ||
- LHSType->isMemberPointerType() || RHSType->isMemberPointerType());
+ assert((LHSType->isPointerType() && RHSType->isPointerType()) ||
+ (LHSType->isMemberPointerType() && RHSType->isMemberPointerType()));
- QualType T = S.FindCompositePointerType(Loc, LHS, RHS);
+ bool NonStandardCompositeType = false;
+ bool *BoolPtr = S.isSFINAEContext() ? nullptr : &NonStandardCompositeType;
+ QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr);
if (T.isNull()) {
- if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) &&
- (RHSType->isPointerType() || RHSType->isMemberPointerType()))
- diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
- else
- S.InvalidOperands(Loc, LHS, RHS);
+ diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
return true;
}
+ if (NonStandardCompositeType)
+ S.Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
+ << LHSType << RHSType << T << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+
LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast);
RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast);
return false;
@@ -9300,53 +9314,41 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
LHS.get()->getSourceRange());
}
- if ((LHSType->isIntegerType() && !LHSIsNull) ||
- (RHSType->isIntegerType() && !RHSIsNull)) {
- // Skip normal pointer conversion checks in this case; we have better
- // diagnostics for this below.
- } else if (getLangOpts().CPlusPlus) {
- // Equality comparison of a function pointer to a void pointer is invalid,
- // but we allow it as an extension.
- // FIXME: If we really want to allow this, should it be part of composite
- // pointer type computation so it works in conditionals too?
- if (!IsRelational &&
- ((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) ||
- (RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) {
- // This is a gcc extension compatibility comparison.
- // In a SFINAE context, we treat this as a hard error to maintain
- // conformance with the C++ standard.
- diagnoseFunctionPointerToVoidComparison(
- *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext());
-
- if (isSFINAEContext())
- return QualType();
-
- RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
- return ResultTy;
- }
+ // All of the following pointer-related warnings are GCC extensions, except
+ // when handling null pointer constants.
+ if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2
+ QualType LCanPointeeTy =
+ LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
+ QualType RCanPointeeTy =
+ RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
+
+ if (getLangOpts().CPlusPlus) {
+ if (LCanPointeeTy == RCanPointeeTy)
+ return ResultTy;
+ if (!IsRelational &&
+ (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
+ // Valid unless comparison between non-null pointer and function pointer
+ // This is a gcc extension compatibility comparison.
+ // In a SFINAE context, we treat this as a hard error to maintain
+ // conformance with the C++ standard.
+ if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
+ && !LHSIsNull && !RHSIsNull) {
+ diagnoseFunctionPointerToVoidComparison(
+ *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext());
+
+ if (isSFINAEContext())
+ return QualType();
+
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
+ return ResultTy;
+ }
+ }
- // C++ [expr.eq]p2:
- // If at least one operand is a pointer [...] bring them to their
- // composite pointer type.
- // C++ [expr.rel]p2:
- // If both operands are pointers, [...] bring them to their composite
- // pointer type.
- if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >=
- (IsRelational ? 2 : 1)) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
else
return ResultTy;
}
- } else if (LHSType->isPointerType() &&
- RHSType->isPointerType()) { // C99 6.5.8p2
- // All of the following pointer-related warnings are GCC extensions, except
- // when handling null pointer constants.
- QualType LCanPointeeTy =
- LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
- QualType RCanPointeeTy =
- RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
-
// C99 6.5.9p2 and C99 6.5.8p2
if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
RCanPointeeTy.getUnqualifiedType())) {
@@ -9391,63 +9393,36 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
if (getLangOpts().CPlusPlus) {
- // C++ [expr.eq]p4:
- // Two operands of type std::nullptr_t or one operand of type
- // std::nullptr_t and the other a null pointer constant compare equal.
- if (!IsRelational && LHSIsNull && RHSIsNull) {
- if (LHSType->isNullPtrType()) {
- RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- return ResultTy;
- }
- if (RHSType->isNullPtrType()) {
- LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return ResultTy;
- }
- }
-
- // Comparison of Objective-C pointers and block pointers against nullptr_t.
- // These aren't covered by the composite pointer type rules.
- if (!IsRelational && RHSType->isNullPtrType() &&
- (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
- RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
+ // Comparison of nullptr_t with itself.
+ if (LHSType->isNullPtrType() && RHSType->isNullPtrType())
return ResultTy;
- }
- if (!IsRelational && LHSType->isNullPtrType() &&
- (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
- LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
+
+ // Comparison of pointers with null pointer constants and equality
+ // comparisons of member pointers to null pointer constants.
+ if (RHSIsNull &&
+ ((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) ||
+ (!IsRelational &&
+ (LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) {
+ RHS = ImpCastExprToType(RHS.get(), LHSType,
+ LHSType->isMemberPointerType()
+ ? CK_NullToMemberPointer
+ : CK_NullToPointer);
return ResultTy;
}
-
- if (IsRelational &&
- ((LHSType->isNullPtrType() && RHSType->isPointerType()) ||
- (RHSType->isNullPtrType() && LHSType->isPointerType()))) {
- // HACK: Relational comparison of nullptr_t against a pointer type is
- // invalid per DR583, but we allow it within std::less<> and friends,
- // since otherwise common uses of it break.
- // FIXME: Consider removing this hack once LWG fixes std::less<> and
- // friends to have std::nullptr_t overload candidates.
- DeclContext *DC = CurContext;
- if (isa<FunctionDecl>(DC))
- DC = DC->getParent();
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
- if (CTSD->isInStdNamespace() &&
- llvm::StringSwitch<bool>(CTSD->getName())
- .Cases("less", "less_equal", "greater", "greater_equal", true)
- .Default(false)) {
- if (RHSType->isNullPtrType())
- RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- else
- LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return ResultTy;
- }
- }
+ if (LHSIsNull &&
+ ((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) ||
+ (!IsRelational &&
+ (RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) {
+ LHS = ImpCastExprToType(LHS.get(), RHSType,
+ RHSType->isMemberPointerType()
+ ? CK_NullToMemberPointer
+ : CK_NullToPointer);
+ return ResultTy;
}
- // C++ [expr.eq]p2:
- // If at least one operand is a pointer to member, [...] bring them to
- // their composite pointer type.
+ // Comparison of member pointers.
if (!IsRelational &&
- (LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) {
+ LHSType->isMemberPointerType() && RHSType->isMemberPointerType()) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
else
@@ -9556,19 +9531,15 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// Under a debugger, allow the comparison of pointers to integers,
// since users tend to want to compare addresses.
} else if ((LHSIsNull && LHSType->isIntegerType()) ||
- (RHSIsNull && RHSType->isIntegerType())) {
- if (IsRelational) {
- isError = getLangOpts().CPlusPlus;
- DiagID =
- isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero
- : diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
- }
- } else if (getLangOpts().CPlusPlus) {
+ (RHSIsNull && RHSType->isIntegerType())) {
+ if (IsRelational && !getLangOpts().CPlusPlus)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
+ } else if (IsRelational && !getLangOpts().CPlusPlus)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
+ else if (getLangOpts().CPlusPlus) {
DiagID = diag::err_typecheck_comparison_of_pointer_integer;
isError = true;
- } else if (IsRelational)
- DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
- else
+ } else
DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
if (DiagID) {
OpenPOWER on IntegriCloud