aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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
12 files changed, 518 insertions, 284 deletions
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 must be complete.
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ return 0;
- if (SD) {
+ Found = LookupQualifiedName(LookupCtx, &II, LookupNestedNameSpecifierName,
+ false);
+
+ if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound && S) {
+ // C++ [basic.lookup.classref]p4:
+ // If the id-expression in a class member access is a qualified-id of
+ // the form
+ //
+ // class-name-or-namespace-name::...
+ //
+ // the class-name-or-namespace-name following the . or -> operator is
+ // looked up both in the context of the entire postfix-expression and in
+ // the scope of the class of the object expression. If the name is found
+ // only in the scope of the class of the object expression, the name
+ // shall refer to a class-name. If the name is found only in the
+ // context of the entire postfix-expression, the name shall refer to a
+ // class-name or namespace-name. [...]
+ //
+ // Qualified name lookup into a class will not find a namespace-name,
+ // so we do not need to diagnoste that case specifically. However,
+ // this qualified name lookup may find nothing. In that case, perform
+ // unqualified name lookup in the given scope.
+
+ // FIXME: When we're instantiating a template, do we actually have to
+ // look in the scope of the template? Seems fishy...
+ Found = LookupName(S, &II, LookupNestedNameSpecifierName);
+ ObjectTypeSearchedInScope = true;
+ }
+ } else if (isDependent) {
+ // We were not able to compute the declaration context for a dependent
+ // base object type or prior nested-name-specifier, so this
+ // nested-name-specifier refers to an unknown specialization. Just build
+ // a dependent nested-name-specifier.
+ return NestedNameSpecifier::Create(Context, Prefix, &II);
+ } else {
+ // Perform unqualified name lookup in the current scope.
+ Found = LookupName(S, &II, LookupNestedNameSpecifierName);
+ }
+
+ // FIXME: Deal with ambiguities cleanly.
+ NamedDecl *SD = Found;
+ if (isAcceptableNestedNameSpecifier(Context, SD)) {
+ if (ObjectTypePtr && !ObjectTypeSearchedInScope && S) {
+ // C++ [basic.lookup.classref]p4:
+ // [...] If the name is found in both contexts, the
+ // class-name-or-namespace-name shall refer to the same entity.
+ //
+ // We already found the name in the scope of the object. Now, look
+ // into the current scope (the scope of the postfix-expression) to
+ // see if we can find the same name there.
+ LookupResult FoundOuter
+ = LookupName(S, &II, LookupNestedNameSpecifierName);
+
+ // FIXME: Handle ambiguities in FoundOuter!
+ NamedDecl *OuterDecl = FoundOuter;
+ if (isAcceptableNestedNameSpecifier(Context, OuterDecl) &&
+ OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
+ (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
+ !Context.hasSameType(
+ Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
+ Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
+ Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+ << &II;
+ Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
+ << QualType::getFromOpaquePtr(ObjectTypePtr);
+ Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
+
+ // Fall through so that we'll pick the name we found in the object type,
+ // since that's probably what the user wanted anyway.
+ }
+ }
+
if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
return NestedNameSpecifier::Create(Context, Prefix, Namespace);
- if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
- // 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(Type);
- bool AcceptableType = false;
- if (T->isDependentType())
- AcceptableType = true;
- else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
- if (TD->getUnderlyingType()->isRecordType() ||
- (getLangOptions().CPlusPlus0x &&
- TD->getUnderlyingType()->isEnumeralType()))
- AcceptableType = true;
- } else if (isa<RecordDecl>(Type) ||
- (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
- AcceptableType = true;
-
- if (AcceptableType)
- return NestedNameSpecifier::Create(Context, Prefix, false,
- T.getTypePtr());
- }
-
// FIXME: It would be nice to maintain the namespace alias name, then
// see through that alias when resolving the nested-name-specifier down to
// a declaration context.
if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
return NestedNameSpecifier::Create(Context, Prefix,
- Alias->getNamespace());
- // Fall through to produce an error: we found something that isn't
- // a class or a namespace.
- } else if (SS.isSet() && isDependentScopeSpecifier(SS))
- return NestedNameSpecifier::Create(Context, Prefix, &II);
+ Alias->getNamespace());
+
+ QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+ return NestedNameSpecifier::Create(Context, Prefix, false,
+ T.getTypePtr());
+ }
// If we didn't find anything during our lookup, try again with
// ordinary name lookup, which can help us produce better error
// messages.
if (!SD)
- SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName,
- false, false, SourceLocation(),
- EnteringContext);
+ SD = LookupName(S, &II, LookupOrdinaryName);
+
unsigned DiagID;
if (SD)
DiagID = diag::err_expected_class_or_namespace;
@@ -338,58 +458,6 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
T.getTypePtr());
}
-Action::OwningExprResult
-Sema::ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS, ExprArg Base,
- tok::TokenKind OpKind) {
- // Since this might be a postfix expression, get rid of ParenListExprs.
- Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
-
- Expr *BaseExpr = (Expr*)Base.get();
- assert(BaseExpr && "no record expansion");
-
- QualType BaseType = BaseExpr->getType();
- // FIXME: handle dependent types
- if (BaseType->isDependentType())
- return move(Base);
-
- // C++ [over.match.oper]p8:
- // [...] When operator->returns, the operator-> is applied to the value
- // returned, with the original second operand.
- if (OpKind == tok::arrow) {
- while (BaseType->isRecordType()) {
- Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc());
- BaseExpr = (Expr*)Base.get();
- if (BaseExpr == NULL)
- return ExprError();
- BaseType = BaseExpr->getType();
- }
- }
-
- if (BaseType->isPointerType())
- BaseType = BaseType->getPointeeType();
-
- // We could end up with various non-record types here, such as extended
- // vector types or Objective-C interfaces. Just return early and let
- // ActOnMemberReferenceExpr do the work.
- if (!BaseType->isRecordType())
- return move(Base);
-
- SS.setRange(BaseExpr->getSourceRange());
- SS.setScopeRep(
- NestedNameSpecifier::Create(Context, 0, false, BaseType.getTypePtr())
- );
-
- if (S)
- ActOnCXXEnterDeclaratorScope(S,SS);
- return move(Base);
-}
-
-void Sema::ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS) {
- if (S && SS.isSet())
- ActOnCXXExitDeclaratorScope(S,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
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 0dc4b8d180..87330ab0b6 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1754,6 +1754,48 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
return E;
}
+Sema::OwningExprResult
+Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, TypeTy *&ObjectType) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
+ Expr *BaseExpr = (Expr*)Base.get();
+ assert(BaseExpr && "no record expansion");
+
+ QualType BaseType = BaseExpr->getType();
+ if (BaseType->isDependentType()) {
+ // FIXME: member of the current instantiation
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+ }
+
+ // C++ [over.match.oper]p8:
+ // [...] When operator->returns, the operator-> is applied to the value
+ // returned, with the original second operand.
+ if (OpKind == tok::arrow) {
+ while (BaseType->isRecordType()) {
+ Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc());
+ BaseExpr = (Expr*)Base.get();
+ if (BaseExpr == NULL)
+ return ExprError();
+ BaseType = BaseExpr->getType();
+ }
+ }
+
+ if (BaseType->isPointerType())
+ BaseType = BaseType->getPointeeType();
+
+ // We could end up with various non-record types here, such as extended
+ // vector types or Objective-C interfaces. Just return early and let
+ // ActOnMemberReferenceExpr do the work.
+ if (!BaseType->isRecordType())
+ return move(Base);
+
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+}
+
Sema::OwningExprResult
Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 4a699de6c8..38abd1641d 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -1004,8 +1004,9 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
LookupNameKind NameKind, bool RedeclarationOnly) {
assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
- if (!Name) return LookupResult::CreateLookupResult(Context, 0);
-
+ if (!Name)
+ return LookupResult::CreateLookupResult(Context, 0);
+
// If we're performing qualified name lookup (e.g., lookup into a
// struct), find fields as part of ordinary name lookup.
unsigned IDNS
@@ -1013,16 +1014,25 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
getLangOptions().CPlusPlus);
if (NameKind == LookupOrdinaryName)
IDNS |= Decl::IDNS_Member;
-
+
+ // Make sure that the declaration context is complete.
+ assert((!isa<TagDecl>(LookupCtx) ||
+ LookupCtx->isDependentContext() ||
+ cast<TagDecl>(LookupCtx)->isDefinition() ||
+ Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
+ ->isBeingDefined()) &&
+ "Declaration context must already be complete!");
+
// Perform qualified name lookup into the LookupCtx.
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
if (isAcceptableLookupResult(*I, NameKind, IDNS))
retu