summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2017-07-14 09:23:40 +0000
committerOlivier Goffart <ogoffart@woboq.com>2017-07-14 09:23:40 +0000
commit90f981bc5bbe053e3ef4d25f463f5eff0cbe6daf (patch)
tree199486ce35777ab9ea84af644f8fcfd4cf0fc5c5
parenta84f9f5364207f71f2d5aafdbc63ab8e0f026d77 (diff)
downloadbcm5719-llvm-90f981bc5bbe053e3ef4d25f463f5eff0cbe6daf.tar.gz
bcm5719-llvm-90f981bc5bbe053e3ef4d25f463f5eff0cbe6daf.zip
Keep the IdentifierInfo in the Token for alternative operator keyword
The goal of this commit is to fix clang-format so it does not merge tokens when using the alternative spelling keywords. (eg: "not foo" should not become "notfoo") The problem is that Preprocessor::HandleIdentifier used to drop the identifier info from the token for these keyword. This means the first condition of TokenAnnotator::spaceRequiredBefore is not met. We could add explicit check for the spelling in that condition, but I think it is better to keep the IdentifierInfo and handle the operator keyword explicitly when needed. That actually leads to simpler code, and probably slightly more efficient as well. Another side effect of this change is that __identifier(and) will now work as one would expect, removing a FIXME from the MicrosoftExtensions.cpp test Differential Revision: https://reviews.llvm.org/D35172 llvm-svn: 308008
-rw-r--r--clang/include/clang/Basic/IdentifierTable.h11
-rw-r--r--clang/lib/Lex/PPDirectives.cpp14
-rw-r--r--clang/lib/Lex/PPExpressions.cpp59
-rw-r--r--clang/lib/Lex/Preprocessor.cpp8
-rw-r--r--clang/test/Parser/MicrosoftExtensions.cpp4
-rw-r--r--clang/test/Preprocessor/cxx_oper_keyword.cpp12
-rw-r--r--clang/unittests/Format/FormatTest.cpp10
7 files changed, 61 insertions, 57 deletions
diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index 9b1ba4a98e6..f94b2c9b2f4 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -272,10 +272,6 @@ public:
/// this identifier is a C++ alternate representation of an operator.
void setIsCPlusPlusOperatorKeyword(bool Val = true) {
IsCPPOperatorKeyword = Val;
- if (Val)
- NeedsHandleIdentifier = true;
- else
- RecomputeNeedsHandleIdentifier();
}
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
@@ -381,10 +377,9 @@ private:
/// This method is very tied to the definition of HandleIdentifier. Any
/// change to it should be reflected here.
void RecomputeNeedsHandleIdentifier() {
- NeedsHandleIdentifier =
- (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
- isExtensionToken() | isFutureCompatKeyword() || isOutOfDate() ||
- isModulesImport());
+ NeedsHandleIdentifier = isPoisoned() || hasMacroDefinition() ||
+ isExtensionToken() || isFutureCompatKeyword() ||
+ isOutOfDate() || isModulesImport();
}
};
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 8c79e50176e..4440cf2094e 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -220,26 +220,18 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
- if (!II) {
- bool Invalid = false;
- std::string Spelling = getSpelling(MacroNameTok, &Invalid);
- if (Invalid)
- return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
- II = getIdentifierInfo(Spelling);
-
- if (!II->isCPlusPlusOperatorKeyword())
- return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ if (!II)
+ return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ if (II->isCPlusPlusOperatorKeyword()) {
// C++ 2.5p2: Alternative tokens behave the same as its primary token
// except for their spellings.
Diag(MacroNameTok, getLangOpts().MicrosoftExt
? diag::ext_pp_operator_used_as_macro_name
: diag::err_pp_operator_used_as_macro_name)
<< II << MacroNameTok.getKind();
-
// Allow #defining |and| and friends for Microsoft compatibility or
// recovery when legacy C headers are included in C++.
- MacroNameTok.setIdentifierInfo(II);
}
if ((isDefineUndef != MU_Other) && II->getPPKeywordID() == tok::pp_defined) {
diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index 12f5084298d..d8431827e9c 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -237,35 +237,32 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.setCodeCompletionReached();
PP.LexNonComment(PeekTok);
}
-
- // If this token's spelling is a pp-identifier, check to see if it is
- // 'defined' or if it is a macro. Note that we check here because many
- // keywords are pp-identifiers, so we can't check the kind.
- if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
- // Handle "defined X" and "defined(X)".
- if (II->isStr("defined"))
- return EvaluateDefined(Result, PeekTok, DT, ValueLive, PP);
-
- // If this identifier isn't 'defined' or one of the special
- // preprocessor keywords and it wasn't macro expanded, it turns
- // into a simple 0, unless it is the C++ keyword "true", in which case it
- // turns into "1".
- if (ValueLive &&
- II->getTokenID() != tok::kw_true &&
- II->getTokenID() != tok::kw_false)
- PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
- Result.Val = II->getTokenID() == tok::kw_true;
- Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
- Result.setIdentifier(II);
- Result.setRange(PeekTok.getLocation());
- DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true &&
- II->getTokenID() != tok::kw_false);
- PP.LexNonComment(PeekTok);
- return false;
- }
switch (PeekTok.getKind()) {
- default: // Non-value token.
+ default:
+ // If this token's spelling is a pp-identifier, check to see if it is
+ // 'defined' or if it is a macro. Note that we check here because many
+ // keywords are pp-identifiers, so we can't check the kind.
+ if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
+ // Handle "defined X" and "defined(X)".
+ if (II->isStr("defined"))
+ return EvaluateDefined(Result, PeekTok, DT, ValueLive, PP);
+
+ if (!II->isCPlusPlusOperatorKeyword()) {
+ // If this identifier isn't 'defined' or one of the special
+ // preprocessor keywords and it wasn't macro expanded, it turns
+ // into a simple 0
+ if (ValueLive)
+ PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
+ Result.Val = 0;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setIdentifier(II);
+ Result.setRange(PeekTok.getLocation());
+ DT.IncludedUndefinedIds = true;
+ PP.LexNonComment(PeekTok);
+ return false;
+ }
+ }
PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr);
return true;
case tok::eod:
@@ -481,6 +478,14 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
DT.State = DefinedTracker::DefinedMacro;
return false;
}
+ case tok::kw_true:
+ case tok::kw_false:
+ Result.Val = PeekTok.getKind() == tok::kw_true;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setIdentifier(PeekTok.getIdentifierInfo());
+ Result.setRange(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ return false;
// FIXME: Handle #assert
}
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 63f39524d12..d1dc8e1c001 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -712,14 +712,6 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
II.setIsFutureCompatKeyword(false);
}
- // C++ 2.11p2: If this is an alternative representation of a C++ operator,
- // then we act as if it is the actual operator and not the textual
- // representation of it.
- if (II.isCPlusPlusOperatorKeyword() &&
- !(getLangOpts().MSVCCompat &&
- getSourceManager().isInSystemHeader(Identifier.getLocation())))
- Identifier.setIdentifierInfo(nullptr);
-
// If this is an extension token, diagnose its use.
// We avoid diagnosing tokens that originate from macro definitions.
// FIXME: This warning is disabled in cases where it shouldn't be,
diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp
index 74f4bb3268d..c796eded1f0 100644
--- a/clang/test/Parser/MicrosoftExtensions.cpp
+++ b/clang/test/Parser/MicrosoftExtensions.cpp
@@ -261,9 +261,7 @@ int __identifier(else} = __identifier(for); // expected-error {{missing ')' afte
#define identifier_weird(x) __identifier(x
int k = identifier_weird(if)); // expected-error {{use of undeclared identifier 'if'}}
-// This is a bit weird, but the alternative tokens aren't keywords, and this
-// behavior matches MSVC. FIXME: Consider supporting this anyway.
-extern int __identifier(and) r; // expected-error {{cannot convert '&&' token to an identifier}}
+extern int __identifier(and);
void f() {
__identifier(() // expected-error {{cannot convert '(' token to an identifier}}
diff --git a/clang/test/Preprocessor/cxx_oper_keyword.cpp b/clang/test/Preprocessor/cxx_oper_keyword.cpp
index 89a094d073c..a66e8904973 100644
--- a/clang/test/Preprocessor/cxx_oper_keyword.cpp
+++ b/clang/test/Preprocessor/cxx_oper_keyword.cpp
@@ -29,3 +29,15 @@
#ifdef and
#warning and is defined
#endif
+
+#ifdef OPERATOR_NAMES
+//expected-error@+2 {{invalid token at start of a preprocessor expression}}
+#endif
+#if or
+#endif
+
+#ifdef OPERATOR_NAMES
+//expected-error@+2 {{invalid token at start of a preprocessor expression}}
+#endif
+#if and_eq
+#endif
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 937362f5c9d..eb7bcc1ed8f 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -333,6 +333,16 @@ TEST_F(FormatTest, RecognizesBinaryOperatorKeywords) {
verifyFormat("x = (a) xor (b);");
}
+TEST_F(FormatTest, RecognizesUnaryOperatorKeywords) {
+ verifyFormat("x = compl(a);");
+ verifyFormat("x = not(a);");
+ verifyFormat("x = bitand(a);");
+ // Unary operator must not be merged with the next identifier
+ verifyFormat("x = compl a;");
+ verifyFormat("x = not a;");
+ verifyFormat("x = bitand a;");
+}
+
//===----------------------------------------------------------------------===//
// Tests for control statements.
//===----------------------------------------------------------------------===//
OpenPOWER on IntegriCloud