summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Parse/MinimalAction.cpp5
-rw-r--r--clang/lib/Parse/ParseDecl.cpp9
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp13
-rw-r--r--clang/lib/Parse/ParseExpr.cpp17
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp52
-rw-r--r--clang/lib/Parse/Parser.cpp13
-rw-r--r--clang/lib/Sema/Sema.h33
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp238
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp42
-rw-r--r--clang/lib/Sema/SemaLookup.cpp41
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp326
-rw-r--r--clang/lib/Sema/TreeTransform.h13
12 files changed, 518 insertions, 284 deletions
diff --git a/clang/lib/Parse/MinimalAction.cpp b/clang/lib/Parse/MinimalAction.cpp
index ee23c0038ac..d89cc8c3ea2 100644
--- a/clang/lib/Parse/MinimalAction.cpp
+++ b/clang/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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 25bed0937b6..25ff53ca9f3 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/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/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 31926ce0f5c..f50147c599a 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/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/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 36b6dd4a930..8fca14ff989 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/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/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index e9cca9fe1d2..4cd952e393f 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/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/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 4d37ac7202a..36d5db599d4 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index e2205d6df54..6f462e593b5 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/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/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index d89a610caec..251ffea925c 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/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/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 0dc4b8d1800..87330ab0b63 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/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/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 4a699de6c8d..38abd1641d5 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/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))
return LookupResult::CreateLookupResult(Context, I, E);
- // If this isn't a C++ class or we aren't allowed to look into base
- // classes, we're done.
- if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
+ // If this isn't a C++ class, we aren't allowed to look into base
+ // classes, we're done, or the lookup context is dependent, we're done.
+ if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx) ||
+ LookupCtx->isDependentContext())
return LookupResult::CreateLookupResult(Context, 0);
// Perform lookup into our base classes.
@@ -1152,24 +1162,9 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
// We have resolved the scope specifier to a particular declaration
// contex, and will perform name lookup in that context.
-
- if (DC->isDependentContext()) {
- // If this is a dependent context, then we are looking for a member of
- // the current instantiation. This is a narrow search that looks into
- // just the described declaration context (C++0x [temp.dep.type]).
- unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind,
- true);
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I)
- if (isAcceptableLookupResult(*I, NameKind, IDNS))
- return LookupResult::CreateLookupResult(Context, I, E);
- }
-
- // Qualified name lookup into the named declaration context.
- // The declaration context must be complete.
- if (RequireCompleteDeclContext(*SS))
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS))
return LookupResult::CreateLookupResult(Context, 0);
-
+
return LookupQualifiedName(DC, Name, NameKind, RedeclarationOnly);
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f0165c91e10..119e17f814d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -21,122 +21,215 @@
using namespace clang;
-/// isTemplateName - Determines whether the identifier II is a
-/// template name in the current scope, and returns the template
-/// declaration if II names a template. An optional CXXScope can be
-/// passed to indicate the C++ scope in which the identifier will be
-/// found.
-TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
- const CXXScopeSpec *SS,
- bool EnteringContext,
- TemplateTy &TemplateResult) {
- LookupResult Found = LookupParsedName(S, SS, &II, LookupOrdinaryName,
- false, false, SourceLocation(),
- EnteringContext);
+/// \brief Determine whether the declaration found is acceptable as the name
+/// of a template and, if so, return that template declaration. Otherwise,
+/// returns NULL.
+static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
+ if (!D)
+ return 0;
- // FIXME: Cope with ambiguous name-lookup results.
- assert(!Found.isAmbiguous() &&
- "Cannot handle template name-lookup ambiguities");
+ if (isa<TemplateDecl>(D))
+ return D;
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ // C++ [temp.local]p1:
+ // Like normal (non-template) classes, class templates have an
+ // injected-class-name (Clause 9). The injected-class-name
+ // can be used with or without a template-argument-list. When
+ // it is used without a template-argument-list, it is
+ // equivalent to the injected-class-name followed by the
+ // template-parameters of the class template enclosed in
+ // <>. When it is used with a template-argument-list, it
+ // refers to the specified class template specialization,
+ // which could be the current specialization or another
+ // specialization.
+ if (Record->isInjectedClassName()) {
+ Record = cast<CXXRecordDecl>(Record->getCanonicalDecl());
+ if (Record->getDescribedClassTemplate())
+ return Record->getDescribedClassTemplate();
+
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ return Spec->getSpecializedTemplate();
+ }
+
+ return 0;
+ }
- NamedDecl *IIDecl = Found;
+ OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D);
+ if (!Ovl)
+ return 0;
- TemplateNameKind TNK = TNK_Non_template;
- TemplateDecl *Template = 0;
-
- if (IIDecl) {
- if ((Template = dyn_cast<TemplateDecl>(IIDecl))) {
- if (isa<FunctionTemplateDecl>(IIDecl))
- TNK = TNK_Function_template;
- else if (isa<ClassTemplateDecl>(IIDecl) ||
- isa<TemplateTemplateParmDecl>(IIDecl))
- TNK = TNK_Type_template;
- else
- assert(false && "Unknown template declaration kind");
- } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
- // C++ [temp.local]p1:
- // Like normal (non-template) classes, class templates have an
- // injected-class-name (Clause 9). The injected-class-name
- // can be used with or without a template-argument-list. When
- // it is used without a template-argument-list, it is
- // equivalent to the injected-class-name followed by the
- // template-parameters of the class template enclosed in
- // <>. When it is used with a template-argument-list, it
- // refers to the specified class template specialization,
- // which could be the current specialization or another
- // specialization.
- if (Record->isInjectedClassName()) {
- Record = cast<CXXRecordDecl>(Record->getCanonicalDecl());
- if ((Template = Record->getDescribedClassTemplate()))
- TNK = TNK_Type_template;
- else if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
- Template = Spec->getSpecializedTemplate();
- TNK = TNK_Type_template;
- }
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if (FunctionTemplateDecl *FuncTmpl = dyn_cast<FunctionTemplateDecl>(*F)) {
+ // We've found a function template. Determine whether there are
+ // any other function templates we need to bundle together in an
+ // OverloadedFunctionDecl
+ for (++F; F != FEnd; ++F) {
+ if (isa<FunctionTemplateDecl>(*F))
+ break;
}
- } else if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- if (FunctionTemplateDecl *FuncTmpl
- = dyn_cast<FunctionTemplateDecl>(*F)) {
- // We've found a function template. Determine whether there are
- // any other function templates we need to bundle together in an
- // OverloadedFunctionDecl
- for (++F; F != FEnd; ++F) {
- if (isa<FunctionTemplateDecl>(*F))
- break;
- }
-
- if (F != FEnd) {
- // Build an overloaded function decl containing only the
- // function templates in Ovl.
- OverloadedFunctionDecl *OvlTemplate
- = OverloadedFunctionDecl::Create(Context,
- Ovl->getDeclContext(),
- Ovl->getDeclName());
- OvlTemplate->addOverload(FuncTmpl);
+
+ if (F != FEnd) {
+ // Build an overloaded function decl containing only the
+ // function templates in Ovl.
+ OverloadedFunctionDecl *OvlTemplate
+ = OverloadedFunctionDecl::Create(Context,
+ Ovl->getDeclContext(),
+ Ovl->getDeclName());
+ OvlTemplate->addOverload(FuncTmpl);
+ OvlTemplate->addOverload(*F);
+ for (++F; F != FEnd; ++F) {
+ if (isa<FunctionTemplateDecl>(*F))
OvlTemplate->addOverload(*F);
- for (++F; F != FEnd; ++F) {
- if (isa<FunctionTemplateDecl>(*F))
- OvlTemplate->addOverload(*F);
- }
-
- // Form the resulting TemplateName
- if (SS && SS->isSet() && !SS->isInvalid()) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
- TemplateResult
- = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier,
- false,
- OvlTemplate));
- } else {
- TemplateResult = TemplateTy::make(TemplateName(OvlTemplate));
- }
- return TNK_Function_template;
- }
-
- TNK = TNK_Function_template;
- Template = FuncTmpl;
- break;
}
+
+ return OvlTemplate;
}
+
+ return FuncTmpl;
}
+ }
+
+ return 0;
+}
- if (TNK != TNK_Non_template) {
- if (SS && SS->isSet() && !SS->isInvalid()) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
- TemplateResult
- = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier,
- false,
- Template));
- } else
- TemplateResult = TemplateTy::make(TemplateName(Template));
+TemplateNameKind Sema::isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectTypePtr,
+ bool EnteringContext,
+ TemplateTy &TemplateResult) {
+ // 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 || !SS->isSet()) &&
+ "ObjectType and scope specifier cannot coexist");
+ QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+ LookupCtx = computeDeclContext(ObjectType);
+ isDependent = ObjectType->isDependentType();
+ } else if (SS && 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);
+ }
+
+ 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 TNK_Non_template;
+
+ Found = LookupQualifiedName(LookupCtx, &II, LookupOrdinaryName);
+
+ if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) {
+ // C++ [basic.lookup.classref]p1:
+ // In a class member access expression (5.2.5), if the . or -> token is
+ // immediately followed by an identifier followed by a <, the
+ // identifier must be looked up to determine whether the < is the
+ // beginning of a template argument list (14.2) or a less-than operator.
+ // The identifier is first looked up in the class of the object
+ // expression. If the identifier is not found, it is then looked up in
+ // the context of the entire postfix-expression and shall name a class
+ // or function template.
+ //
+ // 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, LookupOrdinaryName);
+ ObjectTypeSearchedInScope = true;
}
+ } else if (isDependent) {
+ // We cannot look into a dependent object type or
+ return TNK_Non_template;
+ } else {
+ // Perform unqualified name lookup in the current scope.
+ Found = LookupName(S, &II, LookupOrdinaryName);
+ }
+
+ // FIXME: Cope with ambiguous name-lookup results.
+ assert(!Found.isAmbiguous() &&
+ "Cannot handle template name-lookup ambiguities");
+
+ NamedDecl *Template = isAcceptableTemplateName(Context, Found);
+ if (!Template)
+ return TNK_Non_template;
+
+ if (ObjectTypePtr && !ObjectTypeSearchedInScope) {
+ // C++ [basic.lookup.classref]p1:
+ // [...] If the lookup in the class of the object expression finds a
+ // template, the name is also looked up in the context of the entire
+ // postfix-expression and [...]
+ //
+ LookupResult FoundOuter = LookupName(S, &II, LookupOrdinaryName);
+ // FIXME: Handle ambiguities in this lookup better
+ NamedDecl *OuterTemplate = isAcceptableTemplateName(Context, FoundOuter);
+
+ if (!OuterTemplate) {
+ // - if the name is not found, the name found in the class of the
+ // object expression is used, otherwise
+ } else if (!isa<ClassTemplateDecl>(OuterTemplate)) {
+ // - if the name is found in the context of the entire
+ // postfix-expression and does not name a class template, the name
+ // found in the class of the object expression is used, otherwise
+ } else {
+ // - if the name found is a class template, it must refer to the same
+ // entity as the one found in the class of the object expression,
+ // otherwise the program is ill-formed.
+ if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) {
+ Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+ << &II;
+ Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type)
+ << QualType::getFromOpaquePtr(ObjectTypePtr);
+ Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope);
+
+ // Recover by taking the template that we found in the object
+ // expression's type.
+ }
+ }
}
- return TNK;
+
+ if (SS && SS->isSet() && !SS->isInvalid()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template))
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ Ovl));
+ else
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ cast<TemplateDecl>(Template)));
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template)) {
+ TemplateResult = TemplateTy::make(TemplateName(Ovl));
+ } else {
+ TemplateResult = TemplateTy::make(
+ TemplateName(cast<TemplateDecl>(Template)));
+ }
+
+ if (isa<ClassTemplateDecl>(Template) ||
+ isa<TemplateTemplateParmDecl>(Template))
+ return TNK_Type_template;
+
+ assert((isa<FunctionTemplateDecl>(Template) ||
+ isa<OverloadedFunctionDecl>(Template)) &&
+ "Unhandled template kind in Sema::isTemplateName");
+ return TNK_Function_template;
}
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -1130,14 +1223,11 @@ Sema::TemplateTy
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
- const CXXScopeSpec &SS) {
- if (!SS.isSet() || SS.isInvalid())
- return TemplateTy();
-
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
-
- if (computeDeclContext(SS, false)) {
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType) {
+ if ((ObjectType &&
+ computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
+ (SS.isSet() && computeDeclContext(SS, false))) {
// C++0x [temp.names]p5:
// If a name prefixed by the keyword template is not the name of
// a template, the program is ill-formed. [Note: the keyword
@@ -1155,7 +1245,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode, retroactively applying the DR.
TemplateTy Template;
- TemplateNameKind TNK = isTemplateName(Name, 0, &SS, false, Template);
+ TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType,
+ false, Template);
if (TNK == TNK_Non_template) {
Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
<< &Name;
@@ -1165,6 +1256,13 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
return Template;
}
+ // FIXME: We need to be able to create a dependent template name with just
+ // an identifier, to handle the x->template f<T> case.
+ assert(!ObjectType &&
+ "Cannot handle dependent template names without a nested-name-specifier");
+
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index e7400e74734..8fe28a46bf5 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1454,7 +1454,10 @@ public:
OwningExprResult Base = move(BaseE);
tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
CXXScopeSpec SS;
- Base = SemaRef.ActOnCXXEnterMemberScope(0, SS, move(Base), OpKind);
+ Sema::TypeTy *ObjectType = 0;
+
+ Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), OperatorLoc,
+ OpKind, ObjectType);
if (Base.isInvalid())
return SemaRef.ExprError();
@@ -1463,7 +1466,6 @@ public:
MemberLoc,
Name,
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
- SemaRef.ActOnCXXExitMemberScope(0, SS);
return move(Base);
}
@@ -4410,6 +4412,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
return static_cast<NestedNameSpecifier *>(
SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(),
Range.getEnd(), II,
+ /*FIXME:ObjectType=*/0,
false));
}
@@ -4467,7 +4470,11 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
SS.setRange(SourceRange(getDerived().getBaseLocation()));
SS.setScopeRep(Qualifier);
Sema::TemplateTy Template;
- TemplateNameKind TNK = SemaRef.isTemplateName(II, 0, &SS, false, Template);
+ TemplateNameKind TNK = SemaRef.isTemplateName(0, II,
+ /*FIXME:*/getDerived().getBaseLocation(),
+ &SS,
+ /*FIXME:ObjectType=*/0, false,
+ Template);
if (TNK == TNK_Non_template) {
SemaRef.Diag(getDerived().getBaseLocation(),
diag::err_template_kw_refers_to_non_template)
OpenPOWER on IntegriCloud