diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-10-14 21:53:03 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-10-14 21:53:03 +0000 |
commit | 7e8fe67f0e2625a538a17958614dddb65453a210 (patch) | |
tree | cea5cab82bdd9c89016962b0c98142abbbaf077c /clang/lib/Sema/SemaExpr.cpp | |
parent | 9efbc564baab71e3260d211041a9df8acf8a8764 (diff) | |
download | bcm5719-llvm-7e8fe67f0e2625a538a17958614dddb65453a210.tar.gz bcm5719-llvm-7e8fe67f0e2625a538a17958614dddb65453a210.zip |
PR43080: Do not build context-sensitive expressions during name classification.
Summary:
We don't know what context to use until the classification result is
consumed by the parser, which could happen in a different semantic
context. So don't build the expression that results from name
classification until we get to that point and can handle it properly.
This covers everything except C++ implicit class member access, which
is a little awkward to handle properly in the face of the protected
member access check. But it at least fixes all the currently-filed
instances of PR43080.
Reviewers: efriedma
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D68896
llvm-svn: 374826
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 177 |
1 files changed, 100 insertions, 77 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3b6389ab7e6..6e3980275a0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2482,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr( return BuildDeclarationNameExpr(SS, R, /* ADL */ false); } -/// LookupInObjCMethod - The parser has read a name in, and Sema has -/// detected that we're currently inside an ObjC method. Perform some -/// additional lookup. +/// The parser has read a name in, and Sema has detected that we're currently +/// inside an ObjC method. Perform some additional checks and determine if we +/// should form a reference to an ivar. /// /// Ideally, most of this would be done by lookup, but there's /// actually quite a lot of extra work involved. -/// -/// Returns a null sentinel to indicate trivial success. -ExprResult -Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, - IdentifierInfo *II, bool AllowBuiltinCreation) { +DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, + IdentifierInfo *II) { SourceLocation Loc = Lookup.getNameLoc(); ObjCMethodDecl *CurMethod = getCurMethodDecl(); // Check for error condition which is already reported. if (!CurMethod) - return ExprError(); + return DeclResult(true); // There are two cases to handle here. 1) scoped lookup could have failed, // in which case we should look for an ivar. 2) scoped lookup could have @@ -2526,18 +2523,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, ObjCIvarDecl *IV = nullptr; if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) { // Diagnose using an ivar in a class method. - if (IsClassMethod) - return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method) - << IV->getDeclName()); - - // If we're referencing an invalid decl, just return this as a silent - // error node. The error diagnostic was already emitted on the decl. - if (IV->isInvalidDecl()) - return ExprError(); - - // Check if referencing a field with __attribute__((deprecated)). - if (DiagnoseUseOfDecl(IV, Loc)) - return ExprError(); + if (IsClassMethod) { + Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); + return DeclResult(true); + } // Diagnose the use of an ivar outside of the declaring class. if (IV->getAccessControl() == ObjCIvarDecl::Private && @@ -2545,46 +2534,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, !getLangOpts().DebuggerSupport) Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName(); - // FIXME: This should use a new expr for a direct reference, don't - // turn this into Self->ivar, just return a BareIVarExpr or something. - IdentifierInfo &II = Context.Idents.get("self"); - UnqualifiedId SelfName; - SelfName.setIdentifier(&II, SourceLocation()); - SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam); - CXXScopeSpec SelfScopeSpec; - SourceLocation TemplateKWLoc; - ExprResult SelfExpr = - ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName, - /*HasTrailingLParen=*/false, - /*IsAddressOfOperand=*/false); - if (SelfExpr.isInvalid()) - return ExprError(); - - SelfExpr = DefaultLvalueConversion(SelfExpr.get()); - if (SelfExpr.isInvalid()) - return ExprError(); - - MarkAnyDeclReferenced(Loc, IV, true); - - ObjCMethodFamily MF = CurMethod->getMethodFamily(); - if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize && - !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV)) - Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); - - ObjCIvarRefExpr *Result = new (Context) - ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, - IV->getLocation(), SelfExpr.get(), true, true); - - if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { - if (!isUnevaluatedContext() && - !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) - getCurFunction()->recordUseOfWeak(Result); - } - if (getLangOpts().ObjCAutoRefCount) - if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) - ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); - - return Result; + // Success. + return IV; } } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. @@ -2599,25 +2550,97 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, } else if (Lookup.isSingleResult() && Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) { // If accessing a stand-alone ivar in a class method, this is an error. - if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) - return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method) - << IV->getDeclName()); - } - - if (Lookup.empty() && II && AllowBuiltinCreation) { - // FIXME. Consolidate this with similar code in LookupName. - if (unsigned BuiltinID = II->getBuiltinID()) { - if (!(getLangOpts().CPlusPlus && - Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) { - NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, - S, Lookup.isForRedeclaration(), - Lookup.getNameLoc()); - if (D) Lookup.addDecl(D); - } + if (const ObjCIvarDecl *IV = + dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) { + Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); + return DeclResult(true); } } + + // Didn't encounter an error, didn't find an ivar. + return DeclResult(false); +} + +ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc, + ObjCIvarDecl *IV) { + ObjCMethodDecl *CurMethod = getCurMethodDecl(); + assert(CurMethod && CurMethod->isInstanceMethod() && + "should not reference ivar from this context"); + + ObjCInterfaceDecl *IFace = CurMethod->getClassInterface(); + assert(IFace && "should not reference ivar from this context"); + + // If we're referencing an invalid decl, just return this as a silent + // error node. The error diagnostic was already emitted on the decl. + if (IV->isInvalidDecl()) + return ExprError(); + + // Check if referencing a field with __attribute__((deprecated)). + if (DiagnoseUseOfDecl(IV, Loc)) + return ExprError(); + + // FIXME: This should use a new expr for a direct reference, don't + // turn this into Self->ivar, just return a BareIVarExpr or something. + IdentifierInfo &II = Context.Idents.get("self"); + UnqualifiedId SelfName; + SelfName.setIdentifier(&II, SourceLocation()); + SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam); + CXXScopeSpec SelfScopeSpec; + SourceLocation TemplateKWLoc; + ExprResult SelfExpr = + ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName, + /*HasTrailingLParen=*/false, + /*IsAddressOfOperand=*/false); + if (SelfExpr.isInvalid()) + return ExprError(); + + SelfExpr = DefaultLvalueConversion(SelfExpr.get()); + if (SelfExpr.isInvalid()) + return ExprError(); + + MarkAnyDeclReferenced(Loc, IV, true); + + ObjCMethodFamily MF = CurMethod->getMethodFamily(); + if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize && + !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV)) + Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); + + ObjCIvarRefExpr *Result = new (Context) + ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, + IV->getLocation(), SelfExpr.get(), true, true); + + if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + if (!isUnevaluatedContext() && + !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) + getCurFunction()->recordUseOfWeak(Result); + } + if (getLangOpts().ObjCAutoRefCount) + if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) + ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); + + return Result; +} + +/// The parser has read a name in, and Sema has detected that we're currently +/// inside an ObjC method. Perform some additional checks and determine if we +/// should form a reference to an ivar. If so, build an expression referencing +/// that ivar. +ExprResult +Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, + IdentifierInfo *II, bool AllowBuiltinCreation) { + // FIXME: Integrate this lookup step into LookupParsedName. + DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II); + if (Ivar.isInvalid()) + return ExprError(); + if (Ivar.isUsable()) + return BuildIvarRefExpr(S, Lookup.getNameLoc(), + cast<ObjCIvarDecl>(Ivar.get())); + + if (Lookup.empty() && II && AllowBuiltinCreation) + LookupBuiltin(Lookup); + // Sentinel value saying that we didn't do anything special. - return ExprResult((Expr *)nullptr); + return ExprResult(false); } /// Cast a base object to a member's actual type. |