aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--include/clang/Parse/Action.h130
-rw-r--r--include/clang/Parse/Parser.h8
-rw-r--r--lib/Parse/MinimalAction.cpp5
-rw-r--r--lib/Parse/ParseDecl.cpp9
-rw-r--r--lib/Parse/ParseDeclCXX.cpp13
-rw-r--r--lib/Parse/ParseExpr.cpp17
-rw-r--r--lib/Parse/ParseExprCXX.cpp52
-rw-r--r--lib/Parse/Parser.cpp13
-rw-r--r--lib/Sema/Sema.h33
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp238
-rw-r--r--lib/Sema/SemaExprCXX.cpp42
-rw-r--r--lib/Sema/SemaLookup.cpp41
-rw-r--r--lib/Sema/SemaTemplate.cpp326
-rw-r--r--lib/Sema/TreeTransform.h13
-rw-r--r--test/SemaCXX/nested-name-spec.cpp2
-rw-r--r--test/SemaCXX/qual-id-test.cpp41
-rw-r--r--test/SemaTemplate/member-function-template.cpp1
18 files changed, 644 insertions, 346 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index e29e6ab4c7..a5d318eb25 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -366,6 +366,12 @@ def note_previous_access_declaration : Note<
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
"incomplete type %0 named in nested name specifier">;
+def err_nested_name_member_ref_lookup_ambiguous : Error<
+ "lookup of %0 in member access expression is ambiguous">;
+def note_ambig_member_ref_object_type : Note<
+ "lookup in the object type %0 refers here">;
+def note_ambig_member_ref_scope : Note<
+ "lookup from the current scope refers here">;
// C++ class members
def err_storageclass_invalid_for_member : Error<
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 0c70441083..31acc87cb4 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -209,10 +209,12 @@ public:
/// \brief Determine whether the given identifier refers to the name of a
/// template.
///
+ /// \param S the scope in which name lookup occurs
+ ///
/// \param II the identifier that we are querying to determine whether it
/// is a template.
///
- /// \param S the scope in which name lookup occurs
+ /// \param IdLoc the source location of the identifier
///
/// \param SS the C++ scope specifier that precedes the template name, if
/// any.
@@ -224,8 +226,11 @@ public:
/// of the template that the name refers to.
///
/// \returns the kind of template that this name refers to.
- virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+ virtual TemplateNameKind isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template) = 0;
@@ -236,17 +241,39 @@ public:
return 0;
}
- /// ActOnCXXNestedNameSpecifier - Called during parsing of a
- /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
- /// we want to resolve "bar::". 'SS' is empty or the previously parsed
- /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
- /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
- /// Returns a CXXScopeTy* object representing the C++ scope.
+ /// \brief Parsed an identifier followed by '::' in a C++
+ /// nested-name-specifier.
+ ///
+ /// \param S the scope in which the nested-name-specifier was parsed.
+ ///
+ /// \param SS the nested-name-specifier that precedes the identifier. For
+ /// example, if we are parsing "foo::bar::", \p SS will describe the "foo::"
+ /// that has already been parsed.
+ ///
+ /// \param IdLoc the location of the identifier we have just parsed (e.g.,
+ /// the "bar" in "foo::bar::".
+ ///
+ /// \param CCLoc the location of the '::' at the end of the
+ /// nested-name-specifier.
+ ///
+ /// \param II the identifier that represents the scope that this
+ /// nested-name-specifier refers to, e.g., the "bar" in "foo::bar::".
+ ///
+ /// \param ObjectType if this nested-name-specifier occurs as part of a
+ /// C++ member access expression such as "x->Base::f", the type of the base
+ /// object (e.g., *x in the example, if "x" were a pointer).
+ ///
+ /// \param EnteringContext if true, then we intend to immediately enter the
+ /// context of this nested-name-specifier, e.g., for an out-of-line
+ /// definition of a class member.
+ ///
+ /// \returns a CXXScopeTy* object representing the C++ scope.
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
+ TypeTy *ObjectType,
bool EnteringContext) {
return 0;
}
@@ -267,27 +294,6 @@ public:
return 0;
}
- /// ActOnCXXEnterMemberScope - Called when a C++ class member accessor ('.'
- /// or '->') is parsed. After this method is called, according to
- /// [C++ 3.4.5p4], qualified-ids should be looked up in the contexts of both
- /// the entire postfix-expression and the scope of the class of the object
- /// expression.
- /// 'SS' should be an empty CXXScopeSpec to be filled with the class's scope.
- virtual OwningExprResult ActOnCXXEnterMemberScope(Scope *S,
- CXXScopeSpec &SS,
- ExprArg Base,
- tok::TokenKind OpKind) {
- return ExprEmpty();
- }
-
- /// ActOnCXXExitMemberScope - Called when a postfix-expression that previously
- /// invoked ActOnCXXEnterMemberScope() is finished. 'SS' is the same
- /// CXXScopeSpec that was passed to ActOnCXXEnterMemberScope. Used to
- /// indicate that names should revert to being looked up in the defining
- /// scope.
- virtual void ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS) {
- }
-
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
@@ -1280,6 +1286,31 @@ public:
return ExprEmpty();
}
+ /// \brief Invoked when the parser is starting to parse a C++ member access
+ /// expression such as x.f or x->f.
+ ///
+ /// \param S the scope in which the member access expression occurs.
+ ///
+ /// \param Base the expression in which a member is being accessed, e.g., the
+ /// "x" in "x.f".
+ ///
+ /// \param OpLoc the location of the member access operator ("." or "->")
+ ///
+ /// \param OpKind the kind of member access operator ("." or "->")
+ ///
+ /// \param ObjectType originally NULL. The action should fill in this type
+ /// with the type into which name lookup should look to find the member in
+ /// the member access expression.
+ ///
+ /// \returns the (possibly modified) \p Base expression
+ virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
+ ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ TypeTy *&ObjectType) {
+ return ExprEmpty();
+ }
+
/// ActOnDestructorReferenceExpr - Parsed a destructor reference, for example:
///
/// t->~T();
@@ -1597,10 +1628,26 @@ public:
/// example, given "MetaFun::template apply", the scope specifier \p
/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
+ ///
+ /// \param TemplateKWLoc the location of the "template" keyword (if any).
+ ///
+ /// \param Name the name of the template (an identifier)
+ ///
+ /// \param NameLoc the location of the identifier
+ ///
+ /// \param SS the nested-name-specifier that precedes the "template" keyword
+ /// or the template name. FIXME: If the dependent template name occurs in
+ /// a member access expression, e.g., "x.template f<T>", this
+ /// nested-name-specifier will be empty.
+ ///
+ /// \param ObjectType if this dependent template name occurs in the
+ /// context of a member access expression, the type of the object being
+ /// accessed.
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
- const CXXScopeSpec &SS) {
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType) {
return TemplateTy();
}
@@ -2128,26 +2175,11 @@ public:
virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
const CXXScopeSpec *SS);
- /// \brief Determine whether the given identifier refers to the name of a
- /// template.
- ///
- /// \param II the identifier that we are querying to determine whether it
- /// is a template.
- ///
- /// \param S the scope in which name lookup occurs
- ///
- /// \param SS the C++ scope specifier that precedes the template name, if
- /// any.
- ///
- /// \param EnteringContext whether we are potentially entering the context
- /// referred to by the scope specifier \p SS
- ///
- /// \param Template if the name does refer to a template, the declaration
- /// of the template that the name refers to.
- ///
- /// \returns the kind of template that this name refers to.
- virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+ virtual TemplateNameKind isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index e366c2f256..641b09947b 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -770,13 +770,9 @@ private:
// C++ Expressions
OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
- /// ParseOptionalCXXScopeSpecifier - Parse global scope or
- /// nested-name-specifier if present. Returns true if a nested-name-specifier
- /// was parsed from the token stream. Note that this routine will not parse
- /// ::new or ::delete, it will just leave them in the token stream.
- ///
bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
- bool EnteringContext = false);
+ TypeTy *ObjectType,
+ bool EnteringContext);
//===--------------------------------------------------------------------===//
// C++ 5.2p1: C++ Casts
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index ee23c0038a..d89cc8c3ea 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -160,8 +160,11 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
}
TemplateNameKind
-MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
+MinimalAction::isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
bool EnteringScope,
TemplateTy &TemplateDecl) {
return TNK_Non_template;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 25bed0937b..25ff53ca9f 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -743,7 +743,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, true);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
AnnotateTemplateIdTokenAsType(&SS);
@@ -1596,7 +1596,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Attr = ParseAttributes();
CXXScopeSpec SS;
- if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
+ if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
if (Tok.isNot(tok::l_brace)) {
@@ -2034,7 +2034,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
(Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
Tok.is(tok::annot_cxxscope))) {
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, true)) {
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) {
if(Tok.isNot(tok::star)) {
// The scope spec really belongs to the direct-declarator.
D.getCXXScopeSpec() = SS;
@@ -2191,7 +2191,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (D.mayHaveIdentifier()) {
// ParseDeclaratorInternal might already have parsed the scope.
bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
- ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), true);
+ ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
+ true);
if (afterCXXScope) {
// Change the declaration context for name lookup, until this function
// is exited (and the declarator has been parsed).
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 31926ce0f5..f50147c599 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -117,7 +117,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
@@ -216,7 +216,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
AttributeList *AttrList = 0;
IdentifierInfo *NamespcName = 0;
@@ -273,7 +273,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
IsTypeName = false;
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
AttributeList *AttrList = 0;
@@ -538,7 +538,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Parse the (optional) nested-name-specifier.
CXXScopeSpec SS;
- if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, true))
+ if (getLang().CPlusPlus &&
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true))
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
Diag(Tok, diag::err_expected_ident);
@@ -813,7 +814,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
// Parse optional '::' and optional nested-name-specifier.
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, true);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
// The location of the base class itself.
SourceLocation BaseLoc = Tok.getLocation();
@@ -1299,7 +1300,7 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
TypeTy *TemplateTypeTy = 0;
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 36b6dd4a93..8fca14ff98 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -923,14 +923,14 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
tok::TokenKind OpKind = Tok.getKind();
SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token.
- CXXScopeSpec MemberSS;
CXXScopeSpec SS;
+ Action::TypeTy *ObjectType = 0;
if (getLang().CPlusPlus && !LHS.isInvalid()) {
- LHS = Actions.ActOnCXXEnterMemberScope(CurScope, MemberSS, move(LHS),
- OpKind);
+ LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS),
+ OpLoc, OpKind, ObjectType);
if (LHS.isInvalid())
break;
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, ObjectType, false);
}
if (Tok.is(tok::identifier)) {
@@ -947,8 +947,6 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
ConsumeToken();
if (!Tok.is(tok::identifier)) {
- if (getLang().CPlusPlus)
- Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
Diag(Tok, diag::err_expected_ident);
return ExprError();
}
@@ -980,8 +978,6 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
Tok.getLocation(),
ConvType, &SS);
} else {
- if (getLang().CPlusPlus)
- Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
// Don't emit a diagnostic; ParseConversionFunctionId does it for us
return ExprError();
}
@@ -1007,14 +1003,9 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
}
ConsumeToken();
} else {
- if (getLang().CPlusPlus)
- Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
Diag(Tok, diag::err_expected_ident);
return ExprError();
}
-
- if (getLang().CPlusPlus)
- Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
break;
}
case tok::plusplus: // postfix-expression: postfix-expression '++'
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index e9cca9fe1d..4cd952e393 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -16,10 +16,11 @@
#include "clang/Parse/DeclSpec.h"
using namespace clang;
-/// ParseOptionalCXXScopeSpecifier - Parse global scope or
-/// nested-name-specifier if present. Returns true if a nested-name-specifier
-/// was parsed from the token stream. Note that this routine will not parse
-/// ::new or ::delete, it will just leave them in the token stream.
+/// \brief Parse global scope or nested-name-specifier if present.
+///
+/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
+/// may be preceded by '::'). Note that this routine will not parse ::new or
+/// ::delete; it will just leave them in the token stream.
///
/// '::'[opt] nested-name-specifier
/// '::'
@@ -28,9 +29,22 @@ using namespace clang;
/// type-name '::'
/// namespace-name '::'
/// nested-name-specifier identifier '::'
-/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+/// nested-name-specifier 'template'[opt] simple-template-id '::'
+///
+///
+/// \param SS the scope specifier that will be set to the parsed
+/// nested-name-specifier (or empty)
+///
+/// \param ObjectType if this nested-name-specifier is being parsed following
+/// the "." or "->" of a member access expression, this parameter provides the
+/// type of the object whose members are being accessed.
///
+/// \param EnteringContext whether we will be entering into the context of
+/// the nested-name-specifier after parsing it.
+///
+/// \returns true if a scope specifier was parsed.
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
+ Action::TypeTy *ObjectType,
bool EnteringContext) {
assert(getLang().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
@@ -59,16 +73,28 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
}
while (true) {
+ if (HasScopeSpecifier) {
+ // C++ [basic.lookup.classref]p5:
+ // If the qualified-id has the form
+ // ::class-name-or-namespace-name::...
+ // the class-name-or-namespace-name is looked up in global scope as a
+ // class-name or namespace-name.
+ //
+ // To implement this, we clear out the object type as soon as we've
+ // seen a leading '::' or part of a nested-name-specifier.
+ ObjectType = 0;
+ }
+
// nested-name-specifier:
// nested-name-specifier 'template'[opt] simple-template-id '::'
// Parse the optional 'template' keyword, then make sure we have
// 'identifier <' after it.
if (Tok.is(tok::kw_template)) {
- // If we don't have a scope specifier, this isn't a
+ // If we don't have a scope specifier or an object type, this isn't a
// nested-name-specifier, since they aren't allowed to start with
// 'template'.
- if (!HasScopeSpecifier)
+ if (!HasScopeSpecifier && !ObjectType)
break;
SourceLocation TemplateKWLoc = ConsumeToken();
@@ -91,7 +117,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc,
*Tok.getIdentifierInfo(),
- Tok.getLocation(), SS);
+ Tok.getLocation(), SS,
+ ObjectType);
if (!Template)
break;
if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
@@ -173,7 +200,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
SS.setScopeRep(
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II,
- EnteringContext));
+ ObjectType, EnteringContext));
SS.setEndLoc(CCLoc);
continue;
}
@@ -182,7 +209,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// type-name '<'
if (Next.is(tok::less)) {
TemplateTy Template;
- if (TemplateNameKind TNK = Actions.isTemplateName(II, CurScope, &SS,
+ if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II,
+ Tok.getLocation(),
+ &SS,
+ ObjectType,
EnteringContext,
Template)) {
// We have found a template name, so annotate this this token
@@ -267,7 +297,7 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
// '::' unqualified-id
//
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
// unqualified-id:
// identifier
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 4d37ac7202..36d5db599d 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -884,7 +884,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
// simple-template-id
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
- bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS, false);
+ bool HadNestedNameSpecifier
+ = ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
if (!HadNestedNameSpecifier) {
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
return false;
@@ -928,7 +929,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
CXXScopeSpec SS;
if (getLang().CPlusPlus)
- ParseOptionalCXXScopeSpecifier(SS, EnteringContext);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext);
if (Tok.is(tok::identifier)) {
// Determine whether the identifier is a type name.
@@ -959,8 +960,10 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
if (NextToken().is(tok::less)) {
TemplateTy Template;
if (TemplateNameKind TNK
- = Actions.isTemplateName(*Tok.getIdentifierInfo(),
- CurScope, &SS, EnteringContext, Template))
+ = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(),
+ Tok.getLocation(), &SS,
+ /*ObjectType=*/0, EnteringContext,
+ Template))
if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
// If an unrecoverable error occurred, we need to return true here,
// because the token stream is in a damaged state. We may not return
@@ -1022,7 +1025,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
"Cannot be a type or scope token!");
CXXScopeSpec SS;
- if (!ParseOptionalCXXScopeSpecifier(SS, EnteringContext))
+ if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext))
return Tok.is(tok::annot_template_id);
// Push the current token back into the token stream (or revert it if it is
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e2205d6df5..6f462e593b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1983,6 +1983,12 @@ public:
TypeTy *Ty,
SourceLocation RParen);
+ virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
+ ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ TypeTy *&ObjectType);
+
virtual OwningExprResult
ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
@@ -2029,6 +2035,7 @@ public:
bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
+ DeclContext *computeDeclContext(QualType T);
DeclContext *computeDeclContext(const CXXScopeSpec &SS,
bool EnteringContext = false);
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
@@ -2051,6 +2058,7 @@ public:
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
+ TypeTy *ObjectType,
bool EnteringContext);
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
@@ -2067,23 +2075,6 @@ public:
SourceRange TypeRange,
SourceLocation CCLoc);
- /// ActOnCXXEnterMemberScope - Called when a C++ class member accessor ('.'
- /// or '->') is parsed. After this method is called, according to
- /// [C++ 3.4.5p4], qualified-ids should be looked up in the contexts of both
- /// the entire postfix-expression and the scope of the class of the object
- /// expression.
- /// 'SS' should be an empty CXXScopeSpec to be filled with the class's scope.
- virtual OwningExprResult ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS,
- ExprArg Base,
- tok::TokenKind OpKind);
-
- /// ActOnCXXExitMemberScope - Called when a postfix-expression that previously
- /// invoked ActOnCXXEnterMemberScope() is finished. 'SS' is the same
- /// CXXScopeSpec that was passed to ActOnCXXEnterMemberScope. Used to
- /// indicate that names should revert to being looked up in the defining
- /// scope.
- virtual void ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS);
-
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
@@ -2311,8 +2302,11 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
- virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+ virtual TemplateNameKind isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
@@ -2400,7 +2394,8 @@ public:
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
- const CXXScopeSpec &SS);
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType);
bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
ClassTemplateSpecializationDecl *PrevDecl,
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index d89a610cae..251ffea925 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -22,6 +22,20 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+/// \brief Compute the DeclContext that is associated with the given type.
+///
+/// \param T the type for which we are attempting to find a DeclContext.
+///
+/// \returns the declaration context represented by the type T,
+/// or NULL if the declaration context cannot be computed (e.g., because it is
+/// dependent and not the current instantiation).
+DeclContext *Sema::computeDeclContext(QualType T) {
+ if (const TagType *Tag = T->getAs<TagType>())
+ return Tag->getDecl();
+
+ return 0;
+}
+
/// \brief Compute the DeclContext that is associated with the given
/// scope specifier.
///
@@ -244,6 +258,36 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
return NestedNameSpecifier::GlobalSpecifier(Context);
}
+/// \brief Determines whether the given declaration is an valid acceptable
+/// result for name lookup of a nested-name-specifier.
+bool isAcceptableNestedNameSpecifier(ASTContext &Context, NamedDecl *SD) {
+ if (!SD)
+ return false;
+
+ // Namespace and namespace aliases are fine.
+ if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD))
+ return true;
+
+ if (!isa<TypeDecl>(SD))
+ return false;
+
+ // Determine whether we have a class (or, in C++0x, an enum) or
+ // a typedef thereof. If so, build the nested-name-specifier.
+ QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+ if (T->isDependentType())
+ return true;
+ else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (TD->getUnderlyingType()->isRecordType() ||
+ (Context.getLangOptions().CPlusPlus0x &&
+ TD->getUnderlyingType()->isEnumeralType()))
+ return true;
+ } else if (isa<RecordDecl>(SD) ||
+ (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD)))
+ return true;
+
+ return false;
+}
+
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
/// we want to resolve "bar::". 'SS' is empty or the previously parsed
@@ -255,58 +299,134 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
+ TypeTy *ObjectTypePtr,
bool EnteringContext) {
NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+
+ // Determine where to perform name lookup
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ if (ObjectTypePtr) {
+ // This nested-name-specifier occurs in a member access expression, e.g.,
+ // x->B::f, and we are looking into the type of the object.
+ assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
+ QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+ LookupCtx = computeDeclContext(ObjectType);
+ isDependent = ObjectType->isDependentType();
+ } else if (SS.isSet()) {
+ // This nested-name-specifier occurs after another nested-name-specifier,
+ // so long into the context associated with the prior nested-name-specifier.
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(SS);
+ }
- NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName,
- false, false, SourceLocation(),
- EnteringContext);
+ LookupResult Found;
+ bool ObjectTypeSearchedInScope = false;
+ if (LookupCtx) {
+ // Perform "qualified" name lookup into the declaration context we
+ // computed, which is either the type of the base of a member access
+ // expression or the declaration context associated with a prior
+ // nested-name-specifier.
+
+ // The declaration context mu