[Sema] Resolve placeholder types before type deduction to silence

spurious `-Warc-repeated-use-of-weak` warnings

The spurious -Warc-repeated-use-of-weak warnings are issued when an
initializer expression uses a weak ObjC pointer.

My first attempt to silence the warnings (r350917) caused clang to
reject code that is legal in C++17. The patch is based on the feedback I
received from Richard when the patch was reverted.

http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20190422/268945.html
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20190422/268943.html

Differential Revision: https://reviews.llvm.org/D62645

llvm-svn: 365382
This commit is contained in:
Akira Hatanaka 2019-07-08 20:04:39 +00:00
parent c9fa99d066
commit 8b1becf2e3
6 changed files with 71 additions and 14 deletions

View File

@ -490,6 +490,15 @@ public:
return false;
}
/// Returns whether this expression has a placeholder type that isn't
/// Overload.
bool hasNonOverloadPlaceholderType() const {
if (auto *PlaceholderType = getType()->getAsPlaceholderType())
if (PlaceholderType->isNonOverloadPlaceholderType())
return true;
return false;
}
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in

View File

@ -1844,6 +1844,16 @@ def ObjCBoxable : Attr {
let Documentation = [ObjCBoxableDocs];
}
// This is used to indicate that the type of the annotated variable's
// initializer was changed from UnknownAny to 'id'.
def ObjCDefaultedAnyToId : Attr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
let Subjects = SubjectList<[Var]>;
let Documentation = [Undocumented];
}
def OptimizeNone : InheritableAttr {
let Spellings = [Clang<"optnone">];
let Subjects = SubjectList<[Function, ObjCMethod]>;

View File

@ -10985,18 +10985,6 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
return QualType();
}
// Expressions default to 'id' when we're in a debugger.
bool DefaultedAnyToId = false;
if (getLangOpts().DebuggerCastResultToId &&
Init->getType() == Context.UnknownAnyTy && !IsInitCapture) {
ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
if (Result.isInvalid()) {
return QualType();
}
Init = Result.get();
DefaultedAnyToId = true;
}
// C++ [dcl.decomp]p1:
// If the assignment-expression [...] has array type A and no ref-qualifier
// is present, e has type cv A
@ -11030,6 +11018,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
// checks.
// We only want to warn outside of template instantiations, though:
// inside a template, the 'id' could have come from a parameter.
bool DefaultedAnyToId = VDecl && VDecl->hasAttr<ObjCDefaultedAnyToIdAttr>();
if (!inTemplateInstantiation() && !DefaultedAnyToId && !IsInitCapture &&
!DeducedType.isNull() && DeducedType->isObjCIdType()) {
SourceLocation Loc = TSI->getTypeLoc().getBeginLoc();
@ -11108,6 +11097,27 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
}
Init = Res.get();
// Expressions default to 'id' when we're in a debugger
// and we are assigning it to a variable of Objective-C pointer type.
if (getLangOpts().DebuggerCastResultToId &&
Init->getType() == Context.UnknownAnyTy) {
ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
if (Result.isInvalid()) {
VDecl->setInvalidDecl();
return;
}
Init = Result.get();
VDecl->addAttr(ObjCDefaultedAnyToIdAttr::CreateImplicit(Context));
} else if (!Init->getType().isNull() &&
Init->hasNonOverloadPlaceholderType()) {
Res = CheckPlaceholderExpr(Init).get();
if (!Res.isUsable()) {
VDecl->setInvalidDecl();
return;
}
Init = Res.get();
}
if (DeduceVariableDeclarationType(VDecl, DirectInit, Init))
return;
}

View File

@ -6678,6 +6678,14 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
ExprResult Sema::ActOnParenListExpr(SourceLocation L,
SourceLocation R,
MultiExprArg Val) {
for (size_t I = 0, E = Val.size(); I != E; ++I)
if (Val[I]->hasNonOverloadPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(Val[I]);
if (!Result.isUsable())
return ExprError();
Val[I] = Result.get();
}
return ParenListExpr::Create(Context, L, Val, R);
}

View File

@ -1793,6 +1793,14 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
NumInits = List->getNumExprs();
}
for (unsigned I = 0, E = NumInits; I != E; ++I)
if (Inits[I]->hasNonOverloadPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(Inits[I]);
if (!Result.isUsable())
return ExprError();
Inits[I] = Result.get();
}
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wno-objc-root-class -std=c++11 -Warc-repeated-use-of-weak -verify %s
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-weak -fblocks -Wno-objc-root-class -std=c++11 -Warc-repeated-use-of-weak -verify %s
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wno-objc-root-class -std=c++14 -Warc-repeated-use-of-weak -verify %s
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-weak -fblocks -Wno-objc-root-class -std=c++14 -Warc-repeated-use-of-weak -verify %s
@interface Test {
@public
@ -467,6 +467,18 @@ void foo() {
__typeof__(NSBundle2.foo2.weakProp) t5;
}
void testAuto() {
auto __weak wp = NSBundle2.foo2.weakProp;
}
void testLambdaCaptureInit() {
[capture(NSBundle2.foo2.weakProp)] {} ();
}
void testAutoNew() {
auto p = new auto(NSBundle2.foo2.weakProp);
}
// This used to crash in the constructor of WeakObjectProfileTy when a
// DeclRefExpr was passed that didn't reference a VarDecl.