mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-08 02:06:01 +02:00
Bug 442325 - Add support for __has_feature
Change-Id: I6ebbf76f19d1edde0592df0053a74006d5684d9d Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
parent
aea96f8c1b
commit
a9a454f256
6 changed files with 169 additions and 10 deletions
|
@ -11542,4 +11542,25 @@ public class AST2CPPTests extends AST2TestBase {
|
||||||
ICPPVariable test = bh.assertNonProblemOnFirstIdentifier("test");
|
ICPPVariable test = bh.assertNonProblemOnFirstIdentifier("test");
|
||||||
assertTrue(test.getType() instanceof IProblemType); // resolution is ambiguous
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -778,10 +778,17 @@ public class AST2TestBase extends BaseTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertVariableType(String variableName, IType expectedType) {
|
public void assertVariableType(String variableName, IType expectedType) {
|
||||||
IVariable var = assertNonProblem(variableName, IVariable.class);
|
IVariable var = assertNonProblem(variableName);
|
||||||
assertSameType(expectedType, var.getType());
|
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) {
|
public <T, U extends T> U assertType(T obj, Class... cs) {
|
||||||
for (Class c : cs) {
|
for (Class c : cs) {
|
||||||
assertInstance(obj, c);
|
assertInstance(obj, c);
|
||||||
|
|
|
@ -310,6 +310,8 @@ public class Keywords {
|
||||||
public static final char[] cPRAGMA = "pragma".toCharArray();
|
public static final char[] cPRAGMA = "pragma".toCharArray();
|
||||||
public static final char[] cLINE = "line".toCharArray();
|
public static final char[] cLINE = "line".toCharArray();
|
||||||
public static final char[] cDEFINED= "defined".toCharArray();
|
public static final char[] cDEFINED= "defined".toCharArray();
|
||||||
|
/** @since 5.11 */
|
||||||
|
public static final char[] c__HAS_FEATURE = "__has_feature".toCharArray();
|
||||||
/** @since 5.2*/
|
/** @since 5.2*/
|
||||||
public static final char[] _Pragma= "_Pragma".toCharArray();
|
public static final char[] _Pragma= "_Pragma".toCharArray();
|
||||||
public static final char[] cVA_ARGS= "__VA_ARGS__".toCharArray();
|
public static final char[] cVA_ARGS= "__VA_ARGS__".toCharArray();
|
||||||
|
|
|
@ -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 tSPACE= IToken.FIRST_RESERVED_PREPROCESSOR + 3;
|
||||||
public static final int tNOSPACE= IToken.FIRST_RESERVED_PREPROCESSOR + 4;
|
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 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_PREPROCESSOR_DIRECTIVE = OffsetLimitReachedException.ORIGIN_PREPROCESSOR_DIRECTIVE;
|
||||||
private static final int ORIGIN_INACTIVE_CODE = OffsetLimitReachedException.ORIGIN_INACTIVE_CODE;
|
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$
|
private static final char[] ONCE = "once".toCharArray(); //$NON-NLS-1$
|
||||||
|
|
||||||
static final int NO_EXPANSION = 0x01;
|
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 STOP_AT_NL = 0x04;
|
||||||
static final int CHECK_NUMBERS = 0x08;
|
static final int CHECK_NUMBERS = 0x08;
|
||||||
static final int REPORT_SIGNIFICANT_MACROS = 0x10;
|
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 fInputToMacroExpansion= new TokenSequence(false);
|
||||||
TokenSequence fLineInputToMacroExpansion= new TokenSequence(true);
|
TokenSequence fLineInputToMacroExpansion= new TokenSequence(true);
|
||||||
|
|
||||||
|
@ -1883,7 +1888,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
||||||
scannerCtx.clearInactiveCodeMarkerToken();
|
scannerCtx.clearInactiveCodeMarkerToken();
|
||||||
int options= STOP_AT_NL | REPORT_SIGNIFICANT_MACROS;
|
int options= STOP_AT_NL | REPORT_SIGNIFICANT_MACROS;
|
||||||
if (isCondition)
|
if (isCondition)
|
||||||
options |= PROTECT_DEFINED;
|
options |= PROTECT_INTRINSICS;
|
||||||
|
|
||||||
loop: while (true) {
|
loop: while (true) {
|
||||||
Token t= internalFetchToken(scannerCtx, options, withinExpansion);
|
Token t= internalFetchToken(scannerCtx, options, withinExpansion);
|
||||||
|
@ -1899,6 +1904,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
||||||
case tDEFINED:
|
case tDEFINED:
|
||||||
options |= NO_EXPANSION;
|
options |= NO_EXPANSION;
|
||||||
break;
|
break;
|
||||||
|
case t__HAS_FEATURE:
|
||||||
|
options |= NO_EXPANSION;
|
||||||
|
break;
|
||||||
case IToken.tLPAREN:
|
case IToken.tLPAREN:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1988,10 +1996,16 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
||||||
boolean withinExpansion) throws OffsetLimitReachedException {
|
boolean withinExpansion) throws OffsetLimitReachedException {
|
||||||
final boolean reportSignificant = (options & REPORT_SIGNIFICANT_MACROS) != 0;
|
final boolean reportSignificant = (options & REPORT_SIGNIFICANT_MACROS) != 0;
|
||||||
final char[] name= identifier.getCharImage();
|
final char[] name= identifier.getCharImage();
|
||||||
if ((options & PROTECT_DEFINED) != 0 && CharArrayUtils.equals(name, Keywords.cDEFINED)) {
|
if ((options & PROTECT_INTRINSICS) != 0) {
|
||||||
|
if (CharArrayUtils.equals(name, Keywords.cDEFINED)) {
|
||||||
identifier.setType(tDEFINED);
|
identifier.setType(tDEFINED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (CharArrayUtils.equals(name, Keywords.c__HAS_FEATURE)) {
|
||||||
|
identifier.setType(t__HAS_FEATURE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
PreprocessorMacro macro= fMacroDictionary.get(name);
|
PreprocessorMacro macro= fMacroDictionary.get(name);
|
||||||
if (macro == null) {
|
if (macro == null) {
|
||||||
if (reportSignificant && (options & IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0)
|
if (reportSignificant && (options & IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0)
|
||||||
|
@ -2066,4 +2080,94 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
||||||
|| CharArrayUtils.equals(__DATE__.getNameCharArray(), name)
|
|| CharArrayUtils.equals(__DATE__.getNameCharArray(), name)
|
||||||
|| CharArrayUtils.equals(__TIME__.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,6 +258,8 @@ public class ExpressionEvaluator {
|
||||||
return 0;
|
return 0;
|
||||||
case CPreprocessor.tDEFINED:
|
case CPreprocessor.tDEFINED:
|
||||||
return handleDefined();
|
return handleDefined();
|
||||||
|
case CPreprocessor.t__HAS_FEATURE:
|
||||||
|
return handleHasFeature();
|
||||||
case IToken.tLPAREN:
|
case IToken.tLPAREN:
|
||||||
consume();
|
consume();
|
||||||
long r1 = expression();
|
long r1 = expression();
|
||||||
|
@ -323,6 +325,25 @@ public class ExpressionEvaluator {
|
||||||
return result;
|
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() {
|
private int LA() {
|
||||||
return fTokens.getType();
|
return fTokens.getType();
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,7 @@ public class MacroExpander {
|
||||||
public TokenList expand(ITokenSequence lexer, final int ppOptions,
|
public TokenList expand(ITokenSequence lexer, final int ppOptions,
|
||||||
PreprocessorMacro macro, Token identifier, boolean completionMode,
|
PreprocessorMacro macro, Token identifier, boolean completionMode,
|
||||||
ScannerContext scannerContext) throws OffsetLimitReachedException {
|
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) {
|
if ((ppOptions & CPreprocessor.REPORT_SIGNIFICANT_MACROS) != 0) {
|
||||||
fReportMacros= scannerContext;
|
fReportMacros= scannerContext;
|
||||||
fReportUndefined= (ppOptions & CPreprocessor.IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0;
|
fReportUndefined= (ppOptions & CPreprocessor.IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0;
|
||||||
|
@ -184,7 +184,7 @@ public class MacroExpander {
|
||||||
|
|
||||||
input.prepend(firstExpansion);
|
input.prepend(firstExpansion);
|
||||||
|
|
||||||
result= expandAll(input, forbidden, protectDefined, null);
|
result= expandAll(input, forbidden, protectIntrinsics, null);
|
||||||
} catch (CompletionInMacroExpansionException e) {
|
} catch (CompletionInMacroExpansionException e) {
|
||||||
// For content assist in macro expansions, we return the list of tokens of the
|
// 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
|
// 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,
|
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();
|
final TokenList result= new TokenList();
|
||||||
boolean protect= false;
|
boolean protect= false;
|
||||||
Token l= null;
|
Token l= null;
|
||||||
|
@ -366,10 +366,14 @@ public class MacroExpander {
|
||||||
PreprocessorMacro macro= fDictionary.get(image);
|
PreprocessorMacro macro= fDictionary.get(image);
|
||||||
if (protect || (tracker != null && tracker.isDone())) {
|
if (protect || (tracker != null && tracker.isDone())) {
|
||||||
result.append(t);
|
result.append(t);
|
||||||
} else if (protectDefinedConstructs && Arrays.equals(image, Keywords.cDEFINED)) {
|
} else if (protectIntrinsics && Arrays.equals(image, Keywords.cDEFINED)) {
|
||||||
t.setType(CPreprocessor.tDEFINED);
|
t.setType(CPreprocessor.tDEFINED);
|
||||||
result.append(t);
|
result.append(t);
|
||||||
protect= true;
|
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())) {
|
} else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) {
|
||||||
// Tricky: Don't mark function-style macros if you don't find the left parenthesis
|
// Tricky: Don't mark function-style macros if you don't find the left parenthesis
|
||||||
if (fReportMacros != null) {
|
if (fReportMacros != null) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue