Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Ridge2015-07-03 22:27:43 +0000
committerGerrit Code Review @ Eclipse.org2015-07-09 19:13:16 +0000
commita9a454f2569a9249df13364193f394487ebf148c (patch)
treea076b14c9389c4932d21021a101df9078607b5d4
parentaea96f8c1bea1757e2d935e7c951dce3d85a88b1 (diff)
downloadorg.eclipse.cdt-a9a454f2569a9249df13364193f394487ebf148c.tar.gz
org.eclipse.cdt-a9a454f2569a9249df13364193f394487ebf148c.tar.xz
org.eclipse.cdt-a9a454f2569a9249df13364193f394487ebf148c.zip
Bug 442325 - Add support for __has_feature
Change-Id: I6ebbf76f19d1edde0592df0053a74006d5684d9d Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java21
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java9
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java114
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java21
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java12
6 files changed, 169 insertions, 10 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
index 51994d1ce75..520c156573f 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
@@ -11541,5 +11541,26 @@ public class AST2CPPTests extends AST2TestBase {
BindingAssertionHelper bh = getAssertionHelper();
ICPPVariable test = bh.assertNonProblemOnFirstIdentifier("test");
assertTrue(test.getType() instanceof IProblemType); // resolution is ambiguous
+ }
+
+ // constexpr int lambdas_supported =
+ // #if __has_feature(cxx_lambdas)
+ // 1;
+ // #else
+ // 0;
+ // #endif
+ //
+ // constexpr int generic_lambdas_supported =
+ // #if __has_feature(cxx_generic_lambdas)
+ // 1;
+ // #else
+ // 0;
+ // #endif
+ public void testHasFeature_442325() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+ helper.assertVariableValue("lambdas_supported", 1);
+ // Note: when support for generic lambdas is implemented,
+ // this test will need to be updated.
+ helper.assertVariableValue("generic_lambdas_supported", 0);
}
}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java
index 956894f3a16..d81d29936ea 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java
@@ -778,9 +778,16 @@ public class AST2TestBase extends BaseTestCase {
}
public void assertVariableType(String variableName, IType expectedType) {
- IVariable var = assertNonProblem(variableName, IVariable.class);
+ IVariable var = assertNonProblem(variableName);
assertSameType(expectedType, var.getType());
}
+
+ public void assertVariableValue(String variableName, long expectedValue) {
+ IVariable var = assertNonProblem(variableName);
+ assertNotNull(var.getInitialValue());
+ assertNotNull(var.getInitialValue().numericalValue());
+ assertEquals(expectedValue, var.getInitialValue().numericalValue().longValue());
+ }
public <T, U extends T> U assertType(T obj, Class... cs) {
for (Class c : cs) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java
index c2b7cf67d0d..274dcc982f1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java
@@ -310,6 +310,8 @@ public class Keywords {
public static final char[] cPRAGMA = "pragma".toCharArray();
public static final char[] cLINE = "line".toCharArray();
public static final char[] cDEFINED= "defined".toCharArray();
+ /** @since 5.11 */
+ public static final char[] c__HAS_FEATURE = "__has_feature".toCharArray();
/** @since 5.2*/
public static final char[] _Pragma= "_Pragma".toCharArray();
public static final char[] cVA_ARGS= "__VA_ARGS__".toCharArray();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
index 6b9617fc552..48dba5636cf 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
@@ -85,6 +85,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
public static final int tSPACE= IToken.FIRST_RESERVED_PREPROCESSOR + 3;
public static final int tNOSPACE= IToken.FIRST_RESERVED_PREPROCESSOR + 4;
public static final int tMACRO_PARAMETER= IToken.FIRST_RESERVED_PREPROCESSOR + 5;
+ public static final int t__HAS_FEATURE = IToken.FIRST_RESERVED_PREPROCESSOR + 6;
private static final int ORIGIN_PREPROCESSOR_DIRECTIVE = OffsetLimitReachedException.ORIGIN_PREPROCESSOR_DIRECTIVE;
private static final int ORIGIN_INACTIVE_CODE = OffsetLimitReachedException.ORIGIN_INACTIVE_CODE;
@@ -108,7 +109,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
private static final char[] ONCE = "once".toCharArray(); //$NON-NLS-1$
static final int NO_EXPANSION = 0x01;
- static final int PROTECT_DEFINED = 0x02;
+ // Set in contexts where preprocessor intrinsics such as 'defined'
+ // or '__has_feature' need to be recognized.
+ static final int PROTECT_INTRINSICS = 0x02;
static final int STOP_AT_NL = 0x04;
static final int CHECK_NUMBERS = 0x08;
static final int REPORT_SIGNIFICANT_MACROS = 0x10;
@@ -224,6 +227,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
}
}
+ private static Set<String> sSupportedFeatures;
+
TokenSequence fInputToMacroExpansion= new TokenSequence(false);
TokenSequence fLineInputToMacroExpansion= new TokenSequence(true);
@@ -1883,7 +1888,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
scannerCtx.clearInactiveCodeMarkerToken();
int options= STOP_AT_NL | REPORT_SIGNIFICANT_MACROS;
if (isCondition)
- options |= PROTECT_DEFINED;
+ options |= PROTECT_INTRINSICS;
loop: while (true) {
Token t= internalFetchToken(scannerCtx, options, withinExpansion);
@@ -1899,6 +1904,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case tDEFINED:
options |= NO_EXPANSION;
break;
+ case t__HAS_FEATURE:
+ options |= NO_EXPANSION;
+ break;
case IToken.tLPAREN:
break;
default:
@@ -1988,9 +1996,15 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
boolean withinExpansion) throws OffsetLimitReachedException {
final boolean reportSignificant = (options & REPORT_SIGNIFICANT_MACROS) != 0;
final char[] name= identifier.getCharImage();
- if ((options & PROTECT_DEFINED) != 0 && CharArrayUtils.equals(name, Keywords.cDEFINED)) {
- identifier.setType(tDEFINED);
- return false;
+ if ((options & PROTECT_INTRINSICS) != 0) {
+ if (CharArrayUtils.equals(name, Keywords.cDEFINED)) {
+ identifier.setType(tDEFINED);
+ return false;
+ }
+ if (CharArrayUtils.equals(name, Keywords.c__HAS_FEATURE)) {
+ identifier.setType(t__HAS_FEATURE);
+ return false;
+ }
}
PreprocessorMacro macro= fMacroDictionary.get(name);
if (macro == null) {
@@ -2066,4 +2080,94 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|| CharArrayUtils.equals(__DATE__.getNameCharArray(), name)
|| CharArrayUtils.equals(__TIME__.getNameCharArray(), name);
}
+
+ @SuppressWarnings("nls")
+ public static Set<String> getSupportedFeatures() {
+ if (sSupportedFeatures == null) {
+ sSupportedFeatures = new HashSet<>();
+
+ // C++98 features
+ sSupportedFeatures.add("cxx_exceptions");
+ sSupportedFeatures.add("cxx_rtti");
+
+ // C++11 features
+ // missing: cxx_access_control_sfinae (needs to be tested)
+ sSupportedFeatures.add("cxx_alias_templates");
+ sSupportedFeatures.add("cxx_alignas");
+ sSupportedFeatures.add("cxx_alignof");
+ sSupportedFeatures.add("cxx_attributes");
+ sSupportedFeatures.add("cxx_auto_type");
+ sSupportedFeatures.add("cxx_constexpr");
+ sSupportedFeatures.add("cxx_decltype");
+ // missing: cxx_decltype_incomplete_return_types (needs to be tested; see bug 324096)
+ sSupportedFeatures.add("cxx_default_function_template_args");
+ sSupportedFeatures.add("cxx_defaulted_functions");
+ sSupportedFeatures.add("cxx_delegating_constructors");
+ sSupportedFeatures.add("cxx_explicit_conversions");
+ sSupportedFeatures.add("cxx_generalized_initializers");
+ // missing: cxx_implicit_moves (bug 327301)
+ sSupportedFeatures.add("cxx_inheriting_constructors");
+ sSupportedFeatures.add("cxx_inline_namespaces");
+ sSupportedFeatures.add("cxx_lambdas");
+ sSupportedFeatures.add("cxx_local_type_template_args");
+ sSupportedFeatures.add("cxx_noexcept");
+ sSupportedFeatures.add("cxx_nonstatic_member_init");
+ sSupportedFeatures.add("cxx_nullptr");
+ sSupportedFeatures.add("cxx_override_control");
+ sSupportedFeatures.add("cxx_range_for");
+ sSupportedFeatures.add("cxx_raw_string_literals");
+ sSupportedFeatures.add("cxx_reference_qualified_functions");
+ sSupportedFeatures.add("cxx_rvalue_references");
+ sSupportedFeatures.add("cxx_static_assert");
+ sSupportedFeatures.add("cxx_strong_enums");
+ sSupportedFeatures.add("cxx_thread_local");
+ sSupportedFeatures.add("cxx_trailing_return");
+ sSupportedFeatures.add("cxx_unicode_literals");
+ // missing: cxx_unrestricted_unions (bug 327299)
+ sSupportedFeatures.add("cxx_user_literals");
+ sSupportedFeatures.add("cxx_variadic_templates");
+
+ // C++14 features
+ // none supported yet
+
+ // C11 features
+ sSupportedFeatures.add("c_alignas");
+ sSupportedFeatures.add("c_alignof");
+ // missing: c_atomic (bug 445297)
+ // missing: c_generic_selections (bug 445296)
+ // missing: c_static_assert (bug 445297)
+ // missing: c_thread_local (bug 445297)
+
+ // Type trait primitives
+ // missing: has_nothrow_assign
+ // missing: has_nothrow_copy
+ // missing: has_nothrow_constructor
+ // missing: has_trivial_assign
+ sSupportedFeatures.add("has_trivial_copy");
+ // missing: has_trivial_constructor
+ // missing: has_trivial_destructor
+ // missing: has_virtual_destructor
+ sSupportedFeatures.add("is_abstract");
+ sSupportedFeatures.add("is_base_of");
+ sSupportedFeatures.add("is_class");
+ // missing: is_constructible
+ // missing: is_convertible_to
+ // missing: is_destructible
+ // missing: is_empty
+ sSupportedFeatures.add("is_enum");
+ sSupportedFeatures.add("is_final");
+ // missing: is_interface_class
+ // missing: is_literal
+ // missing: is_nothrow_assignable
+ // missing: is_nothrow_constructible
+ // missing: is_nothrow_destructible
+ sSupportedFeatures.add("is_pod");
+ sSupportedFeatures.add("is_polymorphic");
+ // missing: is_trivially_assignable
+ // missing: is_trivially_constructible
+ sSupportedFeatures.add("is_union");
+ sSupportedFeatures.add("underlying_type");
+ }
+ return sSupportedFeatures;
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java
index ec046024afa..ca78dfb9434 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java
@@ -258,6 +258,8 @@ public class ExpressionEvaluator {
return 0;
case CPreprocessor.tDEFINED:
return handleDefined();
+ case CPreprocessor.t__HAS_FEATURE:
+ return handleHasFeature();
case IToken.tLPAREN:
consume();
long r1 = expression();
@@ -322,6 +324,25 @@ public class ExpressionEvaluator {
}
return result;
}
+
+ private long handleHasFeature() throws EvalException {
+ consume(); // '__has_feature'
+ if (LA() != IToken.tLPAREN) {
+ throw new EvalException(IProblem.SCANNER_EXPRESSION_SYNTAX_ERROR, null);
+ }
+ consume(); // opening parenthesis
+ if (LA() != IToken.tIDENTIFIER) {
+ throw new EvalException(IProblem.SCANNER_EXPRESSION_SYNTAX_ERROR, null);
+ }
+ final char[] featureName = fTokens.getCharImage();
+ boolean supported = CPreprocessor.getSupportedFeatures().contains(new String(featureName));
+ consume(); // feature name token
+ if (LA() != IToken.tRPAREN) {
+ throw new EvalException(IProblem.SCANNER_MISSING_R_PAREN, null);
+ }
+ consume(); // closing parenthesis
+ return supported ? 1 : 0;
+ }
private int LA() {
return fTokens.getType();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java
index 17d53908aa8..3fc31dea7ff 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java
@@ -155,7 +155,7 @@ public class MacroExpander {
public TokenList expand(ITokenSequence lexer, final int ppOptions,
PreprocessorMacro macro, Token identifier, boolean completionMode,
ScannerContext scannerContext) throws OffsetLimitReachedException {
- final boolean protectDefined= (ppOptions & CPreprocessor.PROTECT_DEFINED) != 0;
+ final boolean protectIntrinsics= (ppOptions & CPreprocessor.PROTECT_INTRINSICS) != 0;
if ((ppOptions & CPreprocessor.REPORT_SIGNIFICANT_MACROS) != 0) {
fReportMacros= scannerContext;
fReportUndefined= (ppOptions & CPreprocessor.IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0;
@@ -184,7 +184,7 @@ public class MacroExpander {
input.prepend(firstExpansion);
- result= expandAll(input, forbidden, protectDefined, null);
+ result= expandAll(input, forbidden, protectIntrinsics, null);
} catch (CompletionInMacroExpansionException e) {
// For content assist in macro expansions, we return the list of tokens of the
// parameter at the current cursor position and hope that they make sense if
@@ -351,7 +351,7 @@ public class MacroExpander {
}
private TokenList expandAll(TokenSource input, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden,
- boolean protectDefinedConstructs, MacroExpansionTracker tracker) throws OffsetLimitReachedException {
+ boolean protectIntrinsics, MacroExpansionTracker tracker) throws OffsetLimitReachedException {
final TokenList result= new TokenList();
boolean protect= false;
Token l= null;
@@ -366,10 +366,14 @@ public class MacroExpander {
PreprocessorMacro macro= fDictionary.get(image);
if (protect || (tracker != null && tracker.isDone())) {
result.append(t);
- } else if (protectDefinedConstructs && Arrays.equals(image, Keywords.cDEFINED)) {
+ } else if (protectIntrinsics && Arrays.equals(image, Keywords.cDEFINED)) {
t.setType(CPreprocessor.tDEFINED);
result.append(t);
protect= true;
+ } else if (protectIntrinsics && Arrays.equals(image, Keywords.c__HAS_FEATURE)) {
+ t.setType(CPreprocessor.t__HAS_FEATURE);
+ result.append(t);
+ protect= true;
} else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) {
// Tricky: Don't mark function-style macros if you don't find the left parenthesis
if (fReportMacros != null) {

Back to the top