Tighten up the conditions under which we consider ourselves to be

entering the context of a nested-name-specifier. Fixes
<rdar://problem/10397846>.

llvm-svn: 143967
This commit is contained in:
Douglas Gregor 2011-11-07 17:33:42 +00:00
parent 7635bb7ae2
commit df593fbeda
7 changed files with 56 additions and 17 deletions

View File

@ -1997,6 +1997,7 @@ private:
DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none,
bool EnteringContext = false,
bool SuppressDeclarations = false);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);

View File

@ -1652,6 +1652,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.SetRangeEnd(Tok.getLocation());
}
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
while (1) {
bool isInvalid = false;
const char *PrevSpec = 0;
@ -2208,7 +2209,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS);
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, EnteringContext);
continue;
}
@ -2500,6 +2501,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none,
/*EnteringContext=*/false,
SuppressDeclarations);
return true;
}
@ -2862,7 +2864,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// if a fixed underlying type is allowed.
ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false))
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/false))
return;
if (SS.isSet() && Tok.isNot(tok::identifier)) {
@ -3483,7 +3486,8 @@ bool Parser::isConstructorDeclarator() {
// Parse the C++ scope specifier.
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true)) {
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/true)) {
TPA.Revert();
return false;
}
@ -3681,8 +3685,10 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
if (getLang().CPlusPlus &&
(Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
Tok.is(tok::annot_cxxscope))) {
bool EnteringContext = D.getContext() == Declarator::FileContext ||
D.getContext() == Declarator::MemberContext;
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true); // ignore fail
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext);
if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
@ -3848,7 +3854,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (getLang().CPlusPlus && D.mayHaveIdentifier()) {
// ParseDeclaratorInternal might already have parsed the scope.
if (D.getCXXScopeSpec().isEmpty()) {
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), true);
bool EnteringContext = D.getContext() == Declarator::FileContext ||
D.getContext() == Declarator::MemberContext;
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(),
EnteringContext);
}
if (D.getCXXScopeSpec().isValid()) {

View File

@ -234,7 +234,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
@ -382,7 +382,7 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
IdentifierInfo *NamespcName = 0;
SourceLocation IdentLoc = SourceLocation();
@ -450,7 +450,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
IsTypeName = false;
// Parse nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
// Check nested-name specifier.
if (SS.isInvalid()) {
@ -876,7 +876,9 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS, bool SuppressDeclarations){
AccessSpecifier AS,
bool EnteringContext,
bool SuppressDeclarations){
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@ -955,7 +957,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// "FOO : BAR" is not a potential typo for "FOO::BAR".
ColonProtectionRAIIObject X(*this);
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true))
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
DS.SetTypeSpecError();
if (SS.isSet())
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
@ -1637,7 +1639,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (isAccessDecl) {
// Collect the scope specifier token we annotated earlier.
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/false);
// Try to parse an unqualified-id.
UnqualifiedId Name;
@ -2335,7 +2338,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
ParsedType TemplateTypeTy;
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);

View File

@ -974,7 +974,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// type, translate it into a type and continue parsing as a
// cast expression.
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/false);
AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
@ -1333,7 +1334,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (LHS.isInvalid())
break;
ParseOptionalCXXScopeSpecifier(SS, ObjectType, false,
ParseOptionalCXXScopeSpecifier(SS, ObjectType,
/*EnteringContext=*/false,
&MayBePseudoDestructor);
if (SS.isNotEmpty())
ObjectType = ParsedType();

View File

@ -487,7 +487,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
// '::' unqualified-id
//
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
UnqualifiedId Name;
if (ParseUnqualifiedId(SS,

View File

@ -1205,7 +1205,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
// simple-template-id
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false,
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(),
/*EnteringContext=*/false,
0, /*IsTypename*/true))
return true;
if (!SS.isSet()) {
@ -1484,7 +1485,8 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
}
// Parse nested-name-specifier.
ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(), false);
ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(),
/*EnteringContext=*/false);
// Check nested-name specifier.
if (Result.SS.isInvalid()) {

View File

@ -118,3 +118,25 @@ namespace AliasTagDef {
int m = F<int>::S().g();
int n = F<int>::U().g();
}
namespace rdar10397846 {
template<int I> struct A
{
struct B
{
struct C { C() { int *ptr = I; } }; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
};
};
template<int N> void foo()
{
class A<N>::B::C X; // expected-note{{in instantiation of member function}}
int A<N+1>::B::C::*member = 0;
}
void bar()
{
foo<0>();
foo<1>(); // expected-note{{in instantiation of function template}}
}
}