[PATCH] Start to unify contextual keywords
Alp Toker
alp at nuanti.com
Thu Dec 12 06:46:54 PST 2013
Hi,
Now that we emit diagnostics for keyword-as-identifier hacks
(-Wkeyword-compat) we can go ahead and simplify some of the old
revertible keyword support.
This patch adds a TryIdentKeywordUpgrade() function to mirror the
recently added TryKeywordIdentFallback(), and uses it to replace
hard-coded REVERTIBLE_TYPE_TRAITs.
The mid-term goal is to work with libc++ to remove dependence on the GNU
token hacks, and to unify context-sensitive keyword handing in the C++
frontend.
4 files changed, 43 insertions(+), 70 deletions(-)
Alp.
--
http://www.nuanti.com
the browser experts
-------------- next part --------------
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index c124c69..1bf0b6a 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -138,7 +138,8 @@ class Parser : public CodeCompletionHandler {
// C++ type trait keywords that can be reverted to identifiers and still be
// used as type traits.
- llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
+ llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>
+ ContextualKeywords;
OwningPtr<PragmaHandler> AlignHandler;
OwningPtr<PragmaHandler> GCCVisibilityHandler;
@@ -574,6 +575,12 @@ private:
/// otherwise emits a diagnostic and returns true.
bool TryKeywordIdentFallback(bool DisableKeyword);
+ /// TryIdentKeywordUpgrade - Convert the current identifier token back to
+ /// its original kind and return true if it was disabled by
+ /// TryKeywordIdentFallback(), otherwise return false. Use this to
+ /// contextually enable keywords.
+ bool TryIdentKeywordUpgrade();
+
/// \brief Get the TemplateIdAnnotation from the token.
TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index b34b111..51d914d 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1180,31 +1180,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// C++11 attributes
SourceLocation AttrFixitLoc = Tok.getLocation();
- if (TagType == DeclSpec::TST_struct &&
- !Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo() &&
- (Tok.is(tok::kw___is_arithmetic) ||
- Tok.is(tok::kw___is_convertible) ||
- Tok.is(tok::kw___is_empty) ||
- Tok.is(tok::kw___is_floating_point) ||
- Tok.is(tok::kw___is_function) ||
- Tok.is(tok::kw___is_fundamental) ||
- Tok.is(tok::kw___is_integral) ||
- Tok.is(tok::kw___is_member_function_pointer) ||
- Tok.is(tok::kw___is_member_pointer) ||
- Tok.is(tok::kw___is_pod) ||
- Tok.is(tok::kw___is_pointer) ||
- Tok.is(tok::kw___is_same) ||
- Tok.is(tok::kw___is_scalar) ||
- Tok.is(tok::kw___is_signed) ||
- Tok.is(tok::kw___is_unsigned) ||
- Tok.is(tok::kw___is_void)))
- // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
- // name of struct templates, but some are keywords in GCC >= 4.3
- // and Clang. Therefore, when we see the token sequence "struct
- // X", make X into a normal identifier rather than a keyword, to
- // allow libstdc++ 4.2 and libc++ to work properly.
- TryKeywordIdentFallback(true);
+ // GNU libstdc++ and libc++ use certain intrinsic names as the
+ // name of struct templates, but some are keywords in GCC >= 4.3
+ // MSVC and Clang. For compatibility, convert the token to an identifier
+ // and issue a warning diagnostic.
+ if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier)) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ // We rarely end up here so the following check is efficient.
+ if (II && II->getName().startswith("__is_"))
+ TryKeywordIdentFallback(true);
+ }
// Parse the (optional) nested-name-specifier.
CXXScopeSpec &SS = DS.getTypeSpecScope();
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index f988590..de41463 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -715,48 +715,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// If this identifier was reverted from a token ID, and the next token
// is a parenthesis, this is likely to be a use of a type trait. Check
// those tokens.
- if (Next.is(tok::l_paren) &&
- Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
- // Build up the mapping of revertible type traits, for future use.
- if (RevertibleTypeTraits.empty()) {
-#define RTT_JOIN(X,Y) X##Y
-#define REVERTIBLE_TYPE_TRAIT(Name) \
- RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
- = RTT_JOIN(tok::kw_,Name)
-
- REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
- REVERTIBLE_TYPE_TRAIT(__is_convertible);
- REVERTIBLE_TYPE_TRAIT(__is_empty);
- REVERTIBLE_TYPE_TRAIT(__is_floating_point);
- REVERTIBLE_TYPE_TRAIT(__is_function);
- REVERTIBLE_TYPE_TRAIT(__is_fundamental);
- REVERTIBLE_TYPE_TRAIT(__is_integral);
- REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
- REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
- REVERTIBLE_TYPE_TRAIT(__is_pod);
- REVERTIBLE_TYPE_TRAIT(__is_pointer);
- REVERTIBLE_TYPE_TRAIT(__is_same);
- REVERTIBLE_TYPE_TRAIT(__is_scalar);
- REVERTIBLE_TYPE_TRAIT(__is_signed);
- REVERTIBLE_TYPE_TRAIT(__is_unsigned);
- REVERTIBLE_TYPE_TRAIT(__is_void);
-#undef REVERTIBLE_TYPE_TRAIT
-#undef RTT_JOIN
- }
-
- // If we find that this is in fact the name of a type trait,
- // update the token kind in place and parse again to treat it as
- // the appropriate kind of type trait.
- llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
- = RevertibleTypeTraits.find(II);
- if (Known != RevertibleTypeTraits.end()) {
- Tok.setKind(Known->second);
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
- }
- }
+ if (Next.is(tok::l_paren) && Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() &&
+ TryIdentKeywordUpgrade())
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 310105a..fd79cac 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1521,12 +1521,30 @@ bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
Diag(Tok, diag::ext_keyword_as_ident)
<< PP.getSpelling(Tok)
<< DisableKeyword;
- if (DisableKeyword)
- Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
+ if (DisableKeyword) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ ContextualKeywords[II] = Tok.getKind();
+ II->RevertTokenIDToIdentifier();
+ }
Tok.setKind(tok::identifier);
return true;
}
+bool Parser::TryIdentKeywordUpgrade() {
+ assert(Tok.is(tok::identifier));
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ assert(II->hasRevertedTokenIDToIdentifier());
+ // If we find that this is in fact the name of a type trait,
+ // update the token kind in place and parse again to treat it as
+ // the appropriate kind of type trait.
+ llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>::iterator Known =
+ ContextualKeywords.find(II);
+ if (Known == ContextualKeywords.end())
+ return false;
+ Tok.setKind(Known->second);
+ return true;
+}
+
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
More information about the cfe-commits
mailing list