From 470561caec48886d353a567e1dcbbe6ae1d1dde1 Mon Sep 17 00:00:00 2001 From: Thomas Corbat Date: Thu, 11 Aug 2016 14:11:33 +0200 Subject: [PATCH] Bug Bug 482225 - decltype(auto) not parsed * Adapted the parser to cope with decltype(auto) * Extended IASTSimpleDeclSpecifier to have a kind for decltype(auto) * Added tests (syntactic recognition and type deduction for variables) * Modified DeclSpecWriter to cope with the decltype(auto) kind simple decl specifier Change-Id: Ib1ded823027d124cef35e9d6355c0f48f57709a0 Signed-off-by: Thomas Corbat --- .../core/parser/tests/ast2/AST2CPPTests.java | 70 +++++++++++ .../rewrite/ASTWriterDeclSpecTestSource.awts | 7 ++ .../core/dom/ast/IASTSimpleDeclSpecifier.java | 9 +- .../cdt/core/dom/ast/ISemanticProblem.java | 2 + .../dom/parser/cpp/GNUCPPSourceParser.java | 9 +- .../dom/parser/cpp/semantics/CPPVisitor.java | 111 +++++++++++++----- .../dom/rewrite/astwriter/DeclSpecWriter.java | 7 +- 7 files changed, 179 insertions(+), 36 deletions(-) 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 6bdfb3a48c5..e49cd7ed0e2 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 @@ -11956,4 +11956,74 @@ public class AST2CPPTests extends AST2TestBase { public void testEnumDeclaredLaterInClass_491747() throws Exception { parseAndCheckBindings(); } + + // namespace std { + // template class initializer_list; + // } + // struct A {}; + // A&& foo(); + // A a; + // decltype(auto) b = a; // decltype(b) is A + // decltype(auto) c(a); // decltype(c) is A + // decltype(auto) d = (a); // decltype(d) is A & + // decltype(auto) e = foo(); // decltype(e) is A && + // static decltype(auto) f = 0.0; // decltype(f) is double + // decltype(auto) g = &a, h = &b; // decltype(g) and decltype(h) are A * + // decltype(auto) i = { 'a', 'b' }; // Error - cannot deduce decltype(auto) from initializer list. + // decltype(auto) j{42}; // Valid since C++17: decltype(j) is int + // decltype(auto) k = new decltype(auto)(1L); // decltype(j) is long int * + // decltype(auto) l; // Error - missing initializer. + public void testDecltypeAutoVariableTypes_482225() throws Exception { + String code = getAboveComment(); + BindingAssertionHelper bh = new BindingAssertionHelper(code, true); + + ICPPVariable b = bh.assertNonProblem("b =", 1); + assertEquals("A", ASTTypeUtil.getType(b.getType())); + + ICPPVariable c = bh.assertNonProblem("c(a)", 1); + assertEquals("A", ASTTypeUtil.getType(c.getType())); + + ICPPVariable d = bh.assertNonProblem("d =", 1); + assertEquals("A &", ASTTypeUtil.getType(d.getType())); + + ICPPVariable e = bh.assertNonProblem("e =", 1); + assertEquals("A &&", ASTTypeUtil.getType(e.getType())); + + ICPPVariable f = bh.assertNonProblem("f =", 1); + assertEquals("double", ASTTypeUtil.getType(f.getType())); + + ICPPVariable g = bh.assertNonProblem("g =", 1); + assertEquals("A *", ASTTypeUtil.getType(g.getType())); + + ICPPVariable h = bh.assertNonProblem("h =", 1); + assertEquals("A *", ASTTypeUtil.getType(h.getType())); + + ICPPVariable i = bh.assertNonProblem("i =", 1); + IProblemType iType = (IProblemType) i.getType(); + assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE, iType.getID()); + + ICPPVariable j = bh.assertNonProblem("j{42}", 1); + assertEquals("int", ASTTypeUtil.getType(j.getType())); + + ICPPVariable k = bh.assertNonProblem("k =", 1); + assertEquals("long int *", ASTTypeUtil.getType(k.getType())); + + ICPPVariable l = bh.assertNonProblem("l;", 1); + IProblemType lType = (IProblemType) l.getType(); + assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE, lType.getID()); + } + + // auto foo() -> decltype(auto) { + // return 23.0; + // } + public void testDecltypeAutoTrailingReturnType_482225() throws Exception { + parseAndCheckBindings(); + } + + // decltype(auto) foo() { + // return 23.0; + // } + public void testDecltypeAutoReturnType_482225() throws Exception { + parseAndCheckBindings(); + } } diff --git a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclSpecTestSource.awts b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclSpecTestSource.awts index bb20b9eae41..3fddd1d2332 100644 --- a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclSpecTestSource.awts +++ b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclSpecTestSource.awts @@ -189,3 +189,10 @@ class Base class TestClass final : public Base { }; +//!decltype(auto) +//%CPP +decltype(auto) function() +{ + decltype(auto) a = new decltype(auto)(5); + return a; +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTSimpleDeclSpecifier.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTSimpleDeclSpecifier.java index de288a83df0..5eb2bd1ca4b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTSimpleDeclSpecifier.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTSimpleDeclSpecifier.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2015 IBM Corporation and others. + * Copyright (c) 2004, 2016 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 @@ -9,6 +9,7 @@ * Doug Schaefer (IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) + * Thomas Corbat (IFS) *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; @@ -130,6 +131,12 @@ public interface IASTSimpleDeclSpecifier extends IASTDeclSpecifier { */ public static final int t_decimal128 = 17; + /** + * decltype(auto) c = expression; + * @since 6.1 + */ + public static final int t_decltype_auto = 18; + /** * @since 5.1 */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java index db4d8ff5b91..ed1cbe84578 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java @@ -43,6 +43,8 @@ public interface ISemanticProblem { int TYPE_NOT_PERSISTED = 10005; /** @since 5.6 */ int TYPE_ENUMERATION_EXPECTED = 10006; + /** @since 6.1 */ + int TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = 10007; /** * Returns the ID of the problem. 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 7e80f489d06..6f313c16559 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 @@ -3365,10 +3365,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } // Otherwise we have a simple-decl-specifier. - simpleType= IASTSimpleDeclSpecifier.t_decltype; consume(IToken.t_decltype); consume(IToken.tLPAREN); - typeofExpression= expression(); + if (LT(1) == IToken.t_auto) { + simpleType= IASTSimpleDeclSpecifier.t_decltype_auto; + consume(IToken.t_auto); + } else { + simpleType= IASTSimpleDeclSpecifier.t_decltype; + typeofExpression= expression(); + } endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset(); encounteredTypename= true; 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 8d18fd3cf01..60241a7b9e3 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 @@ -2028,9 +2028,14 @@ public class CPPVisitor extends ASTQueries { throw new IllegalArgumentException(); } - if (declSpec instanceof ICPPASTSimpleDeclSpecifier && - ((ICPPASTSimpleDeclSpecifier) declSpec).getType() == IASTSimpleDeclSpecifier.t_auto) { - return createAutoType(declSpec, declarator); + if (declSpec instanceof ICPPASTSimpleDeclSpecifier) { + ICPPASTSimpleDeclSpecifier simpleDeclSpecifier = (ICPPASTSimpleDeclSpecifier) declSpec; + int declSpecifierType = simpleDeclSpecifier.getType(); + if (declSpecifierType == IASTSimpleDeclSpecifier.t_auto) { + return createAutoType(declSpec, declarator); + } else if (declSpecifierType == IASTSimpleDeclSpecifier.t_decltype_auto) { + return createDecltypeAutoType(declarator, simpleDeclSpecifier); + } } IType type = createType(declSpec); @@ -2058,6 +2063,41 @@ public class CPPVisitor extends ASTQueries { return type; } + private static IType createDecltypeAutoType(IASTDeclarator declarator, ICPPASTSimpleDeclSpecifier simpleDeclSpecifier) { + IASTInitializerClause initializerClause = getInitializerClauseForDecltypeAuto(declarator); + if (initializerClause instanceof IASTExpression) { + return getDeclType((IASTExpression) initializerClause); + } + return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE); + } + + private static IASTInitializerClause getInitializerClauseForDecltypeAuto(IASTDeclarator declarator) { + IASTInitializer initializer = declarator.getInitializer(); + if (initializer == null) { + ICPPASTNewExpression newExpression = CPPVisitor.findAncestorWithType(declarator, ICPPASTNewExpression.class); + if (newExpression != null) { + initializer = newExpression.getInitializer(); + } + } + if (initializer instanceof IASTEqualsInitializer) { + return ((IASTEqualsInitializer) initializer).getInitializerClause(); + } else if (initializer instanceof ICPPASTConstructorInitializer) { + ICPPASTConstructorInitializer constructorInitializer = (ICPPASTConstructorInitializer) initializer; + IASTInitializerClause[] arguments = constructorInitializer.getArguments(); + if (arguments.length == 1) { + return arguments[0]; + } + } else if (initializer instanceof IASTInitializerList) { + IASTInitializerList initializerList = (IASTInitializerList) initializer; + IASTInitializerClause[] clauses = initializerList.getClauses(); + if (clauses.length == 1) { + return clauses[0]; + } + } + + return null; + } + private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator) { Set recursionProtectionSet = autoTypeDeclSpecs.get(); if (!recursionProtectionSet.add(declSpec)) { @@ -2281,41 +2321,48 @@ public class CPPVisitor extends ASTQueries { */ private static IType getDeclType(ICPPASTSimpleDeclSpecifier spec) { IASTExpression expr = spec.getDeclTypeExpression(); - if (expr == null) + if (expr == null) { return null; + } + int specifierType = spec.getType(); + if (specifierType == IASTSimpleDeclSpecifier.t_decltype) { + return getDeclType(expr); + } + return expr.getExpressionType(); + } - if (spec.getType() == IASTSimpleDeclSpecifier.t_decltype) { - IASTName namedEntity= null; - if (expr instanceof IASTIdExpression) { - namedEntity= ((IASTIdExpression) expr).getName(); - } else if (expr instanceof IASTFieldReference) { - namedEntity= ((IASTFieldReference) expr).getFieldName(); + /** + * Computes the type for an expression in decltype(expr) context. + */ + private static IType getDeclType(IASTExpression expr) { + IASTName namedEntity= null; + if (expr instanceof IASTIdExpression) { + namedEntity= ((IASTIdExpression) expr).getName(); + } else if (expr instanceof IASTFieldReference) { + namedEntity= ((IASTFieldReference) expr).getFieldName(); + } + if (namedEntity != null) { + IBinding b= namedEntity.resolvePreBinding(); + if (b instanceof IType) { + return (IType) b; } - if (namedEntity != null) { - IBinding b= namedEntity.resolvePreBinding(); - if (b instanceof IType) { - return (IType) b; - } - if (b instanceof IVariable) { - return ((IVariable) b).getType(); - } - if (b instanceof IFunction) { - return ((IFunction) b).getType(); - } + if (b instanceof IVariable) { + return ((IVariable) b).getType(); + } + if (b instanceof IFunction) { + return ((IFunction) b).getType(); } } IType type = expr.getExpressionType(); - if (spec.getType() == IASTSimpleDeclSpecifier.t_decltype) { - switch (expr.getValueCategory()) { - case XVALUE: - type= new CPPReferenceType(type, true); - break; - case LVALUE: - type= new CPPReferenceType(type, false); - break; - case PRVALUE: - break; - } + switch (expr.getValueCategory()) { + case XVALUE: + type= new CPPReferenceType(type, true); + break; + case LVALUE: + type= new CPPReferenceType(type, false); + break; + case PRVALUE: + break; } return type; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java index 1bca8212414..ba4e8aa09e4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2015 Institute for Software, HSR Hochschule fuer Technik + * Copyright (c) 2008, 2016 Institute for Software, HSR Hochschule fuer Technik * Rapperswil, University of applied sciences and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -123,6 +123,7 @@ public class DeclSpecWriter extends NodeWriter { return Keywords.TYPEOF; break; case IASTSimpleDeclSpecifier.t_decltype: + case IASTSimpleDeclSpecifier.t_decltype_auto: if (isCpp) return Keywords.DECLTYPE; break; @@ -382,6 +383,10 @@ public class DeclSpecWriter extends NodeWriter { scribe.print('('); visitNodeIfNotNull(simpDeclSpec.getDeclTypeExpression()); scribe.print(')'); + } else if (simpDeclSpec.getType() == IASTSimpleDeclSpecifier.t_decltype_auto) { + scribe.print('('); + scribe.print(Keywords.AUTO); + scribe.print(')'); } }