1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-25 18:05:33 +02:00

Bug 379684 Support for User Defined Literals

This patch adds preliminary support for C++11 user defined literals:
* Syntax support
* Type deduction in expressions
* Template literal operators
* String literal concatenation

Change-Id: I8a9760036a2c8428295f0e1ffb4b519a0a2577c9
Signed-off-by: Richard Eames <eclipse@naddiseo.ca>
This commit is contained in:
Richard Eames 2015-01-22 19:10:37 -07:00 committed by Sergey Prigogin
parent b49fa67882
commit 795c418f10
27 changed files with 1747 additions and 182 deletions

View file

@ -14,6 +14,7 @@
* Thomas Corbat (IFS)
* Nathan Ridge
* Marc-Andre Laperle
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
@ -53,12 +54,14 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
@ -134,6 +137,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
@ -256,6 +260,21 @@ public class AST2CPPTests extends AST2TestBase {
assertTrue("Expected types to be the same, but first was: '" + first.toString() + "' and second was: '" + second + "'", first.isSameType(second));
}
private void checkUserDefinedLiteralIsType(String code, String type_name) throws Exception {
IASTTranslationUnit tu = parseAndCheckBindings(code, CPP);
IASTDeclaration[] declarations = tu.getDeclarations();
IASTDeclaration declaration = declarations[declarations.length - 1];
IASTInitializer init = ((IASTSimpleDeclaration) declaration).getDeclarators()[0].getInitializer();
IType type = ((IASTExpression)((IASTEqualsInitializer) init).getInitializerClause()).getExpressionType();
assertEquals(type_name, type.toString());
}
private void checkUserDefinedLiteralIsRet(String code) throws Exception {
checkUserDefinedLiteralIsType(code, "Ret");
}
// int *zzz1 (char);
// int (*zzz2) (char);
// int ((*zzz3)) (char);
@ -11142,4 +11161,375 @@ public class AST2CPPTests extends AST2TestBase {
public void testAlignas_451082() throws Exception {
parseAndCheckBindings();
}
// int operator "" _A(unsigned long long i) { return 1; }
// int operator "" _B(long double d) { return 1; }
// int operator "" _C(const char* s, unsigned int sz) { return sz; }
// int operator "" _D(const wchar_t* s, unsigned int sz) { return sz; }
// int operator "" _E(const char16_t* s, unsigned int sz) { return sz; }
// int operator "" _F(const char32_t* s, unsigned int sz) { return sz; }
// int operator "" _G(char c) { return (int)c; }
// constexpr double operator "" _km_to_miles(long double km) { return km * 0.6213; }
public void testSimpleUserDefinedLiteralOperators() throws Exception {
parseAndCheckBindings();
}
// int integers[] = {
// 1,
// 1U,
// 1L,
// 1LL,
// 1ULL,
// 1suff,
// 1_suff,
// 0x3003,
// 0x3003U,
// 0x3003L,
// 0x3003LL,
// 0x3003ULL,
// 0x3003suff,
// 0x3003_suff,
// 0xabcdef,
// 0xABCDEF,
// 0Xabcdef,
// 0xABCDEF,
// 0xABCDEFU,
// 0xABCDEFL,
// 0xABCDEFULL,
// 0xABCDEFsuff,
// 0xABCDEF_suff,
// 01,
// 01U,
// 01L,
// 07LL,
// 04ULL,
// 01_suff,
// 1ULL << 34,
// };
public void testIntegerUserDefinedLiterals() throws Exception {
parseAndCheckBindings();
}
// double numbers[] = {
// 1f,
// 1.f,
// 1.X,
// 1.0x,
// 0x01p3,
// 0x01p3XX,
// 1._X
// };
public void testDoublesUserDefinedLiterals() throws Exception {
parseAndCheckBindings();
}
// char c1 = '0'_suff;
// char c2 = '0'suff;
// char* c3 = "Hello"_suff;
// char* c4 = "Hello"suff;
public void testCharStringUserDefinedLiterals() throws Exception {
parseAndCheckBindings();
}
// class Ret {};
// Ret operator "" _X(unsigned long long i) { return Ret(); }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes1() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(long double i) { return Ret(); }
// auto test = 12.3_X;
public void testUserDefinedLiteralOperatorTypes2() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s) { return Ret(); }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes1a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s) { return Ret(); }
// auto test = 12.3_X;
public void testUserDefinedLiteralOperatorTypes2a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(unsigned long long d) { return Ret(); }
// bool operator "" _X(const char* s) { return false; }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes1b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(long double d) { return Ret(); }
// bool operator "" _X(const char* s) { return false; }
// auto test = 12.3_X;
public void testUserDefinedLiteralOperatorTypes2b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X;
public void testUserDefinedLiteralOperatorTypes3() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = L"123"_X;
public void testUserDefinedLiteralOperatorTypes3a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = u"123"_X;
public void testUserDefinedLiteralOperatorTypes3b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = U"123"_X;
public void testUserDefinedLiteralOperatorTypes3c() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// template<char... Chars> Ret operator "" _X() { return Ret(); }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes4a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// template<char... Chars> Ret operator "" _X() { return Ret(); }
// auto test = 123.123_X;
public void testUserDefinedLiteralOperatorTypes4b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123" "123"_X;
public void testUserDefinedLiteralConcatenation1a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X "123";
public void testUserDefinedLiteralConcatenation1b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = u8"123" "123"_X;
public void testUserDefinedLiteralConcatenation2a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = u8"123"_X "123";
public void testUserDefinedLiteralConcatenation2b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123" u8"123"_X;
public void testUserDefinedLiteralConcatenation2c() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X u8"123";
public void testUserDefinedLiteralConcatenation2d() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = L"123" "123"_X;
public void testUserDefinedLiteralConcatenation3a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = L"123"_X "123";
public void testUserDefinedLiteralConcatenation3b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = "123" L"123"_X;
public void testUserDefinedLiteralConcatenation3c() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X L"123";
public void testUserDefinedLiteralConcatenation3d() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = u"123" "123"_X;
public void testUserDefinedLiteralConcatenation4a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = u"123"_X "123";
public void testUserDefinedLiteralConcatenation4b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = "123" u"123"_X;
public void testUserDefinedLiteralConcatenation4c() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X u"123";
public void testUserDefinedLiteralConcatenation4d() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = U"123" "123"_X;
public void testUserDefinedLiteralConcatenation5a() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = U"123"_X "123";
public void testUserDefinedLiteralConcatenation5b() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = "123" U"123"_X;
public void testUserDefinedLiteralConcatenation5c() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X U"123";
public void testUserDefinedLiteralConcatenation5d() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X U"123"_X;
public void testUserDefinedLiteralConcatenation6() throws Exception {
checkUserDefinedLiteralIsRet(getAboveComment());
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// Ret operator "" _Y(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X "123"_Y;
public void testUserDefinedLiteralBadConcatenation1() throws Exception {
IASTTranslationUnit tu = parse(getAboveComment(), CPP, true, false);
IASTProblem[] problems = tu.getPreprocessorProblems();
assertEquals(1, problems.length);
assertEquals(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION, problems[0].getID());
}
// // Test name lacking a space
// int operator ""_X(const char* s) { return 0; }
public void testUserDefinedLiteralNoWhiteSpace1() throws Exception {
IASTTranslationUnit tu = parse(getAboveComment(), CPP, true, false);
IASTDeclaration decl = tu.getDeclarations()[0];
assertTrue(decl instanceof IASTProblemDeclaration);
assertEquals(IProblem.SYNTAX_ERROR, ((IASTProblemDeclaration)decl).getProblem().getID());
}
// // Test literals with spaces before the suffix
// int operator "" _X(const char* s) { return 0; }
// auto a = 1 _X;
// auto b = 1.0 _X;
// auto c1 = '1' _X;
// auto c2 = L'1' _X;
// auto c3 = u8'1' _X;
// auto c4 = u'1' _X;
// auto c5 = U'1' _X;
// auto d1 = "1" _X;
// auto d2 = L"1" _X;
// auto d3 = u8"1" _X;
// auto d4 = u"1" _X;
// auto d5 = U"1" _X;
// auto e1 = "1" _X "2";
// auto e2 = L"1" _X "2";
// auto e3 = u8"1" _X "2";
// auto e4 = u"1" _X "2";
// auto e5 = U"1" _X "2";
// auto d5 = U"1" _X;
public void testUserDefinedLiteralNoWhiteSpace2() throws Exception {
IASTTranslationUnit tu = parse(getAboveComment(), CPP, true, false);
IASTDeclaration[] decls = tu.getDeclarations();
for (int i = 1; i < decls.length; i++) {
IASTDeclaration decl = decls[i];
assertTrue(decl instanceof IASTProblemDeclaration);
assertEquals(IProblem.SYNTAX_ERROR, ((IASTProblemDeclaration)decl).getProblem().getID());
}
}
// class RetA {};
// class RetB {};
// template<char... Chars> RetA operator "" _X() { return RetA(); }
// RetB operator "" _X(unsigned long long i) { return RetB(); }
// auto a = 123_X;
public void testUserDefinedLiteralResolution1() throws Exception {
checkUserDefinedLiteralIsType(getAboveComment(), "RetB");
}
// class RetA {};
// class RetB {};
// template<char... Chars> RetA operator "" _X() { return RetA(); }
// RetB operator "" _X(long double i) { return RetB(); }
// auto a = 123.123_X;
public void testUserDefinedLiteralResolution2() throws Exception {
checkUserDefinedLiteralIsType(getAboveComment(), "RetB");
}
// class RetA {};
// class RetB {};
// template<char... Chars> RetA operator "" _X() { return RetA(); }
// RetB operator "" _X(const char * c) { return RetB(); }
// auto test = 123_X;
public void testUserDefinedLiteralResolution3() throws Exception {
BindingAssertionHelper bh = getAssertionHelper();
ICPPVariable test = bh.assertNonProblemOnFirstIdentifier("test");
assertTrue(test.getType() instanceof IProblemType); // resolution is ambiguous
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2009 IBM Corporation and others.
* Copyright (c) 2004, 2015 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
@ -1796,9 +1796,9 @@ public class PortedScannerTests extends PreprocessorTestsBase {
assertEquals(17, problems.length);
int i= 0;
assertEquals(IProblem.SCANNER_BAD_OCTAL_FORMAT, problems[i].getID());
assertEquals(IProblem.SCANNER_BAD_DECIMAL_FORMAT, problems[++i].getID());
assertEquals(IProblem.SCANNER_BAD_HEX_FORMAT, problems[++i].getID());
assertEquals(IProblem.SCANNER_BAD_HEX_FORMAT, problems[++i].getID());
assertEquals(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, problems[++i].getID());
assertEquals(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, problems[++i].getID());
assertEquals(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, problems[++i].getID());
assertEquals(IProblem.SCANNER_DIVIDE_BY_ZERO, problems[++i].getID());
assertEquals(IProblem.SCANNER_MISSING_R_PAREN, problems[++i].getID());
assertEquals(IProblem.SCANNER_MISSING_R_PAREN, problems[++i].getID());

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others.
* Copyright (c) 2004, 2015 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)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.scanner;
@ -16,6 +17,7 @@ import java.util.List;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.ParserLanguage;
import junit.framework.TestSuite;
@ -217,11 +219,25 @@ public class PreprocessorTests extends PreprocessorTestsBase {
validateProblem(0, IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, "m0");
}
// #define tp(x,y) #x##y
// tp(a, );
// tp(a,_b);
public void testStringifyAndPasteCPP() throws Exception {
initializeScanner(getAboveComment(), ParserLanguage.CPP);
validateString("a");
validateToken(IToken.tSEMI);
validateUserDefinedLiteralString("a", "_b");
validateToken(IToken.tSEMI);
validateEOF();
validateProblemCount(0);
}
// #define tp(x,y) #x##y
// tp(a, );
// tp(a,b);
public void testStringifyAndPaste() throws Exception {
initializeScanner();
public void testStringifyAndPasteC() throws Exception {
initializeScanner(getAboveComment(), ParserLanguage.C);
validateString("a");
validateToken(IToken.tSEMI);
@ -1329,13 +1345,40 @@ public class PreprocessorTests extends PreprocessorTestsBase {
validateToken(IToken.tSEMI);
validateEOF();
validateProblemCount(0);
}
public void testBadBinaryNumbersC() throws Exception {
String badbinary = "{0b012, 0b01b, 0b1111e01, 0b1111p10, 0b10010.10010}";
initializeScanner(badbinary, ParserLanguage.C);
fullyTokenize();
validateProblemCount(5);
validateProblem(0, IProblem.SCANNER_BAD_BINARY_FORMAT, null);
validateProblem(1, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "b");
validateProblem(2, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
validateProblem(3, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "p10");
validateProblem(4, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
}
public void testBadBinaryNumbersCPP() throws Exception {
// First, third, and fifth are invalid in c++11.
String badbinary = "{0b012, 0b01b, 0b1111e01, 0b1111p10, 0b10010.10010}";
initializeScanner(badbinary);
fullyTokenize();
validateProblemCount(5);
for (int i = 0; i < 5; i++) {
validateProblem(i, IProblem.SCANNER_BAD_BINARY_FORMAT, null);
}
validateProblemCount(3);
validateProblem(0, IProblem.SCANNER_BAD_BINARY_FORMAT, null);
validateProblem(1, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
validateProblem(2, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
}
// #if 123ASDF
// #endif
// #if 0xU
// #endif
public void testUDLInPP() throws Exception {
initializeScanner();
validateEOF();
validateProblemCount(2);
validateProblem(0, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "ASDF");
validateProblem(1, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "xU");
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
* Copyright (c) 2007, 2015 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
@ -12,8 +12,6 @@ package org.eclipse.cdt.core.parser.tests.scanner;
import java.io.IOException;
import junit.framework.ComparisonFailure;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
@ -36,6 +34,8 @@ import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
import junit.framework.ComparisonFailure;
public abstract class PreprocessorTestsBase extends BaseTestCase {
private static final IParserLogService NULL_LOG = new NullLogService();
protected CPreprocessor fScanner;
@ -150,6 +150,10 @@ public abstract class PreprocessorTestsBase extends BaseTestCase {
validateToken(IToken.tUTF32STRING, "U\"" + expectedImage + "\"");
}
protected void validateUserDefinedLiteralString(String expectedImage, String expectedSuffix) throws Exception {
validateToken(IToken.tUSER_DEFINED_STRING_LITERAL, "\"" + expectedImage + "\"" + expectedSuffix);
}
protected void validateChar(String expectedImage) throws Exception {
validateToken(IToken.tCHAR, "'" + expectedImage + "'");
}

View file

@ -21,12 +21,14 @@ import java.util.Set;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
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.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IProblemType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
@ -45,6 +47,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.core.runtime.CoreException;
@ -175,7 +178,11 @@ public abstract class IndexCPPBindingResolutionTest extends IndexBindingResoluti
assertNotNull(numericalValue);
assertEquals(i, numericalValue.longValue());
}
private void assertUserDefinedLiteralType(String retName) {
ICPPVariable v= getBindingFromFirstIdentifier("test =");
assertEquals(retName, ASTTypeUtil.getType(v.getType()));
}
// namespace ns { class A; enum E {E1}; typedef int T; }
//
@ -1978,4 +1985,296 @@ public abstract class IndexCPPBindingResolutionTest extends IndexBindingResoluti
assertEquals(1, ors.length);
assertEquals(ors[0], m1);
}
// class Ret {};
// Ret operator "" _X(unsigned long long i) { return Ret(); }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes1() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(long double i) { return Ret(); }
// auto test = 12.3_X;
public void testUserDefinedLiteralOperatorTypes2() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s) { return Ret(); }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes1a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s) { return Ret(); }
// auto test = 12.3_X;
public void testUserDefinedLiteralOperatorTypes2a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(unsigned long long d) { return Ret(); }
// bool operator "" _X(const char* s) { return false; }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes1b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(long double d) { return Ret(); }
// bool operator "" _X(const char* s) { return false; }
// auto test = 12.3_X;
public void testUserDefinedLiteralOperatorTypes2b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X;
public void testUserDefinedLiteralOperatorTypes3() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = L"123"_X;
public void testUserDefinedLiteralOperatorTypes3a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = u"123"_X;
public void testUserDefinedLiteralOperatorTypes3b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = U"123"_X;
public void testUserDefinedLiteralOperatorTypes3c() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// template<char... Chars> Ret operator "" _X() { return Ret(); }
// auto test = 123_X;
public void testUserDefinedLiteralOperatorTypes4a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// template<char... Chars> Ret operator "" _X() { return Ret(); }
// auto test = 123.123_X;
public void testUserDefinedLiteralOperatorTypes4b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123" "123"_X;
public void testUserDefinedLiteralConcatenation1a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X "123";
public void testUserDefinedLiteralConcatenation1b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = u8"123" "123"_X;
public void testUserDefinedLiteralConcatenation2a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = u8"123"_X "123";
public void testUserDefinedLiteralConcatenation2b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123" u8"123"_X;
public void testUserDefinedLiteralConcatenation2c() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X u8"123";
public void testUserDefinedLiteralConcatenation2d() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = L"123" "123"_X;
public void testUserDefinedLiteralConcatenation3a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = L"123"_X "123";
public void testUserDefinedLiteralConcatenation3b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = "123" L"123"_X;
public void testUserDefinedLiteralConcatenation3c() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X L"123";
public void testUserDefinedLiteralConcatenation3d() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = u"123" "123"_X;
public void testUserDefinedLiteralConcatenation4a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = u"123"_X "123";
public void testUserDefinedLiteralConcatenation4b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = "123" u"123"_X;
public void testUserDefinedLiteralConcatenation4c() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X u"123";
public void testUserDefinedLiteralConcatenation4d() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = U"123" "123"_X;
public void testUserDefinedLiteralConcatenation5a() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = U"123"_X "123";
public void testUserDefinedLiteralConcatenation5b() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = "123" U"123"_X;
public void testUserDefinedLiteralConcatenation5c() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X U"123";
public void testUserDefinedLiteralConcatenation5d() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
// auto test = "123"_X U"123"_X;
public void testUserDefinedLiteralConcatenation6() throws Exception {
assertUserDefinedLiteralType("Ret");
}
// class Ret {};
// Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
// Ret operator "" _Y(const char* s, unsigned sz) { return Ret(); }
// auto test = "123"_X "123"_Y;
public void testUserDefinedLiteralBadConcat1() throws Exception {
IASTProblem[] problems = strategy.getAst(0).getPreprocessorProblems();
assertEquals(1, problems.length);
assertEquals(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION, problems[0].getID());
}
// class RetA {};
// class RetB {};
// template<char... Chars> RetA operator "" _X() { return RetA(); }
// RetB operator "" _X(unsigned long long i) { return RetB(); }
// auto test = 123_X;
public void testUserDefinedLiteralResolution1() throws Exception {
assertUserDefinedLiteralType("RetB");
}
// class RetA {};
// class RetB {};
// template<char... Chars> RetA operator "" _X() { return RetA(); }
// RetB operator "" _X(long double i) { return RetB(); }
// auto test = 123.123_X;
public void testUserDefinedLiteralResolution2() throws Exception {
assertUserDefinedLiteralType("RetB");
}
// class RetA {};
// class RetB {};
// template<char... Chars> RetA operator "" _X() { return RetA(); }
// RetB operator "" _X(const char * c) { return RetB(); }
// auto test = 123_X;
public void testUserDefinedLiteralResolution3() throws Exception {
ICPPVariable v= getBindingFromFirstIdentifier("test");
assertTrue(v.getType() instanceof IProblemType);
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
* Copyright (c) 2007, 2015 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
@ -8,6 +8,7 @@
* Contributors:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser;
@ -111,6 +112,15 @@ public abstract class AbstractScannerExtensionConfiguration implements IScannerE
return false;
}
/**
* {@inheritDoc}
* @since 5.11
*/
@Override
public boolean supportUserDefinedLiterals() {
return false;
}
@Override
public CharArrayIntMap getAdditionalPreprocessorKeywords() {
return fAddPreprocessorKeywords;

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation and others.
* Copyright (c) 2004, 2015 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 @@
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser;
@ -89,7 +90,15 @@ public abstract class GNUScannerExtensionConfiguration extends AbstractScannerEx
public char[] supportAdditionalNumericLiteralSuffixes() {
return "ij".toCharArray(); //$NON-NLS-1$
}
/**
* @since 5.10
*/
@Override
public boolean supportUserDefinedLiterals() {
return false;
}
/**
* @deprecated simply derive from this class and use {@link #addMacro(String, String)} to
* add additional macros.

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2009 IBM Corporation and others.
* Copyright (c) 2004, 2015 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
@ -115,4 +115,10 @@ public interface IScannerExtensionConfiguration {
* @since 5.5
*/
public boolean supportRawStringLiterals();
/**
* Support for User Defined Literals such as 123_suffix
* @since 5.11
*/
public boolean supportUserDefinedLiterals();
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
* Copyright (c) 2007, 2015 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
@ -8,6 +8,7 @@
* Contributors:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser.cpp;
@ -116,7 +117,19 @@ public abstract class AbstractCPPParserExtensionConfiguration implements ICPPPar
public boolean supportFunctionStyleAssembler() {
return false;
}
/**
* {@inheritDoc}
* @since 5.11
*/
@Override
public boolean supportUserDefinedLiterals() {
return true;
}
/*
* @see org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration#getBuiltinBindingsProvider()
*/
@Override
public IBuiltinBindingsProvider getBuiltinBindingsProvider() {
return new GCCBuiltinSymbolProvider(ParserLanguage.CPP, supportGCCOtherBuiltinSymbols());

View file

@ -11,6 +11,7 @@
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser.cpp;
@ -133,4 +134,13 @@ public class GPPScannerExtensionConfiguration extends GNUScannerExtensionConfigu
public boolean supportRawStringLiterals() {
return true;
}
/**
* User Defined Literals
* @since 5.10
*/
@Override
public boolean supportUserDefinedLiterals() {
return true;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2002, 2009 IBM Corporation and others.
* Copyright (c) 2002, 2015 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
@ -137,6 +137,13 @@ public interface ICPPParserExtensionConfiguration {
* @since 5.1
*/
public boolean supportFunctionStyleAssembler();
/**
* Support user-defined literal expressions:
* (char_expr | string_expr | int_expr | float_expr) ud-suffix
* @since 5.11
*/
public boolean supportUserDefinedLiterals();
/**
* Additional variants of context-sensitive keywords.

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
* Copyright (c) 2000, 2015 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 Corporation) - initial API and implementation
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.parser;
@ -221,7 +222,19 @@ public interface IProblem {
* @since 5.1
*/
public final static int SCANNER_BAD_BINARY_FORMAT = SCANNER_RELATED | 0x00F;
/**
* Invalid suffix on constant
* @since 5.11
*/
public final static int SCANNER_CONSTANT_WITH_BAD_SUFFIX = SCANNER_RELATED | 0x010;
/**
* Invalid prefix on float
* @since 5.11
*/
public final static int SCANNER_FLOAT_WITH_BAD_PREFIX = SCANNER_RELATED | 0x011;
// Preprocessor
/**
* #error encountered by Preprocessor.
@ -305,12 +318,12 @@ public interface IProblem {
* macro argument "..." encountered without the required ')' i.e. must be last argument if used
* Required attributes: none
*/
public final static int PREPROCESSOR_MISSING_RPAREN_PARMLIST = PREPROCESSOR_RELATED | 0x00C;
public final static int PREPROCESSOR_MISSING_RPAREN_PARMLIST = PREPROCESSOR_RELATED | 0x00C;
/**
* __VA_ARGS__ encountered in macro definition without the required '...' parameter
* Required attributes: none
*/
*/
public final static int PREPROCESSOR_INVALID_VA_ARGS = PREPROCESSOR_RELATED | 0x00D;
/**
@ -327,6 +340,12 @@ public interface IProblem {
public final static int PREPROCESSOR_EXCEEDS_MAXIMUM_INCLUSION_DEPTH= PREPROCESSOR_RELATED | 0x00F;
/**
* During concatenation of string literals, at least two were found with more than one type of UDL suffix.
* @since 5.11
*/
public final static int PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION = PREPROCESSOR_RELATED | 0x010;
/*
* Syntax error, detected by the parser.
*/
public final static int SYNTAX_ERROR = SYNTAX_RELATED | 0x001;

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2003, 2013 IBM Corporation and others.
* Copyright (c) 2003, 2015 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
@ -118,4 +118,11 @@ public interface IScanner {
*/
@Deprecated
public void setScanComments(boolean val);
/**
* Returns a list of additional (compiler specific) suffixes which can
* be placed on numbers. e.g. 'u' 'l' -> 1l or 1u.
* @noreference This method is not intended to be referenced by clients.
*/
public char[] getAdditionalNumericLiteralSuffixes();
}

View file

@ -188,11 +188,13 @@ public interface IToken {
int tLSTRING = 131;
/** @since 5.1 */ int tUTF16STRING = 5000;
/** @since 5.1 */ int tUTF32STRING = 5001;
/** @since 5.11 */ int tUSER_DEFINED_STRING_LITERAL = 51002;
int tCHAR = 132;
int tLCHAR = 133;
/** @since 5.1 */ int tUTF16CHAR = 5002;
/** @since 5.1 */ int tUTF32CHAR = 5003;
/** @since 5.11 */ int tUSER_DEFINED_CHAR_LITERAL = 51003;
/** @since 5.10 */ int t__Alignas = 51000;
/** @since 5.10 */ int t__Alignof = 51001;

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation and others.
* Copyright (c) 2004, 2015 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
@ -57,7 +57,7 @@ public class ASTProblem extends ASTNode implements IASTProblem {
errorMessages.put(new Integer(PREPROCESSOR_MISSING_RPAREN_PARMLIST),
ParserMessages.getString("ScannerProblemFactory.error.preproc.missingRParen")); //$NON-NLS-1$
errorMessages.put(new Integer(PREPROCESSOR_INVALID_VA_ARGS),
ParserMessages.getString("ScannerProblemFactory.error.preproc.invalidVaArgs")); //$NON-NLS-1$
ParserMessages.getString("ScannerProblemFactory.error.preproc.invalidVaArgs")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_INVALID_ESCAPECHAR),
ParserMessages.getString("ScannerProblemFactory.error.scanner.invalidEscapeChar")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_UNBOUNDED_STRING),
@ -88,6 +88,12 @@ public class ASTProblem extends ASTNode implements IASTProblem {
ParserMessages.getString("ScannerProblemFactory.error.scanner.unexpectedEOF")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_BAD_CHARACTER),
ParserMessages.getString("ScannerProblemFactory.error.scanner.badCharacter")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_CONSTANT_WITH_BAD_SUFFIX),
ParserMessages.getString("ScannerProblemFactory.error.scanner.constantWithBadSuffix")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_FLOAT_WITH_BAD_PREFIX),
ParserMessages.getString("ScannerProblemFactory.error.scanner.floatWithBadPrefix")); //$NON-NLS-1$
errorMessages.put(new Integer(PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION),
ParserMessages.getString("ScannerProblemFactory.error.preproc.multipleUserDefinedLiteralSuffixesOnStringLiteral")); //$NON-NLS-1$
errorMessages.put(new Integer(SYNTAX_ERROR),
ParserMessages.getString("ParserProblemFactory.error.syntax.syntaxError")); //$NON-NLS-1$
errorMessages.put(new Integer(MISSING_SEMICOLON),

View file

@ -9,6 +9,7 @@
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -16,16 +17,22 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName;
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.IScope;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator;
@ -45,6 +52,8 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
private int fKind;
private char[] fValue = CharArrayUtils.EMPTY;
private int fStringLiteralSize = -1; // Accounting for escape sequences and the null terminator.
private char[] fSuffix = CharArrayUtils.EMPTY;
private boolean fIsCompilerSuffix = true;
private ICPPEvaluation fEvaluation;
public CPPASTLiteralExpression() {
@ -54,6 +63,11 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
this.fKind = kind;
this.fValue = value;
}
public CPPASTLiteralExpression(int kind, char[] value, char[] suffix) {
this(kind, value);
this.setSuffix(suffix);
}
@Override
public CPPASTLiteralExpression copy() {
@ -62,8 +76,10 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
@Override
public CPPASTLiteralExpression copy(CopyStyle style) {
CPPASTLiteralExpression copy =
new CPPASTLiteralExpression(fKind, fValue == null ? null : fValue.clone());
CPPASTLiteralExpression copy = new CPPASTLiteralExpression(fKind,
fValue == null ? null : fValue.clone(),
fSuffix == null ? null : fSuffix.clone());
copy.setOffsetAndLength(this);
return copy(copy, style);
}
@ -89,7 +105,76 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
this.fValue= value;
}
@Override
public char[] getSuffix() {
return fSuffix;
}
public void setSuffix(char[] suffix) {
this.fSuffix = suffix;
}
public void calculateSuffix() {
this.calculateSuffix(CharArrayUtils.EMPTY);
}
/**
* Returns the suffix of a user-defined literal integer or float
* @param compilerSuffixes
*/
public void calculateSuffix(char[] compilerSuffixes) {
try {
switch (fKind) {
case lk_float_constant:
case lk_integer_constant:
int udOffset = (fValue[0] == '.' ? afterDecimalPoint(0) : integerLiteral());
if (udOffset > 0) {
/*
* 2.14.8.1
* "If a token matches both user-defined-literal and another literal kind, it is treated as the latter"
*/
setSuffix(CharArrayUtils.subarray(fValue, udOffset, -1));
for (int i = 0; i < fSuffix.length; i++) {
switch (fSuffix[i]) {
case 'l': case 'L':
case 'u': case 'U':
case 'f': case 'F':
continue;
}
for (int j = 0; j < compilerSuffixes.length; j++) {
if (fSuffix[i] == compilerSuffixes[j]) {
continue;
}
}
fIsCompilerSuffix = false;
// Remove the suffix from the value if it's a UDL
setValue(CharArrayUtils.subarray(fValue, 0, udOffset));
break;
}
}
break;
case lk_string_literal:
{
final int offset = CharArrayUtils.lastIndexOf('"', fValue, CharArrayUtils.indexOf('"', fValue) + 1);
if (offset > 0) {
setSuffix(CharArrayUtils.subarray(fValue, offset + 1, -1));
}
}
break;
case lk_char_constant:
{
final int offset = CharArrayUtils.lastIndexOf('\'', fValue, CharArrayUtils.indexOf('\'', fValue) + 1);
if (offset > 0) {
setSuffix(CharArrayUtils.subarray(fValue, offset + 1, -1));
}
}
break;
}
} catch (ArrayIndexOutOfBoundsException e) {
// pass
}
}
@Override
public String toString() {
return new String(fValue);
}
@ -186,9 +271,41 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
}
return Value.create(fStringLiteralSize);
}
private Kind getCharType() {
switch (getValue()[0]) {
private IType getStringType() {
if (fSuffix.length > 0) {
return getUserDefinedLiteralOperatorType();
}
IType type = new CPPBasicType(getBasicCharKind(), 0, this);
type = new CPPQualifierType(type, true, false);
return new CPPArrayType(type, getStringLiteralSize());
}
private IType getCharType() {
return fSuffix.length > 0 ? getUserDefinedLiteralOperatorType() : new CPPBasicType(getBasicCharKind(), 0, this);
}
// 13.5.8
private IType getUserDefinedLiteralOperatorType() {
IType ret = new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
try {
IBinding func = CPPSemantics.findUserDefinedLiteralOperator(this);
if (func != null && func instanceof ICPPFunction) {
ret = ((ICPPFunction) func).getType().getReturnType();
}
} catch (DOMException e) { /* ignore and return the problem type */ }
return ret;
}
public char[] getOperatorName() {
return CharArrayUtils.concat("operator \"\"".toCharArray(), fSuffix); //$NON-NLS-1$
}
public Kind getBasicCharKind() {
switch (fValue[0]) {
case 'L':
return Kind.eWChar;
case 'u':
@ -198,21 +315,25 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
default:
return Kind.eChar;
}
}
}
private IType classifyTypeOfFloatLiteral() {
final char[] lit= getValue();
final char[] lit= fSuffix;
final int len= lit.length;
Kind kind= Kind.eDouble;
int flags= 0;
if (len > 0) {
switch (lit[len - 1]) {
case 'f': case 'F':
kind= Kind.eFloat;
break;
case 'l': case 'L':
flags |= IBasicType.IS_LONG;
break;
if (fIsCompilerSuffix) {
switch (lit[len - 1]) {
case 'f': case 'F':
kind= Kind.eFloat;
break;
case 'l': case 'L':
flags |= IBasicType.IS_LONG;
break;
}
} else {
return getUserDefinedLiteralOperatorType();
}
}
return new CPPBasicType(kind, flags, this);
@ -221,36 +342,236 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
private IType classifyTypeOfIntLiteral() {
int makelong= 0;
boolean unsigned= false;
final char[] lit= getValue();
for (int i= lit.length - 1; i >= 0; i--) {
final char c= lit[i];
if (!(c > 'f' && c <= 'z') && !(c > 'F' && c <= 'Z')) {
break;
}
switch (c) {
case 'u':
case 'U':
unsigned = true;
break;
case 'l':
case 'L':
makelong++;
break;
}
}
final char[] lit= fSuffix;
int flags= 0;
if (unsigned) {
flags |= IBasicType.IS_UNSIGNED;
if (fIsCompilerSuffix) {
for (int i= lit.length - 1; i >= 0; i--) {
final char c= lit[i];
if (!(c > 'f' && c <= 'z') && !(c > 'F' && c <= 'Z')) {
break;
}
switch (c) {
case 'u':
case 'U':
unsigned = true;
break;
case 'l':
case 'L':
makelong++;
break;
}
}
if (unsigned) {
flags |= IBasicType.IS_UNSIGNED;
}
if (makelong > 1) {
flags |= IBasicType.IS_LONG_LONG;
} else if (makelong == 1) {
flags |= IBasicType.IS_LONG;
}
} else if (lit.length > 0) {
return getUserDefinedLiteralOperatorType();
}
return new CPPBasicType(Kind.eInt, flags, this);
}
private int integerLiteral() {
int i = 0;
char c = fValue[i++];
if (c == '0' && i < fValue.length) {
// Probably octal/hex/binary
c = fValue[i];
switch ((c | 0x20)) {
case 'x':
return probablyHex(i);
case 'b':
return probablyBinary(i);
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
/* octal-literal:
* 0
* octal-literal octal-digit
*/
while (isOctal(c) && i < fValue.length) {
c = fValue[++i];
}
break;
case '.':
return afterDecimalPoint(i);
}
/*
* If there is an 8 or 9, then we have a malformed octal
*/
if (c == '8' || c == '9') {
// eat remaining numbers
c = fValue[i];
while (Character.isDigit(c) && i < fValue.length) {
c = fValue[++i];
}
return i;
}
} else if (Character.isDigit(c)) {
/* decimal-literal :
* nonzero-digit (c has to be this to get into this else)
* decimal-literal digit
*/
c = fValue[i];
while (Character.isDigit(c) && i < fValue.length) {
c = fValue[++i];
}
if (c == '.') {
return afterDecimalPoint(i);
} else if ((c | 0x20) == 'e') {
return exponentPart(i);
}
} else {
// Somehow we got called and there wasn't a digit
// Shouldn't get here
assert false;
}
if (makelong > 1) {
flags |= IBasicType.IS_LONG_LONG;
} else if (makelong == 1) {
flags |= IBasicType.IS_LONG;
}
return new CPPBasicType(Kind.eInt, flags, this);
return i;
}
/*
* Called with the expectation that fValue[i] == '.'
*/
private int afterDecimalPoint(int i) {
char c = fValue[++i];
while (Character.isDigit(c) && i < fValue.length) {
c = fValue[++i];
}
if ((c | 0x20) == 'e') {
return exponentPart(i);
}
return i;
}
/*
* Called with the expectation that c == 'e'
*/
private int exponentPart(int i) {
char c = fValue[++i];
// optional '+' or '-'
if (c == '+' || c == '-') {
c = fValue[++i];
}
while (Character.isDigit(c) && i < fValue.length) {
c = fValue[++i];
}
// If there were no digits following the 'e' then we have
// D.De or .De which is a UDL on a double
return i--;
}
// GCC's binary constant notation
private int probablyBinary(int i) {
char c = fValue[++i];
if (c == '1' || c == '0') {
while (c == '1' || c == '0' && i < fValue.length) {
c = fValue[i++];
}
if (Character.isDigit(c)) {
// UDL can't begin with digit, so this is a malformed binary
return -1;
} else if (c == '.') {
// no such thing as binary floating point
c = fValue[++i];
while (Character.isDigit(c) && i < fValue.length) {
c = fValue[i++];
}
}
} else {
// Here we have 0b or 0B
return i - 1;
}
return i;
}
private int probablyHex(int i) {
/* hexadecimal-literal
* 0x hexadecimal-digit
* 0X hexadecimal-digit
* hexadecimal-literal hexadecimal-digit
*/
char c = fValue[++i];
if (isHexDigit(c)) {
while (isHexDigit(c) && i < fValue.length) {
c = fValue[++i];
}
if (c == '.') {
// Could be GCC's hex float
return hexFloatAfterDecimal(i);
} else if ((c | 0x20) == 'p') {
return hexFloatExponent(i);
}
} else {
return i - 1;
}
return i;
}
// Assumes fValue[i] == '.'
private int hexFloatAfterDecimal(int i) {
// 0xHHH.
char c = fValue[++i];
if (isHexDigit(c)) {
while (isHexDigit(c) && i < fValue.length) {
c = fValue[++i];
}
if ((c | 0x20) == 'p') {
return hexFloatExponent(i);
} else {
// The parser is very confused at this point
// as the expression is 0x1.f
return -1;
}
}
// Probably shouldn't be able to get here
// we have 0xHHH.
return -1;
}
// Assumes image[i] == 'p'
private int hexFloatExponent(int i) {
// 0xHH.HH[pP][-+]?DDDD
char c = fValue[++i];
if (c == '-' || c == '+') {
c = fValue[++i];
}
if (Character.isDigit(c)) {
while (Character.isDigit(c) && i < fValue.length) {
c = fValue[++i];
}
} else {
return i - 1;
}
return i;
}
private boolean isHexDigit(char c) {
c |= 0x20;
return ((c <= 'f' && c >= 'a') || (c <= '9' && c >= '0'));
}
private boolean isOctal(final char c) {
return c >= '0' && c <= '7';
}
/**
@ -292,15 +613,13 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
case lk_false:
return EVAL_FALSE;
case lk_char_constant:
return new EvalFixed(new CPPBasicType(getCharType(), 0, this), PRVALUE, createCharValue());
case lk_float_constant:
return new EvalFixed(getCharType(), PRVALUE, createCharValue());
case lk_float_constant:
return new EvalFixed(classifyTypeOfFloatLiteral(), PRVALUE, Value.UNKNOWN);
case lk_integer_constant:
case lk_integer_constant:
return new EvalFixed(classifyTypeOfIntLiteral(), PRVALUE, createIntValue());
case lk_string_literal:
IType type = new CPPBasicType(getCharType(), 0, this);
type = new CPPQualifierType(type, true, false);
return new EvalFixed(new CPPArrayType(type, getStringLiteralSize()), LVALUE, Value.UNKNOWN);
return new EvalFixed(getStringType(), LVALUE, Value.UNKNOWN);
case lk_nullptr:
return EVAL_NULL_PTR;
}

View file

@ -108,7 +108,7 @@ public class CPPASTSimpleDeclSpecifier extends CPPASTBaseDeclSpecifier
case eVoid:
return t_void;
case eNullPtr:
// Null pointer type cannot be expressed wit ha simple decl specifier.
// Null pointer type cannot be expressed with a simple decl specifier.
break;
}
return t_unspecified;

View file

@ -44,6 +44,7 @@ public class CPPBasicType implements ICPPBasicType, ISerializableType {
public static final CPPBasicType UNSIGNED_LONG = new CPPBasicType(Kind.eInt, IBasicType.IS_LONG | IBasicType.IS_UNSIGNED);
public static final CPPBasicType UNSIGNED_LONG_LONG = new CPPBasicType(Kind.eInt, IBasicType.IS_LONG_LONG | IBasicType.IS_UNSIGNED);
public static final CPPBasicType UNSIGNED_INT128 = new CPPBasicType(Kind.eInt128, IBasicType.IS_UNSIGNED);
public static final CPPBasicType CHAR = new CPPBasicType(Kind.eChar, 0);
private static final int FROM_STRING_LITERAL = 1 << 31;

View file

@ -16,6 +16,7 @@
* Thomas Corbat (IFS)
* Anders Dahlberg (Ericsson) - bug 84144
* Nathan Ridge
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -195,12 +196,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
private final boolean allowCPPRestrict;
private final boolean supportExtendedTemplateSyntax;
private final boolean supportAutoTypeSpecifier;
private final boolean supportUserDefinedLiterals;
private final IIndex index;
protected ICPPASTTranslationUnit translationUnit;
private int functionBodyCount;
private char[] currentClassName;
private char[] additionalNumericalSuffixes;
private final ICPPNodeFactory nodeFactory;
private TemplateIdStrategy fTemplateParameterListStrategy;
@ -229,10 +232,12 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
supportFunctionStyleAsm= config.supportFunctionStyleAssembler();
functionCallCanBeLValue= true;
supportAutoTypeSpecifier= true;
supportUserDefinedLiterals= config.supportUserDefinedLiterals();
this.index= index;
this.nodeFactory = CPPNodeFactory.getDefault();
scanner.setSplitShiftROperator(true);
fContextSensitiveTokens = createContextSensitiveTokenMap(config);
additionalNumericalSuffixes = scanner.getAdditionalNumericLiteralSuffixes();
}
private Map<String, ContextSensitiveTokenType> createContextSensitiveTokenMap(
@ -843,6 +848,29 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
endOffset= consume(IToken.tGT_in_SHIFTR).getEndOffset();
op= OverloadableOperator.SHIFTR;
break;
case IToken.tSTRING: // User defined literal T operator "" SUFFIX
IToken strOp = consume();
// Should be an empty string
if (strOp.getLength() == 2) {
endOffset = strOp.getEndOffset();
IToken ident = consume(IToken.tIDENTIFIER);
// Make sure there is at least one white space
if (ident.getOffset() <= endOffset) {
break;
}
char[] operatorName = CharArrayUtils.concat(firstToken.getCharImage(), " ".toCharArray()); //$NON-NLS-1$
operatorName = CharArrayUtils.concat(operatorName, strOp.getCharImage());
operatorName = CharArrayUtils.concat(operatorName, ident.getCharImage());
IASTName name = nodeFactory.newOperatorName(operatorName);
setRange(name, firstToken.getOffset(), ident.getEndOffset());
return name;
}
break;
default:
op= OverloadableOperator.valueOf(LA(1));
if (op != null) {
@ -1790,29 +1818,45 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IToken t = null;
IASTLiteralExpression literalExpr = null;
IASTLiteralExpression literalExprWithRange = null;
switch (LT(1)) {
case IToken.tINTEGER:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
((CPPASTLiteralExpression) literalExpr).calculateSuffix(additionalNumericalSuffixes);
break;
case IToken.tFLOATINGPT:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
((CPPASTLiteralExpression) literalExpr).calculateSuffix(additionalNumericalSuffixes);
break;
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
return stringLiteral();
case IToken.tUSER_DEFINED_STRING_LITERAL:
literalExprWithRange = stringLiteral();
if (supportUserDefinedLiterals) {
((CPPASTLiteralExpression) literalExprWithRange).calculateSuffix();
}
break;
case IToken.tCHAR:
case IToken.tLCHAR:
case IToken.tUTF16CHAR:
case IToken.tUTF32CHAR:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_char_constant, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
case IToken.t_false:
case IToken.tUSER_DEFINED_CHAR_LITERAL:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(
IASTLiteralExpression.lk_char_constant, t.getImage());
literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
if (supportUserDefinedLiterals) {
((CPPASTLiteralExpression) literalExprWithRange).calculateSuffix();
}
break;
case IToken.t_false:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_false, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
@ -1869,6 +1913,22 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
throwBacktrack(startingOffset, la.getLength());
return null;
}
if (supportUserDefinedLiterals) {
IToken la = LA(1);
int offset = ((ASTNode) literalExprWithRange).getOffset();
int length = ((ASTNode) literalExprWithRange).getLength();
if (la.getType() == IToken.tIDENTIFIER) {
if ((offset + length) != la.getOffset()) {
return literalExprWithRange;
}
IToken opName = consume(IToken.tIDENTIFIER);
((CPPASTLiteralExpression) literalExprWithRange).setSuffix(opName.getCharImage());
setRange(literalExprWithRange, offset, opName.getEndOffset());
}
}
return literalExprWithRange;
}
private ICPPASTLiteralExpression stringLiteral() throws EndOfFileException, BacktrackException {
@ -1877,6 +1937,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
case IToken.tUSER_DEFINED_STRING_LITERAL:
break;
default:
throwBacktrack(LA(1));

View file

@ -14,10 +14,12 @@
* Mike Kucera (IBM)
* Thomas Corbat (IFS)
* Nathan Ridge
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ARRAY;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
@ -83,6 +85,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
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;
@ -151,6 +154,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
@ -195,6 +199,7 @@ import org.eclipse.cdt.internal.core.dom.parser.IRecursionResolvingBinding;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit;
@ -206,8 +211,10 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownConstructor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMemberClass;
@ -3050,6 +3057,156 @@ public class CPPSemantics {
return function;
}
/**
* Given a LiteralExpression with a user-defined literal suffix,
* finds the corresponding defined operator.
* Tries to implement 2.14.8.(2-10)
* @param exp <code>IASTLiteralExpression</code> which has a user-defined literal suffix
* @return CPPFunction or null
* @throws DOMException
*/
public static IBinding findUserDefinedLiteralOperator(IASTLiteralExpression exp) throws DOMException {
IBinding ret = null;
/*
* 2.14.8.2
* Let `IASTLiteralExpression exp` = L
* Let `exp.getSuffix()` = X
* Let `bindings` = S
* A user-defined-literal is treated as a call to a literal operator or
* literal operator template (13.5.8). To determine the form of this
* call for a given user-defined-literal L with ud-suffix X, the
* literal-operator-id whose literal suffix identifier is X is looked up
* in the context of L using the rules for unqualified name lookup (3.4.1).
* Let S be the set of declarations found by this lookup.
* S shall not be empty.
*
*/
int kind = exp.getKind();
IBinding[] bindings = findBindings(exp.getTranslationUnit().getScope(), ((CPPASTLiteralExpression) exp).getOperatorName(), false);
ICPPFunction[] funcs = new ICPPFunction[bindings.length];
ICPPFunctionTemplate[] tplFunctions = new ICPPFunctionTemplate[bindings.length];
LookupData data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp);
int i = 0, j = 0;
for (IBinding binding : bindings) {
if (binding instanceof ICPPFunction || binding instanceof ICPPFunctionTemplate) {
funcs[i++] = (ICPPFunction) binding;
if (binding instanceof ICPPFunctionTemplate) {
tplFunctions[j++] = (ICPPFunctionTemplate) binding;
}
}
}
funcs = ArrayUtil.trim(funcs, i);
tplFunctions = ArrayUtil.trim(tplFunctions, j);
if (funcs.length == 0) {
// S shall not be empty
return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_INVALID_TYPE);
}
if (kind == IASTLiteralExpression.lk_integer_constant || kind == IASTLiteralExpression.lk_float_constant) {
if (kind == IASTLiteralExpression.lk_integer_constant) {
/*
* 2.14.8.3
* Let `exp.getValue()` = n
* If L is a user-defined-integer-literal, let n be the literal
* without its ud-suffix. If S contains a literal operator with
* parameter type unsigned long long, then use operator "" X(n ULL)
*/
CPPBasicType t = new CPPBasicType(Kind.eInt, IBasicType.IS_UNSIGNED | IBasicType.IS_LONG_LONG, exp);
data.setFunctionArguments(false, createArgForType(exp, t));
ret = resolveFunction(data, funcs, true);
if (ret != null && !(ret instanceof ProblemBinding)) {
return ret;
}
} else if (kind == IASTLiteralExpression.lk_float_constant) {
/*
* 2.14.8.4
* Let `exp.getValue()` = f
* If L is a user-defined-floating-literal, let f be the literal
* without its ud-suffix. If S contains a literal operator with
* parameter type long double, then use operator "" X(f L)
*/
CPPBasicType t = new CPPBasicType(Kind.eDouble, IBasicType.IS_LONG, exp);
data.setFunctionArguments(false, createArgForType(exp, t));
ret = resolveFunction(data, funcs, true);
if (ret != null && !(ret instanceof ProblemBinding)) {
return ret;
}
}
/*
* 2.14.8.3 (cont.), 2.14.8.4 (cont.)
* Otherwise, S shall contain a raw literal operator or a literal
* operator template but not both.
*/
// Raw literal operator `operator "" _op(const char * c)`
CPPPointerType charArray = new CPPPointerType(CPPBasicType.CHAR, true, false, false);
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp);
data.setFunctionArguments(false, createArgForType(exp, charArray));
ret = resolveFunction(data, funcs, true);
//
char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator
// The string literal is passed to the operator as chars:
// "literal"_op -> operator "" _op<'l', 'i', 't', 'e', 'r', 'a', 'l'>();
ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length];
for (int k = 0; k < stringLiteral.length; k++) {
args[k] = new CPPTemplateNonTypeArgument(new EvalFixed(CPPBasicType.CHAR, PRVALUE, Value.create(stringLiteral[k])), exp);
}
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), args, exp);
IBinding litTpl = resolveFunction(data, tplFunctions, true);
// Do we have valid template and non-template bindings?
if (ret != null && litTpl != null) {
if (!(ret instanceof IProblemBinding) && litTpl instanceof ICPPFunctionInstance) {
// Ambiguity? It has two valid options, and the spec says it shouldn't
return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, tplFunctions);
}
if ((ret instanceof IProblemBinding) && litTpl instanceof ICPPFunctionInstance) {
// Only the template binding is valid
ret = litTpl;
}
}
else if (ret == null) {
// Couldn't find a valid operator
return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_INVALID_TYPE);
}
} else if (kind == IASTLiteralExpression.lk_string_literal) {
/*
* 2.14.8.5
* If L is a user-defined-string-literal, let str be the literal
* without its ud-suffix and let len be the number of code units in
* str (i.e., its length excluding the terminating null character).
* L is treated as operator "" X(str, len)
*/
CPPPointerType strType = new CPPPointerType(new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, null), true, false, false);
IASTInitializerClause[] initializer = new IASTInitializerClause[] {
createArgForType(exp, strType),
createArgForType(null, CPPBasicType.UNSIGNED_INT)
};
data.setFunctionArguments(false, initializer);
ret = resolveFunction(data, funcs, true);
} else if (kind == IASTLiteralExpression.lk_char_constant) {
/*
* 2.14.8.6
* If L is a user-defined-character-literal, let ch be the literal
* without its ud-suffix. S shall contain a literal operator whose
* only parameter has the type ch and the literal L is treated as a
* call operator "" X(ch)
*/
CPPBasicType t = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, exp);
data.setFunctionArguments(false, createArgForType(exp, t));
ret = resolveFunction(data, funcs, true);
}
return ret;
}
static ICPPFunction resolveTargetedFunction(IType targetType, CPPFunctionSet set, IASTNode point) {
targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR);

