diff options
author | Nathan Ridge | 2012-12-07 08:49:54 +0000 |
---|---|---|
committer | Sergey Prigogin | 2012-12-07 20:13:15 +0000 |
commit | 12637bcda31ffa3e165a7008ae33f842c388de6f (patch) | |
tree | fed11adcf834c687410dbcadcbc17a57cc1afd8f | |
parent | f429bd5482da5a034e0dab8752e68bf8304b8f72 (diff) | |
download | org.eclipse.cdt-12637bcda31ffa3e165a7008ae33f842c388de6f.tar.gz org.eclipse.cdt-12637bcda31ffa3e165a7008ae33f842c388de6f.tar.xz org.eclipse.cdt-12637bcda31ffa3e165a7008ae33f842c388de6f.zip |
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>
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 a54e0bc32e3..71b4341cedb 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 97b8e1f9f70..41fe973a720 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 8b0b4163d8f..c9e68fe1402 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 4c5ff020493..f265c57a3bc 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 58e8713a21f..a447998e76e 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 267b5c018dd..1e29599345a 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 cacff06b092..3e8308c84fc 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; } |