aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AttributeList.cpp5
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp3
-rw-r--r--lib/Sema/JumpDiagnostics.cpp144
-rw-r--r--lib/Sema/Sema.cpp40
-rw-r--r--lib/Sema/SemaCXXCast.cpp137
-rw-r--r--lib/Sema/SemaChecking.cpp282
-rw-r--r--lib/Sema/SemaCodeComplete.cpp97
-rw-r--r--lib/Sema/SemaDecl.cpp240
-rw-r--r--lib/Sema/SemaDeclAttr.cpp112
-rw-r--r--lib/Sema/SemaDeclCXX.cpp45
-rw-r--r--lib/Sema/SemaDeclObjC.cpp429
-rw-r--r--lib/Sema/SemaExpr.cpp229
-rw-r--r--lib/Sema/SemaExprCXX.cpp308
-rw-r--r--lib/Sema/SemaExprObjC.cpp409
-rw-r--r--lib/Sema/SemaInit.cpp315
-rw-r--r--lib/Sema/SemaObjCProperty.cpp383
-rw-r--r--lib/Sema/SemaOverload.cpp298
-rw-r--r--lib/Sema/SemaStmt.cpp51
-rw-r--r--lib/Sema/SemaTemplate.cpp15
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp7
-rw-r--r--lib/Sema/SemaType.cpp313
-rw-r--r--lib/Sema/TreeTransform.h84
-rw-r--r--lib/Sema/TypeLocBuilder.h9
23 files changed, 3470 insertions, 485 deletions
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 619a5b961b..fda4e0ccd8 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -177,6 +177,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("cf_consumed", AT_cf_consumed)
.Case("cf_returns_not_retained", AT_cf_returns_not_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
+ .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
+ .Case("ns_consumes_self", AT_ns_consumes_self)
+ .Case("ns_consumed", AT_ns_consumed)
+ .Case("objc_lifetime", AT_objc_lifetime)
+ .Case("objc_precise_lifetime", AT_objc_precise_lifetime)
.Case("ownership_returns", AT_ownership_returns)
.Case("ownership_holds", AT_ownership_holds)
.Case("ownership_takes", AT_ownership_takes)
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index af548fe134..c6744ed80d 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -47,5 +47,8 @@ void DelayedDiagnostic::Destroy() {
case Deprecation:
delete [] DeprecationData.Message;
break;
+
+ case ForbiddenType:
+ break;
}
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 679f4fefa2..007d755a87 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -111,90 +111,110 @@ unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
return A;
}
+typedef std::pair<unsigned,unsigned> ScopePair;
+
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
/// diagnostic that should be emitted if control goes over it. If not, return 0.
-static std::pair<unsigned,unsigned>
- GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
+static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
unsigned InDiag = 0, OutDiag = 0;
if (VD->getType()->isVariablyModifiedType())
InDiag = diag::note_protected_by_vla;
- if (VD->hasAttr<BlocksAttr>()) {
- InDiag = diag::note_protected_by___block;
- OutDiag = diag::note_exits___block;
- } else if (VD->hasAttr<CleanupAttr>()) {
- InDiag = diag::note_protected_by_cleanup;
- OutDiag = diag::note_exits_cleanup;
- } else if (isCPlusPlus) {
- if (!VD->hasLocalStorage())
- return std::make_pair(InDiag, OutDiag);
-
- ASTContext &Context = D->getASTContext();
- QualType T = Context.getBaseElementType(VD->getType());
- if (!T->isDependentType()) {
- // C++0x [stmt.dcl]p3:
- // A program that jumps from a point where a variable with automatic
- // storage duration is not in scope to a point where it is in scope
- // is ill-formed unless the variable has scalar type, class type with
- // a trivial default constructor and a trivial destructor, a
- // cv-qualified version of one of these types, or an array of one of
- // the preceding types and is declared without an initializer (8.5).
- // Check whether this is a C++ class.
- CXXRecordDecl *Record = T->getAsCXXRecordDecl();
-
- if (const Expr *Init = VD->getInit()) {
- bool CallsTrivialConstructor = false;
- if (Record) {
- // FIXME: With generalized initializer lists, this may
- // classify "X x{};" as having no initializer.
- if (const CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>(Init))
- if (const CXXConstructorDecl *Constructor
- = Construct->getConstructor())
- if ((Context.getLangOptions().CPlusPlus0x
- ? Record->hasTrivialDefaultConstructor()
- : Record->isPOD()) &&
- Constructor->isDefaultConstructor())
- CallsTrivialConstructor = true;
-
- if (CallsTrivialConstructor && !Record->hasTrivialDestructor())
- InDiag = diag::note_protected_by_variable_nontriv_destructor;
+ if (VD->hasAttr<BlocksAttr>())
+ return ScopePair(diag::note_protected_by___block,
+ diag::note_exits___block);
+
+ if (VD->hasAttr<CleanupAttr>())
+ return ScopePair(diag::note_protected_by_cleanup,
+ diag::note_exits_cleanup);
+
+ if (Context.getLangOptions().ObjCAutoRefCount && VD->hasLocalStorage()) {
+ switch (VD->getType().getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ return ScopePair(diag::note_protected_by_objc_lifetime,
+ diag::note_exits_objc_lifetime);
+ }
+ }
+
+ if (Context.getLangOptions().CPlusPlus && VD->hasLocalStorage()) {
+ // C++0x [stmt.dcl]p3:
+ // A program that jumps from a point where a variable with automatic
+ // storage duration is not in scope to a point where it is in scope
+ // is ill-formed unless the variable has scalar type, class type with
+ // a trivial default constructor and a trivial destructor, a
+ // cv-qualified version of one of these types, or an array of one of
+ // the preceding types and is declared without an initializer.
+
+ // C++03 [stmt.dcl.p3:
+ // A program that jumps from a point where a local variable
+ // with automatic storage duration is not in scope to a point
+ // where it is in scope is ill-formed unless the variable has
+ // POD type and is declared without an initializer.
+
+ if (const Expr *init = VD->getInit()) {
+ // We actually give variables of record type (or array thereof)
+ // an initializer even if that initializer only calls a trivial
+ // ctor. Detect that case.
+ // FIXME: With generalized initializer lists, this may
+ // classify "X x{};" as having no initializer.
+ unsigned inDiagToUse = diag::note_protected_by_variable_init;
+
+ const CXXRecordDecl *record = 0;
+
+ if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
+ const CXXConstructorDecl *ctor = cce->getConstructor();
+ record = ctor->getParent();
+
+ if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+ if (Context.getLangOptions().CPlusPlus0x) {
+ inDiagToUse = (record->hasTrivialDestructor() ? 0 :
+ diag::note_protected_by_variable_nontriv_destructor);
+ } else {
+ if (record->isPOD())
+ inDiagToUse = 0;
+ }
}
-
- if (!CallsTrivialConstructor)
- InDiag = diag::note_protected_by_variable_init;
+ } else if (VD->getType()->isArrayType()) {
+ record = VD->getType()->getBaseElementTypeUnsafe()
+ ->getAsCXXRecordDecl();
}
-
- // Note whether we have a class with a non-trivial destructor.
- if (Record && !Record->hasTrivialDestructor())
+
+ if (inDiagToUse)
+ InDiag = inDiagToUse;
+
+ // Also object to indirect jumps which leave scopes with dtors.
+ if (record && !record->hasTrivialDestructor())
OutDiag = diag::note_exits_dtor;
}
}
- return std::make_pair(InDiag, OutDiag);
+ return ScopePair(InDiag, OutDiag);
}
if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
- return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
+ return ScopePair(diag::note_protected_by_vla_typedef, 0);
}
if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
- return std::make_pair((unsigned) diag::note_protected_by_vla_type_alias, 0);
+ return ScopePair(diag::note_protected_by_vla_type_alias, 0);
}
- return std::make_pair(0U, 0U);
+ return ScopePair(0U, 0U);
}
/// \brief Build scope information for a declaration that is part of a DeclStmt.
void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
- bool isCPlusPlus = this->S.getLangOptions().CPlusPlus;
-
// If this decl causes a new scope, push and switch to it.
- std::pair<unsigned,unsigned> Diags
- = GetDiagForGotoScopeDecl(D, isCPlusPlus);
+ std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D);
if (Diags.first || Diags.second) {
Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
D->getLocation()));
@@ -369,6 +389,18 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
continue;
}
+ // Disallow jumps into the protected statement of an @autoreleasepool.
+ if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
+ // Recursively walk the AST for the @autoreleasepool part, protected by a new
+ // scope.
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_autoreleasepool,
+ diag::note_exits_objc_autoreleasepool,
+ AS->getAtLoc()));
+ BuildScopeInformation(AS->getSubStmt(), Scopes.size()-1);
+ continue;
+ }
+
// Recursively walk the AST.
BuildScopeInformation(SubStmt, ParentScope);
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 8297b3155a..7d22031ecb 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -143,7 +143,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
PackContext(0), MSStructPragmaOn(false), VisContext(0),
- LateTemplateParser(0), OpaqueParser(0),
+ ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -162,7 +162,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
&Context);
ExprEvalContexts.push_back(
- ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
+ ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false));
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
}
@@ -202,6 +202,32 @@ Sema::~Sema() {
ExternalSema->ForgetSema();
}
+
+/// makeUnavailableInSystemHeader - There is an error in the current
+/// context. If we're still in a system header, and we can plausibly
+/// make the relevant declaration unavailable instead of erroring, do
+/// so and return true.
+bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
+ llvm::StringRef msg) {
+ // If we're not in a function, it's an error.
+ FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext);
+ if (!fn) return false;
+
+ // If we're in template instantiation, it's an error.
+ if (!ActiveTemplateInstantiations.empty())
+ return false;
+
+ // If that function's not in a system header, it's an error.
+ if (!Context.getSourceManager().isInSystemHeader(loc))
+ return false;
+
+ // If the function is already unavailable, it's not an error.
+ if (fn->hasAttr<UnavailableAttr>()) return true;
+
+ fn->addAttr(new (Context) UnavailableAttr(loc, Context, msg));
+ return true;
+}
+
ASTMutationListener *Sema::getASTMutationListener() const {
return getASTConsumer().GetASTMutationListener();
}
@@ -211,13 +237,17 @@ ASTMutationListener *Sema::getASTMutationListener() const {
/// The result is of the given category.
ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
CastKind Kind, ExprValueKind VK,
- const CXXCastPath *BasePath) {
+ const CXXCastPath *BasePath,
+ CheckedConversionKind CCK) {
QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
if (ExprTy == TypeTy)
return Owned(E);
+ if (getLangOptions().ObjCAutoRefCount)
+ CheckObjCARCConversion(SourceRange(), Ty, E, CCK);
+
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
if (Kind == CK_DerivedToBase &&
@@ -729,8 +759,8 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
/// \brief Determine whether any errors occurred within this function/method/
/// block.
-bool Sema::hasAnyErrorsInThisFunction() const {
- return getCurFunction()->ErrorTrap.hasErrorOccurred();
+bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
+ return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred();
}
BlockScopeInfo *Sema::getCurBlock() {
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index e46ad5bcfe..0b3083aaa6 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -63,7 +63,8 @@ static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
CastKind &Kind,
CXXCastPath &BasePath);
-static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
+static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
+ bool CheckCVR, bool CheckObjCLifetime);
// The Try functions attempt a specific way of casting. If they succeed, they
// return TC_Success. If their way of casting is not appropriate for the given
@@ -109,12 +110,14 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExp
CXXCastPath &BasePath);
static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType, bool CStyle,
+ QualType DestType,
+ Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType, bool CStyle,
+ QualType DestType,
+ Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind,
@@ -248,8 +251,10 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
InitializationKind initKind
- = InitializationKind::CreateCast(/*type range?*/ range,
- (CT == CT_CStyle || CT == CT_Functional));
+ = (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
+ range)
+ : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range)
+ : InitializationKind::CreateCast(/*type range?*/ range);
InitializationSequence sequence(S, entity, initKind, &src, 1);
assert(sequence.Failed() && "initialization succeeded on second try?");
@@ -373,8 +378,19 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
/// the cast checkers. Both arguments must denote pointer (possibly to member)
/// types.
+///
+/// \param CheckCVR Whether to check for const/volatile/restrict qualifiers.
+///
+/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers.
static bool
-CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
+CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
+ bool CheckCVR, bool CheckObjCLifetime) {
+ // If the only checking we care about is for Objective-C lifetime qualifiers,
+ // and we're not in ARC mode, there's nothing to check.
+ if (!CheckCVR && CheckObjCLifetime &&
+ !Self.Context.getLangOptions().ObjCAutoRefCount)
+ return false;
+
// Casting away constness is defined in C++ 5.2.11p8 with reference to
// C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
// the rules are non-trivial. So first we construct Tcv *...cv* as described
@@ -394,13 +410,23 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
// purpose of this check, because other qualifiers (address spaces,
// Objective-C GC, etc.) are part of the type's identity.
while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
- Qualifiers SrcQuals;
+ // Determine the relevant qualifiers at this level.
+ Qualifiers SrcQuals, DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
- cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()));
-
- Qualifiers DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
- cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()));
+
+ Qualifiers RetainedSrcQuals, RetainedDestQuals;
+ if (CheckCVR) {
+ RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
+ RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers());
+ }
+
+ if (CheckObjCLifetime &&
+ !DestQuals.compatiblyIncludesObjCLifetime(SrcQuals))
+ return true;
+
+ cv1.push_back(RetainedSrcQuals);
+ cv2.push_back(RetainedDestQuals);
}
if (cv1.empty())
return false;
@@ -420,8 +446,10 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
}
// Test if they're compatible.
+ bool ObjCLifetimeConversion;
return SrcConstruct != DestConstruct &&
- !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false);
+ !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false,
+ ObjCLifetimeConversion);
}
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
@@ -595,9 +623,10 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
- msg, Kind)
- != TC_Success && msg != 0)
+ TryCastResult tcr =
+ TryReinterpretCast(Self, SrcExpr, DestType,
+ /*CStyle*/false, OpRange, msg, Kind);
+ if (tcr != TC_Success && msg != 0)
{
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@@ -611,7 +640,10 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
} else {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType);
}
- }
+ } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) {
+ Self.CheckObjCARCConversion(OpRange, DestType,
+ SrcExpr.get(), Sema::CCK_OtherCast);
+ }
}
@@ -654,8 +686,10 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
- Kind, BasePath) != TC_Success && msg != 0) {
+ TryCastResult tcr
+ = TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
+ Kind, BasePath);
+ if (tcr != TC_Success && msg != 0) {
if (SrcExpr.isInvalid())
return;
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
@@ -667,6 +701,12 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
} else {
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType);
}
+ } else if (tcr == TC_Success) {
+ if (Kind == CK_BitCast)
+ Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
+ if (Self.getLangOptions().ObjCAutoRefCount)
+ Self.CheckObjCARCConversion(OpRange, DestType,
+ SrcExpr.get(), Sema::CCK_OtherCast);
}
else if (Kind == CK_BitCast)
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
@@ -676,10 +716,15 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType, bool CStyle,
+ QualType DestType,
+ Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath) {
+ // Determine whether we have the semantics of a C-style cast.
+ bool CStyle
+ = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
+
// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
// struct A {};
@@ -715,7 +760,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
- tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
+ tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg,
Kind);
if (SrcExpr.isInvalid())
return TC_Failed;
@@ -792,10 +837,20 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestPointee = DestPointer->getPointeeType();
if (DestPointee->isIncompleteOrObjectType()) {
// This is definitely the intended conversion, but it might fail due
- // to a const violation.
- if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- msg = diag::err_bad_cxx_cast_qualifiers_away;
- return TC_Failed;
+ // to a qualifier violation. Note that we permit Objective-C lifetime
+ // and GC qualifier mismatches here.
+ if (!CStyle) {
+ Qualifiers DestPointeeQuals = DestPointee.getQualifiers();
+ Qualifiers SrcPointeeQuals = SrcPointee.getQualifiers();
+ DestPointeeQuals.removeObjCGCAttr();
+ DestPointeeQuals.removeObjCLifetime();
+ SrcPointeeQuals.removeObjCGCAttr();
+ SrcPointeeQuals.removeObjCLifetime();
+ if (DestPointeeQuals != SrcPointeeQuals &&
+ !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
+ return TC_Failed;
+ }
}
Kind = CK_BitCast;
return TC_Success;
@@ -845,6 +900,7 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// FIXME: Should allow casting away constness if CStyle.
bool DerivedToBase;
bool ObjCConversion;
+ bool ObjCLifetimeConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@@ -854,8 +910,9 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
ToType, FromType,
- DerivedToBase, ObjCConversion) <
- Sema::Ref_Compatible_With_Added_Qualification) {
+ DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion)
+ < Sema::Ref_Compatible_With_Added_Qualification) {
msg = diag::err_bad_lvalue_to_rvalue_cast;
return TC_Failed;
}
@@ -1172,7 +1229,8 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- bool CStyle, const SourceRange &OpRange, unsigned &msg,
+ Sema::CheckedConversionKind CCK,
+ const SourceRange &OpRange, unsigned &msg,
CastKind &Kind) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
@@ -1184,7 +1242,11 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
- = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle);
+ = (CCK == Sema::CCK_CStyleCast)
+ ? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange)
+ : (CCK == Sema::CCK_FunctionalCast)
+ ? InitializationKind::CreateFunctionalCast(OpRange)
+ : InitializationKind::CreateCast(OpRange);
Expr *SrcExprRaw = SrcExpr.get();
InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1);
@@ -1193,7 +1255,8 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
// There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
-
+ bool CStyle
+ = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
@@ -1428,7 +1491,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// constness.
// A reinterpret_cast followed by a const_cast can, though, so in C-style,
// we accept it.
- if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+ /*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1543,7 +1607,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
// The C-style cast operator can.
- if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+ /*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1675,11 +1740,14 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
if (tcr == TC_Success)
Kind = CK_NoOp;
+ Sema::CheckedConversionKind CCK
+ = FunctionalStyle? Sema::CCK_FunctionalCast
+ : Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
ExprResult CastExprRes = Owned(CastExpr);
- tcr = TryStaticCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, msg,
- Kind, BasePath);
+ tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind,
+ BasePath);
if (CastExprRes.isInvalid())
return ExprError();
CastExpr = CastExprRes.take();
@@ -1694,6 +1762,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
}
}
+ if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success)
+ CheckObjCARCConversion(R, CastTy, CastExpr, CCK);
+
if (tcr != TC_Success && msg != 0) {
if (CastExpr->getType() == Context.OverloadTy) {
DeclAccessPair Found;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 389dd91f32..d45ebf9033 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -382,14 +383,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// casts here.
// FIXME: We don't allow floating point scalars as input.
Expr *FirstArg = TheCall->getArg(0);
- if (!FirstArg->getType()->isPointerType()) {
+ const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
+ if (!pointerType) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
<< FirstArg->getType() << FirstArg->getSourceRange();
return ExprError();
}
- QualType ValType =
- FirstArg->getType()->getAs<PointerType>()->getPointeeType();
+ QualType ValType = pointerType->getPointeeType();
if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
!ValType->isBlockPointerType()) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr)
@@ -397,6 +398,20 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
return ExprError();
}
+ switch (ValType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // okay
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Autoreleasing:
+ Diag(DRE->getLocStart(), diag::err_arc_atomic_lifetime)
+ << ValType << FirstArg->getSourceRange();
+ return ExprError();
+ }
+
// The majority of builtins return a value, but a few have special return
// types, so allow them to override appropriately below.
QualType ResultType = ValType;
@@ -518,7 +533,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
CastKind Kind = CK_Invalid;
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
- Arg = CheckCastTypes(Arg.get()->getSourceRange(), ValType, Arg.take(), Kind, VK, BasePath);
+ Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(),
+ ValType, Arg.take(), Kind, VK, BasePath);
if (Arg.isInvalid())
return ExprError();
@@ -1849,6 +1865,7 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
QualType DestTy = Dest->getType();
if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
QualType PointeeTy = DestPtrTy->getPointeeType();
+
if (PointeeTy->isVoidType())
continue;
@@ -1863,16 +1880,22 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
break;
}
+ unsigned DiagID;
+
// Always complain about dynamic classes.
- if (isDynamicClassType(PointeeTy)) {
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_dyn_class_memaccess)
- << ArgIdx << FnName << PointeeTy
- << Call->getCallee()->getSourceRange());
- } else {
+ if (isDynamicClassType(PointeeTy))
+ DiagID = diag::warn_dyn_class_memaccess;
+ else if (PointeeTy.hasNonTrivialObjCLifetime() &&
+ !FnName->isStr("memset"))
+ DiagID = diag::warn_arc_object_memaccess;
+ else
continue;
- }
+
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(DiagID)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
@@ -1899,7 +1922,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
// Perform checking for returned stack addresses, local blocks,
// label addresses or references to temporaries.
- if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
+ if (lhsType->isPointerType() ||
+ (!getLangOptions().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
stackE = EvalAddr(RetValExp, refVars);
} else if (lhsType->isReferenceType()) {
stackE = EvalVal(RetValExp, refVars);
@@ -2070,7 +2094,8 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
// pointer values, and pointer-to-pointer conversions.
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
- case Stmt::CXXFunctionalCast