This is an archive of the discontinued LLVM Phabricator instance.

[lldb] Add support for using variables with C++ keywords names in non-C++ expressions
ClosedPublic

Authored by teemperor on Jun 29 2020, 7:42 AM.

Details

Summary

LLDB is currently always activating C++ when parsing expressions as LLDB itself is using C++ features
when creating the final AST that will be codegen'd (specifically, references to variables, namespaces
and using declarations are used).

This is causing problems for users that have variables in non-C++ programs (e.g. plain C or Objective-C)
that have names which are keywords in C++. Expressions referencing those variables fail to parse
as LLDB's Clang parser thinks those identifiers are C++ keywords and not identifiers that may belong
to a declaration.

We can't just disable C++ in the expression parser for those situations as replacing the functionality of the
injected C++ code isn't trivial. So this patch is just disabling most keywords that are exclusive to C++ in
LLDB's Clang parser when we are in a non-C++ expression. There are a few keywords we can't disable for now:

  • using as that's currently used in some situations to inject variables into the expression function.
  • __null as that's used by LLDB to define NULL/Nil/nil.

Getting rid of these last two keywords is possible but is a large enough change that this will be handled in
follow up patches.

Note that this only changes the keyword status of those tokens but this patch does not remove any C++
functionality from the expression parser. The type system still follows C++ rules and so does the rest
of the expression parser.

There is another small change that gives the hardcoded macro definitions in LLDB a higher precedence
than the macros imported from the Objective-C modules. The reason for this is that the Objective-C
modules in LLDB are actually parsed in Objective-C++ mode and they end up providing the C++ definitions
of certain system macros (like NULL being defined as nullptr). So we have to move the LLDB definition
forward and surround the definition from the module with an #ifdef to make sure that we use the correct
LLDB definition that doesn't reference C++ keywords. Or to give an example, this is how the expression
source code changes:

Before:

#define NULL (nullptr) // injected module definition
#ifndef NULL
#define NULL (__null) // hardcoded LLDB definition
#endif

After:

#ifndef NULL
#define NULL (__null) // hardcoded LLDB definition
#endif
#ifndef NULL
#define NULL (nullptr) // injected module definition
#endif

Fixes rdar://10356912

Diff Detail

Event Timeline

teemperor created this revision.Jun 29 2020, 7:42 AM
teemperor updated this revision to Diff 274132.Jun 29 2020, 8:05 AM
  • Fixed a typo.
  • Added tests for using a struct with a keyword name in a C++ expression.
shafik added inline comments.Jun 29 2020, 4:06 PM
lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
319

I was looking at isCPlusPlusKeyword() and C++14 nor C++17 added any keywords. If note that function does use either of those.

I was also wondering, b/c it was not obvious after looking at this for a bit, if shared keywords like 'register' (although that is deprecated) also get clobbered.

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
354

Is change actually tested? I don't see it being tested but maybe I am missing it.

It also feels like it should be a separate PR.

I don't really have much to say on this. At first I though this was going to be very hacky, but it actually looks fairly elegant. It may still make sense to check whether doing this is reasonable with some clang folks, if you haven't already.

lldb/test/API/lang/c/cpp_keyword_identifiers/TestCppKeywordsAsCIdentifiers.py
11

What's up with this?

lldb/test/API/lang/objcxx/cpp_keywords_enabled/TestObjCppKeywordsEnabled.py
12

Should maybe this have @skipUnlessDarwin instead?

teemperor edited the summary of this revision. (Show Details)Jul 1 2020, 5:30 AM
teemperor updated this revision to Diff 297592.Oct 12 2020, 8:11 AM
teemperor edited the summary of this revision. (Show Details)
teemperor set the repository for this revision to rLLDB LLDB.

Sorry, this was still on my "Waiting on review" queue as no one pressed the "changes requested" button.

Changes for this revision:

  • Moved test decorator to right test.
  • Removed C++14/17 from keyword check.
  • Refactored the NULL workaround to make it easier to follow (and also more generic).
teemperor updated this revision to Diff 298341.Oct 15 2020, 3:49 AM
teemperor marked an inline comment as done.
  • Added a explicit check for the module related change.
teemperor added inline comments.Oct 26 2020, 11:55 AM
lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
354

I described in the review description what this was for, but I change the code now and replaced it with a more generic "put #ifdefs around our defines" approach (which should hopefully be less cryptic and also general seems like a good idea).

The change is tested by the existing LLDB tests that use macros from Clang modules.

lldb/test/API/lang/c/cpp_keyword_identifiers/TestCppKeywordsAsCIdentifiers.py
11

That's me editing the wrong file :)

lldb/test/API/lang/objcxx/cpp_keywords_enabled/TestObjCppKeywordsEnabled.py
12

Jepp, thanks!

shafik accepted this revision.Oct 26 2020, 4:15 PM

LGTM

This revision is now accepted and ready to land.Oct 26 2020, 4:15 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 16 2020, 7:05 AM