static constexpr int ObjCOrBuiltinIDBits = 16;
+/// The "layout" of ObjCOrBuiltinID is:
+/// - The first value (0) represents "not a special identifier".
+/// - The next (NUM_OBJC_KEYWORDS - 1) values represent ObjCKeywordKinds (not
+/// including objc_not_keyword).
+/// - The next (NUM_INTERESTING_IDENTIFIERS - 1) values represent
+/// InterestingIdentifierKinds (not including not_interesting).
+/// - The rest of the values represent builtin IDs (not including NotBuiltin).
+static constexpr int FirstObjCKeywordID = 1;
+static constexpr int LastObjCKeywordID =
+ FirstObjCKeywordID + tok::NUM_OBJC_KEYWORDS - 2;
+static constexpr int FirstInterestingIdentifierID = LastObjCKeywordID + 1;
+static constexpr int LastInterestingIdentifierID =
+ FirstInterestingIdentifierID + tok::NUM_INTERESTING_IDENTIFIERS - 2;
+static constexpr int FirstBuiltinID = LastInterestingIdentifierID + 1;
+
/// One of these records is kept for each identifier that
/// is lexed. This contains information about whether the token was \#define'd,
/// is a language keyword, or if it is a front-end token of some sort (e.g. a
///
/// For example, 'class' will return tok::objc_class if ObjC is enabled.
tok::ObjCKeywordKind getObjCKeywordID() const {
- if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS)
+ static_assert(FirstObjCKeywordID == 1,
+ "hard-coding this assumption to simplify code");
+ if (ObjCOrBuiltinID <= LastObjCKeywordID)
return tok::ObjCKeywordKind(ObjCOrBuiltinID);
else
return tok::objc_not_keyword;
///
/// 0 is not-built-in. 1+ are specific builtin functions.
unsigned getBuiltinID() const {
- if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS)
- return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS;
+ if (ObjCOrBuiltinID >= FirstBuiltinID)
+ return 1 + (ObjCOrBuiltinID - FirstBuiltinID);
else
return 0;
}
void setBuiltinID(unsigned ID) {
- ObjCOrBuiltinID = ID + tok::NUM_OBJC_KEYWORDS;
- assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID
- && "ID too large for field!");
+ assert(ID != 0);
+ ObjCOrBuiltinID = FirstBuiltinID + (ID - 1);
+ assert(getBuiltinID() == ID && "ID too large for field!");
+ }
+ void clearBuiltinID() { ObjCOrBuiltinID = 0; }
+
+ tok::InterestingIdentifierKind getInterestingIdentifierID() const {
+ if (ObjCOrBuiltinID >= FirstInterestingIdentifierID &&
+ ObjCOrBuiltinID <= LastInterestingIdentifierID)
+ return tok::InterestingIdentifierKind(
+ 1 + (ObjCOrBuiltinID - FirstInterestingIdentifierID));
+ else
+ return tok::not_interesting;
+ }
+ void setInterestingIdentifierID(unsigned ID) {
+ assert(ID != tok::not_interesting);
+ ObjCOrBuiltinID = FirstInterestingIdentifierID + (ID - 1);
+ assert(getInterestingIdentifierID() == ID && "ID too large for field!");
}
unsigned getObjCOrBuiltinID() const { return ObjCOrBuiltinID; }
#ifndef PRAGMA_ANNOTATION
#define PRAGMA_ANNOTATION(X) ANNOTATION(X)
#endif
+#ifndef INTERESTING_IDENTIFIER
+#define INTERESTING_IDENTIFIER(X)
+#endif
//===----------------------------------------------------------------------===//
// Preprocessor keywords.
OBJC_AT_KEYWORD(import)
OBJC_AT_KEYWORD(available)
+//===----------------------------------------------------------------------===//
+// Interesting idenitifiers.
+//===----------------------------------------------------------------------===//
+INTERESTING_IDENTIFIER(not_interesting)
+INTERESTING_IDENTIFIER(FILE)
+INTERESTING_IDENTIFIER(jmp_buf)
+INTERESTING_IDENTIFIER(sigjmp_buf)
+INTERESTING_IDENTIFIER(ucontext_t)
+
// TODO: What to do about context-sensitive keywords like:
// bycopy/byref/in/inout/oneway/out?
#undef TOK
#undef C99_KEYWORD
#undef C2X_KEYWORD
+#undef INTERESTING_IDENTIFIER
NUM_OBJC_KEYWORDS
};
+/// Provides a namespace for interesting identifers such as float_t and
+/// double_t.
+enum InterestingIdentifierKind {
+#define INTERESTING_IDENTIFIER(X) X,
+#include "clang/Basic/TokenKinds.def"
+ NUM_INTERESTING_IDENTIFIERS
+};
+
/// Defines the possible values of an on-off-switch (C99 6.10.6p2).
enum OnOffSwitch {
OOS_ON, OOS_OFF, OOS_DEFAULT
unsigned ID = NameIt->second->getBuiltinID();
if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) &&
isInStdNamespace(ID) == InStdNamespace) {
- Table.get(Name).setBuiltinID(Builtin::NotBuiltin);
+ NameIt->second->clearBuiltinID();
}
}
}
Table.get(Name).setObjCKeywordID(ObjCID);
}
+static void AddInterestingIdentifier(StringRef Name,
+ tok::InterestingIdentifierKind BTID,
+ IdentifierTable &Table) {
+ // Don't add 'not_interesting' identifier.
+ if (BTID != tok::not_interesting) {
+ IdentifierInfo &Info = Table.get(Name, tok::identifier);
+ Info.setInterestingIdentifierID(BTID);
+ }
+}
+
/// AddKeywords - Add all keywords to the symbol table.
///
void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
#define OBJC_AT_KEYWORD(NAME) \
if (LangOpts.ObjC) \
AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
+#define INTERESTING_IDENTIFIER(NAME) \
+ AddInterestingIdentifier(StringRef(#NAME), tok::NAME, *this);
+
#define TESTING_KEYWORD(NAME, FLAGS)
#include "clang/Basic/TokenKinds.def"
if (IdentifierInfo *II = NewTD->getIdentifier())
if (!NewTD->isInvalidDecl() &&
NewTD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
- if (II->isStr("FILE"))
+ switch (II->getInterestingIdentifierID()) {
+ case tok::InterestingIdentifierKind::FILE:
Context.setFILEDecl(NewTD);
- else if (II->isStr("jmp_buf"))
+ break;
+ case tok::InterestingIdentifierKind::jmp_buf:
Context.setjmp_bufDecl(NewTD);
- else if (II->isStr("sigjmp_buf"))
+ break;
+ case tok::InterestingIdentifierKind::sigjmp_buf:
Context.setsigjmp_bufDecl(NewTD);
- else if (II->isStr("ucontext_t"))
+ break;
+ case tok::InterestingIdentifierKind::ucontext_t:
Context.setucontext_tDecl(NewTD);
+ break;
+ default:
+ break;
+ }
}
return NewTD;