// 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())"
/// 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.
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;
}
NameClassificationKind getKind() const { return Kind; }
ExprResult getExpression() const {
- assert(Kind == NC_ContextIndependentExpr);
+ assert(Kind == NC_OverloadSet);
return Expr;
}
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 {
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,
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:
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);
// 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;
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())
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
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<UnresolvedLookupExpr>(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();
}
/// 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);
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:
}
};
}
+
+namespace test7 {
+ struct C { void g(); };
+ template<typename T> struct A {
+ T x;
+ static void f() {
+ (x.g()); // expected-error {{invalid use of member 'x' in static member function}}
+ }
+ };
+ void h() { A<C>::f(); }
+}