Update aosp/master clang for rebase to r233350
Change-Id: I12d4823f10bc9e445b8b86e7721b71f98d1df442
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 5a0d8d4..abcccba 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -319,6 +319,15 @@
if (SemaBuiltinLongjmp(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_setjmp:
+ if (SemaBuiltinSetjmp(TheCall))
+ return ExprError();
+ break;
+ case Builtin::BI_setjmp:
+ case Builtin::BI_setjmpex:
+ if (checkArgCount(*this, TheCall, 1))
+ return true;
+ break;
case Builtin::BI__builtin_classify_type:
if (checkArgCount(*this, TheCall, 1)) return true;
@@ -499,6 +508,19 @@
break;
}
+ case Builtin::BI__GetExceptionInfo:
+ if (checkArgCount(*this, TheCall, 1))
+ return ExprError();
+
+ if (CheckCXXThrowOperand(
+ TheCall->getLocStart(),
+ Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()),
+ TheCall))
+ return ExprError();
+
+ TheCall->setType(Context.VoidPtrTy);
+ break;
+
}
// Since the target specific builtins for each arch overlap, only check those
@@ -878,14 +900,6 @@
switch (BuiltinID) {
default: return false;
case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break;
- case X86::BI__builtin_ia32_vextractf128_pd256:
- case X86::BI__builtin_ia32_vextractf128_ps256:
- case X86::BI__builtin_ia32_vextractf128_si256:
- case X86::BI__builtin_ia32_extract128i256: i = 1, l = 0, u = 1; break;
- case X86::BI__builtin_ia32_vinsertf128_pd256:
- case X86::BI__builtin_ia32_vinsertf128_ps256:
- case X86::BI__builtin_ia32_vinsertf128_si256:
- case X86::BI__builtin_ia32_insert128i256: i = 2, l = 0; u = 1; break;
case X86::BI__builtin_ia32_sha1rnds4: i = 2, l = 0; u = 3; break;
case X86::BI__builtin_ia32_vpermil2pd:
case X86::BI__builtin_ia32_vpermil2pd256:
@@ -1309,9 +1323,10 @@
// M is C if C is an integer, and ptrdiff_t if C is a pointer, and
// the int parameters are for orderings.
- assert(AtomicExpr::AO__c11_atomic_init == 0 &&
- AtomicExpr::AO__c11_atomic_fetch_xor + 1 == AtomicExpr::AO__atomic_load
- && "need to update code for modified C11 atomics");
+ static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
+ AtomicExpr::AO__c11_atomic_fetch_xor + 1 ==
+ AtomicExpr::AO__atomic_load,
+ "need to update code for modified C11 atomics");
bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init &&
Op <= AtomicExpr::AO__c11_atomic_fetch_xor;
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
@@ -2128,7 +2143,7 @@
if (checkBuiltinArgument(*this, Call, 0))
return true;
- static const struct {
+ const struct {
unsigned ArgNo;
QualType Type;
} ArgumentTypes[] = {
@@ -2460,8 +2475,13 @@
}
/// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val).
-/// This checks that val is a constant 1.
+/// This checks that the target supports __builtin_longjmp and
+/// that val is a constant 1.
bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
+ if (!Context.getTargetInfo().hasSjLjLowering())
+ return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_unsupported)
+ << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd());
+
Expr *Arg = TheCall->getArg(1);
llvm::APSInt Result;
@@ -2476,6 +2496,16 @@
return false;
}
+
+/// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]).
+/// This checks that the target supports __builtin_setjmp.
+bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) {
+ if (!Context.getTargetInfo().hasSjLjLowering())
+ return Diag(TheCall->getLocStart(), diag::err_builtin_setjmp_unsupported)
+ << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd());
+ return false;
+}
+
namespace {
enum StringLiteralCheckType {
SLCT_NotALiteral,
@@ -3669,8 +3699,11 @@
ExprTy = TET->getUnderlyingExpr()->getType();
}
- if (AT.matchesType(S.Context, ExprTy))
+ analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy);
+
+ if (match == analyze_printf::ArgType::Match) {
return true;
+ }
// Look through argument promotions for our error message's reported type.
// This includes the integral and floating promotions, but excludes array
@@ -3765,16 +3798,18 @@
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
+ unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
+ if (match == analyze_format_string::ArgType::NoMatchPedantic) {
+ diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ }
// In this case, the specifier is wrong and should be changed to match
// the argument.
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum
- << E->getSourceRange(),
- E->getLocStart(),
- /*IsStringLocation*/false,
- SpecRange,
- FixItHint::CreateReplacement(SpecRange, os.str()));
+ EmitFormatDiagnostic(S.PDiag(diag)
+ << AT.getRepresentativeTypeName(S.Context)
+ << IntendedTy << IsEnum << E->getSourceRange(),
+ E->getLocStart(),
+ /*IsStringLocation*/ false, SpecRange,
+ FixItHint::CreateReplacement(SpecRange, os.str()));
} else {
// The canonical type for formatting this value is different from the
@@ -3848,15 +3883,18 @@
// arguments here.
switch (S.isValidVarArgType(ExprTy)) {
case Sema::VAK_Valid:
- case Sema::VAK_ValidInCXX11:
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum
- << CSR
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation*/false, CSR);
- break;
+ case Sema::VAK_ValidInCXX11: {
+ unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
+ if (match == analyze_printf::ArgType::NoMatchPedantic) {
+ diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ }
+ EmitFormatDiagnostic(
+ S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ << IsEnum << CSR << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/ false, CSR);
+ break;
+ }
case Sema::VAK_Undefined:
case Sema::VAK_MSVCUndefined:
EmitFormatDiagnostic(
@@ -3988,13 +4026,13 @@
FixItHint::CreateRemoval(R));
}
}
-
+
if (!FS.consumesDataArgument()) {
// FIXME: Technically specifying a precision or field width here
// makes no sense. Worth issuing a warning at some point.
return true;
}
-
+
// Consume the argument.
unsigned argIndex = FS.getArgIndex();
if (argIndex < NumDataArgs) {
@@ -4003,7 +4041,7 @@
// function if we encounter some other error.
CoveredArgs.set(argIndex);
}
-
+
// Check the length modifier is valid with the given conversion specifier.
if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
@@ -4020,47 +4058,57 @@
// The remaining checks depend on the data arguments.
if (HasVAListArg)
return true;
-
+
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
return false;
-
+
// Check that the argument type matches the format specifier.
const Expr *Ex = getDataArg(argIndex);
if (!Ex)
return true;
const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
- if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) {
- ScanfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(Ex->getType(),
- Ex->IgnoreImpCasts()->getType(),
- S.getLangOpts(), S.Context);
- if (success) {
- // Get the fix string from the fixed format specifier.
- SmallString<128> buf;
- llvm::raw_svector_ostream os(buf);
- fixedFS.toString(os);
+ if (!AT.isValid()) {
+ return true;
+ }
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false
- << Ex->getSourceRange(),
+ analyze_format_string::ArgType::MatchKind match =
+ AT.matchesType(S.Context, Ex->getType());
+ if (match == analyze_format_string::ArgType::Match) {
+ return true;
+ }
+
+ ScanfSpecifier fixedFS = FS;
+ bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(),
+ S.getLangOpts(), S.Context);
+
+ unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
+ if (match == analyze_format_string::ArgType::NoMatchPedantic) {
+ diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ }
+
+ if (success) {
+ // Get the fix string from the fixed format specifier.
+ SmallString<128> buf;
+ llvm::raw_svector_ostream os(buf);
+ fixedFS.toString(os);
+
+ EmitFormatDiagnostic(
+ S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context)
+ << Ex->getType() << false << Ex->getSourceRange(),
Ex->getLocStart(),
- /*IsStringLocation*/false,
+ /*IsStringLocation*/ false,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateReplacement(
- getSpecifierRange(startSpecifier, specifierLen),
- os.str()));
- } else {
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false
- << Ex->getSourceRange(),
- Ex->getLocStart(),
- /*IsStringLocation*/false,
- getSpecifierRange(startSpecifier, specifierLen));
- }
+ getSpecifierRange(startSpecifier, specifierLen), os.str()));
+ } else {
+ EmitFormatDiagnostic(S.PDiag(diag)
+ << AT.getRepresentativeTypeName(S.Context)
+ << Ex->getType() << false << Ex->getSourceRange(),
+ Ex->getLocStart(),
+ /*IsStringLocation*/ false,
+ getSpecifierRange(startSpecifier, specifierLen));
}
return true;
@@ -4602,7 +4650,7 @@
/// \brief If E is a sizeof expression, returns its argument expression,
/// otherwise returns NULL.
-static const Expr *getSizeOfExprArg(const Expr* E) {
+static const Expr *getSizeOfExprArg(const Expr *E) {
if (const UnaryExprOrTypeTraitExpr *SizeOf =
dyn_cast<UnaryExprOrTypeTraitExpr>(E))
if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType())
@@ -4612,7 +4660,7 @@
}
/// \brief If E is a sizeof expression, returns its argument type.
-static QualType getSizeOfArgType(const Expr* E) {
+static QualType getSizeOfArgType(const Expr *E) {
if (const UnaryExprOrTypeTraitExpr *SizeOf =
dyn_cast<UnaryExprOrTypeTraitExpr>(E))
if (SizeOf->getKind() == clang::UETT_SizeOf)
@@ -4658,8 +4706,9 @@
SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange();
QualType DestTy = Dest->getType();
+ QualType PointeeTy;
if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
- QualType PointeeTy = DestPtrTy->getPointeeType();
+ PointeeTy = DestPtrTy->getPointeeType();
// Never warn about void type pointers. This can be used to suppress
// false positives.
@@ -4739,47 +4788,53 @@
break;
}
}
+ } else if (DestTy->isArrayType()) {
+ PointeeTy = DestTy;
+ }
- // Always complain about dynamic classes.
- bool IsContained;
- if (const CXXRecordDecl *ContainedRD =
- getContainedDynamicClass(PointeeTy, IsContained)) {
+ if (PointeeTy == QualType())
+ continue;
- unsigned OperationType = 0;
- // "overwritten" if we're warning about the destination for any call
- // but memcmp; otherwise a verb appropriate to the call.
- if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
- if (BId == Builtin::BImemcpy)
- OperationType = 1;
- else if(BId == Builtin::BImemmove)
- OperationType = 2;
- else if (BId == Builtin::BImemcmp)
- OperationType = 3;
- }
-
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_dyn_class_memaccess)
- << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
- << FnName << IsContained << ContainedRD << OperationType
- << Call->getCallee()->getSourceRange());
- } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
- BId != Builtin::BImemset)
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_arc_object_memaccess)
- << ArgIdx << FnName << PointeeTy
- << Call->getCallee()->getSourceRange());
- else
- continue;
+ // Always complain about dynamic classes.
+ bool IsContained;
+ if (const CXXRecordDecl *ContainedRD =
+ getContainedDynamicClass(PointeeTy, IsContained)) {
+ unsigned OperationType = 0;
+ // "overwritten" if we're warning about the destination for any call
+ // but memcmp; otherwise a verb appropriate to the call.
+ if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
+ if (BId == Builtin::BImemcpy)
+ OperationType = 1;
+ else if(BId == Builtin::BImemmove)
+ OperationType = 2;
+ else if (BId == Builtin::BImemcmp)
+ OperationType = 3;
+ }
+
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
- PDiag(diag::note_bad_memaccess_silence)
- << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
- break;
- }
+ PDiag(diag::warn_dyn_class_memaccess)
+ << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
+ << FnName << IsContained << ContainedRD << OperationType
+ << Call->getCallee()->getSourceRange());
+ } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
+ BId != Builtin::BImemset)
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_arc_object_memaccess)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
+ else
+ continue;
+
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::note_bad_memaccess_silence)
+ << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ break;
}
+
}
// A little helper routine: ignore addition and subtraction of integer literals.
@@ -8169,6 +8224,236 @@
return !isLowercase(str.front());
}
+static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S,
+ ObjCMessageExpr *Message) {
+ if (S.NSMutableArrayPointer.isNull()) {
+ IdentifierInfo *NSMutableArrayId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableArray);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableArrayId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (!InterfaceDecl) {
+ return None;
+ }
+ QualType NSMutableArrayObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableArrayPointer =
+ S.Context.getObjCObjectPointerType(NSMutableArrayObject);
+ }
+
+ if (S.NSMutableArrayPointer != Message->getReceiverType()) {
+ return None;
+ }
+
+ Selector Sel = Message->getSelector();
+
+ Optional<NSAPI::NSArrayMethodKind> MKOpt =
+ S.NSAPIObj->getNSArrayMethodKind(Sel);
+ if (!MKOpt) {
+ return None;
+ }
+
+ NSAPI::NSArrayMethodKind MK = *MKOpt;
+
+ switch (MK) {
+ case NSAPI::NSMutableArr_addObject:
+ case NSAPI::NSMutableArr_insertObjectAtIndex:
+ case NSAPI::NSMutableArr_setObjectAtIndexedSubscript:
+ return 0;
+ case NSAPI::NSMutableArr_replaceObjectAtIndex:
+ return 1;
+
+ default:
+ return None;
+ }
+
+ return None;
+}
+
+static
+Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,
+ ObjCMessageExpr *Message) {
+
+ if (S.NSMutableDictionaryPointer.isNull()) {
+ IdentifierInfo *NSMutableDictionaryId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableDictionary);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableDictionaryId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (!InterfaceDecl) {
+ return None;
+ }
+ QualType NSMutableDictionaryObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableDictionaryPointer =
+ S.Context.getObjCObjectPointerType(NSMutableDictionaryObject);
+ }
+
+ if (S.NSMutableDictionaryPointer != Message->getReceiverType()) {
+ return None;
+ }
+
+ Selector Sel = Message->getSelector();
+
+ Optional<NSAPI::NSDictionaryMethodKind> MKOpt =
+ S.NSAPIObj->getNSDictionaryMethodKind(Sel);
+ if (!MKOpt) {
+ return None;
+ }
+
+ NSAPI::NSDictionaryMethodKind MK = *MKOpt;
+
+ switch (MK) {
+ case NSAPI::NSMutableDict_setObjectForKey:
+ case NSAPI::NSMutableDict_setValueForKey:
+ case NSAPI::NSMutableDict_setObjectForKeyedSubscript:
+ return 0;
+
+ default:
+ return None;
+ }
+
+ return None;
+}
+
+static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
+
+ ObjCInterfaceDecl *InterfaceDecl;
+ if (S.NSMutableSetPointer.isNull()) {
+ IdentifierInfo *NSMutableSetId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableSet);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableSetId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (InterfaceDecl) {
+ QualType NSMutableSetObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableSetPointer =
+ S.Context.getObjCObjectPointerType(NSMutableSetObject);
+ }
+ }
+
+ if (S.NSCountedSetPointer.isNull()) {
+ IdentifierInfo *NSCountedSetId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSCountedSet);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSCountedSetId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (InterfaceDecl) {
+ QualType NSCountedSetObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSCountedSetPointer =
+ S.Context.getObjCObjectPointerType(NSCountedSetObject);
+ }
+ }
+
+ if (S.NSMutableOrderedSetPointer.isNull()) {
+ IdentifierInfo *NSOrderedSetId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableOrderedSet);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSOrderedSetId,
+ Message->getLocStart(),
+ Sema::LookupOrdinaryName);
+ InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (InterfaceDecl) {
+ QualType NSOrderedSetObject =
+ S.Context.getObjCInterfaceType(InterfaceDecl);
+ S.NSMutableOrderedSetPointer =
+ S.Context.getObjCObjectPointerType(NSOrderedSetObject);
+ }
+ }
+
+ QualType ReceiverType = Message->getReceiverType();
+
+ bool IsMutableSet = !S.NSMutableSetPointer.isNull() &&
+ ReceiverType == S.NSMutableSetPointer;
+ bool IsMutableOrderedSet = !S.NSMutableOrderedSetPointer.isNull() &&
+ ReceiverType == S.NSMutableOrderedSetPointer;
+ bool IsCountedSet = !S.NSCountedSetPointer.isNull() &&
+ ReceiverType == S.NSCountedSetPointer;
+
+ if (!IsMutableSet && !IsMutableOrderedSet && !IsCountedSet) {
+ return None;
+ }
+
+ Selector Sel = Message->getSelector();
+
+ Optional<NSAPI::NSSetMethodKind> MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel);
+ if (!MKOpt) {
+ return None;
+ }
+
+ NSAPI::NSSetMethodKind MK = *MKOpt;
+
+ switch (MK) {
+ case NSAPI::NSMutableSet_addObject:
+ case NSAPI::NSOrderedSet_setObjectAtIndex:
+ case NSAPI::NSOrderedSet_setObjectAtIndexedSubscript:
+ case NSAPI::NSOrderedSet_insertObjectAtIndex:
+ return 0;
+ case NSAPI::NSOrderedSet_replaceObjectAtIndexWithObject:
+ return 1;
+ }
+
+ return None;
+}
+
+void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
+ if (!Message->isInstanceMessage()) {
+ return;
+ }
+
+ Optional<int> ArgOpt;
+
+ if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) &&
+ !(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) &&
+ !(ArgOpt = GetNSSetArgumentIndex(*this, Message))) {
+ return;
+ }
+
+ int ArgIndex = *ArgOpt;
+
+ Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts();
+ if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) {
+ Receiver = OE->getSourceExpr()->IgnoreImpCasts();
+ }
+
+ Expr *Arg = Message->getArg(ArgIndex)->IgnoreImpCasts();
+ if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Arg)) {
+ Arg = OE->getSourceExpr()->IgnoreImpCasts();
+ }
+
+ if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) {
+ if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) {
+ if (ReceiverRE->getDecl() == ArgRE->getDecl()) {
+ ValueDecl *Decl = ReceiverRE->getDecl();
+ Diag(Message->getSourceRange().getBegin(),
+ diag::warn_objc_circular_container)
+ << Decl->getName();
+ Diag(Decl->getLocation(),
+ diag::note_objc_circular_container_declared_here)
+ << Decl->getName();
+ }
+ }
+ } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) {
+ if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) {
+ if (IvarRE->getDecl() == IvarArgRE->getDecl()) {
+ ObjCIvarDecl *Decl = IvarRE->getDecl();
+ Diag(Message->getSourceRange().getBegin(),
+ diag::warn_objc_circular_container)
+ << Decl->getName();
+ Diag(Decl->getLocation(),
+ diag::note_objc_circular_container_declared_here)
+ << Decl->getName();
+ }
+ }
+ }
+
+}
+
/// Check a message send to see if it's likely to cause a retain cycle.
void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
// Only check instance methods whose selector looks like a setter.
@@ -8353,7 +8638,7 @@
// Get line numbers of statement and body.
bool StmtLineInvalid;
- unsigned StmtLine = SourceMgr.getSpellingLineNumber(StmtLoc,
+ unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc,
&StmtLineInvalid);
if (StmtLineInvalid)
return false;