diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2012-04-05 22:30:04 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2012-04-05 22:30:04 +0000 |
commit | ae916a14cf727b4ce3ac316f4fd780d1c83c5baf (patch) | |
tree | 58e3ef0eb588c148e9bfb24ee4a8247c75268337 | |
parent | bf393be8a0b8b573ceb23ed19ac953832a2a69e4 (diff) |
Properly implement the C rules for composite types for qualified pointers in conditionals. Patch by Tim Northover.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154134 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 38 | ||||
-rw-r--r-- | test/Sema/conditional-expr.c | 17 |
2 files changed, 44 insertions, 11 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 9339c04c51..709b944447 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4568,8 +4568,28 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, rhptee = RHSTy->castAs<PointerType>()->getPointeeType(); } - if (!S.Context.typesAreCompatible(lhptee.getUnqualifiedType(), - rhptee.getUnqualifiedType())) { + // C99 6.5.15p6: If both operands are pointers to compatible types or to + // differently qualified versions of compatible types, the result type is + // a pointer to an appropriately qualified version of the composite + // type. + + // Only CVR-qualifiers exist in the standard, and the differently-qualified + // clause doesn't make sense for our extensions. E.g. address space 2 should + // be incompatible with address space 3: they may live on different devices or + // anything. + Qualifiers lhQual = lhptee.getQualifiers(); + Qualifiers rhQual = rhptee.getQualifiers(); + + unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers(); + lhQual.removeCVRQualifiers(); + rhQual.removeCVRQualifiers(); + + lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); + rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); + + QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); + + if (CompositeTy.isNull()) { S.Diag(Loc, diag::warn_typecheck_cond_incompatible_pointers) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); @@ -4583,16 +4603,12 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, } // The pointer types are compatible. - // C99 6.5.15p6: If both operands are pointers to compatible types *or* to - // differently qualified versions of compatible types, the result type is - // a pointer to an appropriately qualified version of the *composite* - // type. - // FIXME: Need to calculate the composite type. - // FIXME: Need to add qualifiers + QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual); + ResultTy = S.Context.getPointerType(ResultTy); - LHS = S.ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); - return LHSTy; + LHS = S.ImpCastExprToType(LHS.take(), ResultTy, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), ResultTy, CK_BitCast); + return ResultTy; } /// \brief Return the resulting type when the operands are both block pointers. diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c index 436ecdbebc..184ac4a9e7 100644 --- a/test/Sema/conditional-expr.c +++ b/test/Sema/conditional-expr.c @@ -60,6 +60,23 @@ void foo() { test0 = test0 ? EVal : test1; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}} test0 = test0 ? test1 : EVal; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}} + const int *const_int; + int *nonconst_int; + *(test0 ? const_int : nonconst_int) = 42; // expected-error {{read-only variable is not assignable}} + *(test0 ? nonconst_int : const_int) = 42; // expected-error {{read-only variable is not assignable}} + + // The composite type here should be "int (*)[12]", fine for the sizeof + int (*incomplete)[]; + int (*complete)[12]; + sizeof(*(test0 ? incomplete : complete)); // expected-warning {{expression result unused}} + sizeof(*(test0 ? complete : incomplete)); // expected-warning {{expression result unused}} + + int __attribute__((address_space(2))) *adr2; + int __attribute__((address_space(3))) *adr3; + test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} + + // Make sure address-space mask ends up in the result type + (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}} } int Postgresql() { |