1
0
Fork 0
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:
Nathan Ridge 2012-12-07 03:49:54 -05:00 committed by Sergey Prigogin
parent 63a7756b6c
commit 88b19449f2
7 changed files with 249 additions and 20 deletions

View file

@ -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) {

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;
}