From 76f23d05c3a3cec7f9e4a46d462ef1ac6ae2e8da Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Sat, 21 Mar 2015 03:00:07 -0400 Subject: [PATCH] Bug 462705 - Derived-to-base pointer conversion in conditional operator Change-Id: I04f792ae9485f9fbc67a7fd3658ef571d1ae7d0c Signed-off-by: Nathan Ridge --- .../core/parser/tests/ast2/AST2CPPTests.java | 13 ++++ .../dom/parser/cpp/semantics/Conversions.java | 62 ++++++++++++------- .../parser/cpp/semantics/EvalConditional.java | 2 +- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 854f30caf77..4dbc48a3fee 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -10651,6 +10651,19 @@ public class AST2CPPTests extends AST2TestBase { public void testThrowExpressionInConditional_396663() throws Exception { parseAndCheckBindings(getAboveComment(), CPP, true); } + + // struct A {}; + // + // struct B : A {}; + // + // void foo(A*); + // + // int main() { + // foo(true ? new A() : new B()); + // } + public void testBasePointerConverstionInConditional_462705() throws Exception { + parseAndCheckBindings(); + } // template // struct enable_if { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index 70624d86462..4b99eb5d6d8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -1180,7 +1180,7 @@ public class Conversions { * Composite pointer type computed as described in 5.9-2 except that if the conversion to * the pointer is not possible, the method returns {@code null}. */ - public static IType compositePointerType(IType t1, IType t2) { + public static IType compositePointerType(IType t1, IType t2, IASTNode point) { final boolean isPtr1 = t1 instanceof IPointerType; if (isPtr1 || isNullPtr(t1)) { if (isNullPointerConstant(t2)) { @@ -1210,7 +1210,7 @@ public class Conversions { return addQualifiers(p2, p1.isConst(), p1.isVolatile(), p1.isRestrict()); } - IType t= mergePointers(target1, target2, true); + IType t= mergePointers(target1, target2, point, true, true); if (t == null) return null; if (t == target1) @@ -1220,7 +1220,7 @@ public class Conversions { return copyPointer(p1, t, false, false); } - private static IType mergePointers(IType t1, IType t2, boolean allcq) { + private static IType mergePointers(IType t1, IType t2, IASTNode point, boolean allcq, boolean allowInheritance) { t1= getNestedType(t1, TDEF | REF); t2= getNestedType(t2, TDEF | REF); if (t1 instanceof IPointerType && t2 instanceof IPointerType) { @@ -1234,7 +1234,7 @@ public class Conversions { return null; final IType p1target = p1.getType(); - IType merged= mergePointers(p1target, p2.getType(), allcq && (cv1.isConst() || cv2.isConst())); + IType merged= mergePointers(p1target, p2.getType(), point, allcq && (cv1.isConst() || cv2.isConst()), false); if (merged == null) return null; if (p1target == merged && cv1.isAtLeastAsQualifiedAs(cv2)) @@ -1247,27 +1247,47 @@ public class Conversions { final IType uq1= getNestedType(t1, TDEF|REF|CVTYPE); final IType uq2= getNestedType(t2, TDEF|REF|CVTYPE); - if (uq1 == null || ! uq1.isSameType(uq2)) + if (uq1 == null) { return null; - - if (uq1 == t1 && uq2 == t2) - return t1; - - CVQualifier cv1= getCVQualifier(t1); - CVQualifier cv2= getCVQualifier(t2); - if (cv1 == cv2) - return t1; + } - if (!allcq) - return null; + if (uq1.isSameType(uq2)) { + if (uq1 == t1 && uq2 == t2) + return t1; - if (cv1.isAtLeastAsQualifiedAs(cv2)) - return t1; - if (cv2.isAtLeastAsQualifiedAs(cv1)) - return t2; + CVQualifier cv1= getCVQualifier(t1); + CVQualifier cv2= getCVQualifier(t2); + if (cv1 == cv2) + return t1; + + if (!allcq) + return null; - // One type is const the other is volatile. - return new CPPQualifierType(uq1, true, true); + if (cv1.isAtLeastAsQualifiedAs(cv2)) + return t1; + if (cv2.isAtLeastAsQualifiedAs(cv1)) + return t2; + + // One type is const the other is volatile. + return new CPPQualifierType(uq1, true, true); + } else if (allowInheritance) { + // Allow for conversion from pointer-to-derived to pointer-to-base as per [conv.ptr] p3. + IType base; + if (SemanticUtil.calculateInheritanceDepth(uq1, uq2, point) > 0) { + base = uq2; + } else if (SemanticUtil.calculateInheritanceDepth(uq2, uq1, point) > 0) { + base = uq1; + } else { + return null; + } + CVQualifier cv1= getCVQualifier(t1); + CVQualifier cv2= getCVQualifier(t2); + if (cv1 == CVQualifier.NONE && cv2 == CVQualifier.NONE) { + return base; + } + return new CPPQualifierType(base, cv1.isConst() || cv2.isConst(), cv1.isVolatile() || cv2.isVolatile()); + } + return null; } public static IType copyPointer(final IPointerType p1, IType target, final boolean isConst, diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java index 1b6199f9a8b..43be81821aa 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java @@ -260,7 +260,7 @@ public class EvalConditional extends CPPDependentEvaluation { } else { fType= CPPArithmeticConversion.convertCppOperandTypes(IASTBinaryExpression.op_plus, t2, t3); if (fType == null) { - fType= Conversions.compositePointerType(t2, t3); + fType= Conversions.compositePointerType(t2, t3, point); if (fType == null) { fType= ProblemType.UNKNOWN_FOR_EXPRESSION; }