From: Eli Friedman Date: Fri, 6 Aug 2010 23:41:47 +0000 (+0000) Subject: PR7837: For qualified id's, make sure the decl context is complete if not X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=647c8b32c2a6e38ee44dde1782a629e9c03786e2;p=clang PR7837: For qualified id's, make sure the decl context is complete if not dependent in ActOnIdExpression. (This issue only shows up with member operators because an operator is never a type.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110486 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 46c5a65f75..82a2bb2982 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -699,23 +699,6 @@ static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { return true; } -/// Determines whether we can lookup this id-expression now or whether -/// we have to wait until template instantiation is complete. -static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) { - DeclContext *DC = SemaRef.computeDeclContext(SS, false); - - // If the qualifier scope isn't computable, it's definitely dependent. - if (!DC) return true; - - // If the qualifier scope doesn't name a record, we can always look into it. - if (!isa(DC)) return false; - - // We can't look into record types unless they're fully-formed. - if (!IsFullyFormedScope(SemaRef, cast(DC))) return true; - - return false; -} - /// Determines if the given class is provably not derived from all of /// the prospective base classes. static bool IsProvablyNotDerivedFrom(Sema &SemaRef, @@ -1100,9 +1083,24 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // names a dependent type. // Determine whether this is a member of an unknown specialization; // we need to handle these differently. - if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName && - Name.getCXXNameType()->isDependentType()) || - (SS.isSet() && IsDependentIdExpression(*this, SS))) { + bool DependentID = false; + if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) { + DependentID = true; + } else if (SS.isSet()) { + DeclContext *DC = computeDeclContext(SS, false); + if (DC) { + if (RequireCompleteDeclContext(SS, DC)) + return ExprError(); + // FIXME: We should be checking whether DC is the current instantiation. + if (CXXRecordDecl *RD = dyn_cast(DC)) + DependentID = !IsFullyFormedScope(*this, RD); + } else { + DependentID = true; + } + } + + if (DependentID) { return ActOnDependentIdExpression(SS, Name, NameLoc, isAddressOfOperand, TemplateArgs); diff --git a/test/SemaTemplate/dependent-class-member-operator.cpp b/test/SemaTemplate/dependent-class-member-operator.cpp new file mode 100644 index 0000000000..d70a60cfdf --- /dev/null +++ b/test/SemaTemplate/dependent-class-member-operator.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// PR7837 + +template struct C1 { void operator()(T); }; +template struct C2; // expected-note {{template is declared here}} +template void foo(T); +void wrap() { + foo(&C1::operator()); + foo(&C1::operator+); // expected-error {{no member named 'operator+' in 'C1'}} + foo(&C2::operator+); // expected-error {{implicit instantiation of undefined template 'C2'}} +}