mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
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>
This commit is contained in:
parent
63a7756b6c
commit
88b19449f2
7 changed files with 249 additions and 20 deletions
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue