From df593fbedaafde7e4a42785ba50c969587b6e290 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 7 Nov 2011 17:33:42 +0000 Subject: [PATCH] Tighten up the conditions under which we consider ourselves to be entering the context of a nested-name-specifier. Fixes . llvm-svn: 143967 --- clang/include/clang/Parse/Parser.h | 1 + clang/lib/Parse/ParseDecl.cpp | 19 +++++++++++----- clang/lib/Parse/ParseDeclCXX.cpp | 17 ++++++++------ clang/lib/Parse/ParseExpr.cpp | 6 +++-- clang/lib/Parse/ParseExprCXX.cpp | 2 +- clang/lib/Parse/Parser.cpp | 6 +++-- .../SemaTemplate/instantiate-member-class.cpp | 22 +++++++++++++++++++ 7 files changed, 56 insertions(+), 17 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 673b5df09335..dba7ffb47880 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 07a52586e9f8..3bddd3de13d0 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -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()) { diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 1ba1cbfbd66d..721d185f5392 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -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); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index f77d8eaf2a18..4b8fd76269ab 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -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(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 2bfb6158739f..dfc77e17d495 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -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, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index fabb8e2a594a..6e84e4296846 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -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()) { diff --git a/clang/test/SemaTemplate/instantiate-member-class.cpp b/clang/test/SemaTemplate/instantiate-member-class.cpp index c67eb4022a47..bb6427670c3e 100644 --- a/clang/test/SemaTemplate/instantiate-member-class.cpp +++ b/clang/test/SemaTemplate/instantiate-member-class.cpp @@ -118,3 +118,25 @@ namespace AliasTagDef { int m = F::S().g(); int n = F::U().g(); } + +namespace rdar10397846 { + template 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 void foo() + { + class A::B::C X; // expected-note{{in instantiation of member function}} + int A::B::C::*member = 0; + } + + void bar() + { + foo<0>(); + foo<1>(); // expected-note{{in instantiation of function template}} + } +}