From 8b1becf2e31d9170ee356a19c7b6ea991d3a520f Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 8 Jul 2019 20:04:39 +0000 Subject: [PATCH] [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 --- clang/include/clang/AST/Expr.h | 9 +++++++ clang/include/clang/Basic/Attr.td | 10 +++++++ clang/lib/Sema/SemaDecl.cpp | 34 +++++++++++++++--------- clang/lib/Sema/SemaExpr.cpp | 8 ++++++ clang/lib/Sema/SemaExprCXX.cpp | 8 ++++++ clang/test/SemaObjC/arc-repeated-weak.mm | 16 +++++++++-- 6 files changed, 71 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index d44a815c8699..1d4a847422ec 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -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 diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 93913b043ec8..c70e5dfdb5bf 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -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]>; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 03b6cc916570..f2838df69235 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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(); 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; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 466d9fdb9b97..f44235491d6e 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 32b35ba7c32b..5a71443e7924 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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: diff --git a/clang/test/SemaObjC/arc-repeated-weak.mm b/clang/test/SemaObjC/arc-repeated-weak.mm index 4eec4d2fe69c..6c7a6292f992 100644 --- a/clang/test/SemaObjC/arc-repeated-weak.mm +++ b/clang/test/SemaObjC/arc-repeated-weak.mm @@ -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.