Extend the "__is_pod" hack, which demotes various type trait keywords

(__is_pod, __is_signed, etc.) to normal identifiers if they are
encountered in certain places in the grammar where we know that prior
versions of libstdc++ or libc++ use them, to still allow the use of
these keywords as type traits. Fixes <rdar://problem/9836262> and PR10184.

llvm-svn: 162937
This commit is contained in:
Douglas Gregor 2012-08-30 20:04:43 +00:00
parent fdf98763ac
commit 8bea83a866
4 changed files with 66 additions and 15 deletions

View File

@ -164,6 +164,10 @@ class Parser : public CodeCompletionHandler {
mutable IdentifierInfo *Ident_final;
mutable IdentifierInfo *Ident_override;
// C++ type trait keywords that have can be reverted to identifiers and
// still used as type traits.
llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertableTypeTraits;
OwningPtr<PragmaHandler> AlignHandler;
OwningPtr<PragmaHandler> GCCVisibilityHandler;
OwningPtr<PragmaHandler> OptionsHandler;

View File

@ -719,22 +719,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
// "struct __is_empty" parsing hack hasn't been needed in this
// translation unit. If it has, __is_empty reverts to a normal
// identifier and __has_feature(is_empty) evaluates false.
.Case("is_empty",
LangOpts.CPlusPlus &&
PP.getIdentifierInfo("__is_empty")->getTokenID()
!= tok::identifier)
.Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_final", LangOpts.CPlusPlus)
.Case("is_literal", LangOpts.CPlusPlus)
.Case("is_standard_layout", LangOpts.CPlusPlus)
// __is_pod is available only if the horrible
// "struct __is_pod" parsing hack hasn't been needed in this
// translation unit. If it has, __is_pod reverts to a normal
// identifier and __has_feature(is_pod) evaluates false.
.Case("is_pod",
LangOpts.CPlusPlus &&
PP.getIdentifierInfo("__is_pod")->getTokenID()
!= tok::identifier)
.Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
.Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_trivially_assignable", LangOpts.CPlusPlus)

View File

@ -741,6 +741,55 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// Avoid the unnecessary parse-time lookup in the common case
// where the syntax forbids a type.
const Token &Next = NextToken();
// 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 revertable type traits, for future use.
if (RevertableTypeTraits.empty()) {
#define RTT_JOIN2(X) X
#define RTT_JOIN(X,Y) X##Y
#define REVERTABLE_TYPE_TRAIT(Name) \
RevertableTypeTraits[PP.getIdentifierInfo(#Name)] \
= RTT_JOIN(tok::kw_,Name)
REVERTABLE_TYPE_TRAIT(__is_arithmetic);
REVERTABLE_TYPE_TRAIT(__is_convertible);
REVERTABLE_TYPE_TRAIT(__is_empty);
REVERTABLE_TYPE_TRAIT(__is_floating_point);
REVERTABLE_TYPE_TRAIT(__is_function);
REVERTABLE_TYPE_TRAIT(__is_fundamental);
REVERTABLE_TYPE_TRAIT(__is_integral);
REVERTABLE_TYPE_TRAIT(__is_member_function_pointer);
REVERTABLE_TYPE_TRAIT(__is_member_pointer);
REVERTABLE_TYPE_TRAIT(__is_pod);
REVERTABLE_TYPE_TRAIT(__is_pointer);
REVERTABLE_TYPE_TRAIT(__is_same);
REVERTABLE_TYPE_TRAIT(__is_scalar);
REVERTABLE_TYPE_TRAIT(__is_signed);
REVERTABLE_TYPE_TRAIT(__is_unsigned);
REVERTABLE_TYPE_TRAIT(__is_void);
#undef REVERTABLE_TYPE_TRAIT
#undef RTT_JOIN2
#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
= RevertableTypeTraits.find(II);
if (Known != RevertableTypeTraits.end()) {
Tok.setKind(Known->second);
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
}
}
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
Next.is(tok::less) ||
@ -758,7 +807,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// '.'.
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation ILoc = ConsumeToken();
// Support 'Class.property' and 'super.property' notation.
if (getLangOpts().ObjC1 && Tok.is(tok::period) &&
(Actions.getTypeName(II, ILoc, getCurScope()) ||

View File

@ -8,6 +8,7 @@
template<typename T>
struct __is_pod {
__is_pod() {}
};
__is_pod<int> ipi;
@ -28,6 +29,13 @@ struct test_is_signed {
bool check_signed = test_is_signed::__is_signed;
#if __has_feature(is_pod)
# error __is_pod won't work now anyway
template<bool B> struct must_be_true {};
template<> struct must_be_true<false>;
void foo() {
bool b = __is_pod(int);
must_be_true<__is_pod(int)> mbt;
}
#if !__has_feature(is_pod)
# error __is_pod should still be available.
#endif