View file

@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2005, 2014 IBM Corporation and others.
# Copyright (c) 2005, 2015 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 @@
# IBM Rational Software - Initial API and implementation
# Anton Leherbauer (Wind River Systems)
# Markus Schorn (Wind River Systems)
# Richard Eames
###############################################################################
ScannerProblemFactory.error.preproc.error=#error encountered with text: {0}
@ -25,6 +26,7 @@ ScannerProblemFactory.error.preproc.invalidDirective=Invalid preprocessor direct
ScannerProblemFactory.error.preproc.macroPasting=Invalid use of macro pasting in macro: {0}
ScannerProblemFactory.error.preproc.missingRParen=missing '')'' in parameter list of macro: {0}
ScannerProblemFactory.error.preproc.invalidVaArgs=__VA_ARGS__ can only appear in the expansion of a variadic macro
ScannerProblemFactory.error.preproc.multipleUserDefinedLiteralSuffixesOnStringLiteral=Multiple user-defined suffixes found when concatenating string literals
ScannerProblemFactory.error.scanner.invalidEscapeChar=Invalid escape character encountered
ScannerProblemFactory.error.scanner.unboundedString=Unbounded string encountered
@ -41,6 +43,8 @@ ScannerProblemFactory.error.scanner.illegalIdentifier=Illegal identifier in defi
ScannerProblemFactory.error.scanner.badConditionalExpression=Bad conditional expression
ScannerProblemFactory.error.scanner.unexpectedEOF=Unexpected End Of File encountered
ScannerProblemFactory.error.scanner.badCharacter=Bad character sequence encountered: {0}
ScannerProblemFactory.error.scanner.constantWithBadSuffix=Constant "{0}" has an invalid suffix
ScannerProblemFactory.error.scanner.floatWithBadPrefix=Floating constant "{0}" has an invalid prefix
ParserProblemFactory.error.syntax.syntaxError=Syntax error
ParserProblemFactory.error.syntax.missingSemicolon=Missing ';'

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2013 IBM Corporation and others.
* Copyright (c) 2004, 2015 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
@ -11,11 +11,13 @@
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
* Marc-Andre Laperle (Ericsson)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@ -294,6 +296,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fLexOptions.fSupportSlashPercentComments= configuration.supportSlashPercentComments();
fLexOptions.fSupportUTFLiterals = configuration.supportUTFLiterals();
fLexOptions.fSupportRawStringLiterals = configuration.supportRawStringLiterals();
fLexOptions.fSupportUserDefinedLiterals = configuration.supportUserDefinedLiterals();
if (info instanceof ExtendedScannerInfo)
fLexOptions.fIncludeExportPatterns = ((ExtendedScannerInfo) info).getIncludeExportPatterns();
fLocationMap= new LocationMap(fLexOptions);
@ -386,7 +389,16 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
public ILocationResolver getLocationResolver() {
return fLocationMap;
}
/**
* @see IScannerExtensionConfiguration#supportAdditionalNumericLiteralSuffixes
* @since 5.10
*/
@Override
public char[] getAdditionalNumericLiteralSuffixes() {
return fAdditionalNumericLiteralSuffixes;
}
private void configureKeywords(ParserLanguage language, IScannerExtensionConfiguration configuration) {
Keywords.addKeywordsPreprocessor(fPPKeywords);
if (language == ParserLanguage.C) {
@ -620,14 +632,13 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
t.setNext(null);
return t;
}
try {
try {
t= internalFetchToken(fRootContext, CHECK_NUMBERS | REPORT_SIGNIFICANT_MACROS | IGNORE_UNDEFINED_SIGNIFICANT_MACROS, false);
} catch (OffsetLimitReachedException e) {
fHandledCompletion= true;
throw e;
}
final int offset= fLocationMap.getSequenceNumberForOffset(t.getOffset());
final int offset= fLocationMap.getSequenceNumberForOffset(t.getOffset());
final int endOffset= fLocationMap.getSequenceNumberForOffset(t.getEndOffset());
t.setOffset(offset, endOffset);
t.setNext(null);
@ -638,7 +649,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
t.setNext(fPrefetchedTokens);
fPrefetchedTokens= t;
}
/**
* Returns next token for the parser. String literals are not concatenated. When
* the end is reached tokens with type {@link IToken#tEND_OF_INPUT}.
@ -715,11 +726,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
*/
@Override
public IToken nextToken() throws EndOfFileException {
if (isCancelled) {
if (isCancelled) {
throw new ParseError(ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED);
}
Token t1= fetchToken();
char[] udlSuffix = null;
final int tt1= t1.getType();
switch (tt1) {
@ -741,24 +753,34 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case IToken.t_PRAGMA:
handlePragmaOperator(t1);
return nextToken();
case IToken.tUSER_DEFINED_STRING_LITERAL:
udlSuffix = getUserDefinedLiteralSuffix(t1);
//$FALL-THROUGH$
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
StringType st = StringType.fromToken(tt1);
StringType st = StringType.fromToken(t1);
Token t2;
StringBuilder buf= null;
int endOffset= 0;
int endOffset= t1.getEndOffset();
loop: while (true) {
t2= fetchToken();
final int tt2= t2.getType();
switch (tt2) {
case IToken.tLSTRING:
case IToken.tUSER_DEFINED_STRING_LITERAL:
if (udlSuffix == null) {
udlSuffix = getUserDefinedLiteralSuffix(t2);
} else if (!Arrays.equals(udlSuffix, getUserDefinedLiteralSuffix(t2))) {
handleProblem(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION,
udlSuffix, t2.getOffset(), endOffset);
}
//$FALL-THROUGH$
case IToken.tLSTRING:
case IToken.tSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
st = StringType.max(st, StringType.fromToken(tt2));
st = StringType.max(st, StringType.fromToken(t2));
if (buf == null) {
buf= new StringBuilder();
appendStringContent(buf, t1);
@ -773,23 +795,30 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case IToken.t_PRAGMA:
handlePragmaOperator(t2);
continue loop;
default:
default:
break loop;
}
}
pushbackToken(t2);
if (buf != null) {
char[] prefix = st.getPrefix();
char[] image= new char[buf.length() + prefix.length + 2];
final int imageLength = buf.length() + prefix.length + 2 + (udlSuffix == null ? 0 : udlSuffix.length);
char[] image= new char[imageLength];
int off= -1;
int tokenType = st.getTokenValue();
for (char c : prefix)
image[++off] = c;
image[++off]= '"';
buf.getChars(0, buf.length(), image, ++off);
image[image.length - 1]= '"';
t1= new TokenWithImage(st.getTokenValue(), null, t1.getOffset(), endOffset, image);
off += buf.length();
image[off]= '"';
if (udlSuffix != null) {
System.arraycopy(udlSuffix, 0, image, ++off, udlSuffix.length);
tokenType = IToken.tUSER_DEFINED_STRING_LITERAL;
}
t1= new TokenWithImage(tokenType, null, t1.getOffset(), endOffset, image);
}
break;
@ -841,7 +870,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
}
if (length > 1) {
final int diff= image[length - 1] == '"' ? length - start - 1 : length - start;
int diff = 0;
if (t1.getType() == IToken.tUSER_DEFINED_STRING_LITERAL) {
diff = t1.getImage().lastIndexOf('"') - start;
} else {
diff= image[length - 1] == '"' ? length - start - 1 : length - start;
}
if (diff > 0) {
buf.append(image, start, diff);
}
@ -850,6 +884,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
Token internalFetchToken(final ScannerContext uptoEndOfCtx, int options, boolean withinExpansion)
throws OffsetLimitReachedException {
Token ppToken= fCurrentContext.currentLexerToken();
while (true) {
switch (ppToken.getType()) {
@ -966,6 +1002,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
boolean isHex = false;
boolean isOctal = false;
boolean hasDot= false;
boolean badSuffix = false;
int pos= 0;
if (image.length > 1) {
@ -1002,6 +1040,10 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
switch (image[pos]) {
case '0': case'1':
continue;
case 'e': case 'E':
case '.':
handleProblem(IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b".toCharArray(), number.getOffset(), number.getEndOffset()); //$NON-NLS-1$
return;
default:
// 0 and 1 are the only allowed digits for binary integers
// No floating point, exponents etc. are allowed
@ -1069,38 +1111,71 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
break loop;
}
}
// check the suffix
loop: for (; pos < image.length; pos++) {
final char c= image[pos];
switch (c) {
case 'u': case 'U': case 'L': case 'l':
continue;
case 'f': case 'F':
if (isFloat) {
continue loop;
}
}
for (int i= 0; i < fAdditionalNumericLiteralSuffixes.length; i++) {
if (fAdditionalNumericLiteralSuffixes[i] == c) {
continue loop;
}
}
if (isBin) {
// The check for bin has to come before float, otherwise binary integers
// with float components get flagged as BAD_FLOATING_POINT
handleProblem(IProblem.SCANNER_BAD_BINARY_FORMAT, image, number.getOffset(), number.getEndOffset());
} else if (isFloat) {
handleProblem(IProblem.SCANNER_BAD_FLOATING_POINT, image, number.getOffset(), number.getEndOffset());
} else if (isHex) {
handleProblem(IProblem.SCANNER_BAD_HEX_FORMAT, image, number.getOffset(), number.getEndOffset());
} else if (isOctal) {
handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset());
} else {
handleProblem(IProblem.SCANNER_BAD_DECIMAL_FORMAT, image, number.getOffset(), number.getEndOffset());
}
return;
if (pos < image.length) {
char c = image[pos];
if (Character.isLetter(c) || c == '_') {
// check the suffix
final int suffixStart = pos;
loop: for (; pos < image.length; pos++) {
c= image[pos];
switch (c) {
case 'u': case 'U': case 'L': case 'l':
continue;
case 'f': case 'F':
if (isFloat) {
continue loop;
}
//$FALL-THROUGH$
case 'a': case 'b': case 'c': case 'd': case 'e': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'v': case 'w': case 'x': case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T':case 'V': case 'W': case 'X': case 'Y': case 'Z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '_':
if (fLexOptions.fSupportUserDefinedLiterals) {
continue loop;
}
}
for (int i= 0; i < fAdditionalNumericLiteralSuffixes.length; i++) {
if (fAdditionalNumericLiteralSuffixes[i] == c) {
continue loop;
} else {
badSuffix = true;
}
}
if (badSuffix) {
char[] suffix = CharArrayUtils.subarray(image, suffixStart, -1);
handleProblem(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, suffix, number.getOffset(), number.getEndOffset());
return;
}
}
return;
}
}
else {
return;
}
if (isBin) {
// The check for bin has to come before float, otherwise binary integers
// with float components get flagged as BAD_FLOATING_POINT
handleProblem(IProblem.SCANNER_BAD_BINARY_FORMAT, image, number.getOffset(), number.getEndOffset());
} else if (isFloat) {
handleProblem(IProblem.SCANNER_BAD_FLOATING_POINT, image, number.getOffset(), number.getEndOffset());
} else if (isHex) {
handleProblem(IProblem.SCANNER_BAD_HEX_FORMAT, image, number.getOffset(), number.getEndOffset());
} else if (isOctal) {
handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset());
} else {
handleProblem(IProblem.SCANNER_BAD_DECIMAL_FORMAT, image, number.getOffset(), number.getEndOffset());
}
return;
}
private <T> T findInclusion(final String includeDirective, final boolean quoteInclude,
@ -1953,6 +2028,25 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
return true;
}
/**
* Returns the user-defined suffix of a user-define string literal.
*
* @param token
* @return the suffix of the token, if it exists
*/
private static char[] getUserDefinedLiteralSuffix(IToken token) {
if (token.getType() != IToken.tUSER_DEFINED_STRING_LITERAL)
throw new IllegalArgumentException();
char[] image = token.getCharImage();
int offset = CharArrayUtils.lastIndexOf('"', image) + 1;
if (offset <= 0)
throw new IllegalArgumentException();
if (offset == image.length)
return CharArrayUtils.EMPTY_CHAR_ARRAY;
return CharArrayUtils.subarray(image, offset, image.length);
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2009 IBM Corporation and others.
* Copyright (c) 2004, 2015 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)
* Bryan Wilkinson (QNX) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=151207
* Anton Leherbauer (Wind River Systems)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
@ -19,6 +20,7 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.util.CharArrayMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
/**
* Used to evaluate expressions in preprocessor directives.
@ -352,42 +354,26 @@ public class ExpressionEvaluator {
// supported by GCC since 4.3 and by some other C compilers
// They consist of a prefix 0b or 0B, followed by a sequence of 0 and 1 digits
// see http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html
boolean isBin = false;
boolean isHex = false;
boolean isOctal = false;
int pos= 0;
if (image.length > 1) {
if (image[0] == '0') {
switch (image[++pos]) {
switch (image[1]) {
case 'b':
case 'B':
isBin = true;
++pos;
break;
return getNumber(image, 2, image.length, 2, IProblem.SCANNER_BAD_BINARY_FORMAT);
case 'x':
case 'X':
isHex = true;
++pos;
break;
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
isOctal = true;
++pos;
break;
return getNumber(image, 2, image.length, 16, IProblem.SCANNER_BAD_HEX_FORMAT);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return getNumber(image, 1, image.length, 8, IProblem.SCANNER_BAD_OCTAL_FORMAT);
}
}
}
if (isBin) {
return getNumber(image, 2, image.length, 2, IProblem.SCANNER_BAD_BINARY_FORMAT);
}
if (isHex) {
return getNumber(image, 2, image.length, 16, IProblem.SCANNER_BAD_HEX_FORMAT);
}
if (isOctal) {
return getNumber(image, 1, image.length, 8, IProblem.SCANNER_BAD_OCTAL_FORMAT);
}
return getNumber(image, 0, image.length, 10, IProblem.SCANNER_BAD_DECIMAL_FORMAT);
return getNumber(image, 0, image.length, 10, IProblem.SCANNER_BAD_DECIMAL_FORMAT);
}
public static long getChar(char[] tokenImage, int i) throws EvalException {
@ -425,23 +411,50 @@ public class ExpressionEvaluator {
}
private static long getNumber(char[] tokenImage, int from, int to, int base, int problemID) throws EvalException {
if (from == to) {
throw new EvalException(problemID, tokenImage);
}
long result= 0;
int i= from;
for (; i < to; i++) {
int digit= getDigit(tokenImage[i]);
if (digit >= base) {
break;
char c;
long result = 0;
int i = from;
if (from != to) {
for (; i < to; i++) {
int digit = getDigit(tokenImage[i]);
if (digit >= base) {
break;
}
result = result * base + digit;
}
result= result*base + digit;
if (i >= to) {
return result; // return early
}
c = tokenImage[i];
if ('0' <= c && c <= '9') {
// A suffix cannot start with a number
throw new EvalException(problemID, tokenImage);
} else if (i == 2 && base != 10) {
// Possible that the prefix is bad.
i--;
}
} else {
/*
* If we get in here, then the number literal is 2 characters,
* but hasn't had the last character checked if it's a suffix
*/
i = 1;
}
// The rest should be a suffix
final int suffixStart = i;
for (; i < to; i++) {
switch (tokenImage[i]) {
case 'u' : case 'l': case 'U': case 'L':
break;
default:
c = tokenImage[i];
if (Character.isLetterOrDigit(c) || c == '_') {
char[] suffix = CharArrayUtils.subarray(tokenImage, suffixStart, -1);
throw new EvalException(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, suffix);
}
throw new EvalException(problemID, tokenImage);
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2013 Wind River Systems, Inc. and others.
* Copyright (c) 2007, 2015 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
@ -9,6 +9,7 @@
* Markus Schorn - initial API and implementation
* Mike Kucera (IBM) - UTF string literals
* Sergey Prigogin (Google)
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
@ -57,6 +58,7 @@ final public class Lexer implements ITokenSequence {
public boolean fSupportSlashPercentComments= false;
public boolean fSupportUTFLiterals= true;
public boolean fSupportRawStringLiterals= false;
public boolean fSupportUserDefinedLiterals = false;
public IncludeExportPatterns fIncludeExportPatterns;
@Override
@ -348,7 +350,7 @@ final public class Lexer implements ITokenSequence {
if (fInsideIncludeDirective) {
return headerName(start, true);
}
return stringLiteral(start, 1, IToken.tSTRING);
return stringLiteral(start, 1, IToken.tSTRING);
case '\'':
return charLiteral(start, IToken.tCHAR);
@ -732,8 +734,17 @@ final public class Lexer implements ITokenSequence {
c= nextCharPhase3();
}
}
private Token stringLiteral(final int start, int length, final int tokenType) throws OffsetLimitReachedException {
private boolean isIdentifierStart(int c) {
return Character.isLetter((char)c) ||
Character.isDigit((char)c) ||
Character.isUnicodeIdentifierPart(c) ||
(fOptions.fSupportDollarInIdentifiers && c == '$') ||
(fOptions.fSupportAtSignInIdentifiers && c == '@') ||
c == '_';
}
private Token stringLiteral(final int start, int length, int tokenType) throws OffsetLimitReachedException {
boolean escaped = false;
boolean done = false;
@ -766,10 +777,35 @@ final public class Lexer implements ITokenSequence {
length++;
c= nextCharPhase3();
}
if (fOptions.fSupportUserDefinedLiterals && isUDLSuffixStart(c)) {
Token t = identifier(start + length, 0);
tokenType = IToken.tUSER_DEFINED_STRING_LITERAL;
length += t.getLength();
}
return newToken(tokenType, start, length);
}
private Token rawStringLiteral(final int start, int length, final int tokenType) throws OffsetLimitReachedException {
private boolean isUDLSuffixStart(int c) {
// C++11 introduced a backward incompatible change breaking the following code:
// #define __STDC_FORMAT_MACROS
// #include <inttypes.h>
// #include <stdio.h>
//
// void test() {
// int64_t i64 = 123;
// printf("My int64: %"PRId64"\n", i64);
// }
//
// We follow the example of Clang and GCC that are working around this by interpreting literal
// suffixes that don't start with underscores as separate tokens, which allows them to expand
// as macros: http://llvm.org/viewvc/llvm-project?view=rev&revision=152287 and
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52538
return c == '_';
}
private Token rawStringLiteral(final int start, int length, int tokenType) throws OffsetLimitReachedException {
final int delimOffset= fOffset;
int delimEndOffset = delimOffset;
int offset;
@ -813,10 +849,17 @@ final public class Lexer implements ITokenSequence {
fEndOffset= offset;
fCharPhase3= 0;
nextCharPhase3();
if (fOptions.fSupportUserDefinedLiterals && isUDLSuffixStart(fCharPhase3)) {
Token t = identifier(offset, 0);
tokenType = IToken.tUSER_DEFINED_STRING_LITERAL;
offset += t.getLength();
}
return newToken(tokenType, start, offset - start);
}
private Token charLiteral(final int start, final int tokenType) throws OffsetLimitReachedException {
private Token charLiteral(final int start, int tokenType) throws OffsetLimitReachedException {
boolean escaped = false;
boolean done = false;
int length= tokenType == IToken.tCHAR ? 1 : 2;
@ -848,6 +891,13 @@ final public class Lexer implements ITokenSequence {
length++;
c= nextCharPhase3();
}
if (fOptions.fSupportUserDefinedLiterals && isIdentifierStart(c)) {
Token t = identifier(start+length, 0);
tokenType = IToken.tUSER_DEFINED_CHAR_LITERAL;
length += t.getLength();
}
return newToken(tokenType, start, length);
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* Copyright (c) 2009, 2015 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:
* Mike Kucera (IBM) - Initial API and implementation
* Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
@ -59,7 +60,7 @@ public enum StringType {
* @throws IllegalArgumentException if the tokenVal does not represent a string literal
*/
public static StringType fromToken(int tokenVal) {
switch(tokenVal) {
switch (tokenVal) {
case IToken.tSTRING: return NARROW;
case IToken.tLSTRING: return WIDE;
case IToken.tUTF16STRING: return UTF16;
@ -68,4 +69,35 @@ public enum StringType {
throw new IllegalArgumentException(tokenVal + " is not a string token");
}
}
/**
* Returns the StringType for a given string literal token, including a user-defined string literal
* @see StringType#fromToken(int)
* @since 5.10
*/
public static StringType fromToken(IToken token) {
switch (token.getType()) {
case IToken.tSTRING: return NARROW;
case IToken.tLSTRING: return WIDE;
case IToken.tUTF16STRING: return UTF16;
case IToken.tUTF32STRING: return UTF32;
case IToken.tUSER_DEFINED_STRING_LITERAL: {
char[] image = token.getCharImage();
switch (image[0]) {
case 'R':
case '"': return NARROW;
case 'L': return WIDE;
case 'u':
if (image.length > 3 && image[1] == '8') {
return NARROW;
}
return UTF16;
case 'U': return UTF32;
}
}
//$FALL-THROUGH$
default:
throw new IllegalArgumentException(token.getType() + " is not a string token");
}
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008 IBM Corporation and others All rights reserved. This
* Copyright (c) 2008, 2015 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 http://www.eclipse.org/legal/epl-v10.html
@ -41,4 +41,8 @@ public class ScannerExtensionConfiguration extends AbstractScannerExtensionConfi
return true;
}
@Override
public boolean supportUserDefinedLiterals() {
return false;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2013 QNX Software Systems and others.
* Copyright (c) 2013, 2015 QNX Software Systems 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
@ -116,4 +116,9 @@ public class StringScanner implements IScanner {
@Deprecated
public void setScanComments(boolean val) {
}
@Override
public char[] getAdditionalNumericLiteralSuffixes() {
return new char[] {};
}
}