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:
parent
fdf98763ac
commit
8bea83a866
|
@ -164,6 +164,10 @@ class Parser : public CodeCompletionHandler {
|
||||||
mutable IdentifierInfo *Ident_final;
|
mutable IdentifierInfo *Ident_final;
|
||||||
mutable IdentifierInfo *Ident_override;
|
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> AlignHandler;
|
||||||
OwningPtr<PragmaHandler> GCCVisibilityHandler;
|
OwningPtr<PragmaHandler> GCCVisibilityHandler;
|
||||||
OwningPtr<PragmaHandler> OptionsHandler;
|
OwningPtr<PragmaHandler> OptionsHandler;
|
||||||
|
|
|
@ -719,22 +719,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
|
||||||
// "struct __is_empty" parsing hack hasn't been needed in this
|
// "struct __is_empty" parsing hack hasn't been needed in this
|
||||||
// translation unit. If it has, __is_empty reverts to a normal
|
// translation unit. If it has, __is_empty reverts to a normal
|
||||||
// identifier and __has_feature(is_empty) evaluates false.
|
// identifier and __has_feature(is_empty) evaluates false.
|
||||||
.Case("is_empty",
|
.Case("is_empty", LangOpts.CPlusPlus)
|
||||||
LangOpts.CPlusPlus &&
|
|
||||||
PP.getIdentifierInfo("__is_empty")->getTokenID()
|
|
||||||
!= tok::identifier)
|
|
||||||
.Case("is_enum", LangOpts.CPlusPlus)
|
.Case("is_enum", LangOpts.CPlusPlus)
|
||||||
.Case("is_final", LangOpts.CPlusPlus)
|
.Case("is_final", LangOpts.CPlusPlus)
|
||||||
.Case("is_literal", LangOpts.CPlusPlus)
|
.Case("is_literal", LangOpts.CPlusPlus)
|
||||||
.Case("is_standard_layout", LangOpts.CPlusPlus)
|
.Case("is_standard_layout", LangOpts.CPlusPlus)
|
||||||
// __is_pod is available only if the horrible
|
.Case("is_pod", LangOpts.CPlusPlus)
|
||||||
// "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_polymorphic", LangOpts.CPlusPlus)
|
.Case("is_polymorphic", LangOpts.CPlusPlus)
|
||||||
.Case("is_trivial", LangOpts.CPlusPlus)
|
.Case("is_trivial", LangOpts.CPlusPlus)
|
||||||
.Case("is_trivially_assignable", LangOpts.CPlusPlus)
|
.Case("is_trivially_assignable", LangOpts.CPlusPlus)
|
||||||
|
|
|
@ -741,6 +741,55 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
// Avoid the unnecessary parse-time lookup in the common case
|
// Avoid the unnecessary parse-time lookup in the common case
|
||||||
// where the syntax forbids a type.
|
// where the syntax forbids a type.
|
||||||
const Token &Next = NextToken();
|
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) ||
|
if (Next.is(tok::coloncolon) ||
|
||||||
(!ColonIsSacred && Next.is(tok::colon)) ||
|
(!ColonIsSacred && Next.is(tok::colon)) ||
|
||||||
Next.is(tok::less) ||
|
Next.is(tok::less) ||
|
||||||
|
@ -758,7 +807,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
// '.'.
|
// '.'.
|
||||||
IdentifierInfo &II = *Tok.getIdentifierInfo();
|
IdentifierInfo &II = *Tok.getIdentifierInfo();
|
||||||
SourceLocation ILoc = ConsumeToken();
|
SourceLocation ILoc = ConsumeToken();
|
||||||
|
|
||||||
// Support 'Class.property' and 'super.property' notation.
|
// Support 'Class.property' and 'super.property' notation.
|
||||||
if (getLangOpts().ObjC1 && Tok.is(tok::period) &&
|
if (getLangOpts().ObjC1 && Tok.is(tok::period) &&
|
||||||
(Actions.getTypeName(II, ILoc, getCurScope()) ||
|
(Actions.getTypeName(II, ILoc, getCurScope()) ||
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct __is_pod {
|
struct __is_pod {
|
||||||
|
__is_pod() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
__is_pod<int> ipi;
|
__is_pod<int> ipi;
|
||||||
|
@ -28,6 +29,13 @@ struct test_is_signed {
|
||||||
|
|
||||||
bool check_signed = test_is_signed::__is_signed;
|
bool check_signed = test_is_signed::__is_signed;
|
||||||
|
|
||||||
#if __has_feature(is_pod)
|
template<bool B> struct must_be_true {};
|
||||||
# error __is_pod won't work now anyway
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue