From 8649b655701c4e56d00da6ff0f7361ff71572e2b Mon Sep 17 00:00:00 2001 From: qdagans Date: Fri, 20 Jun 2014 03:09:30 +0200 Subject: [PATCH] Bug 84144 - [Parser2] GCC: labels as values Add support for GNU goto label references. "http://gcc.gnu.org/onlinedocs/gcc-3.3.2/gcc/Labels-as-Values.html#Labels%20as%20Values GCC extensions to C allow taking the address of labels. These addresses can be used in a goto statement where any expression of type void * is allowed: foo: void* labelPtr = &&foo; goto *labelPtr;", comment from Andrew Niefer Add new classes and necessary changes in existing classes to support the above. Change-Id: I60b64957af3fdfd5463e89c2a36eea13bd280887 Signed-off-by: qdagans Reviewed-on: https://git.eclipse.org/r/28826 Tested-by: Hudson CI Reviewed-by: Elena Laskavaia --- .../parser/tests/ast2/AST2CPPSpecTest.java | 16 +++- .../core/parser/tests/ast2/AST2CSpecTest.java | 16 +++- .../cdt/core/dom/ast/IASTUnaryExpression.java | 17 +++- .../cdt/core/dom/ast/INodeFactory.java | 5 +- .../dom/ast/gnu/IGNUASTGotoStatement.java | 61 ++++++++++++ .../parser/AbstractGNUSourceCodeParser.java | 20 ++-- .../core/dom/parser/BacktrackException.java | 16 +++- .../core/dom/parser/c/CNodeFactory.java | 9 +- .../internal/core/dom/parser/c/CVisitor.java | 67 ++++++++++++- .../dom/parser/c/GNUCASTGotoStatement.java | 91 ++++++++++++++++++ .../core/dom/parser/c/GNUCSourceParser.java | 3 + .../core/dom/parser/cpp/CPPNodeFactory.java | 9 +- .../parser/cpp/GNUCPPASTGotoStatement.java | 94 +++++++++++++++++++ .../dom/parser/cpp/GNUCPPSourceParser.java | 3 + .../dom/parser/cpp/semantics/CPPVisitor.java | 64 ++++++++++++- .../lrparser/action/BuildASTParserAction.java | 6 +- 16 files changed, 472 insertions(+), 25 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/gnu/IGNUASTGotoStatement.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCASTGotoStatement.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPASTGotoStatement.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index 21bf614a867..e778847f82b 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2013 IBM Corporation and others. + * Copyright (c) 2005, 2014 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,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) * Nathan Ridge + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; @@ -1010,6 +1011,19 @@ public class AST2CPPSpecTest extends AST2SpecTestBase { parse(getAboveComment(), ParserLanguage.CPP, true, 1); } + // void f() + // { + // // ... + // void* labelPtr; + // labelPtr = &&foo; + // goto *labelPtr; + // foo: + // return; + // } + public void test6_bug84144() throws Exception { + parse(getAboveComment(), ParserLanguage.CPP, true, 0); + } + // int foo(int i) // { // static int s = foo(2*i); // recursive call - undefined diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java index 9ad87f0b996..d8312b55782 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2009 IBM Corporation and others. + * Copyright (c) 2005, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; @@ -1728,6 +1729,19 @@ public class AST2CSpecTest extends AST2SpecTestBase { parseCandCPP(buffer.toString(), false, 0); } + // void f() + // { + // // ... + // void* labelPtr; + // labelPtr = &&foo; + // goto *labelPtr; + // foo: + // return; + // } + public void test6_bug84144() throws Exception { + parseCandCPP(getAboveComment(), true, 0); + } + /** [--Start Example(C 6.8.6.4-4): struct s { double i; } f(void); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTUnaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTUnaryExpression.java index de04aa6ec1d..c01f6713ea8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTUnaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTUnaryExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2011 IBM Corporation and others. + * Copyright (c) 2004, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * John Camelon (IBM Rational Software) - Initial API and implementation + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; @@ -104,24 +105,30 @@ public interface IASTUnaryExpression extends IASTExpression { */ @Deprecated public static final int op_typeof = 14; - + + /** + * For GCC parsers, only. {@code op_labelReference} is used for &&label type + * expressions. + */ + public static final int op_labelReference = 15; + /** * For GCC parsers, only. {@code op_alignOf} is used for __alignOf( unaryExpression ) type * expressions. */ - public static final int op_alignOf = 15; + public static final int op_alignOf = 16; /** * For C++, only: 'sizeof... ( parameterPack )' * @since 5.2 */ - public static final int op_sizeofParameterPack = 16; + public static final int op_sizeofParameterPack = 17; /** * For C++, only: noexcept ( expression ) * @since 5.5 */ - public static final int op_noexcept = 17; + public static final int op_noexcept = 18; /** * {@code op_last} is made available for subclasses. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java index 69c2573a957..ad82acc1748 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) * Thoams Corbat (IFS) + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; @@ -120,7 +121,9 @@ public interface INodeFactory { public IGNUASTCompoundStatementExpression newGNUCompoundStatementExpression(IASTCompoundStatement compoundStatement); - public IASTGotoStatement newGotoStatement(IASTName name); + public IASTStatement newGotoStatement(IASTName name); + + public IASTStatement newGotoStatement(IASTExpression expression); public IASTIdExpression newIdExpression(IASTName name); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/gnu/IGNUASTGotoStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/gnu/IGNUASTGotoStatement.java new file mode 100644 index 00000000000..2b666e98ee6 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/gnu/IGNUASTGotoStatement.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * 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: + * Anders Dahlberg (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.dom.ast.gnu; + +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTNameOwner; +import org.eclipse.cdt.core.dom.ast.IASTStatement; + +/** + * Represents a GNU goto expression. + * + * + * foo: + * void *labelPtr = &&foo; + * goto *labelPtr; + * + * + * @since 8.4 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IGNUASTGotoStatement extends IASTStatement, IASTNameOwner { + public static final ASTNodeProperty LABEL_NAME = + new ASTNodeProperty("IASTGotoExpression.LABEL_NAME [IASTExpression]"); //$NON-NLS-1$ + + /** + * Returns the label-name expression. The expression resolves to a ILabel binding. + * + * @return IASTExpression + */ + public IASTExpression getLabelNameExpression(); + + /** + * Set the label-name expression. + * + * @param expression + * IASTExpression + */ + public void setLabelNameExpression(IASTExpression expression); + + /** + * @since 5.1 + */ + @Override + public IGNUASTGotoStatement copy(); + + /** + * @since 5.3 + */ + @Override + public IGNUASTGotoStatement copy(CopyStyle style); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 2750988e60a..d73353a4811 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -12,6 +12,7 @@ * Mike Kucera (IBM) - bug #206952 * Sergey Prigogin (Google) * Thomas Corbat (IFS) + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; @@ -23,6 +24,7 @@ import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration; import org.eclipse.cdt.core.dom.ast.IASTAttribute; +import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner; import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTBreakStatement; @@ -43,7 +45,6 @@ import org.eclipse.cdt.core.dom.ast.IASTDoStatement; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; -import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionList; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; @@ -51,7 +52,6 @@ import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; -import org.eclipse.cdt.core.dom.ast.IASTGotoStatement; import org.eclipse.cdt.core.dom.ast.IASTIfStatement; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; @@ -112,7 +112,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } } - protected static class Decl extends Exception { + protected static class Decl { public Decl() { } @@ -1991,10 +1991,18 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { protected IASTStatement parseGotoStatement() throws EndOfFileException, BacktrackException { int startOffset = consume().getOffset(); // t_goto - IASTName goto_label_name = identifier(); + IASTStatement goto_statement = null; + + if (LT(1) == IToken.tSTAR) + { + IASTExpression goto_label_name_expression = expression(); + goto_statement = nodeFactory.newGotoStatement(goto_label_name_expression); + } else { + IASTName goto_label_name = identifier(); + goto_statement = nodeFactory.newGotoStatement(goto_label_name); + } + int lastOffset = consume(IToken.tSEMI).getEndOffset(); - - IASTGotoStatement goto_statement = nodeFactory.newGotoStatement(goto_label_name); ((ASTNode) goto_statement).setOffsetAndLength(startOffset, lastOffset - startOffset); return goto_statement; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java index 0be886eca5d..f0f465a5c05 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2008 IBM Corporation and others. + * Copyright (c) 2004, 2014 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 @@ -8,6 +8,7 @@ * Contributors: * IBM - Initial API and implementation * Markus Schorn (Wind River Systems) + * Anders Dahlberg (Ericsson) - bug 84144, indexer optimization *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; @@ -18,6 +19,8 @@ import org.eclipse.cdt.core.dom.ast.IASTProblem; * @author jcamelon */ public class BacktrackException extends Exception { + private static final StackTraceElement[] EMPTY_STACK = new StackTraceElement[0]; + private IASTProblem problem; private IASTNode nodeBeforeProblem; // a node has been created in spite of the problem. private int offset, length; @@ -82,4 +85,15 @@ public class BacktrackException extends Exception { public int getOffset() { return offset; } + + @Override + public Throwable fillInStackTrace() { + // Do nothing, performance optimization + return this; + } + + @Override + public StackTraceElement[] getStackTrace() { + return EMPTY_STACK; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java index 22786b1e921..96fd8720d27 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java @@ -9,6 +9,7 @@ * Mike Kucera (IBM Corporation) - initial API and implementation * Markus Schorn (Wind River Systems) * Thomas Corbat (IFS) + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.c; @@ -40,7 +41,6 @@ import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; -import org.eclipse.cdt.core.dom.ast.IASTGotoStatement; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTIfStatement; import org.eclipse.cdt.core.dom.ast.IASTInitializer; @@ -298,10 +298,15 @@ public class CNodeFactory extends NodeFactory implements ICNodeFactory { } @Override - public IASTGotoStatement newGotoStatement(IASTName name) { + public IASTStatement newGotoStatement(IASTName name) { return new CASTGotoStatement(name); } + @Override + public IASTStatement newGotoStatement(IASTExpression expression) { + return new GNUCASTGotoStatement(expression); + } + @Override public IASTIdExpression newIdExpression(IASTName name) { return new CASTIdExpression(name); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java index 648c774806b..9521c60abbf 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2013 IBM Corporation and others. + * Copyright (c) 2005, 2014 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 @@ -13,6 +13,7 @@ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) * Sergey Prigogin (Google) * Marc-Andre Laperle (Ericsson) + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.c; @@ -57,6 +58,7 @@ import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; +import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; 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; @@ -104,6 +106,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPLabel; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory; @@ -455,7 +458,17 @@ public class CVisitor extends ASTQueries { IBinding binding = null; IASTNode parent = name.getParent(); - if (parent instanceof CASTIdExpression) { + // GNU Goto label reference + // + // void* labelPtr = &&foo; <-- label reference + // foo: + // + boolean labelReference = isLabelReference(parent); + + if (labelReference) { + IASTUnaryExpression expression = (IASTUnaryExpression) parent.getParent(); + binding = createLabelReferenceBinding(name, expression); + } else if (parent instanceof CASTIdExpression) { binding = resolveBinding(parent); } else if (parent instanceof ICASTTypedefNameSpecifier) { binding = resolveBinding(parent); @@ -596,6 +609,56 @@ public class CVisitor extends ASTQueries { return null; } + + private static boolean isLabelReference(IASTNode node) { + boolean labelReference = false; + IASTNode parent = node.getParent(); + + if (parent instanceof IASTUnaryExpression) { + int operator = ((IASTUnaryExpression) parent).getOperator(); + labelReference = operator == IASTUnaryExpression.op_labelReference; + } + + return labelReference; + } + + private static IBinding createLabelReferenceBinding(IASTName name, IASTUnaryExpression expression) { + IBinding binding = null; + + // Find function scope for r-value expression + // void* labelPtr = &&foo; + // foo: ^^^ + // return + IScope scope = getContainingScope(name); + IASTInternalScope s = (IASTInternalScope) scope; + IASTNode node = s.getPhysicalNode(); + + while (node != null && !(node instanceof IASTFunctionDefinition)) { + node = node.getParent(); + } + + if (node != null) { + IASTFunctionDefinition definition = (IASTFunctionDefinition) node; + CASTFunctionDeclarator declarator = (CASTFunctionDeclarator) definition.getDeclarator(); + scope = declarator.getFunctionScope(); + + if (scope != null) { + binding = scope.getBinding(name, false); + if (!(binding instanceof ILabel)) { + binding = new CPPLabel(name); + ASTInternal.addName(scope, name); + } + } + } + + if (binding == null) { + binding = new ProblemBinding(expression, IProblemBinding.SEMANTIC_BAD_SCOPE, + expression.getRawSignature().toCharArray()); + } + + return binding; + } + /** * if prefix == false, return an IBinding or null * if prefix == true, return an IBinding[] or null diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCASTGotoStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCASTGotoStatement.java new file mode 100644 index 00000000000..f3b90d94c7a --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCASTGotoStatement.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson. + * 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: + * Anders Dahlberg (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.c; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTGotoStatement; +import org.eclipse.cdt.internal.core.dom.parser.ASTAttributeOwner; + +/** + * GNU C goto statement. + * + * + * foo: + * void *labelPtr = &&foo; + * goto *labelPtr; // this is the statement + * + * @since 8.4 + */ +public class GNUCASTGotoStatement extends ASTAttributeOwner + implements IGNUASTGotoStatement { + private IASTExpression fExpression; + + public GNUCASTGotoStatement() { + } + + public GNUCASTGotoStatement(IASTExpression expression) { + setLabelNameExpression(expression); + } + + @Override + public GNUCASTGotoStatement copy() { + return copy(CopyStyle.withoutLocations); + } + + @Override + public GNUCASTGotoStatement copy(CopyStyle style) { + GNUCASTGotoStatement copy = new GNUCASTGotoStatement(); + copy.setLabelNameExpression(fExpression == null ? null : fExpression.copy(style)); + return copy(copy, style); + } + + @Override + public boolean accept(ASTVisitor action) { + if (action.shouldVisitExpressions) { + switch (action.visit(this)) { + case ASTVisitor.PROCESS_ABORT: return false; + case ASTVisitor.PROCESS_SKIP: return true; + default: break; + } + } + + if (fExpression != null && !fExpression.accept(action)) + return false; + + if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT) + return false; + + return true; + } + + @Override + public IASTExpression getLabelNameExpression() { + return fExpression; + } + + @Override + public void setLabelNameExpression(IASTExpression expression) { + assertNotFrozen(); + this.fExpression = expression; + + if (expression != null) { + expression.setParent(this); + expression.setPropertyInParent(LABEL_NAME); + } + } + + @Override + public int getRoleForName(IASTName n) { + return r_unclear; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index 94ec7c33a2f..33756577651 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -12,6 +12,7 @@ * Mike Kucera (IBM) - bug #206952 * Sergey Prigogin (Google) * Thomas Corbat (IFS) + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.c; @@ -594,6 +595,8 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { return unaryExpression(IASTUnaryExpression.op_star, ctx, strat); case IToken.tAMPER: return unaryExpression(IASTUnaryExpression.op_amper, ctx, strat); + case IToken.tAND: + return unaryExpression(IASTUnaryExpression.op_labelReference, ctx, strat); case IToken.tPLUS: return unaryExpression(IASTUnaryExpression.op_plus, ctx, strat); case IToken.tMINUS: diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java index 883a84030d0..a4146d99a73 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java @@ -9,6 +9,7 @@ * Mike Kucera (IBM) - initial API and implementation * Markus Schorn (Wind River Systems) * Thomas Corbat (IFS) + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -31,7 +32,6 @@ import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTGotoStatement; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; @@ -430,10 +430,15 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory { } @Override - public IASTGotoStatement newGotoStatement(IASTName name) { + public IASTStatement newGotoStatement(IASTName name) { return new CPPASTGotoStatement(name); } + @Override + public IASTStatement newGotoStatement(IASTExpression expression) { + return new GNUCPPASTGotoStatement(expression); + } + @Override public IASTIdExpression newIdExpression(IASTName name) { return new CPPASTIdExpression(name); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPASTGotoStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPASTGotoStatement.java new file mode 100644 index 00000000000..9fa287d601b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPASTGotoStatement.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson. + * 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: + * Anders Dahlberg (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTGotoStatement; +import org.eclipse.cdt.internal.core.dom.parser.ASTAttributeOwner; + +/** + * GNU C++ goto statement. + * + * + * foo: + * void *labelPtr = &&foo; + * goto *labelPtr; // this is the statement + * + * + * @since 8.4 + */ +public class GNUCPPASTGotoStatement extends ASTAttributeOwner implements IGNUASTGotoStatement { + private IASTExpression expression; + + public GNUCPPASTGotoStatement() { + } + + public GNUCPPASTGotoStatement(IASTExpression expression) { + setLabelNameExpression(expression); + } + + @Override + public GNUCPPASTGotoStatement copy() { + return copy(CopyStyle.withoutLocations); + } + + @Override + public GNUCPPASTGotoStatement copy(CopyStyle style) { + GNUCPPASTGotoStatement copy = new GNUCPPASTGotoStatement(expression == null ? null : expression.copy(style)); + return copy(copy, style); + } + + @Override + public boolean accept(ASTVisitor action) { + if (action.shouldVisitStatements) { + switch (action.visit(this)) { + case ASTVisitor.PROCESS_ABORT : return false; + case ASTVisitor.PROCESS_SKIP : return true; + default : break; + } + } + + if (!acceptByAttributeSpecifiers(action)) return false; + if (expression != null && !expression.accept(action)) return false; + + if (action.shouldVisitStatements) { + switch (action.leave(this)) { + case ASTVisitor.PROCESS_ABORT : return false; + case ASTVisitor.PROCESS_SKIP : return true; + default : break; + } + } + return true; + } + + @Override + public IASTExpression getLabelNameExpression() { + return expression; + } + + @Override + public void setLabelNameExpression(IASTExpression expression) { + assertNotFrozen(); + this.expression = expression; + + if (expression != null) { + expression.setParent(this); + expression.setPropertyInParent(LABEL_NAME); + } + } + + @Override + public int getRoleForName(IASTName n) { + return r_unclear; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index d8463f1dc07..00d36d76c40 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -14,6 +14,7 @@ * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) * Thomas Corbat (IFS) + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -1327,6 +1328,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return unaryExpression(IASTUnaryExpression.op_star, ctx, strat); case IToken.tAMPER: return unaryExpression(IASTUnaryExpression.op_amper, ctx, strat); + case IToken.tAND: + return unaryExpression(IASTUnaryExpression.op_labelReference, ctx, strat); case IToken.tPLUS: return unaryExpression(IASTUnaryExpression.op_plus, ctx, strat); case IToken.tMINUS: diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index c79dee6062a..2e32732f1e0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -13,6 +13,7 @@ * Thomas Corbat (IFS) * Nathan Ridge * Marc-Andre Laperle + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; @@ -178,6 +179,7 @@ import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionCallExpression; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDeclarator; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit; @@ -299,7 +301,18 @@ public class CPPVisitor extends ASTQueries { id.resolveBinding(); return name.getBinding(); } - if (parent instanceof IASTIdExpression) { + + // GNU Goto label reference + // + // void* labelPtr = &&foo; <-- label reference + // foo: + // + boolean labelReference = isLabelReference(parent); + + if (labelReference) { + IASTUnaryExpression expression = (IASTUnaryExpression) parent.getParent(); + return createLabelReferenceBinding(name, expression); + } else if (parent instanceof IASTIdExpression) { return resolveBinding(parent); } else if (parent instanceof ICPPASTFieldReference) { return resolveBinding(parent); @@ -376,6 +389,55 @@ public class CPPVisitor extends ASTQueries { return scope == inScope; } + private static boolean isLabelReference(IASTNode node) { + boolean labelReference = false; + IASTNode parent = node.getParent(); + + if (parent instanceof IASTUnaryExpression) { + int operator = ((IASTUnaryExpression) parent).getOperator(); + labelReference = operator == IASTUnaryExpression.op_labelReference; + } + + return labelReference; + } + + private static IBinding createLabelReferenceBinding(IASTName name, IASTUnaryExpression expression) { + IBinding binding = null; + + // Find function scope for r-value expression + // void* labelPtr = &&foo; + // foo: ^^^ + // return + IScope scope = getContainingScope(name); + IASTInternalScope s = (IASTInternalScope) scope; + IASTNode node = s.getPhysicalNode(); + + while (node != null && !(node instanceof IASTFunctionDefinition)) { + node = node.getParent(); + } + + if (node != null) { + IASTFunctionDefinition definition = (IASTFunctionDefinition) node; + CPPASTFunctionDeclarator declarator = (CPPASTFunctionDeclarator) definition.getDeclarator(); + scope = declarator.getFunctionScope(); + + if (scope != null) { + binding = scope.getBinding(name, false); + if (!(binding instanceof ILabel)) { + binding = new CPPLabel(name); + ASTInternal.addName(scope, name); + } + } + } + + if (binding == null) { + binding = new CPPScope.CPPScopeProblem(expression, IProblemBinding.SEMANTIC_BAD_SCOPE, + expression.getRawSignature().toCharArray()); + } + + return binding; + } + private static IBinding createBinding(IASTGotoStatement gotoStatement) { IASTName name = gotoStatement.getName(); ICPPFunctionScope functionScope = (ICPPFunctionScope) getContainingScope(name); diff --git a/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/BuildASTParserAction.java b/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/BuildASTParserAction.java index 0ff7eb74b49..422dfd265fe 100644 --- a/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/BuildASTParserAction.java +++ b/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/BuildASTParserAction.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 IBM Corporation and others. + * Copyright (c) 2006, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.core.dom.lrparser.action; @@ -44,7 +45,6 @@ import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTGotoStatement; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; @@ -598,7 +598,7 @@ public abstract class BuildASTParserAction extends AbstractParserAction { */ public void consumeStatementGoto() { IASTName name = createName(stream.getRuleTokens().get(1)); - IASTGotoStatement gotoStat = nodeFactory.newGotoStatement(name); + IASTStatement gotoStat = nodeFactory.newGotoStatement(name); setOffsetAndLength(gotoStat); astStack.push(gotoStat); }