summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Ridge2012-12-07 03:49:54 (EST)
committerSergey Prigogin2012-12-07 15:13:15 (EST)
commit12637bcda31ffa3e165a7008ae33f842c388de6f (patch)
treefed11adcf834c687410dbcadcbc17a57cc1afd8f
parentf429bd5482da5a034e0dab8752e68bf8304b8f72 (diff)
downloadorg.eclipse.cdt-12637bcda31ffa3e165a7008ae33f842c388de6f.zip
org.eclipse.cdt-12637bcda31ffa3e165a7008ae33f842c388de6f.tar.gz
org.eclipse.cdt-12637bcda31ffa3e165a7008ae33f842c388de6f.tar.bz2
Bug 389782 - Error with uniform initialization involving conversion
Change-Id: I2a8227b187bd3b4f7fcc7b7a9b9f0b1c9f289117 Reviewed-on: https://git.eclipse.org/r/9058 Reviewed-by: Sergey Prigogin <eclipse.sprigogin@gmail.com> IP-Clean: Sergey Prigogin <eclipse.sprigogin@gmail.com> Tested-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java30
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java94
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ArithmeticConversion.java57
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java4
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java4
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java76
7 files changed, 248 insertions, 19 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java
index a54e0bc..71b4341 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java
@@ -11,6 +11,7 @@
* Andrew Ferguson (Symbian)
* Mike Kucera (IBM)
* Sergey Prigogin (Google)
+ * Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
@@ -106,6 +107,7 @@ public class AST2BaseTest extends BaseTestCase {
Map<String, String> map= new HashMap<String, String>();
map.put("__GNUC__", "4");
map.put("__GNUC_MINOR__", "7");
+ map.put("__SIZEOF_SHORT__", "2");
map.put("__SIZEOF_INT__", "4");
map.put("__SIZEOF_LONG__", "8");
return map;
@@ -113,6 +115,7 @@ public class AST2BaseTest extends BaseTestCase {
private static Map<String, String> getStdMap() {
Map<String, String> map= new HashMap<String, String>();
+ map.put("__SIZEOF_SHORT__", "2");
map.put("__SIZEOF_INT__", "4");
map.put("__SIZEOF_LONG__", "8");
return map;
@@ -511,7 +514,7 @@ public class AST2BaseTest extends BaseTestCase {
protected IASTTranslationUnit tu;
protected String contents;
protected boolean isCPP;
-
+
public BindingAssertionHelper(String contents, boolean isCPP) throws ParserException {
this(contents, isCPP ? ParserLanguage.CPP : ParserLanguage.C);
}
@@ -567,6 +570,31 @@ public class AST2BaseTest extends BaseTestCase {
return (T) binding;
}
+ private int getIdentifierLength(String str) {
+ int i;
+ for (i = 0; i < str.length() && Character.isJavaIdentifierPart(str.charAt(i)); ++i) {
+ }
+ return i;
+ }
+
+ public IProblemBinding assertProblemOnFirstIdentifier(String section) {
+ return assertProblem(section, getIdentifierLength(section));
+ }
+
+ public IProblemBinding assertProblemOnFirstIdentifier(String section, int problemId) {
+ IProblemBinding problemBinding = assertProblemOnFirstIdentifier(section);
+ assertEquals(problemId, problemBinding.getID());
+ return problemBinding;
+ }
+
+ public <T extends IBinding> T assertNonProblemOnFirstIdentifier(String section, Class<T> type, Class... cs) {
+ return assertNonProblem(section, getIdentifierLength(section), type, cs);
+ }
+
+ public IBinding assertNonProblemOnFirstIdentifier(String section) {
+ return assertNonProblem(section, getIdentifierLength(section), IBinding.class);
+ }
+
public void assertNoName(String section, int len) {
IASTName name= findName(section, len);
if (name != null) {
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 97b8e1f..41fe973 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
@@ -12,6 +12,7 @@
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
* Thomas Corbat (IFS)
+ * Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
@@ -9985,4 +9986,97 @@ public class AST2CPPTests extends AST2BaseTest {
public void testIsBaseOf_395019() throws Exception {
parseAndCheckBindings(getAboveComment(), CPP, true);
}
+
+ // struct Bool { Bool(bool); };
+ // struct Char { Char(char); };
+ // struct Short { Short(short); };
+ // struct Int { Int(int); };
+ // struct UInt { UInt(unsigned int); };
+ // struct Long { Long(long); };
+ // struct ULong { ULong(unsigned long); };
+ // struct Float { Float(float); };
+ // struct Double { Double(double); };
+ // struct LongDouble { LongDouble(long double); };
+ // void fbool(Bool);
+ // void fchar(Char);
+ // void fshort(Short);
+ // void fint(Int);
+ // void flong(Long);
+ // void fuint(UInt);
+ // void fulong(ULong);
+ // void ffloat(Float);
+ // void fdouble(Double);
+ // void flongdouble(LongDouble);
+ // enum UnscopedEnum : int { x, y, z };
+ //
+ // int main() {
+ // bool vbool;
+ // char vchar;
+ // short vshort;
+ // unsigned short vushort;
+ // int vint;
+ // unsigned int vuint;
+ // long vlong;
+ // float vfloat;
+ // double vdouble;
+ // long double vlongdouble;
+ // UnscopedEnum vue;
+ //
+ // // Narrowing conversions
+ // fint({vdouble});
+ // ffloat({vlongdouble});
+ // ffloat({vdouble});
+ // fdouble({vlongdouble});
+ // fdouble({vint});
+ // fdouble({vue});
+ // fshort({vint});
+ // fuint({vint});
+ // fint({vuint});
+ // fulong({vshort});
+ // fbool({vint});
+ // fchar({vint});
+ //
+ // // Non-narrowing conversions
+ // fint({vshort});
+ // flong({vint});
+ // fuint({vushort});
+ // flong({vshort});
+ // fulong({vuint});
+ // fulong({vushort});
+ // fdouble({vfloat});
+ // flongdouble({vfloat});
+ // flongdouble({vdouble});
+ // fint({vbool});
+ // fint({vchar});
+ // }
+ public void testNarrowingConversionsInListInitialization_389782() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ // Narrowing conversions
+ helper.assertProblemOnFirstIdentifier("fint({vdouble");
+ helper.assertProblemOnFirstIdentifier("ffloat({vlongdouble");
+ helper.assertProblemOnFirstIdentifier("ffloat({vdouble");
+ helper.assertProblemOnFirstIdentifier("fdouble({vlongdouble");
+ helper.assertProblemOnFirstIdentifier("fdouble({vint");
+ helper.assertProblemOnFirstIdentifier("fdouble({vue");
+ helper.assertProblemOnFirstIdentifier("fshort({vint");
+ helper.assertProblemOnFirstIdentifier("fuint({vint");
+ helper.assertProblemOnFirstIdentifier("fint({vuint");
+ helper.assertProblemOnFirstIdentifier("fulong({vshort");
+ helper.assertProblemOnFirstIdentifier("fbool({vint");
+ helper.assertProblemOnFirstIdentifier("fchar({vint");
+
+ // Non-narrowing conversions
+ helper.assertNonProblemOnFirstIdentifier("fint({vshort");
+ helper.assertNonProblemOnFirstIdentifier("flong({vint");
+ helper.assertNonProblemOnFirstIdentifier("fuint({vushort");
+ helper.assertNonProblemOnFirstIdentifier("flong({vshort");
+ helper.assertNonProblemOnFirstIdentifier("fulong({vuint");
+ helper.assertNonProblemOnFirstIdentifier("fulong({vushort");
+ helper.assertNonProblemOnFirstIdentifier("fdouble({vfloat");
+ helper.assertNonProblemOnFirstIdentifier("flongdouble({vfloat");
+ helper.assertNonProblemOnFirstIdentifier("flongdouble({vdouble");
+ helper.assertNonProblemOnFirstIdentifier("fint({vbool");
+ helper.assertNonProblemOnFirstIdentifier("fint({vchar");
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ArithmeticConversion.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ArithmeticConversion.java
index 8b0b416..c9e68fe 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ArithmeticConversion.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ArithmeticConversion.java
@@ -7,18 +7,21 @@
*
* Contributors:
* Markus Schorn - initial API and implementation
+ * Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
+import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
@@ -367,4 +370,58 @@ public abstract class ArithmeticConversion {
return false;
}
}
+
+ /**
+ * Make a best-effort guess at the sizeof() of an integral type.
+ */
+ private static long getApproximateSize(ICPPBasicType type) {
+ switch (type.getKind()) {
+ case eChar: return 1;
+ case eWChar: return 2;
+ case eInt:
+ // Note: we return 6 for long so that both long -> int
+ // and long long -> long conversions are reported
+ // as narrowing, to be on the safe side.
+ return type.isShort() ? 2
+ : type.isLong() ? 6
+ : type.isLongLong() ? 8
+ : 4;
+ case eBoolean: return 1;
+ case eChar16: return 2;
+ case eChar32: return 4;
+ case eInt128: return 16;
+ default: return 0; // shouldn't happen
+ }
+ }
+
+ /**
+ * Checks whether a target integral type can represent all values of a source integral type.
+ * @param target the target integral type
+ * @param source the source integral type
+ * @param point point for sizeof lookup
+ * @return whether the target integral type can represent all values of the source integral type
+ */
+ public static boolean fitsIntoType(ICPPBasicType target, ICPPBasicType source, IASTNode point) {
+ // A boolean cannot represent any other type.
+ if (target.getKind() == Kind.eBoolean && source.getKind() != Kind.eBoolean)
+ return false;
+ // A boolean can be represented by any other integral type.
+ if (source.getKind() == Kind.eBoolean)
+ return true;
+
+ // If the source is signed, it might be negative, so an unsigned target cannot represent it.
+ if (!source.isUnsigned() && target.isUnsigned())
+ return false;
+
+ // Otherwise, go by the size and signedness of the type.
+ SizeAndAlignment sourceSizeAndAlignment = SizeofCalculator.getSizeAndAlignment(source, point);
+ SizeAndAlignment targetSizeAndAlignment = SizeofCalculator.getSizeAndAlignment(target, point);
+ long sizeofSource = sourceSizeAndAlignment == null ? getApproximateSize(source) : sourceSizeAndAlignment.size;
+ long sizeofTarget = targetSizeAndAlignment == null ? getApproximateSize(target) : targetSizeAndAlignment.size;
+
+ if (sizeofSource == sizeofTarget)
+ return target.isUnsigned() == source.isUnsigned();
+ else
+ return sizeofSource < sizeofTarget;
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java
index 4c5ff02..f265c57 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java
@@ -590,7 +590,7 @@ class BuiltinOperators {
return type instanceof IBasicType && ((IBasicType) type).getKind() == Kind.eBoolean;
}
- private static boolean isFloatingPoint(IType type) {
+ public static boolean isFloatingPoint(IType type) {
if (type instanceof IBasicType) {
IBasicType.Kind kind= ((IBasicType) type).getKind();
switch (kind) {
@@ -638,7 +638,7 @@ class BuiltinOperators {
return false;
}
- private static boolean isIntegral(IType type) {
+ public static boolean isIntegral(IType type) {
if (type instanceof IBasicType) {
IBasicType.Kind kind= ((IBasicType) type).getKind();
switch (kind) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
index 58e8713..a447998 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
@@ -2730,7 +2730,7 @@ public class CPPSemantics {
}
cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue,
udc, ctx, data.getLookupPoint());
- if (data.fNoNarrowing && cost.isNarrowingConversion()) {
+ if (data.fNoNarrowing && cost.isNarrowingConversion(data.getLookupPoint())) {
cost= Cost.NO_CONVERSION;
}
}
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 267b5c0..1e29599 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
@@ -351,7 +351,7 @@ public class Conversions {
clause.getValueCategory(point), UDCMode.ALLOWED, Context.ORDINARY, point);
if (!cost.converts())
return cost;
- if (cost.isNarrowingConversion()) {
+ if (cost.isNarrowingConversion(point)) {
cost.setRank(Rank.NO_MATCH);
return cost;
}
@@ -381,7 +381,7 @@ public class Conversions {
final ICPPEvaluation firstArg = args[0];
if (!firstArg.isInitializerList()) {
Cost cost= checkImplicitConversionSequence(target, firstArg.getTypeOrFunctionSet(point), firstArg.getValueCategory(point), udc, Context.ORDINARY, point);
- if (cost.isNarrowingConversion()) {
+ if (cost.isNarrowingConversion(point)) {
return Cost.NO_CONVERSION;
}
return cost;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java
index cacff06..3e8308c 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * Copyright (c) 2004, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,12 +10,16 @@
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
+ * Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
+import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
@@ -261,22 +265,68 @@ public class Cost {
return buf.toString();
}
- public boolean isNarrowingConversion() {
- if (fCouldNarrow) {
- if (source instanceof CPPBasicType && target instanceof ICPPBasicType) {
- ICPPBasicType basicTarget= (ICPPBasicType) target;
- final Kind targetKind = basicTarget.getKind();
- if (targetKind != Kind.eInt && targetKind != Kind.eFloat && targetKind != Kind.eDouble) {
- return true;
- }
- Long val= ((CPPBasicType) source).getAssociatedNumericalValue();
- if (val != null) {
- long n= val.longValue();
- return !ArithmeticConversion.fitsIntoType(basicTarget, n);
+ public boolean isNarrowingConversion(IASTNode point) {
+ if (!fCouldNarrow)
+ return false;
+
+ // Determine whether this is a narrowing conversion, according to 8.5.4/7 (dcl.list.init).
+
+ if (!(target instanceof ICPPBasicType))
+ return false;
+ ICPPBasicType basicTarget = (ICPPBasicType) target;
+
+ // Deal with an enumeration source type.
+ // If it has a fixed underlying type, treat it as if it were that underlying type.
+ // If not, check whether the target type can represent its min and max values.
+ CPPBasicType basicSource = null;
+ if (source instanceof CPPBasicType) {
+ basicSource = (CPPBasicType) source;
+ } else if (source instanceof IEnumeration) {
+ IEnumeration enumSource = (IEnumeration) source;
+ if (enumSource instanceof ICPPEnumeration) {
+ IType fixedType = ((ICPPEnumeration) enumSource).getFixedType();
+ if (fixedType instanceof CPPBasicType) {
+ basicSource = (CPPBasicType) fixedType;
}
}
+ if (basicSource == null) { // C enumeration or no fixed type
+ return !ArithmeticConversion.fitsIntoType(basicTarget, enumSource.getMinValue()) ||
+ !ArithmeticConversion.fitsIntoType(basicTarget, enumSource.getMaxValue());
+ }
+ }
+
+ if (basicSource == null)
+ return false;
+
+ // The standard provides for an exception in some cases where, based on the types only,
+ // a conversion would be narrowing, but the source expression is a constant-expression
+ // and its value is exactly representable by the target type.
+ boolean constantExprExceptionApplies = false;
+
+ if (BuiltinOperators.isFloatingPoint(basicSource) && BuiltinOperators.isIntegral(basicTarget)) {
+ // From a floating-point type to an integer type
return true;
+ } else if (basicSource.getKind() == Kind.eDouble
+ && (basicTarget.getKind() == Kind.eFloat
+ || (basicTarget.getKind() == Kind.eDouble && !basicTarget.isLong() && basicSource.isLong()))) {
+ // From long double to double or float, or from double to float
+ constantExprExceptionApplies = true;
+ } else if (BuiltinOperators.isIntegral(basicSource) && BuiltinOperators.isFloatingPoint(basicTarget)) {
+ // From an integer type or unscoped enumeration type to a floating-point type
+ constantExprExceptionApplies = true;
+ } else if (BuiltinOperators.isIntegral(basicSource)
+ && BuiltinOperators.isIntegral(basicTarget)
+ && !ArithmeticConversion.fitsIntoType(basicTarget, basicSource, point)) {
+ // From an integer type or unscoped enumeration type to an integer type that
+ // cannot represent all the values of the original type
+ constantExprExceptionApplies = true;
}
+
+ if (constantExprExceptionApplies) {
+ Long val = basicSource.getAssociatedNumericalValue();
+ return val == null || !ArithmeticConversion.fitsIntoType(basicTarget, val.longValue());
+ }
+
return false;
}