diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 980e4b0d4eb..50970756265 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -5553,10 +5553,12 @@ public class AST2TemplateTests extends AST2BaseTest { // typedef B u; // }; // - // typedef C r; + // struct C8 { char c[8]; }; + // + // typedef C r; // typedef r::s t; // t::u x; - public void _testBoolExpressionAsTemplateArgument_361604() throws Exception { + public void testBoolExpressionAsTemplateArgument_361604() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java index f6f48df2dda..75e6fc21f43 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java @@ -6,7 +6,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Markus Schorn - initial API and implementation + * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; @@ -74,7 +75,7 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat private ITranslationUnit fOriginatingTranslationUnit; private ISignificantMacros fSignificantMacros= ISignificantMacros.NONE; private boolean fPragmaOnceSemantics; - + private SizeofCalculator fSizeofCalculator; /** The semaphore controlling exclusive access to the AST. */ private final Semaphore fSemaphore= new Semaphore(1); @@ -486,4 +487,11 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat public void endExclusiveAccess() { fSemaphore.release(); } + + public SizeofCalculator getSizeofCalculator() { + if (fSizeofCalculator == null) { + fSizeofCalculator = new SizeofCalculator(this); + } + return fSizeofCalculator; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java new file mode 100644 index 00000000000..43e1a483a78 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java @@ -0,0 +1,266 @@ +/******************************************************************************* + * Copyright (c) 2011 Google, Inc 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IArrayType; +import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.ICompositeType; +import org.eclipse.cdt.core.dom.ast.IEnumeration; +import org.eclipse.cdt.core.dom.ast.IField; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; + +/** + * Calculator of in-memory size and of types. + */ +public class SizeofCalculator { + /** Size and alignment pair */ + public static class SizeAndAlignment { + public final long size; + public final int alignment; + + public SizeAndAlignment(long size, int alignment) { + this.size = size; + this.alignment = alignment; + } + } + + private static final SizeAndAlignment SIZE_1 = new SizeAndAlignment(1, 1); + + private final SizeAndAlignment size_2; + private final SizeAndAlignment size_4; + private final SizeAndAlignment size_8; + private final SizeAndAlignment sizeof_pointer; + private final SizeAndAlignment sizeof_int; + private final SizeAndAlignment sizeof_long; + private final SizeAndAlignment sizeof_long_long; + private final SizeAndAlignment sizeof_short; + private final SizeAndAlignment sizeof_bool; + private final SizeAndAlignment sizeof_wchar_t; + private final SizeAndAlignment sizeof_float; + private final SizeAndAlignment sizeof_complex_float; + private final SizeAndAlignment sizeof_double; + private final SizeAndAlignment sizeof_complex_double; + private final SizeAndAlignment sizeof_long_double; + private final SizeAndAlignment sizeof_complex_long_double; + + public SizeofCalculator(IASTTranslationUnit ast) { + int maxAlignment = 32; + Map sizeofMacros = new HashMap(); + for (IASTPreprocessorMacroDefinition macro : ast.getBuiltinMacroDefinitions()) { + String name = macro.getName().toString(); + if ("__BIGGEST_ALIGNMENT__".equals(name)) { //$NON-NLS-1$ + try { + maxAlignment = Integer.parseInt(macro.getExpansion()); + } catch (NumberFormatException e) { + // Ignore. + } + } else { + if (name.startsWith("__SIZEOF_")) { //$NON-NLS-1$ + sizeofMacros.put(name, macro.getExpansion()); + } + } + } + size_2 = new SizeAndAlignment(2, Math.min(2, maxAlignment)); + size_4 = new SizeAndAlignment(4, Math.min(4, maxAlignment)); + size_8 = new SizeAndAlignment(8, Math.min(8, maxAlignment)); + sizeof_pointer = getSize(sizeofMacros, "__SIZEOF_POINTER__", maxAlignment); //$NON-NLS-1$ + sizeof_int = getSize(sizeofMacros, "__SIZEOF_INT__", maxAlignment); //$NON-NLS-1$ + sizeof_long = getSize(sizeofMacros, "__SIZEOF_LONG__", maxAlignment); //$NON-NLS-1$ + sizeof_long_long = getSize(sizeofMacros, "__SIZEOF_LONG_LONG__", maxAlignment); //$NON-NLS-1$ + sizeof_short = getSize(sizeofMacros, "__SIZEOF_SHORT__", maxAlignment); //$NON-NLS-1$ + sizeof_bool = getSize(sizeofMacros, "__SIZEOF_BOOL__", maxAlignment); //$NON-NLS-1$ + sizeof_wchar_t = getSize(sizeofMacros, "__SIZEOF_WCHAR_T__", maxAlignment); //$NON-NLS-1$ + sizeof_float = getSize(sizeofMacros, "__SIZEOF_FLOAT__", maxAlignment); //$NON-NLS-1$ + sizeof_complex_float = getDoubleSize(sizeof_float); + sizeof_double = getSize(sizeofMacros, "__SIZEOF_DOUBLE__", maxAlignment); //$NON-NLS-1$ + sizeof_complex_double = getDoubleSize(sizeof_double); + sizeof_long_double = getSize(sizeofMacros, "__SIZEOF_LONG_DOUBLE__", maxAlignment); //$NON-NLS-1$ + sizeof_complex_long_double = getDoubleSize(sizeof_long_double); + } + + /** + * Calculates size and alignment for the given type. + * @param type + * @return size and alignment, or null if could not be calculated. + */ + public SizeAndAlignment sizeAndAlignment(IType type) { + type = SemanticUtil.getNestedType(type, SemanticUtil.CVTYPE | SemanticUtil.TDEF); + + if (type instanceof ICPPBasicType) { + return sizeAndAlignment((IBasicType) type); + } + if (type instanceof IPointerType || type instanceof ICPPReferenceType) { + if (type instanceof ICPPPointerToMemberType) + return null; + return sizeof_pointer; + } + if (type instanceof IEnumeration) { + return sizeAndAlignment((IEnumeration) type); + } + if (type instanceof IArrayType) { + return sizeAndAlignment((IArrayType) type); + } + if (type instanceof ICompositeType) { + return sizeAndAlignment((ICompositeType) type); + } + return null; + } + + private SizeAndAlignment sizeAndAlignment(IBasicType type) { + Kind kind = type.getKind(); + switch (kind) { + case eBoolean: + return sizeof_bool; + case eChar: + return SIZE_1; + case eInt: + return type.isShort() ? sizeof_short : type.isLong() ? sizeof_long : + type.isLongLong() ? sizeof_long_long : sizeof_int; + case eFloat: { + return type.isComplex() ? sizeof_complex_float : sizeof_float; + } + case eDouble: + return type.isComplex() ? + (type.isLong() ? sizeof_long_double : sizeof_double) : + (type.isLong() ? sizeof_complex_long_double : sizeof_complex_double); + case eWChar: + return sizeof_wchar_t; + case eChar16: + return size_2; + case eChar32: + return size_4; + default: + return null; + } + } + + private SizeAndAlignment sizeAndAlignment(IEnumeration type) { + if (type instanceof ICPPEnumeration) { + IType fixedType = ((ICPPEnumeration) type).getFixedType(); + if (fixedType != null) { + return sizeAndAlignment(fixedType); + } + } + long range = Math.max(Math.abs(type.getMinValue()) - 1, Math.abs(type.getMaxValue())); + if (range >= (2 << 32)) + return size_8; + if (type.getMinValue() < 0) + range *= 2; + if (range >= (2 << 32)) + return size_8; + if (range >= (2 << 16)) + return size_4; + if (range >= (2 << 8)) + return size_2; + return SIZE_1; + } + + private SizeAndAlignment sizeAndAlignment(IArrayType type) { + Long numElements = type.getSize().numericalValue(); + if (numElements == null) + return null; + IType elementType = type.getType(); + SizeAndAlignment info = sizeAndAlignment(elementType); + if (numElements.longValue() == 1) + return info; + if (info == null) + return null; + return new SizeAndAlignment(info.size * numElements.longValue(), info.alignment); + } + + private SizeAndAlignment sizeAndAlignment(ICompositeType type) { + /* TODO(sprigogin): May produce incorrect result for structures containing bit fields. + * Unfortunately widths of bit fields is not preserved in the AST. */ + long size = 0; + int maxAlignment = 1; + IField[] fields; + if (type instanceof ICPPClassType) { + ICPPClassType classType = (ICPPClassType) type; + for (ICPPBase base : classType.getBases()) { + if (base.isVirtual()) + return null; // Don't know how to calculate size when there are virtual bases. + IBinding baseClass = base.getBaseClass(); + if (!(baseClass instanceof IType)) + return null; + SizeAndAlignment info = sizeAndAlignment((IType) baseClass); + if (info == null) + return null; + size += info.alignment - (size - 1) % info.alignment - 1 + info.size; + if (maxAlignment < info.alignment) + maxAlignment = info.alignment; + for (ICPPMethod method : classType.getDeclaredMethods()) { + if (method.isVirtual()) { + // Don't know how to calculate size when there are virtual functions. + return null; + } + } + } + fields = classType.getDeclaredFields(); + } else { + fields = type.getFields(); + } + + boolean union = type.getKey() == ICompositeType.k_union; + for (IField field : fields) { + if (field.isStatic()) + continue; + IType fieldType = field.getType(); + SizeAndAlignment info = sizeAndAlignment(fieldType); + if (info == null) + return null; + if (union) { + if (size < info.size) + size = info.size; + } else { + size += info.alignment - (size - 1) % info.alignment - 1 + info.size; + } + if (maxAlignment < info.alignment) + maxAlignment = info.alignment; + } + if (size > 0) + size += maxAlignment - (size - 1) % maxAlignment - 1; + return new SizeAndAlignment(size, maxAlignment); + } + + private static SizeAndAlignment getSize(Map macros, String name, + int maxAlignment) { + String value = macros.get(name); + if (value == null) + return null; + try { + int size = Integer.parseInt(value); + return new SizeAndAlignment(size, Math.min(size, maxAlignment)); + } catch (NumberFormatException e) { + return null; + } + } + + private SizeAndAlignment getDoubleSize(SizeAndAlignment sizeAndAlignment) { + return sizeAndAlignment == null ? + null : new SizeAndAlignment(sizeAndAlignment.size * 2, sizeAndAlignment.alignment); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java index 2dbade05e2c..ebfb4d1c194 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2008, 2011 Wind River Systems, Inc. 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 @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; @@ -23,6 +24,7 @@ import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; +import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumerator; @@ -33,7 +35,9 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException; import org.eclipse.cdt.internal.core.pdom.db.TypeMarshalBuffer; @@ -460,6 +464,19 @@ public class Value implements IValue { } } } + if (e instanceof IASTTypeIdExpression) { + IASTTypeIdExpression typeIdEx = (IASTTypeIdExpression) e; + switch (typeIdEx.getOperator()) { + case IASTTypeIdExpression.op_sizeof: + IType type = CPPVisitor.createType(typeIdEx.getTypeId()); + ASTTranslationUnit ast = (ASTTranslationUnit) typeIdEx.getTranslationUnit(); + SizeofCalculator calculator = ast.getSizeofCalculator(); + SizeAndAlignment info = calculator.sizeAndAlignment(type); + if (info == null) + throw UNKNOWN_EX; + return info.size; + } + } throw UNKNOWN_EX; } @@ -521,7 +538,7 @@ public class Value implements IValue { boolean skipToSeparator= false; for (int i = 0; i < expr.length; i++) { final char c= expr[i]; - switch(c) { + switch (c) { case REFERENCE_CHAR: { int idx= parseNonNegative(expr, i + 1); if (idx >= oldUnknowns.length) @@ -549,9 +566,21 @@ public class Value implements IValue { private static Object evaluateUnaryExpression(IASTUnaryExpression ue, Map unknownSigs, List unknowns, int maxdepth) throws UnknownValueException { final int unaryOp= ue.getOperator(); + + if (unaryOp == IASTUnaryExpression.op_sizeof) { + IType type = ue.getExpressionType(); + ASTTranslationUnit ast = (ASTTranslationUnit) ue.getTranslationUnit(); + SizeofCalculator calculator = ast.getSizeofCalculator(); + SizeAndAlignment info = calculator.sizeAndAlignment(type); + if (info == null) + throw UNKNOWN_EX; + return info.size; + } + if (unaryOp == IASTUnaryExpression.op_amper || unaryOp == IASTUnaryExpression.op_star || - unaryOp == IASTUnaryExpression.op_sizeof || unaryOp == IASTUnaryExpression.op_sizeofParameterPack) + unaryOp == IASTUnaryExpression.op_sizeofParameterPack) { throw UNKNOWN_EX; + } final Object value= evaluate(ue.getOperand(), unknownSigs, unknowns, maxdepth); return combineUnary(unaryOp, value); @@ -563,10 +592,10 @@ public class Value implements IValue { case IASTUnaryExpression.op_plus: return value; } - + if (value instanceof Number) { long v= ((Number) value).longValue(); - switch(unaryOp) { + switch (unaryOp) { case IASTUnaryExpression.op_prefixIncr: case IASTUnaryExpression.op_postFixIncr: return ++v; @@ -609,21 +638,21 @@ public class Value implements IValue { if (o1 instanceof Number && o2 instanceof Number) { long v1= ((Number) o1).longValue(); long v2= ((Number) o2).longValue(); - switch(op) { + switch (op) { case IASTBinaryExpression.op_multiply: return v1 * v2; case IASTBinaryExpression.op_divide: if (v2 == 0) throw UNKNOWN_EX; - return v1/v2; + return v1 / v2; case IASTBinaryExpression.op_modulo: if (v2 == 0) throw UNKNOWN_EX; return v1 % v2; case IASTBinaryExpression.op_plus: - return v1+v2; + return v1 + v2; case IASTBinaryExpression.op_minus: - return v1-v2; + return v1 - v2; case IASTBinaryExpression.op_shiftLeft: return v1 << v2; case IASTBinaryExpression.op_shiftRight: @@ -637,11 +666,11 @@ public class Value implements IValue { case IASTBinaryExpression.op_greaterEqual: return v1 >= v2 ? 1 : 0; case IASTBinaryExpression.op_binaryAnd: - return v1&v2; + return v1 & v2; case IASTBinaryExpression.op_binaryXor: - return v1^v2; + return v1 ^ v2; case IASTBinaryExpression.op_binaryOr: - return v1|v2; + return v1 | v2; case IASTBinaryExpression.op_logicalAnd: return v1 != 0 && v2 != 0 ? 1 : 0; case IASTBinaryExpression.op_logicalOr: @@ -730,7 +759,7 @@ public class Value implements IValue { throw UNKNOWN_EX; final char c= buf[idx]; - switch(c) { + switch (c) { case BINARY_OP_CHAR: int op= parseNonNegative(buf, idx + 1); reeval.nextSeperator();