diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 2b353269ed52d9..daaa54c3db7c21 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -757,10 +757,10 @@ ANNOTATION(non_type_undeclared) // annotation for an undeclared identifier that // was assumed to be an ADL-only function name ANNOTATION(non_type_dependent) // annotation for an assumed non-type member of // a dependent base class -ANNOTATION(primary_expr) // annotation for a primary expression -ANNOTATION( - uneval_primary_expr) // annotation for a primary expression which should be - // transformed to potentially evaluated +ANNOTATION(overload_set) // annotation for an unresolved overload set +ANNOTATION(primary_expr) // annotation for a primary expression, used when + // tentatively parsing a lambda init-capture or ObjC + // message send ANNOTATION(decltype) // annotation for a decltype expression, // e.g., "decltype(foo.bar())" diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0721720f790854..63e2d0d17fca2d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2117,9 +2117,11 @@ class Sema final { /// resolved. ActOnNameClassifiedAsDependentNonType should be called to /// convert the result to an expression. NC_DependentNonType, - /// The name was classified as a non-type, and an expression representing - /// that name has been formed. - NC_ContextIndependentExpr, + /// The name was classified as an overload set, and an expression + /// representing that overload set has been formed. + /// ActOnNameClassifiedAsOverloadSet should be called to form a suitable + /// expression referencing the overload set. + NC_OverloadSet, /// The name was classified as a template whose specializations are types. NC_TypeTemplate, /// The name was classified as a variable template name. @@ -2156,8 +2158,8 @@ class Sema final { return NameClassification(NC_Unknown); } - static NameClassification ContextIndependentExpr(ExprResult E) { - NameClassification Result(NC_ContextIndependentExpr); + static NameClassification OverloadSet(ExprResult E) { + NameClassification Result(NC_OverloadSet); Result.Expr = E; return Result; } @@ -2209,7 +2211,7 @@ class Sema final { NameClassificationKind getKind() const { return Kind; } ExprResult getExpression() const { - assert(Kind == NC_ContextIndependentExpr); + assert(Kind == NC_OverloadSet); return Expr; } @@ -2289,6 +2291,8 @@ class Sema final { NamedDecl *Found, SourceLocation NameLoc, const Token &NextToken); + /// Act on the result of classifying a name as an overload set. + ExprResult ActOnNameClassifiedAsOverloadSet(Scope *S, Expr *OverloadSet); /// Describes the detailed kind of a template name. Used in diagnostics. enum class TemplateNameKindForDiagnostics { @@ -4846,11 +4850,10 @@ class Sema final { Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation()); - ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - const Scope *S); + ExprResult BuildPossibleImplicitMemberExpr( + const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + UnresolvedLookupExpr *AsULE = nullptr); ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c87d240a8206af..7b3a98edb37263 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2837,7 +2837,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, case Sema::NC_Unknown: case Sema::NC_NonType: case Sema::NC_DependentNonType: - case Sema::NC_ContextIndependentExpr: + case Sema::NC_OverloadSet: case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: case Sema::NC_Concept: diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 81e87582c6adec..4f662f00e1df33 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1007,23 +1007,11 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); break; - case tok::annot_uneval_primary_expr: case tok::annot_primary_expr: + case tok::annot_overload_set: Res = getExprAnnotation(Tok); - if (SavedKind == tok::annot_uneval_primary_expr) { - if (Expr *E = Res.get()) { - if (!E->isTypeDependent() && !E->containsErrors()) { - // TransformToPotentiallyEvaluated expects that it will still be in a - // (temporary) unevaluated context and then looks through that context - // to build it in the surrounding context. So we need to push an - // unevaluated context to balance things out. - EnterExpressionEvaluationContext Unevaluated( - Actions, Sema::ExpressionEvaluationContext::Unevaluated, - Sema::ReuseLambdaContextDecl); - Res = Actions.TransformToPotentiallyEvaluated(Res.get()); - } - } - } + if (!Res.isInvalid() && Tok.getKind() == tok::annot_overload_set) + Res = Actions.ActOnNameClassifiedAsOverloadSet(getCurScope(), Res.get()); ConsumeAnnotationToken(); if (!Res.isInvalid() && Tok.is(tok::less)) checkPotentialAngleBracket(Res); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index f026f3a1bfb299..d0f1d2e09a8724 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1276,15 +1276,6 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // this is ambiguous. Typo-correct to type and expression keywords and // to types and identifiers, in order to try to recover from errors. TentativeParseCCC CCC(Next); - // Tentative parsing may not be done in the right evaluation context - // for the ultimate expression. Enter an unevaluated context to prevent - // Sema from immediately e.g. treating this lookup as a potential ODR-use. - // If we generate an expression annotation token and the parser actually - // claims it as an expression, we'll transform the expression to a - // potentially-evaluated one then. - EnterExpressionEvaluationContext Unevaluated( - Actions, Sema::ExpressionEvaluationContext::Unevaluated, - Sema::ReuseLambdaContextDecl); switch (TryAnnotateName(&CCC)) { case ANK_Error: return TPResult::Error; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 764d4e8e9d522a..45cf855cf8c9bf 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1691,9 +1691,8 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { return ANK_Success; } - case Sema::NC_ContextIndependentExpr: - Tok.setKind(Actions.isUnevaluatedContext() ? tok::annot_uneval_primary_expr - : tok::annot_primary_expr); + case Sema::NC_OverloadSet: + Tok.setKind(tok::annot_overload_set); setExprAnnotation(Tok, Classification.getExpression()); Tok.setAnnotationEndLoc(NameLoc); if (SS.isNotEmpty()) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 53f5132a46b650..869e4de02cc418 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1184,23 +1184,20 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, return ParsedType::make(T); } - // FIXME: This is context-dependent. We need to defer building the member - // expression until the classification is consumed. - if (FirstDecl->isCXXClassMember()) - return NameClassification::ContextIndependentExpr( - BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr, - S)); - // If we already know which single declaration is referenced, just annotate - // that declaration directly. + // that declaration directly. Defer resolving even non-overloaded class + // member accesses, as we need to defer certain access checks until we know + // the context. bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); - if (Result.isSingleResult() && !ADL) + if (Result.isSingleResult() && !ADL && !FirstDecl->isCXXClassMember()) return NameClassification::NonType(Result.getRepresentativeDecl()); - // Build an UnresolvedLookupExpr. Note that this doesn't depend on the - // context in which we performed classification, so it's safe to do now. - return NameClassification::ContextIndependentExpr( - BuildDeclarationNameExpr(SS, Result, ADL)); + // Otherwise, this is an overload set that we will need to resolve later. + Result.suppressDiagnostics(); + return NameClassification::OverloadSet(UnresolvedLookupExpr::Create( + Context, Result.getNamingClass(), SS.getWithLocInContext(Context), + Result.getLookupNameInfo(), ADL, Result.isOverloadedResult(), + Result.begin(), Result.end())); } ExprResult @@ -1240,6 +1237,30 @@ ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS, return BuildDeclarationNameExpr(SS, Result, ADL); } +ExprResult Sema::ActOnNameClassifiedAsOverloadSet(Scope *S, Expr *E) { + // For an implicit class member access, transform the result into a member + // access expression if necessary. + auto *ULE = cast(E); + if ((*ULE->decls_begin())->isCXXClassMember()) { + CXXScopeSpec SS; + SS.Adopt(ULE->getQualifierLoc()); + + // Reconstruct the lookup result. + LookupResult Result(*this, ULE->getName(), ULE->getNameLoc(), + LookupOrdinaryName); + Result.setNamingClass(ULE->getNamingClass()); + for (auto I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I) + Result.addDecl(*I, I.getAccess()); + Result.resolveKind(); + return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, + nullptr, S); + } + + // Otherwise, this is already in the form we needed, and no further checks + // are necessary. + return ULE; +} + Sema::TemplateNameKindForDiagnostics Sema::getTemplateNameKindForDiagnostics(TemplateName Name) { auto *TD = Name.getAsTemplateDecl(); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index ebfc1ec4b97498..466d1fe59c7153 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -231,12 +231,10 @@ static void diagnoseInstanceReference(Sema &SemaRef, } /// Builds an expression which might be an implicit member expression. -ExprResult -Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - const Scope *S) { +ExprResult Sema::BuildPossibleImplicitMemberExpr( + const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + UnresolvedLookupExpr *AsULE) { switch (ClassifyImplicitMemberAccess(*this, R)) { case IMA_Instance: return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S); @@ -257,7 +255,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, case IMA_Unresolved_StaticContext: if (TemplateArgs || TemplateKWLoc.isValid()) return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs); - return BuildDeclarationNameExpr(SS, R, false); + return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false); case IMA_Error_StaticContext: case IMA_Error_Unrelated: diff --git a/clang/test/SemaTemplate/member-access-expr.cpp b/clang/test/SemaTemplate/member-access-expr.cpp index 36d60225772897..d6627b954a2872 100644 --- a/clang/test/SemaTemplate/member-access-expr.cpp +++ b/clang/test/SemaTemplate/member-access-expr.cpp @@ -160,3 +160,14 @@ namespace test6 { } }; } + +namespace test7 { + struct C { void g(); }; + template struct A { + T x; + static void f() { + (x.g()); // expected-error {{invalid use of member 'x' in static member function}} + } + }; + void h() { A::f(); } +}