summaryrefslogtreecommitdiffstats
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp84
-rw-r--r--lib/Sema/AttributeList.cpp6
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp8
-rw-r--r--lib/Sema/DeclSpec.cpp80
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp3
-rw-r--r--lib/Sema/JumpDiagnostics.cpp224
-rw-r--r--lib/Sema/Sema.cpp59
-rw-r--r--lib/Sema/SemaCXXCast.cpp162
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp58
-rw-r--r--lib/Sema/SemaChecking.cpp541
-rw-r--r--lib/Sema/SemaCodeComplete.cpp154
-rw-r--r--lib/Sema/SemaDecl.cpp444
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1115
-rw-r--r--lib/Sema/SemaDeclCXX.cpp575
-rw-r--r--lib/Sema/SemaDeclObjC.cpp540
-rw-r--r--lib/Sema/SemaExpr.cpp2769
-rw-r--r--lib/Sema/SemaExprCXX.cpp439
-rw-r--r--lib/Sema/SemaExprMember.cpp1594
-rw-r--r--lib/Sema/SemaExprObjC.cpp627
-rw-r--r--lib/Sema/SemaInit.cpp410
-rw-r--r--lib/Sema/SemaLookup.cpp990
-rw-r--r--lib/Sema/SemaObjCProperty.cpp432
-rw-r--r--lib/Sema/SemaOverload.cpp367
-rw-r--r--lib/Sema/SemaStmt.cpp77
-rw-r--r--lib/Sema/SemaTemplate.cpp134
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp328
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp151
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp42
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp16
-rw-r--r--lib/Sema/SemaType.cpp848
-rw-r--r--lib/Sema/TreeTransform.h175
-rw-r--r--lib/Sema/TypeLocBuilder.h27
33 files changed, 9240 insertions, 4240 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 9efae61..7a14855e 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -486,7 +486,8 @@ static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
const char *initialization = 0;
QualType VariableTy = VD->getType().getCanonicalType();
- if (VariableTy->getAs<ObjCObjectPointerType>()) {
+ if (VariableTy->isObjCObjectPointerType() ||
+ VariableTy->isBlockPointerType()) {
// Check if 'nil' is defined.
if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
initialization = " = nil";
@@ -499,6 +500,13 @@ static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
initialization = " = false";
else if (VariableTy->isEnumeralType())
return;
+ else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) {
+ // Check if 'NULL' is defined.
+ if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL")))
+ initialization = " = NULL";
+ else
+ initialization = " = 0";
+ }
else if (VariableTy->isScalarType())
initialization = " = 0";
@@ -589,7 +597,17 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckUnreachable = 0;
}
-clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
+ : S(s),
+ NumFunctionsAnalyzed(0),
+ NumFunctionsWithBadCFGs(0),
+ NumCFGBlocks(0),
+ MaxCFGBlocksPerFunction(0),
+ NumUninitAnalysisFunctions(0),
+ NumUninitAnalysisVariables(0),
+ MaxUninitAnalysisVariablesPerFunction(0),
+ NumUninitAnalysisBlockVisits(0),
+ MaxUninitAnalysisBlockVisitsPerFunction(0) {
Diagnostic &D = S.getDiagnostics();
DefaultPolicy.enableCheckUnreachable = (unsigned)
(D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
@@ -705,8 +723,68 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
!= Diagnostic::Ignored) {
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
+ UninitVariablesAnalysisStats stats;
+ std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats));
runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
- reporter);
+ reporter, stats);
+
+ if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {
+ ++NumUninitAnalysisFunctions;
+ NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
+ NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
+ MaxUninitAnalysisVariablesPerFunction =
+ std::max(MaxUninitAnalysisVariablesPerFunction,
+ stats.NumVariablesAnalyzed);
+ MaxUninitAnalysisBlockVisitsPerFunction =
+ std::max(MaxUninitAnalysisBlockVisitsPerFunction,
+ stats.NumBlockVisits);
+ }
}
}
+
+ // Collect statistics about the CFG if it was built.
+ if (S.CollectStats && AC.isCFGBuilt()) {
+ ++NumFunctionsAnalyzed;
+ if (CFG *cfg = AC.getCFG()) {
+ // If we successfully built a CFG for this context, record some more
+ // detail information about it.
+ NumCFGBlocks += cfg->getNumBlockIDs();
+ MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
+ cfg->getNumBlockIDs());
+ } else {
+ ++NumFunctionsWithBadCFGs;
+ }
+ }
+}
+
+void clang::sema::AnalysisBasedWarnings::PrintStats() const {
+ llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";
+
+ unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
+ unsigned AvgCFGBlocksPerFunction =
+ !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
+ llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
+ << NumFunctionsWithBadCFGs << " w/o CFGs).\n"
+ << " " << NumCFGBlocks << " CFG blocks built.\n"
+ << " " << AvgCFGBlocksPerFunction
+ << " average CFG blocks per function.\n"
+ << " " << MaxCFGBlocksPerFunction
+ << " max CFG blocks per function.\n";
+
+ unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
+ : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
+ unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
+ : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
+ llvm::errs() << NumUninitAnalysisFunctions
+ << " functions analyzed for uninitialiazed variables\n"
+ << " " << NumUninitAnalysisVariables << " variables analyzed.\n"
+ << " " << AvgUninitVariablesPerFunction
+ << " average variables per function.\n"
+ << " " << MaxUninitAnalysisVariablesPerFunction
+ << " max variables per function.\n"
+ << " " << NumUninitAnalysisBlockVisits << " block visits.\n"
+ << " " << AvgUninitBlockVisitsPerFunction
+ << " average block visits per function.\n"
+ << " " << MaxUninitAnalysisBlockVisitsPerFunction
+ << " max block visits per function.\n";
}
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 619a5b9..5a8330b 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -107,6 +107,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
return llvm::StringSwitch<AttributeList::Kind>(AttrName)
.Case("weak", AT_weak)
.Case("weakref", AT_weakref)
+ .Case("objc_arc_weak_reference_unavailable", AT_arc_weakref_unavailable)
.Case("pure", AT_pure)
.Case("mode", AT_mode)
.Case("used", AT_used)
@@ -177,6 +178,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_ownership", AT_objc_ownership)
+ .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/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 0a67019..6521981 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -23,6 +23,7 @@ add_clang_library(clangSema
SemaExceptionSpec.cpp
SemaExpr.cpp
SemaExprCXX.cpp
+ SemaExprMember.cpp
SemaExprObjC.cpp
SemaInit.cpp
SemaLookup.cpp
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 2334ab5..d7dc5b2 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -46,7 +46,9 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_ObjCImplementation:
case CCC_ObjCIvarList:
case CCC_ClassStructUnion:
- case CCC_MemberAccess:
+ case CCC_DotMemberAccess:
+ case CCC_ArrowMemberAccess:
+ case CCC_ObjCPropertyAccess:
case CCC_EnumTag:
case CCC_UnionTag:
case CCC_ClassOrStructTag:
@@ -64,6 +66,10 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_TypeQualifiers:
case CCC_Other:
case CCC_OtherWithMacros:
+ case CCC_ObjCInstanceMessage:
+ case CCC_ObjCClassMessage:
+ case CCC_ObjCSuperclass:
+ case CCC_ObjCCategoryName:
return false;
}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 5be16e7..c87f2cf 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -13,8 +13,10 @@
#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
@@ -124,6 +126,12 @@ void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) {
Builder.Adopt(Other);
}
+SourceLocation CXXScopeSpec::getLastQualifierNameLoc() const {
+ if (!Builder.getRepresentation())
+ return SourceLocation();
+ return Builder.getTemporary().getLocalBeginLoc();
+}
+
NestedNameSpecifierLoc
CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
if (!Builder.getRepresentation())
@@ -141,6 +149,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
+ SourceLocation MutableLoc,
ExceptionSpecificationType
ESpecType,
SourceLocation ESpecLoc,
@@ -166,6 +175,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
I.Fun.ArgInfo = 0;
I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef;
I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
+ I.Fun.MutableLoc = MutableLoc.getRawEncoding();
I.Fun.ExceptionSpecType = ESpecType;
I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding();
I.Fun.NumExceptions = 0;
@@ -213,6 +223,73 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
return I;
}
+bool Declarator::isDeclarationOfFunction() const {
+ for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
+ switch (DeclTypeInfo[i].Kind) {
+ case DeclaratorChunk::Function:
+ return true;
+ case DeclaratorChunk::Paren:
+ continue;
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ return false;
+ }
+ llvm_unreachable("Invalid type chunk");
+ return false;
+ }
+
+ switch (DS.getTypeSpecType()) {
+ case TST_auto:
+ case TST_bool:
+ case TST_char:
+ case TST_char16:
+ case TST_char32:
+ case TST_class:
+ case TST_decimal128:
+ case TST_decimal32:
+ case TST_decimal64:
+ case TST_double:
+ case TST_enum:
+ case TST_error:
+ case TST_float:
+ case TST_int:
+ case TST_struct:
+ case TST_union:
+ case TST_unknown_anytype:
+ case TST_unspecified:
+ case TST_void:
+ case TST_wchar:
+ return false;
+
+ case TST_decltype:
+ case TST_typeofExpr:
+ if (Expr *E = DS.getRepAsExpr())
+ return E->getType()->isFunctionType();
+ return false;
+
+ case TST_underlyingType:
+ case TST_typename:
+ case TST_typeofType: {
+ QualType QT = DS.getRepAsType().get();
+ if (QT.isNull())
+ return false;
+
+ if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT))
+ QT = LIT->getType();
+
+ if (QT.isNull())
+ return false;
+
+ return QT->isFunctionType();
+ }
+ }
+
+ return false;
+}
+
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
/// declaration specifier includes.
///
@@ -792,9 +869,6 @@ bool DeclSpec::isMissingDeclaratorOk() {
}
void UnqualifiedId::clear() {
- if (Kind == IK_TemplateId)
- TemplateId->Destroy();
-
Kind = IK_Identifier;
Identifier = 0;
StartLocation = SourceLocation();
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index af548fe..c6744ed 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 ae154aa..59bc263 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -68,7 +68,10 @@ public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
void BuildScopeInformation(Decl *D, unsigned &ParentScope);
- void BuildScopeInformation(Stmt *S, unsigned ParentScope);
+ void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl,
+ unsigned &ParentScope);
+ void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
+
void VerifyJumps();
void VerifyIndirectJumps();
void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
@@ -87,7 +90,8 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
// Build information for the top level compound statement, so that we have a
// defined scope record for every "goto" and label.
- BuildScopeInformation(Body, 0);
+ unsigned BodyParentScope = 0;
+ BuildScopeInformation(Body, BodyParentScope);
// Check that all jumps we saw are kosher.
VerifyJumps();
@@ -111,87 +115,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 (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_ownership,
+ diag::note_exits_objc_ownership);
+ }
+ }
+
+ 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()));
@@ -205,11 +232,55 @@ void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
BuildScopeInformation(Init, ParentScope);
}
+/// \brief Build scope information for a captured block literal variables.
+void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
+ const BlockDecl *BDecl,
+ unsigned &ParentScope) {
+ // exclude captured __block variables; there's no destructor
+ // associated with the block literal for them.
+ if (D->hasAttr<BlocksAttr>())
+ return;
+ QualType T = D->getType();
+ QualType::DestructionKind destructKind = T.isDestructedType();
+ if (destructKind != QualType::DK_none) {
+ std::pair<unsigned,unsigned> Diags;
+ switch (destructKind) {
+ case QualType::DK_cxx_destructor:
+ Diags = ScopePair(diag::note_enters_block_captures_cxx_obj,
+ diag::note_exits_block_captures_cxx_obj);
+ break;
+ case QualType::DK_objc_strong_lifetime:
+ Diags = ScopePair(diag::note_enters_block_captures_strong,
+ diag::note_exits_block_captures_strong);
+ break;
+ case QualType::DK_objc_weak_lifetime:
+ Diags = ScopePair(diag::note_enters_block_captures_weak,
+ diag::note_exits_block_captures_weak);
+ break;
+ case QualType::DK_none:
+ llvm_unreachable("no-liftime captured variable");
+ }
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isInvalid())
+ Loc = BDecl->getLocation();
+ Scopes.push_back(GotoScope(ParentScope,
+ Diags.first, Diags.second, Loc));
+ ParentScope = Scopes.size()-1;
+ }
+}
+
/// BuildScopeInformation - The statements from CI to CE are known to form a
/// coherent VLA scope with a specified parent node. Walk through the
/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
/// walking the AST as needed.
-void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
+void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) {
+ // If this is a statement, rather than an expression, scopes within it don't
+ // propagate out into the enclosing scope. Otherwise we have to worry
+ // about block literals, which have the lifetime of their enclosing statement.
+ unsigned independentParentScope = origParentScope;
+ unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
+ ? origParentScope : independentParentScope);
+
bool SkipFirstSubStmt = false;
// If we found a label, remember that it is in ParentScope scope.
@@ -291,17 +362,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
BuildScopeInformation(*I, ParentScope);
continue;
}
-
// Disallow jumps into any part of an @try statement by pushing a scope and
// walking all sub-stmts in that scope.
if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
+ unsigned newParentScope;
// Recursively walk the AST for the @try part.
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_try,
diag::note_exits_objc_try,
AT->getAtTryLoc()));
if (Stmt *TryPart = AT->getTryBody())
- BuildScopeInformation(TryPart, Scopes.size()-1);
+ BuildScopeInformation(TryPart, (newParentScope = Scopes.size()-1));
// Jump from the catch to the finally or try is not valid.
for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
@@ -311,7 +382,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_exits_objc_catch,
AC->getAtCatchLoc()));
// @catches are nested and it isn't
- BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1);
+ BuildScopeInformation(AC->getCatchBody(),
+ (newParentScope = Scopes.size()-1));
}
// Jump from the finally to the try or catch is not valid.
@@ -320,12 +392,13 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_protected_by_objc_finally,
diag::note_exits_objc_finally,
AF->getAtFinallyLoc()));
- BuildScopeInformation(AF, Scopes.size()-1);
+ BuildScopeInformation(AF, (newParentScope = Scopes.size()-1));
}
continue;
}
-
+
+ unsigned newParentScope;
// Disallow jumps into the protected statement of an @synchronized, but
// allow jumps into the object expression it protects.
if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){
@@ -339,7 +412,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_protected_by_objc_synchronized,
diag::note_exits_objc_synchronized,
AS->getAtSynchronizedLoc()));
- BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1);
+ BuildScopeInformation(AS->getSynchBody(),
+ (newParentScope = Scopes.size()-1));
continue;
}
@@ -351,7 +425,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_exits_cxx_try,
TS->getSourceRange().getBegin()));
if (Stmt *TryBlock = TS->getTryBlock())
- BuildScopeInformation(TryBlock, Scopes.size()-1);
+ BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
// Jump from the catch into the try is not allowed either.
for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
@@ -360,12 +434,34 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
diag::note_protected_by_cxx_catch,
diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
- BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1);
+ BuildScopeInformation(CS->getHandlerBlock(),
+ (newParentScope = Scopes.size()-1));
}
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(), (newParentScope = Scopes.size()-1));
+ continue;
+ }
+
+ if (const BlockExpr *BE = dyn_cast<BlockExpr>(SubStmt)) {
+ const BlockDecl *BDecl = BE->getBlockDecl();
+ for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(),
+ ce = BDecl->capture_end(); ci != ce; ++ci) {
+ VarDecl *variable = ci->getVariable();
+ BuildScopeInformation(variable, BDecl, ParentScope);
+ }
+ }
+
// Recursively walk the AST.
BuildScopeInformation(SubStmt, ParentScope);
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 8297b31..fdf3bb3 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -141,9 +141,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
: TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()),
LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
- PackContext(0), MSStructPragmaOn(false), VisContext(0),
- LateTemplateParser(0), OpaqueParser(0),
+ CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
+ CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0),
+ ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -154,6 +154,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
AnalysisWarnings(*this)
{
TUScope = 0;
+ LoadedExternalKnownNamespaces = false;
+
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
@@ -162,7 +164,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,22 +204,61 @@ 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();
}
+/// \brief Print out statistics about the semantic analysis.
+void Sema::PrintStats() const {
+ llvm::errs() << "\n*** Semantic Analysis Stats:\n";
+ llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n";
+
+ BumpAlloc.PrintStats();
+ AnalysisWarnings.PrintStats();
+}
+
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// 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 +770,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() {
@@ -748,6 +789,10 @@ ExternalSemaSource::ReadMethodPool(Selector Sel) {
return std::pair<ObjCMethodList, ObjCMethodList>();
}
+void ExternalSemaSource::ReadKnownNamespaces(
+ llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+}
+
void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
SourceLocation Loc = this->Loc;
if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation();
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index e46ad5b..d053d5a 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,
@@ -131,17 +134,23 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
ExprResult
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
- SourceLocation LAngleBracketLoc, ParsedType Ty,
+ SourceLocation LAngleBracketLoc, Declarator &D,
SourceLocation RAngleBracketLoc,
SourceLocation LParenLoc, Expr *E,
SourceLocation RParenLoc) {
-
- TypeSourceInfo *DestTInfo;
- QualType DestType = GetTypeFromParser(Ty, &DestTInfo);
- if (!DestTInfo)
- DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation());
- return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E),
+ assert(!D.isInvalidType());
+
+ TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, E->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ if (getLangOptions().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E),
SourceRange(LAngleBracketLoc, RAngleBracketLoc),
SourceRange(LParenLoc, RParenLoc));
}
@@ -248,8 +257,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 +384,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 +416,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 +452,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 +629,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 +646,12 @@ 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) {
+ Expr *Exp = SrcExpr.get();
+ // Note that Exp does not change with CCK_OtherCast cast type
+ Self.CheckObjCARCConversion(OpRange, DestType,
+ Exp, Sema::CCK_OtherCast);
+ }
}
@@ -654,8 +694,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 +709,15 @@ 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) {
+ Expr *Exp = SrcExpr.get();
+ // Note that Exp does not change with CCK_OtherCast cast type
+ Self.CheckObjCARCConversion(OpRange, DestType,
+ Exp, Sema::CCK_OtherCast);
+ }
}
else if (Kind == CK_BitCast)
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
@@ -676,10 +727,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 +771,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 +848,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 +911,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 +921,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 +1240,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 +1253,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 +1266,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 +1502,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 +1618,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 +1751,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 +1773,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/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 61d9e93..5f8c9c6 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -211,25 +211,40 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
DeclContext *DC) {
assert(DC != 0 && "given null context");
- if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ if (TagDecl *tag = dyn_cast<TagDecl>(DC)) {
// If this is a dependent type, then we consider it complete.
- if (Tag->isDependentContext())
+ if (tag->isDependentContext())
return false;
// If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet.
- const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>();
- if (TagT && TagT->isBeingDefined())
+ QualType type = Context.getTypeDeclType(tag);
+ const TagType *tagType = type->getAs<TagType>();
+ if (tagType && tagType->isBeingDefined())
return false;
+ SourceLocation loc = SS.getLastQualifierNameLoc();
+ if (loc.isInvalid()) loc = SS.getRange().getBegin();
+
// The type must be complete.
- if (RequireCompleteType(SS.getRange().getBegin(),
- Context.getTypeDeclType(Tag),
+ if (RequireCompleteType(loc, type,
PDiag(diag::err_incomplete_nested_name_spec)
<< SS.getRange())) {
SS.SetInvalid(SS.getRange());
return true;
}
+
+ // Fixed enum types are complete, but they aren't valid as scopes
+ // until we see a definition, so awkwardly pull out this special
+ // case.
+ if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) {
+ if (!enumType->getDecl()->isDefinition()) {
+ Diag(loc, diag::err_incomplete_nested_name_spec)
+ << type << SS.getRange();
+ SS.SetInvalid(SS.getRange());
+ return true;
+ }
+ }
}
return false;
@@ -464,26 +479,29 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
- if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext,
- CTC_NoKeywords) &&
- Found.isSingleResult() &&
- isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) {
+ TypoCorrection Corrected;
+ Found.clear();
+ if ((Corrected = CorrectTypo(Found.getLookupNameInfo(),
+ Found.getLookupKind(), S, &SS, LookupCtx,
+ EnteringContext, CTC_NoKeywords)) &&
+ isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_suggest)
- << Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
- << Name << Found.getLookupName()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
- if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
- Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr;
+ Found.addDecl(ND);
+ }
+ Found.setLookupName(Corrected.getCorrection());
} else {
- Found.clear();
Found.setLookupName(&Identifier);
}
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 05c257a..690a29d 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"
@@ -319,12 +320,41 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
}
// Memset/memcpy/memmove handling
- if (FDecl->getLinkage() == ExternalLinkage &&
- (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
- if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") ||
- FnInfo->isStr("memmove"))
- CheckMemsetcpymoveArguments(TheCall, FnInfo);
+ int CMF = -1;
+ switch (FDecl->getBuiltinID()) {
+ case Builtin::BI__builtin_memset:
+ case Builtin::BI__builtin___memset_chk:
+ case Builtin::BImemset:
+ CMF = CMF_Memset;
+ break;
+
+ case Builtin::BI__builtin_memcpy:
+ case Builtin::BI__builtin___memcpy_chk:
+ case Builtin::BImemcpy:
+ CMF = CMF_Memcpy;
+ break;
+
+ case Builtin::BI__builtin_memmove:
+ case Builtin::BI__builtin___memmove_chk:
+ case Builtin::BImemmove:
+ CMF = CMF_Memmove;
+ break;
+
+ default:
+ if (FDecl->getLinkage() == ExternalLinkage &&
+ (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
+ if (FnInfo->isStr("memset"))
+ CMF = CMF_Memset;
+ else if (FnInfo->isStr("memcpy"))
+ CMF = CMF_Memcpy;
+ else if (FnInfo->isStr("memmove"))
+ CMF = CMF_Memmove;
+ }
+ break;
}
+
+ if (CMF != -1)
+ CheckMemsetcpymoveArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo);
return false;
}
@@ -382,14 +412,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 +427,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_ownership)
+ << 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 +562,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();
@@ -1812,6 +1857,27 @@ static bool isDynamicClassType(QualType T) {
return false;
}
+/// \brief If E is a sizeof expression, returns its argument expression,
+/// otherwise returns NULL.
+static const Expr *getSizeOfExprArg(const Expr* E) {
+ if (const UnaryExprOrTypeTraitExpr *SizeOf =
+ dyn_cast<UnaryExprOrTypeTraitExpr>(E))
+ if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType())
+ return SizeOf->getArgumentExpr()->IgnoreParenImpCasts();
+
+ return 0;
+}
+
+/// \brief If E is a sizeof expression, returns its argument type.
+static QualType getSizeOfArgType(const Expr* E) {
+ if (const UnaryExprOrTypeTraitExpr *SizeOf =
+ dyn_cast<UnaryExprOrTypeTraitExpr>(E))
+ if (SizeOf->getKind() == clang::UETT_SizeOf)
+ return SizeOf->getTypeOfArgument();
+
+ return QualType();
+}
+
/// \brief Check for dangerous or invalid arguments to memset().
///
/// This issues warnings on known problematic, dangerous or unspecified
@@ -1819,35 +1885,95 @@ static bool isDynamicClassType(QualType T) {
///
/// \param Call The call expression to diagnose.
void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
- const IdentifierInfo *FnName) {
+ CheckedMemoryFunction CMF,
+ IdentifierInfo *FnName) {
// It is possible to have a non-standard definition of memset. Validate
- // we have the proper number of arguments, and if not, abort further
- // checking.
- if (Call->getNumArgs() != 3)
+ // we have enough arguments, and if not, abort further checking.
+ if (Call->getNumArgs() < 3)
return;
- unsigned LastArg = FnName->isStr("memset")? 1 : 2;
+ unsigned LastArg = (CMF == CMF_Memset? 1 : 2);
+ const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts();
+
+ // We have special checking when the length is a sizeof expression.
+ QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
+ const Expr *SizeOfArg = getSizeOfExprArg(LenExpr);
+ llvm::FoldingSetNodeID SizeOfArgID;
+
for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) {
const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts();
+ SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange();
QualType DestTy = Dest->getType();
if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
QualType PointeeTy = DestPtrTy->getPointeeType();
+
+ // Never warn about void type pointers. This can be used to suppress
+ // false positives.
if (PointeeTy->isVoidType())
continue;
+ // Catch "memset(p, 0, sizeof(p))" -- needs to be sizeof(*p). Do this by
+ // actually comparing the expressions for equality. Because computing the
+ // expression IDs can be expensive, we only do this if the diagnostic is
+ // enabled.
+ if (SizeOfArg &&
+ Diags.getDiagnosticLevel(diag::warn_sizeof_pointer_expr_memaccess,
+ SizeOfArg->getExprLoc())) {
+ // We only compute IDs for expressions if the warning is enabled, and
+ // cache the sizeof arg's ID.
+ if (SizeOfArgID == llvm::FoldingSetNodeID())
+ SizeOfArg->Profile(SizeOfArgID, Context, true);
+ llvm::FoldingSetNodeID DestID;
+ Dest->Profile(DestID, Context, true);
+ if (DestID == SizeOfArgID) {
+ unsigned ActionIdx = 0; // Default is to suggest dereferencing.
+ if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
+ if (UnaryOp->getOpcode() == UO_AddrOf)
+ ActionIdx = 1; // If its an address-of operator, just remove it.
+ if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
+ ActionIdx = 2; // If the pointee's size is sizeof(char),
+ // suggest an explicit length.
+ DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
+ PDiag(diag::warn_sizeof_pointer_expr_memaccess)
+ << FnName << ArgIdx << ActionIdx
+ << Dest->getSourceRange()
+ << SizeOfArg->getSourceRange());
+ break;
+ }
+ }
+
+ // Also check for cases where the sizeof argument is the exact same
+ // type as the memory argument, and where it points to a user-defined
+ // record type.
+ if (SizeOfArgTy != QualType()) {
+ if (PointeeTy->isRecordType() &&
+ Context.typesAreCompatible(SizeOfArgTy, DestTy)) {
+ DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest,
+ PDiag(diag::warn_sizeof_pointer_type_memaccess)
+ << FnName << SizeOfArgTy << ArgIdx
+ << PointeeTy << Dest->getSourceRange()
+ << LenExpr->getSourceRange());
+ 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() && CMF != CMF_Memset)
+ DiagID = diag::warn_arc_object_memaccess;
+ else
continue;
- }
- SourceRange ArgRange = Call->getArg(0)->getSourceRange();
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(DiagID)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
+
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::note_bad_memaccess_silence)
@@ -1873,7 +1999,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);
@@ -2044,7 +2171,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::CXXFunctionalCastExprClass: {
+ case Stmt::CXXFunctionalCastExprClass:
+ case Stmt::ObjCBridgedCastExprClass: {
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
QualType T = SubExpr->getType();
@@ -2077,6 +2205,14 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
return NULL;
}
+ case Stmt::MaterializeTemporaryExprClass:
+ if (Expr *Result = EvalAddr(
+ cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+ refVars))
+ return Result;
+
+ return E;
+
// Everything else: we simply don't reason about them.
default:
return NULL;
@@ -2178,6 +2314,14 @@ do {
return EvalVal(M->getBase(), refVars);
}
+ case Stmt::MaterializeTemporaryExprClass:
+ if (Expr *Result = EvalVal(
+ cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+ refVars))
+ return Result;
+
+ return E;
+
default:
// Check that we don't return or take the address of a reference to a
// temporary. This is only useful in C++.
@@ -2442,15 +2586,24 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
case BO_NE:
return IntRange::forBoolType();
- // The type of these compound assignments is the type of the LHS,
- // so the RHS is not necessarily an integer.
+ // The type of the assignments is the type of the LHS, so the RHS
+ // is not necessarily the same type.
case BO_MulAssign:
case BO_DivAssign:
case BO_RemAssign:
case BO_AddAssign:
case BO_SubAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ // TODO: bitfields?
return IntRange::forValueOfType(C, E->getType());
+ // Simple assignments just pass through the RHS, which will have
+ // been coerced to the LHS type.
+ case BO_Assign:
+ // TODO: bitfields?
+ return GetExprRange(C, BO->getRHS(), MaxWidth);
+
// Operations with opaque sources are black-listed.
case BO_PtrMemD:
case BO_PtrMemI:
@@ -2506,14 +2659,54 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
case BO_Sub:
if (BO->getLHS()->getType()->isPointerType())
return IntRange::forValueOfType(C, E->getType());
- // fallthrough
+ break;
- default:
+ // The width of a division result is mostly determined by the size
+ // of the LHS.
+ case BO_Div: {
+ // Don't 'pre-truncate' the operands.
+ unsigned opWidth = C.getIntWidth(E->getType());
+ IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
+
+ // If the divisor is constant, use that.
+ llvm::APSInt divisor;
+ if (BO->getRHS()->isIntegerConstantExpr(divisor, C)) {
+ unsigned log2 = divisor.logBase2(); // floor(log_2(divisor))
+ if (log2 >= L.Width)
+ L.Width = (L.NonNegative ? 0 : 1);
+ else
+ L.Width = std::min(L.Width - log2, MaxWidth);
+ return L;
+ }
+
+ // Otherwise, just use the LHS's width.
+ IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+ return IntRange(L.Width, L.NonNegative && R.NonNegative);
+ }
+
+ // The result of a remainder can't be larger than the result of
+ // either side.
+ case BO_Rem: {
+ // Don't 'pre-truncate' the operands.
+ unsigned opWidth = C.getIntWidth(E->getType());
+ IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
+ IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+
+ IntRange meet = IntRange::meet(L, R);
+ meet.Width = std::min(meet.Width, MaxWidth);
+ return meet;
+ }
+
+ // The default behavior is okay for these.
+ case BO_Mul:
+ case BO_Add:
+ case BO_Xor:
+ case BO_Or:
break;
}
- // Treat every other operator as if it were closed on the
- // narrowest type that encompasses both operands.
+ // The default case is to treat the operation as if it were closed
+ // on the narrowest type that encompasses both operands.
IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth);
return IntRange::join(L, R);
@@ -2837,18 +3030,16 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble)
return;
- // Try to convert this exactly to an 64-bit integer. FIXME: It would be
- // nice to support arbitrarily large integers here.
+ // Try to convert this exactly to an integer.
bool isExact = false;
- uint64_t IntegerPart;
- if (Value.convertToInteger(&IntegerPart, 64, /*isSigned=*/true,
+ llvm::APSInt IntegerValue(S.Context.getIntWidth(T),
+ T->hasUnsignedIntegerRepresentation());
+ if (Value.convertToInteger(IntegerValue,
llvm::APFloat::rmTowardZero, &isExact)
!= llvm::APFloat::opOK || !isExact)
return;
- llvm::APInt IntegerValue(64, IntegerPart, /*isSigned=*/true);
-
- std::string LiteralValue = IntegerValue.toString(10, /*isSigned=*/true);
+ std::string LiteralValue = IntegerValue.toString(10);
S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer)
<< FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue);
}
@@ -2895,6 +3086,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar);
}
+
+ // If the vector cast is cast between two vectors of the same size, it is
+ // a bitcast, not a conversion.
+ if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
+ return;
Source = cast<VectorType>(Source)->getElementType().getTypePtr();
Target = cast<VectorType>(Target)->getElementType().getTypePtr();
@@ -2989,9 +3185,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
- // People want to build with -Wshorten-64-to-32 and not -Wconversion
- // and by god we'll let them.
-
+ // People want to build with -Wshorten-64-to-32 and not -Wconversion.
if (isFromSystemMacro(S, CC))
return;
@@ -3356,3 +3550,268 @@ void Sema::CheckArrayAccess(const Expr *expr) {
}
}
}
+
+//===--- CHECK: Objective-C retain cycles ----------------------------------//
+
+namespace {
+ struct RetainCycleOwner {
+ RetainCycleOwner() : Variable(0), Indirect(false) {}
+ VarDecl *Variable;
+ SourceRange Range;
+ SourceLocation Loc;
+ bool Indirect;
+
+ void setLocsFrom(Expr *e) {
+ Loc = e->getExprLoc();
+ Range = e->getSourceRange();
+ }
+ };
+}
+
+/// Consider whether capturing the given variable can possibly lead to
+/// a retain cycle.
+static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) {
+ // In ARC, it's captured strongly iff the variable has __strong
+ // lifetime. In MRR, it's captured strongly if the variable is
+ // __block and has an appropriate type.
+ if (var->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+ return false;
+
+ owner.Variable = var;
+ owner.setLocsFrom(ref);
+ return true;
+}
+
+static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
+ while (true) {
+ e = e->IgnoreParens();
+ if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
+ switch (cast->getCastKind()) {
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_LValueToRValue:
+ case CK_ObjCReclaimReturnedObject:
+ e = cast->getSubExpr();
+ continue;
+
+ case CK_GetObjCProperty: {
+ // Bail out if this isn't a strong explicit property.
+ const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty();
+ if (pre->isImplicitProperty()) return false;
+ ObjCPropertyDecl *property = pre->getExplicitProperty();
+ if (!(property->getPropertyAttributes() &
+ (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy |
+ ObjCPropertyDecl::OBJC_PR_strong)) &&
+ !(property->getPropertyIvarDecl() &&
+ property->getPropertyIvarDecl()->getType()
+ .getObjCLifetime() == Qualifiers::OCL_Strong))
+ return false;
+
+ owner.Indirect = true;
+ e = const_cast<Expr*>(pre->getBase());
+ continue;
+ }
+
+ default:
+ return false;
+ }
+ }
+
+ if (ObjCIvarRefExpr *ref = dyn_cast<ObjCIvarRefExpr>(e)) {
+ ObjCIvarDecl *ivar = ref->getDecl();
+ if (ivar->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+ return false;
+
+ // Try to find a retain cycle in the base.
+ if (!findRetainCycleOwner(ref->getBase(), owner))
+ return false;
+
+ if (ref->isFreeIvar()) owner.setLocsFrom(ref);
+ owner.Indirect = true;
+ return true;
+ }
+
+ if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) {
+ VarDecl *var = dyn_cast<VarDecl>(ref->getDecl());
+ if (!var) return false;
+ return considerVariable(var, ref, owner);
+ }
+
+ if (BlockDeclRefExpr *ref = dyn_cast<BlockDeclRefExpr>(e)) {
+ owner.Variable = ref->getDecl();
+ owner.setLocsFrom(ref);
+ return true;
+ }
+
+ if (MemberExpr *member = dyn_cast<MemberExpr>(e)) {
+ if (member->isArrow()) return false;
+
+ // Don't count this as an indirect ownership.
+ e = member->getBase();
+ continue;
+ }
+
+ // Array ivars?
+
+ return false;
+ }
+}
+
+namespace {
+ struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> {
+ FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
+ : EvaluatedExprVisitor<FindCaptureVisitor>(Context),
+ Variable(variable), Capturer(0) {}
+
+ VarDecl *Variable;
+ Expr *Capturer;
+
+ void VisitDeclRefExpr(DeclRefExpr *ref) {
+ if (ref->getDecl() == Variable && !Capturer)
+ Capturer = ref;
+ }
+
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *ref) {
+ if (ref->getDecl() == Variable && !Capturer)
+ Capturer = ref;
+ }
+
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *ref) {
+ if (Capturer) return;
+ Visit(ref->getBase());
+ if (Capturer && ref->isFreeIvar())
+ Capturer = ref;
+ }
+
+ void VisitBlockExpr(BlockExpr *block) {
+ // Look inside nested blocks
+ if (block->getBlockDecl()->capturesVariable(Variable))
+ Visit(block->getBlockDecl()->getBody());
+ }
+ };
+}
+
+/// Check whether the given argument is a block which captures a
+/// variable.
+static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
+ assert(owner.Variable && owner.Loc.isValid());
+
+ e = e->IgnoreParenCasts();
+ BlockExpr *block = dyn_cast<BlockExpr>(e);
+ if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
+ return 0;
+
+ FindCaptureVisitor visitor(S.Context, owner.Variable);
+ visitor.Visit(block->getBlockDecl()->getBody());
+ return visitor.Capturer;
+}
+
+static void diagnoseRetainCycle(Sema &S, Expr *capturer,
+ RetainCycleOwner &owner) {
+ assert(capturer);
+ assert(owner.Variable && owner.Loc.isValid());
+
+ S.Diag(capturer->getExprLoc(), diag::warn_arc_retain_cycle)
+ << owner.Variable << capturer->getSourceRange();
+ S.Diag(owner.Loc, diag::note_arc_retain_cycle_owner)
+ << owner.Indirect << owner.Range;
+}
+
+/// Check for a keyword selector that starts with the word 'add' or
+/// 'set'.
+static bool isSetterLikeSelector(Selector sel) {
+ if (sel.isUnarySelector()) return false;
+
+ llvm::StringRef str = sel.getNameForSlot(0);
+ while (!str.empty() && str.front() == '_') str = str.substr(1);
+ if (str.startswith("set") || str.startswith("add"))
+ str = str.substr(3);
+ else
+ return false;
+
+ if (str.empty()) return true;
+ return !islower(str.front());
+}
+
+/// 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.
+ if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector()))
+ return;
+
+ // Try to find a variable that the receiver is strongly owned by.
+ RetainCycleOwner owner;
+ if (msg->getReceiverKind() == ObjCMessageExpr::Instance) {
+ if (!findRetainCycleOwner(msg->getInstanceReceiver(), owner))
+ return;
+ } else {
+ assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
+ owner.Variable = getCurMethodDecl()->getSelfDecl();
+ owner.Loc = msg->getSuperLoc();
+ owner.Range = msg->getSuperLoc();
+ }
+
+ // Check whether the receiver is captured by any of the arguments.
+ for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i)
+ if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner))
+ return diagnoseRetainCycle(*this, capturer, owner);
+}
+
+/// Check a property assign to see if it's likely to cause a retain cycle.
+void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
+ RetainCycleOwner owner;
+ if (!findRetainCycleOwner(receiver, owner))
+ return;
+
+ if (Expr *capturer = findCapturingExpr(*this, argument, owner))
+ diagnoseRetainCycle(*this, capturer, owner);
+}
+
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
+ QualType LHS, Expr *RHS) {
+ Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
+ if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+ return false;
+ // strip off any implicit cast added to get to the one arc-specific
+ while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+ if (cast->getCastKind() == CK_ObjCConsumeObject) {
+ Diag(Loc, diag::warn_arc_retained_assign)
+ << (LT == Qualifiers::OCL_ExplicitNone)
+ << RHS->getSourceRange();
+ return true;
+ }
+ RHS = cast->getSubExpr();
+ }
+ return false;
+}
+
+void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ QualType LHSType = LHS->getType();
+ if (checkUnsafeAssigns(Loc, LHSType, RHS))
+ return;
+ Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+ // FIXME. Check for other life times.
+ if (LT != Qualifiers::OCL_None)
+ return;
+
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+ if (PRE->isImplicitProperty())
+ return;
+ const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+ if (!PD)
+ return;
+
+ unsigned Attributes = PD->getPropertyAttributes();
+ if (Attributes & ObjCPropertyDecl::OBJC_PR_assign)
+ while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+ if (cast->getCastKind() == CK_ObjCConsumeObject) {
+ Diag(Loc, diag::warn_arc_retained_property_assign)
+ << RHS->getSourceRange();
+ return;
+ }
+ RHS = cast->getSubExpr();
+ }
+ }
+}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index e328eeb..b555c8a 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1676,6 +1676,34 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// Fall through: conditions and statements can have expressions.
case Sema::PCC_ParenthesizedExpression:
+ if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ CCC == Sema::PCC_ParenthesizedExpression) {
+ // (__bridge <type>)<expression>
+ Builder.AddTypedTextChunk("__bridge");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // (__bridge_transfer <Objective-C type>)<expression>
+ Builder.AddTypedTextChunk("__bridge_transfer");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("Objective-C type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // (__bridge_retained <CF type>)<expression>
+ Builder.AddTypedTextChunk("__bridge_retained");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("CF type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
+ // Fall through
+
case Sema::PCC_Expression: {
if (SemaRef.getLangOptions().CPlusPlus) {
// 'this', if we're in a non-static member function.
@@ -1828,7 +1856,8 @@ static const char *GetCompletionTypeString(QualType T,
CodeCompletionAllocator &Allocator) {
PrintingPolicy Policy(Context.PrintingPolicy);
Policy.AnonymousTagLocations = false;
-
+ Policy.SuppressStrongLifetime = true;
+
if (!T.getLocalQualifiers()) {
// Built-in type names are constant strings.
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))
@@ -1878,9 +1907,9 @@ static void AddResultTypeChunk(ASTContext &Context,
T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
else if (isa<UnresolvedUsingValueDecl>(ND)) {
/* Do nothing: ignore unresolved using declarations*/
- } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
+ } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
T = Value->getType();
- else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ } else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
T = Property->getType();
if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
@@ -1907,6 +1936,10 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
static std::string FormatFunctionParameter(ASTContext &Context,
ParmVarDecl *Param,
bool SuppressName = false) {
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
@@ -1917,8 +1950,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName)
Result = Param->getIdentifier()->getName();
- Param->getType().getAsStringInternal(Result,
- Context.PrintingPolicy);
+ Param->getType().getAsStringInternal(Result, Policy);
if (ObjCMethodParam) {
Result = "(" + Result;
@@ -1968,8 +2000,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// We were unable to find a FunctionProtoTypeLoc with parameter names
// for the block; just use the parameter type as a placeholder.
std::string Result;
- Param->getType().getUnqualifiedType().
- getAsStringInternal(Result, Context.PrintingPolicy);
+ Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy);
if (ObjCMethodParam) {
Result = "(" + Result;
@@ -1986,7 +2017,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
std::string Result;
QualType ResultType = Block->getTypePtr()->getResultType();
if (!ResultType->isVoidType())
- ResultType.getAsStringInternal(Result, Context.PrintingPolicy);
+ ResultType.getAsStringInternal(Result, Policy);
Result = '^' + Result;
if (!BlockProto || Block->getNumArgs() == 0) {
@@ -2071,6 +2102,9 @@ static void AddTemplateParameterChunks(ASTContext &Context,
unsigned MaxParameters = 0,
unsigned Start = 0,
bool InDefaultArg = false) {
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+
typedef CodeCompletionString::Chunk Chunk;
bool FirstParameter = true;
@@ -2098,8 +2132,7 @@ static void AddTemplateParameterChunks(ASTContext &Context,
= dyn_cast<NonTypeTemplateParmDecl>(*P)) {
if (NTTP->getIdentifier())
PlaceholderStr = NTTP->getIdentifier()->getName();
- NTTP->getType().getAsStringInternal(PlaceholderStr,
- Context.PrintingPolicy);
+ NTTP->getType().getAsStringInternal(PlaceholderStr, Policy);
HasDefaultArg = NTTP->hasDefaultArgument();
} else {
assert(isa<TemplateTemplateParmDecl>(*P));
@@ -2286,6 +2319,10 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
typedef CodeCompletionString::Chunk Chunk;
CodeCompletionBuilder Result(Allocator, Priority, Availability);
+ PrintingPolicy Policy(S.Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
if (Kind == RK_Pattern) {
Pattern->Priority = Priority;
Pattern->Availability = Availability;
@@ -2470,7 +2507,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
Arg = FormatFunctionParameter(S.Context, *P, true);
else {
- (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy);
+ (*P)->getType().getAsStringInternal(Arg, Policy);
Arg = "(" + Arg + ")";
if (IdentifierInfo *II = (*P)->getIdentifier())
if (DeclaringEntity || AllParametersAreInformative)
@@ -2519,7 +2556,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Sema &S,
CodeCompletionAllocator &Allocator) const {
typedef CodeCompletionString::Chunk Chunk;
-
+ PrintingPolicy Policy(S.Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
// FIXME: Set priority, availability appropriately.
CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available);
FunctionDecl *FDecl = getFunction();
@@ -2545,7 +2585,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
else
Result.AddTextChunk(
Result.getAllocator().CopyString(
- Proto->getResultType().getAsString(S.Context.PrintingPolicy)));
+ Proto->getResultType().getAsString(Policy)));
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
@@ -2563,7 +2603,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
ArgType = Proto->getArgType(I);
}
- ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy);
+ ArgType.getAsStringInternal(ArgString, Policy);
if (I == CurrentArg)
Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter,
@@ -3204,8 +3244,23 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
return;
}
+ enum CodeCompletionContext::Kind contextKind;
+
+ if (IsArrow) {
+ contextKind = CodeCompletionContext::CCC_ArrowMemberAccess;
+ }
+ else {
+ if (BaseType->isObjCObjectPointerType() ||
+ BaseType->isObjCObjectOrInterfaceType()) {
+ contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess;
+ }
+ else {
+ contextKind = CodeCompletionContext::CCC_DotMemberAccess;
+ }
+ }
+
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext(CodeCompletionContext::CCC_MemberAccess,
+ CodeCompletionContext(contextKind,
BaseType),
&ResultBuilder::IsMember);
Results.EnterNewScope();
@@ -3431,10 +3486,17 @@ void Sema::CodeCompleteCase(Scope *S) {
}
Results.ExitScope();
- if (CodeCompleter->includeMacros())
+ //We need to make sure we're setting the right context,
+ //so only say we include macros if the code completer says we do
+ enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other;
+ if (CodeCompleter->includeMacros()) {
AddMacroResults(PP, Results);
+ kind = CodeCompletionContext::CCC_OtherWithMacros;
+ }
+
+
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_OtherWithMacros,
+ kind,
Results.data(),Results.size());
}
@@ -3786,6 +3848,10 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
CXXCtorInitializer** Initializers,
unsigned NumInitializers) {
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+
CXXConstructorDecl *Constructor
= static_cast<CXXConstructorDecl *>(ConstructorD);
if (!Constructor)
@@ -3825,7 +3891,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(
- Base->getType().getAsString(Context.PrintingPolicy)));
+ Base->getType().getAsString(Policy)));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("args");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -3850,7 +3916,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Builder.AddTypedTextChunk(
Builder.getAllocator().CopyString(
- Base->getType().getAsString(Context.PrintingPolicy)));
+ Base->getType().getAsString(Policy)));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("args");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -4126,18 +4192,24 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
(Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain)))
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong)))
return true;
- // Check for more than one of { assign, copy, retain }.
+ // Check for more than one of { assign, copy, retain, strong }.
unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain);
+ ObjCDeclSpec::DQ_PR_retain|
+ ObjCDeclSpec::DQ_PR_strong);
if (AssignCopyRetMask &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign &&
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain)
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain &&
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong)
return true;
return false;
@@ -4157,10 +4229,15 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Results.AddResult(CodeCompletionResult("readonly"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign))
Results.AddResult(CodeCompletionResult("assign"));
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCDeclSpec::DQ_PR_unsafe_unretained))
+ Results.AddResult(CodeCompletionResult("unsafe_unretained"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite))
Results.AddResult(CodeCompletionResult("readwrite"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain))
Results.AddResult(CodeCompletionResult("retain"));
+ if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_strong))
+ Results.AddResult(CodeCompletionResult("strong"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy))
Results.AddResult(CodeCompletionResult("copy"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
@@ -4522,6 +4599,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
if (Method->isInstanceMethod())
return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
.Case("retain", IFace)
+ .Case("strong", IFace)
.Case("autorelease", IFace)
.Case("copy", IFace)
.Case("copyWithZone", IFace)
@@ -4878,7 +4956,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
bool AtArgumentExpression,
bool IsSuper) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCClassMessage);
AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents,
AtArgumentExpression, IsSuper, Results);
@@ -4898,7 +4976,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCClassMessage,
Results.data(), Results.size());
}
@@ -4941,7 +5019,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
// Build the set of methods we can see.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCInstanceMessage);
Results.EnterNewScope();
// If this is a send-to-super, try to add the special "super" send
@@ -5054,7 +5132,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCInstanceMessage,
Results.data(),Results.size());
}
@@ -5245,8 +5323,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
false, Results);
Results.ExitScope();
- // FIXME: Add a special context for this, use cached global completion
- // results.
+ // FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
Results.data(),Results.size());
@@ -5255,7 +5332,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
SourceLocation ClassNameLoc) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCSuperclass);
Results.EnterNewScope();
// Make sure that we ignore the class we're currently defining.
@@ -5269,10 +5346,9 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
false, Results);
Results.ExitScope();
- // FIXME: Add a special context for this, use cached global completion
- // results.
+ // FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCSuperclass,
Results.data(),Results.size());
}
@@ -5286,8 +5362,7 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
true, Results);
Results.ExitScope();
- // FIXME: Add a special context for this, use cached global completion
- // results.
+ // FIXME: Use cached global completion results.
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
Results.data(),Results.size());
@@ -5299,7 +5374,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCCategoryName);
// Ignore any categories we find that have already been implemented by this
// interface.
@@ -5323,7 +5398,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCCategoryName,
Results.data(),Results.size());
}
@@ -5342,7 +5417,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_Other);
+ CodeCompletionContext::CCC_ObjCCategoryName);
// Add all of the categories that have have corresponding interface
// declarations in this class and any of its superclasses, except for
@@ -5363,7 +5438,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCCategoryName,
Results.data(),Results.size());
}
@@ -6273,6 +6348,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
Results.EnterNewScope();
PrintingPolicy Policy(Context.PrintingPolicy);
Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
for (KnownMethodsMap::iterator M = KnownMethods.begin(),
MEnd = KnownMethods.end();
M != MEnd; ++M) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9446c0e..9d91a48 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -45,7 +45,12 @@
using namespace clang;
using namespace sema;
-Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) {
+Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) {
+ if (OwnedType) {
+ Decl *Group[2] = { OwnedType, Ptr };
+ return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, 2));
+ }
+
return DeclGroupPtrTy::make(DeclGroupRef(Ptr));
}
@@ -287,41 +292,42 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
- LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName,
- NotForRedeclaration);
+ if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc),
+ LookupOrdinaryName, S, SS, NULL,
+ false, CTC_Type)) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
- if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) {
- if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) {
+ if (Corrected.isKeyword()) {
+ // We corrected to a keyword.
+ // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << CorrectedQuotedStr;
+ return true;
+ } else {
+ NamedDecl *Result = Corrected.getCorrectionDecl();
if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
!Result->isInvalidDecl()) {
// We found a similarly-named type or interface; suggest that.
if (!SS || !SS->isSet())
Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << Lookup.getLookupName()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << &II << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << Lookup.getLookupName() << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << &II << DC << CorrectedQuotedStr << SS->getRange()
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else
llvm_unreachable("could not have corrected a typo here");
Diag(Result->getLocation(), diag::note_previous_decl)
- << Result->getDeclName();
+ << CorrectedQuotedStr;
SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
false, false, ParsedType(),
/*NonTrivialTypeSourceInfo=*/true);
return true;
}
- } else if (Lookup.empty()) {
- // We corrected to a keyword.
- // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << Corrected;
- return true;
}
}
@@ -509,11 +515,15 @@ Corrected:
// Perform typo correction to determine if there is another name that is
// close to this name.
if (!SecondTry) {
- if (DeclarationName Corrected = CorrectTypo(Result, S, &SS)) {
+ SecondTry = true;
+ if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
+ Result.getLookupKind(), S, &SS)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
- NamedDecl *FirstDecl = Result.empty()? 0 : *Result.begin();
+ NamedDecl *FirstDecl = Corrected.getCorrectionDecl();
NamedDecl *UnderlyingFirstDecl
= FirstDecl? FirstDecl->getUnderlyingDecl() : 0;
if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
@@ -527,26 +537,33 @@ Corrected:
UnqualifiedDiag = diag::err_unknown_typename_suggest;
QualifiedDiag = diag::err_unknown_nested_typename_suggest;
}
-
+
if (SS.isEmpty())
Diag(NameLoc, UnqualifiedDiag)
- << Name << Corrected
- << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+ << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
else
Diag(NameLoc, QualifiedDiag)
- << Name << computeDeclContext(SS, false) << Corrected
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+ << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
// Update the name, so that the caller has the new name.
- Name = Corrected.getAsIdentifierInfo();
+ Name = Corrected.getCorrectionAsIdentifierInfo();
+ // Also update the LookupResult...
+ // FIXME: This should probably go away at some point
+ Result.clear();
+ Result.setLookupName(Corrected.getCorrection());
+ if (FirstDecl) Result.addDecl(FirstDecl);
+
// Typo correction corrected to a keyword.
- if (Result.empty())
- return Corrected.getAsIdentifierInfo();
+ if (Corrected.isKeyword())
+ return Corrected.getCorrectionAsIdentifierInfo();
- Diag(FirstDecl->getLocation(), diag::note_previous_decl)
- << FirstDecl->getDeclName();
+ if (FirstDecl)
+ Diag(FirstDecl->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
// If we found an Objective-C instance variable, let
// LookupInObjCMethod build the appropriate expression to
@@ -1137,17 +1154,18 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
/// class could not be found.
ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
SourceLocation IdLoc,
- bool TypoCorrection) {
+ bool DoTypoCorrection) {
// The third "scope" argument is 0 since we aren't enabling lazy built-in
// creation from this context.
NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName);
- if (!IDecl && TypoCorrection) {
+ if (!IDecl && DoTypoCorrection) {
// Perform typo correction at the given location, but only if we
// find an Objective-C class name.
- LookupResult R(*this, Id, IdLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection C;
+ if ((C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName,
+ TUScope, NULL, NULL, false, CTC_NoKeywords)) &&
+ (IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
Diag(IdLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
<< FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
@@ -1359,7 +1377,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
// The types match. Link up the redeclaration chain if the old
// declaration was a typedef.
- // FIXME: this is a potential source of wierdness if the type
+ // FIXME: this is a potential source of weirdness if the type
// spellings don't match exactly.
if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old))
New->setPreviousDeclaration(Typedef);
@@ -1527,7 +1545,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
/// GNU89 mode.
static bool canRedefineFunction(const FunctionDecl *FD,
const LangOptions& LangOpts) {
- return (LangOpts.GNUInline && !LangOpts.CPlusPlus &&
+ return ((FD->hasAttr<GNUInlineAttr>() || LangOpts.GNUInline) &&
+ !LangOpts.CPlusPlus &&
FD->isInlineSpecified() &&
FD->getStorageClass() == SC_Extern);
}
@@ -1927,6 +1946,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
return false;
}
+
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
const ObjCMethodDecl *oldMethod) {
// Merge the attributes.
@@ -2037,6 +2057,15 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
mergeDeclAttributes(New, Old, Context);
+ // Warn if an already-declared variable is made a weak_import in a subsequent declaration
+ if (New->getAttr<WeakImportAttr>() &&
+ Old->getStorageClass() == SC_None &&
+ !Old->getAttr<WeakImportAttr>()) {
+ Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ // Remove weak_import attribute on new declaration.
+ New->dropAttr<WeakImportAttr>();
+ }
// Merge the types.
MergeVarDeclTypes(New, Old);
@@ -2597,7 +2626,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
}
// Mock up a declarator.
- Declarator Dc(DS, Declarator::TypeNameContext);
+ Declarator Dc(DS, Declarator::MemberContext);
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
assert(TInfo && "couldn't build declarator info for anonymous struct/union");
@@ -2736,6 +2765,7 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
switch (Name.getKind()) {
+ case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_Identifier:
NameInfo.setName(Name.Identifier);
NameInfo.setLoc(Name.StartLocation);
@@ -2924,10 +2954,9 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
return false;
}
-Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D,
- bool IsFunctionDefinition) {
+Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this),
- IsFunctionDefinition);
+ /*IsFunctionDefinition=*/false);
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@@ -3274,8 +3303,18 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) {
// The previous declaration was found on the identifer resolver
// chain, so remove it from its scope.
- while (S && !S->isDeclScope(PrevDecl))
- S = S->getParent();
+
+ if (S->isDeclScope(PrevDecl)) {
+ // Special case for redeclarations in the SAME scope.
+ // Because this declaration is going to be added to the identifier chain
+ // later, we should temporarily take it OFF the chain.
+ IdResolver.RemoveDecl(ND);
+
+ } else {
+ // Find the scope for the original declaration.
+ while (S && !S->isDeclScope(PrevDecl))
+ S = S->getParent();
+ }
if (S)
S->RemoveDecl(PrevDecl);
@@ -3472,6 +3511,50 @@ static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) {
DD->setQualifierInfo(SS.getWithLocInContext(DD->getASTContext()));
}
+bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
+ QualType type = decl->getType();
+ Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime();
+ if (lifetime == Qualifiers::OCL_Autoreleasing) {
+ // Various kinds of declaration aren't allowed to be __autoreleasing.
+ unsigned kind = -1U;
+ if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
+ if (var->hasAttr<BlocksAttr>())
+ kind = 0; // __block
+ else if (!var->hasLocalStorage())
+ kind = 1; // global
+ } else if (isa<ObjCIvarDecl>(decl)) {
+ kind = 3; // ivar
+ } else if (isa<FieldDecl>(decl)) {
+ kind = 2; // field
+ }
+
+ if (kind != -1U) {
+ Diag(decl->getLocation(), diag::err_arc_autoreleasing_var)
+ << kind;
+ }
+ } else if (lifetime == Qualifiers::OCL_None) {
+ // Try to infer lifetime.
+ if (!type->isObjCLifetimeType())
+ return false;
+
+ lifetime = type->getObjCARCImplicitLifetime();
+ type = Context.getLifetimeQualifiedType(type, lifetime);
+ decl->setType(type);
+ }
+
+ if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
+ // Thread-local variables cannot have lifetime.
+ if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone &&
+ var->isThreadSpecified()) {
+ Diag(var->getLocation(), diag::err_arc_thread_ownership)
+ << var->getType();
+ return true;
+ }
+ }
+
+ return false;
+}
+
NamedDecl*
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R, TypeSourceInfo *TInfo,
@@ -3630,6 +3713,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
+ // In auto-retain/release, infer strong retension for variables of
+ // retainable type.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
+ NewVD->setInvalidDecl();
+
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*)D.getAsmLabel()) {
// The parser guarantees this is a string.
@@ -4007,10 +4095,10 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(),
E = Paths.found_decls_end(); I != E; ++I) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
+ MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
- MD->addOverriddenMethod(OldMD->getCanonicalDecl());
AddedAny = true;
}
}
@@ -4035,7 +4123,7 @@ static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {
}
NamedDecl*
-Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
@@ -4611,9 +4699,18 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// A storage-class-specifier shall not be specified in an explicit
// specialization (14.7.3)
if (SC != SC_None) {
- Diag(NewFD->getLocation(),
- diag::err_explicit_specialization_storage_class)
- << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ if (SC != NewFD->getStorageClass())
+ Diag(NewFD->getLocation(),
+ diag::err_explicit_specialization_inconsistent_storage_class)
+ << SC
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
+
+ else
+ Diag(NewFD->getLocation(),
+ diag::ext_explicit_specialization_storage_class)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
}
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
@@ -5208,12 +5305,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
if (!VDecl) {
- if (getLangOptions().CPlusPlus &&
- RealDecl->getLexicalDeclContext()->isRecord() &&
- isa<NamedDecl>(RealDecl))
- Diag(RealDecl->getLocation(), diag::err_member_initialization);
- else
- Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
+ assert(!isa<FieldDecl>(RealDecl) && "field init shouldn't get here");
+ Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
RealDecl->setInvalidDecl();
return;
}
@@ -5232,6 +5325,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setTypeSourceInfo(DeducedType);
VDecl->setType(DeducedType->getType());
+ // In ARC, infer lifetime.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+ VDecl->setInvalidDecl();
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDeclaration())
@@ -5372,15 +5469,23 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// We allow integer constant expressions in all cases.
} else if (T->isIntegralOrEnumerationType()) {
- if (!Init->isValueDependent()) {
- // Check whether the expression is a constant expression.
- llvm::APSInt Value;
- SourceLocation Loc;
- if (!Init->isIntegerConstantExpr(Value, Context, &Loc)) {
- Diag(Loc, diag::err_in_class_initializer_non_constant)
- << Init->getSourceRange();
- VDecl->setInvalidDecl();
- }
+ // Check whether the expression is a constant expression.
+ SourceLocation Loc;
+ if (Init->isValueDependent())
+ ; // Nothing to check.
+ else if (Init->isIntegerConstantExpr(Context, &Loc))
+ ; // Ok, it's an ICE!
+ else if (Init->isEvaluatable(Context)) {
+ // If we can constant fold the initializer through heroics, accept it,
+ // but report this as a use of an extension for -pedantic.
+ Diag(Loc, diag::ext_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ } else {
+ // Otherwise, this is some crazy unknown case. Report the issue at the
+ // location provided by the isIntegerConstantExpr failed check.
+ Diag(Loc, diag::err_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ VDecl->setInvalidDecl();
}
// We allow floating-point constants as an extension in C++03, and
@@ -5466,7 +5571,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Check any implicit conversions within the expression.
CheckImplicitConversions(Init, VDecl->getLocation());
-
+
+ if (!VDecl->isInvalidDecl())
+ checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
+
Init = MaybeCreateExprWithCleanups(Init);
// Attach the initializer to the decl.
VDecl->setInit(Init);
@@ -5735,6 +5843,23 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;
+ // In ARC, don't allow jumps past the implicit initialization of a
+ // local retaining variable.
+ if (getLangOptions().ObjCAutoRefCount &&
+ var->hasLocalStorage()) {
+ switch (var->getType().getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ getCurFunction()->setHasBranchProtectedScope();
+ break;
+ }
+ }
+
// All the following checks are C++ only.
if (!getLangOptions().CPlusPlus) return;
@@ -5874,21 +5999,13 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
DiagnoseFunctionSpecifiers(D);
- TagDecl *OwnedDecl = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();
if (getLangOptions().CPlusPlus) {
// Check that there are no default arguments inside the type of this
// parameter.
CheckExtraCXXDefaultArguments(D);
-
- if (OwnedDecl && OwnedDecl->isDefinition()) {
- // C++ [dcl.fct]p6:
- // Types shall not be defined in return or parameter types.
- Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
- << Context.getTypeDeclType(OwnedDecl);
- }
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
@@ -6003,7 +6120,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
// Warn if the return value is pass-by-value and larger than the specified
// threshold.
- if (ReturnTy->isPODType()) {
+ if (ReturnTy.isPODType(Context)) {
unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
Diag(D->getLocation(), diag::warn_return_value_size)
@@ -6014,7 +6131,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
// threshold.
for (; Param != ParamEnd; ++Param) {
QualType T = (*Param)->getType();
- if (!T->isPODType())
+ if (!T.isPODType(Context))
continue;
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
@@ -6028,8 +6145,31 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
QualType T, TypeSourceInfo *TSInfo,
VarDecl::StorageClass StorageClass,
VarDecl::StorageClass StorageClassAsWritten) {
+ // In ARC, infer a lifetime qualifier for appropriate parameter types.
+ if (getLangOptions().ObjCAutoRefCount &&
+ T.getObjCLifetime() == Qualifiers::OCL_None &&
+ T->isObjCLifetimeType()) {
+
+ Qualifiers::ObjCLifetime lifetime;
+
+ // Special cases for arrays:
+ // - if it's const, use __unsafe_unretained
+ // - otherwise, it's an error
+ if (T->isArrayType()) {
+ if (!T.isConstQualified()) {
+ Diag(NameLoc, diag::err_arc_array_param_no_ownership)
+ << TSInfo->getTypeLoc().getSourceRange();
+ }
+ lifetime = Qualifiers::OCL_ExplicitNone;
+ } else {
+ lifetime = T->getObjCARCImplicitLifetime();
+ }
+ T = Context.getLifetimeQualifiedType(T, lifetime);
+ }
+
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
- adjustParameterType(T), TSInfo,
+ Context.getAdjustedParameterType(T),
+ TSInfo,
StorageClass, StorageClassAsWritten,
0);
@@ -6318,6 +6458,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
WP.disableCheckFallThrough();
+ } else if (FD->hasAttr<NakedAttr>()) {
+ // If the function is marked 'naked', don't complain about missing return
+ // statements.
+ WP.disableCheckFallThrough();
}
// MSVC permits the use of pure specifier (=0) on function definition,
@@ -6364,7 +6508,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Verify that that gotos and switch cases don't jump into scopes illegally.
if (getCurFunction()->NeedsScopeChecking() &&
!dcl->isInvalidDecl() &&
- !hasAnyErrorsInThisFunction())
+ !hasAnyUnrecoverableErrorsInThisFunction())
DiagnoseInvalidJumps(Body);
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) {
@@ -6379,15 +6523,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
if (PP.getDiagnostics().hasErrorOccurred() ||
- PP.getDiagnostics().getSuppressAllDiagnostics())
+ PP.getDiagnostics().getSuppressAllDiagnostics()) {
ExprTemporaries.clear();
- else if (!isa<FunctionTemplateDecl>(dcl)) {
+ ExprNeedsCleanups = false;
+ } else if (!isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
// enabled.
ActivePolicy = &WP;
}
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
+ assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
}
if (!IsInstantiation)
@@ -6398,8 +6544,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (getDiagnostics().hasErrorOccurred())
+ if (getDiagnostics().hasErrorOccurred()) {
ExprTemporaries.clear();
+ ExprNeedsCleanups = false;
+ }
return dcl;
}
@@ -6439,6 +6587,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
0, 0, true, SourceLocation(),
+ SourceLocation(),
EST_None, SourceLocation(),
0, 0, 0, 0, Loc, Loc, D),
DS.getAttributes(),
@@ -6466,6 +6615,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/// These attributes can apply both to implicitly-declared builtins
/// (like __builtin___printf_chk) or to library-declared functions
/// like NSLog or printf.
+///
+/// We need to check for duplicate attributes both here and where user-written
+/// attributes are applied to declarations.
void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (FD->isInvalidDecl())
return;
@@ -6499,9 +6651,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
}
- if (Context.BuiltinInfo.isNoThrow(BuiltinID))
+ if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>())
FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context));
- if (Context.BuiltinInfo.isConst(BuiltinID))
+ if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>())
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
}
@@ -7728,6 +7880,11 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// FIXME: What to pass instead of TUScope?
ProcessDeclAttributes(TUScope, NewFD, *D);
+ // In auto-retain/release, infer strong retension for fields of
+ // retainable type.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
+ NewFD->setInvalidDecl();
+
if (T.isObjCGCWeak())
Diag(Loc, diag::warn_attribute_weak_on_field);
@@ -7761,6 +7918,21 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
member = CXXDestructor;
if (member != CXXInvalid) {
+ if (getLangOptions().ObjCAutoRefCount && RDecl->hasObjectMember()) {
+ // Objective-C++ ARC: it is an error to have a non-trivial field of
+ // a union. However, system headers in Objective-C programs
+ // occasionally have Objective-C lifetime objects within unions,
+ // and rather than cause the program to fail, we make those
+ // members unavailable.
+ SourceLocation Loc = FD->getLocation();
+ if (getSourceManager().isInSystemHeader(Loc)) {
+ if (!FD->hasAttr<UnavailableAttr>())
+ FD->addAttr(new (Context) UnavailableAttr(Loc, Context,
+ "this system field has retaining ownership"));
+ return false;
+ }
+ }
+
Diag(FD->getLocation(), diag::err_illegal_union_or_anon_struct_member)
<< (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
DiagnoseNontrivial(RT, member);
@@ -7913,6 +8085,21 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
return;
}
}
+
+ if (EltTy->isObjCLifetimeType()) {
+ switch (EltTy.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ break;
+
+ case Qualifiers::OCL_Autoreleasing:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ Diag((*fi)->getLocation(), diag::note_nontrivial_objc_ownership)
+ << QT << EltTy.getObjCLifetime();
+ return;
+ }
+ }
}
assert(0 && "found no explanation for non-trivial member");
@@ -8022,6 +8209,10 @@ Decl *Sema::ActOnIvar(Scope *S,
if (D.isInvalidType())
NewID->setInvalidDecl();
+ // In ARC, infer 'retaining' for ivars of retainable type.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID))
+ NewID->setInvalidDecl();
+
if (II) {
// FIXME: When interfaces are DeclContexts, we'll need to add
// these to the interface.
@@ -8093,6 +8284,7 @@ void Sema::ActOnFields(Scope* S,
llvm::SmallVector<FieldDecl*, 32> RecFields;
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
+ bool ARCErrReported = false;
for (unsigned i = 0; i != NumFields; ++i) {
FieldDecl *FD = cast<FieldDecl>(Fields[i]);
@@ -8158,7 +8350,7 @@ void Sema::ActOnFields(Scope* S,
continue;
}
if (!FD->getType()->isDependentType() &&
- !Context.getBaseElementType(FD->getType())->isPODType()) {
+ !Context.getBaseElementType(FD->getType()).isPODType(Context)) {
Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type)
<< FD->getDeclName() << FD->getType();
FD->setInvalidDecl();
@@ -8205,17 +8397,45 @@ void Sema::ActOnFields(Scope* S,
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (getLangOptions().ObjC1 &&
+ }
+ else if (!getLangOptions().CPlusPlus) {
+ if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) {
+ // It's an error in ARC if a field has lifetime.
+ // We don't want to report this in a system header, though,
+ // so we just make the field unavailable.
+ // FIXME: that's really not sufficient; we need to make the type
+ // itself invalid to, say, initialize or copy.
+ QualType T = FD->getType();
+ Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
+ if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
+ SourceLocation loc = FD->getLocation();
+ if (getSourceManager().isInSystemHeader(loc)) {
+ if (!FD->hasAttr<UnavailableAttr>()) {
+ FD->addAttr(new (Context) UnavailableAttr(loc, Context,
+ "this system field has retaining ownership"));
+ }
+ } else {
+ Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct);
+ }
+ ARCErrReported = true;
+ }
+ }
+ else if (getLangOptions().ObjC1 &&
getLangOptions().getGCMode() != LangOptions::NonGC &&
- Record &&
- (FD->getType()->isObjCObjectPointerType() ||
- FD->getType().isObjCGCStrong()))
- Record->setHasObjectMember(true);
- else if (Context.getAsArrayType(FD->getType())) {
- QualType BaseType = Context.getBaseElementType(FD->getType());
- if (Record && BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
- Record->setHasObjectMember(true);
+ Record && !Record->hasObjectMember()) {
+ if (FD->getType()->isObjCObjectPointerType() ||
+ FD->getType().isObjCGCStrong())
+ Record->setHasObjectMember(true);
+ else if (Context.getAsArrayType(FD->getType())) {
+ QualType BaseType = Context.getBaseElementType(FD->getType());
+ if (BaseType->isRecordType() &&
+ BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
+ Record->setHasObjectMember(true);
+ else if (BaseType->isObjCObjectPointerType() ||
+ BaseType.isObjCGCStrong())
+ Record->setHasObjectMember(true);
+ }
+ }
}
// Keep track of the number of named members.
if (FD->getIdentifier())
@@ -8234,6 +8454,42 @@ void Sema::ActOnFields(Scope* S,
Convs->setAccess(I, (*I)->getAccess());
if (!CXXRecord->isDependentType()) {
+ // Objective-C Automatic Reference Counting:
+ // If a class has a non-static data member of Objective-C pointer
+ // type (or array thereof), it is a non-POD type and its
+ // default constructor (if any), copy constructor, copy assignment
+ // operator, and destructor are non-trivial.
+ //
+ // This rule is also handled by CXXRecordDecl::completeDefinition().
+ // However, here we check whether this particular class is only
+ // non-POD because of the presence of an Objective-C pointer member.
+ // If so, objects of this type cannot be shared between code compiled
+ // with instant objects and code compiled with manual retain/release.
+ if (getLangOptions().ObjCAutoRefCount &&
+ CXXRecord->hasObjectMember() &&
+ CXXRecord->getLinkage() == ExternalLinkage) {
+ if (CXXRecord->isPOD()) {
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_non_pod_class_with_object_member)
+ << CXXRecord;
+ } else {
+ // FIXME: Fix-Its would be nice here, but finding a good location
+ // for them is going to be tricky.
+ if (CXXRecord->hasTrivialCopyConstructor())
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_trivial_member_function_with_object_member)
+ << CXXRecord << 0;
+ if (CXXRecord->hasTrivialCopyAssignment())
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_trivial_member_function_with_object_member)
+ << CXXRecord << 1;
+ if (CXXRecord->hasTrivialDestructor())
+ Diag(CXXRecord->getLocation(),
+ diag::warn_arc_trivial_member_function_with_object_member)
+ << CXXRecord << 2;
+ }
+ }
+
// Adjust user-defined destructor exception spec.
if (getLangOptions().CPlusPlus0x &&
CXXRecord->hasUserDeclaredDestructor())
@@ -8807,7 +9063,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// Adjust the Expr initializer and type.
if (ECD->getInitExpr() &&
- !Context.hasSameType(NewTy, ECD->getInitExpr()->getType()))
+ !Context.hasSameType(NewTy, ECD->getInitExpr()->getType()))
ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy,
CK_IntegralCast,
ECD->getInitExpr(),
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 7f93ab7..61b7b3e 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
@@ -48,14 +49,14 @@ enum {
// Helper functions
//===----------------------------------------------------------------------===//
-static const FunctionType *getFunctionType(const Decl *d,
+static const FunctionType *getFunctionType(const Decl *D,
bool blocksToo = true) {
QualType Ty;
- if (const ValueDecl *decl = dyn_cast<ValueDecl>(d))
+ if (const ValueDecl *decl = dyn_cast<ValueDecl>(D))
Ty = decl->getType();
- else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
+ else if (const FieldDecl *decl = dyn_cast<FieldDecl>(D))
Ty = decl->getType();
- else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(d))
+ else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(D))
Ty = decl->getUnderlyingType();
else
return 0;
@@ -73,46 +74,47 @@ static const FunctionType *getFunctionType(const Decl *d,
/// isFunction - Return true if the given decl has function
/// type (function or function-typed variable).
-static bool isFunction(const Decl *d) {
- return getFunctionType(d, false) != NULL;
+static bool isFunction(const Decl *D) {
+ return getFunctionType(D, false) != NULL;
}
/// isFunctionOrMethod - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method.
-static bool isFunctionOrMethod(const Decl *d) {
- return isFunction(d)|| isa<ObjCMethodDecl>(d);
+static bool isFunctionOrMethod(const Decl *D) {
+ return isFunction(D)|| isa<ObjCMethodDecl>(D);
}
/// isFunctionOrMethodOrBlock - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method or a block.
-static bool isFunctionOrMethodOrBlock(const Decl *d) {
- if (isFunctionOrMethod(d))
+static bool isFunctionOrMethodOrBlock(const Decl *D) {
+ if (isFunctionOrMethod(D))
return true;
// check for block is more involved.
- if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
+ if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
QualType Ty = V->getType();
return Ty->isBlockPointerType();
}
- return isa<BlockDecl>(d);
+ return isa<BlockDecl>(D);
}
/// Return true if the given decl has a declarator that should have
/// been processed by Sema::GetTypeForDeclarator.
-static bool hasDeclarator(const Decl *d) {
- // In some sense, TypedefNameDecl really *ought* to be a DeclaratorDecl.
- return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefNameDecl>(d);
+static bool hasDeclarator(const Decl *D) {
+ // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
+ return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) || isa<TypedefNameDecl>(D) ||
+ isa<ObjCPropertyDecl>(D);
}
/// hasFunctionProto - Return true if the given decl has a argument
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
-static bool hasFunctionProto(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static bool hasFunctionProto(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return isa<FunctionProtoType>(FnTy);
else {
- assert(isa<ObjCMethodDecl>(d) || isa<BlockDecl>(d));
+ assert(isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D));
return true;
}
}
@@ -120,42 +122,42 @@ static bool hasFunctionProto(const Decl *d) {
/// getFunctionOrMethodNumArgs - Return number of function or method
/// arguments. It is an error to call this on a K&R function (use
/// hasFunctionProto first).
-static unsigned getFunctionOrMethodNumArgs(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static unsigned getFunctionOrMethodNumArgs(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return cast<FunctionProtoType>(FnTy)->getNumArgs();
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getNumParams();
- return cast<ObjCMethodDecl>(d)->param_size();
+ return cast<ObjCMethodDecl>(D)->param_size();
}
-static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static QualType getFunctionOrMethodArgType(const Decl *D, unsigned Idx) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getParamDecl(Idx)->getType();
- return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
+ return cast<ObjCMethodDecl>(D)->param_begin()[Idx]->getType();
}
-static QualType getFunctionOrMethodResultType(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d))
+static QualType getFunctionOrMethodResultType(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D))
return cast<FunctionProtoType>(FnTy)->getResultType();
- return cast<ObjCMethodDecl>(d)->getResultType();
+ return cast<ObjCMethodDecl>(D)->getResultType();
}
-static bool isFunctionOrMethodVariadic(const Decl *d) {
- if (const FunctionType *FnTy = getFunctionType(d)) {
+static bool isFunctionOrMethodVariadic(const Decl *D) {
+ if (const FunctionType *FnTy = getFunctionType(D)) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
- } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->isVariadic();
else {
- return cast<ObjCMethodDecl>(d)->isVariadic();
+ return cast<ObjCMethodDecl>(D)->isVariadic();
}
}
-static bool isInstanceMethod(const Decl *d) {
- if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(d))
+static bool isInstanceMethod(const Decl *D) {
+ if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D))
return MethodDecl->isInstance();
return false;
}
@@ -192,6 +194,16 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
}
+static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
+ unsigned int Num) {
+ if (Attr.getNumArgs() != Num) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Num;
+ return false;
+ }
+
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Attribute Implementations
//===----------------------------------------------------------------------===//
@@ -200,9 +212,9 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
// least add some helper functions to check most argument patterns (#
// and types of args).
-static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
- const AttributeList &Attr, Sema &S) {
- TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(d);
+static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr) {
+ TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
if (tDecl == 0) {
S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
return;
@@ -217,13 +229,17 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
CXXScopeSpec SS;
UnqualifiedId id;
id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
- sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs<Expr>();
+
+ ExprResult Size = S.ActOnIdExpression(scope, SS, id, false, false);
+ if (Size.isInvalid())
+ return;
+
+ sizeExpr = Size.get();
} else {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
+
sizeExpr = Attr.getArg(0);
}
@@ -239,16 +255,14 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
}
}
-static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (TagDecl *TD = dyn_cast<TagDecl>(d))
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
TD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context));
- else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) {
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
// If the alignment is less than or equal to 8 bits, the packed attribute
// has no effect.
if (!FD->getType()->isIncompleteType() &&
@@ -261,49 +275,45 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
-static void HandleMsStructAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (TagDecl *TD = dyn_cast<TagDecl>(d))
+static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
-static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
// The IBAction attributes only apply to instance methods.
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
if (MD->isInstanceMethod()) {
- d->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context));
return;
}
S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName();
}
-static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
// The IBOutlet attributes only apply to instance variables of
// Objective-C classes.
- if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d)) {
- d->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context));
+ if (isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D)) {
+ D->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context));
return;
}
S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
}
-static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleIBOutletCollection(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// The iboutletcollection attribute can have zero or one arguments.
if (Attr.getParameterName() && Attr.getNumArgs() > 0) {
@@ -313,17 +323,17 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
// The IBOutletCollection attributes only apply to instance variables of
// Objective-C classes.
- if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) {
+ if (!(isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) {
S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
return;
}
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(d))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type)
<< VD->getType() << 0;
return;
}
- if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(d))
+ if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type)
<< PD->getType() << 1;
@@ -335,7 +345,7 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
II = &S.Context.Idents.get("id");
ParsedType TypeRep = S.getTypeName(*II, Attr.getLoc(),
- S.getScopeForContext(d->getDeclContext()->getParent()));
+ S.getScopeForContext(D->getDeclContext()->getParent()));
if (!TypeRep) {
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
@@ -350,14 +360,29 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
}
- d->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context,
QT));
}
-static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void possibleTransparentUnionPointerType(QualType &T) {
+ if (const RecordType *UT = T->getAsUnionType())
+ if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
+ RecordDecl *UD = UT->getDecl();
+ for (RecordDecl::field_iterator it = UD->field_begin(),
+ itend = UD->field_end(); it != itend; ++it) {
+ QualType QT = it->getType();
+ if (QT->isAnyPointerType() || QT->isBlockPointerType()) {
+ T = QT;
+ return;
+ }
+ }
+ }
+}
+
+static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// GCC ignores the nonnull attribute on K&R style function prototypes, so we
// ignore it as well
- if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
+ if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
@@ -365,8 +390,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
// The nonnull attribute only applies to pointers.
llvm::SmallVector<unsigned, 10> NonNullArgs;
@@ -405,7 +430,9 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(d, x).getNonReferenceType();
+ QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+ possibleTransparentUnionPointerType(T);
+
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only)
@@ -419,23 +446,11 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// If no arguments were specified to __attribute__((nonnull)) then all pointer
// arguments have a nonnull attribute.
if (NonNullArgs.empty()) {
- for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
- QualType T = getFunctionOrMethodArgType(d, I).getNonReferenceType();
+ for (unsigned I = 0, E = getFunctionOrMethodNumArgs(D); I != E; ++I) {
+ QualType T = getFunctionOrMethodArgType(D, I).getNonReferenceType();
+ possibleTransparentUnionPointerType(T);
if (T->isAnyPointerType() || T->isBlockPointerType())
NonNullArgs.push_back(I);
- else if (const RecordType *UT = T->getAsUnionType()) {
- if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
- RecordDecl *UD = UT->getDecl();
- for (RecordDecl::field_iterator it = UD->field_begin(),
- itend = UD->field_end(); it != itend; ++it) {
- T = it->getType();
- if (T->isAnyPointerType() || T->isBlockPointerType()) {
- NonNullArgs.push_back(I);
- break;
- }
- }
- }
- }
}
// No pointer arguments?
@@ -451,11 +466,11 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned* start = &NonNullArgs[0];
unsigned size = NonNullArgs.size();
llvm::array_pod_sort(start, start + size);
- d->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start,
+ D->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start,
size));
}
-static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
+static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
// This attribute must be applied to a function declaration.
// The first argument to the attribute must be a string,
// the name of the resource, for example "malloc".
@@ -500,7 +515,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
llvm_unreachable("Unknown ownership attribute");
}
- if (!isFunction(d) || !hasFunctionProto(d)) {
+ if (!isFunction(D) || !hasFunctionProto(D)) {
S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
<< AL.getName() << ExpectedFunction;
return;
@@ -508,8 +523,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
llvm::StringRef Module = AL.getParameterName()->getName();
@@ -552,7 +567,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
case OwnershipAttr::Takes:
case OwnershipAttr::Holds: {
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(d, x);
+ QualType T = getFunctionOrMethodArgType(D, x);
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(AL.getLoc(), diag::err_ownership_type)
@@ -584,8 +599,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
// Check we don't have a conflict with another ownership attribute.
for (specific_attr_iterator<OwnershipAttr>
- i = d->specific_attr_begin<OwnershipAttr>(),
- e = d->specific_attr_end<OwnershipAttr>();
+ i = D->specific_attr_begin<OwnershipAttr>(),
+ e = D->specific_attr_end<OwnershipAttr>();
i != e; ++i) {
if ((*i)->getOwnKind() != K) {
for (const unsigned *I = (*i)->args_begin(), *E = (*i)->args_end();
@@ -609,7 +624,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module,
+ D->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module,
start, size));
}
@@ -633,20 +648,20 @@ static bool hasEffectivelyInternalLinkage(NamedDecl *D) {
return false;
}
-static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
+ if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableOrFunction;
return;
}
- NamedDecl *nd = cast<NamedDecl>(d);
+ NamedDecl *nd = cast<NamedDecl>(D);
// gcc rejects
// class c {
@@ -658,7 +673,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// static int a __attribute__((weakref ("v2")));
// }
// we reject them
- const DeclContext *Ctx = d->getDeclContext()->getRedeclContext();
+ const DeclContext *Ctx = D->getDeclContext()->getRedeclContext();
if (!Ctx->isFileContext()) {
S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) <<
nd->getNameAsString();
@@ -704,14 +719,14 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// GCC will accept anything as the argument of weakref. Should we
// check for an existing decl?
- d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
Str->getString()));
}
- d->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context));
}
-static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -735,55 +750,52 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: check if target symbol exists in current file
- d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
Str->getString()));
}
-static void HandleNakedAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context));
}
-static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleAlwaysInlineAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getResultType();
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
- d->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context));
return;
}
}
@@ -791,46 +803,44 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
}
-static void HandleMayAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- d->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context));
}
-static void HandleNoCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- assert(Attr.isInvalid() == false);
- if (isa<VarDecl>(d))
- d->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context));
+static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+ if (isa<VarDecl>(D))
+ D->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
}
-static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- assert(Attr.isInvalid() == false);
- if (isa<VarDecl>(d))
- d->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context));
+static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+ if (isa<VarDecl>(D))
+ D->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
}
-static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
- if (hasDeclarator(d)) return;
+static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
+ if (hasDeclarator(D)) return;
if (S.CheckNoReturnAttr(attr)) return;
- if (!isa<ObjCMethodDecl>(d)) {
+ if (!isa<ObjCMethodDecl>(D)) {
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< attr.getName() << ExpectedFunctionOrMethod;
return;
}
- d->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
@@ -843,19 +853,17 @@ bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
return false;
}
-static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// The checking path for 'noreturn' and 'analyzer_noreturn' are different
// because 'analyzer_noreturn' does not impact the type.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
+ if(!checkAttributeNumArgs(S, Attr, 0))
+ return;
- if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) {
- ValueDecl *VD = dyn_cast<ValueDecl>(d);
+ if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) {
+ ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (VD == 0 || (!VD->getType()->isBlockPointerType()
&& !VD->getType()->isFunctionPointerType())) {
S.Diag(Attr.getLoc(),
@@ -866,12 +874,11 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
}
}
- d->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context));
}
// PS3 PPU-specific.
-static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
/*
Returning a Vector Class in Registers
@@ -895,18 +902,18 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
return result; // This will be returned in a register
}
*/
- if (!isa<RecordDecl>(d)) {
+ if (!isa<RecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedClass;
return;
}
- if (d->getAttr<VecReturnAttr>()) {
+ if (D->getAttr<VecReturnAttr>()) {
S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn";
return;
}
- RecordDecl *record = cast<RecordDecl>(d);
+ RecordDecl *record = cast<RecordDecl>(D);
int count = 0;
if (!isa<CXXRecordDecl>(record)) {
@@ -928,11 +935,11 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
count++;
}
- d->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context));
}
-static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
+static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!isFunctionOrMethod(D) && !isa<ParmVarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrParameter;
return;
@@ -940,45 +947,45 @@ static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: Actually store the attribute on the declaration
}
-static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) &&
- !isa<TypeDecl>(d) && !isa<LabelDecl>(d)) {
+ if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
+ !isa<TypeDecl>(D) && !isa<LabelDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableFunctionOrLabel;
return;
}
- d->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context));
}
-static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (const VarDecl *VD = dyn_cast<VarDecl>(d)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
return;
}
- } else if (!isFunctionOrMethod(d)) {
+ } else if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableOrFunction;
return;
}
- d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
}
-static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -998,17 +1005,17 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
priority = Idx.getZExtValue();
}
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context,
priority));
}
-static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -1028,17 +1035,17 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
priority = Idx.getZExtValue();
}
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context,
priority));
}
-static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -1057,10 +1064,10 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Str = SE->getString();
}
- d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str));
+ D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str));
}
-static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
@@ -1078,11 +1085,23 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
Str = SE->getString();
}
- d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str));
+ D->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str));
+}
+
+static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ unsigned NumArgs = Attr.getNumArgs();
+ if (NumArgs > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr(
+ Attr.getLoc(), S.Context));
}
-static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleAvailabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
IdentifierInfo *Platform = Attr.getParameterName();
SourceLocation PlatformLoc = Attr.getParameterLoc();
@@ -1126,7 +1145,7 @@ static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr,
return;
}
- d->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context,
Platform,
Introduced.Version,
Deprecated.Version,
@@ -1134,12 +1153,10 @@ static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr,
IsUnavailable));
}
-static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if(!checkAttributeNumArgs(S, Attr, 1))
return;
- }
Expr *Arg = Attr.getArg(0);
Arg = Arg->IgnoreParenCasts();
@@ -1167,30 +1184,30 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type));
+ D->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type));
}
-static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr,
- Sema &S) {
+static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
+ const AttributeList &Attr) {
ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl);
if (!method) {
- S.Diag(attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< ExpectedMethod;
return;
}
- if (attr.getNumArgs() != 0 || !attr.getParameterName()) {
- if (!attr.getParameterName() && attr.getNumArgs() == 1) {
- S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ if (Attr.getNumArgs() != 0 || !Attr.getParameterName()) {
+ if (!Attr.getParameterName() && Attr.getNumArgs() == 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "objc_method_family" << 1;
} else {
- S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
}
- attr.setInvalid();
+ Attr.setInvalid();
return;
}
- llvm::StringRef param = attr.getParameterName()->getName();
+ llvm::StringRef param = Attr.getParameterName()->getName();
ObjCMethodFamilyAttr::FamilyKind family;
if (param == "none")
family = ObjCMethodFamilyAttr::OMF_None;
@@ -1207,20 +1224,26 @@ static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr,
else {
// Just warn and ignore it. This is future-proof against new
// families being used in system headers.
- S.Diag(attr.getParameterLoc(), diag::warn_unknown_method_family);
+ S.Diag(Attr.getParameterLoc(), diag::warn_unknown_method_family);
return;
}
- decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(),
- S.Context, family));
+ if (family == ObjCMethodFamilyAttr::OMF_init &&
+ !method->getResultType()->isObjCObjectPointerType()) {
+ S.Diag(method->getLocation(), diag::err_init_method_bad_return_type)
+ << method->getResultType();
+ // Ignore the attribute.
+ return;
+ }
+
+ method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getLoc(),
+ S.Context, family));
}
-static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
- Sema &S) {
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+static void handleObjCExceptionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
if (OCI == 0) {
@@ -1231,7 +1254,7 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getLoc(), S.Context));
}
-static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1248,7 +1271,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
}
static void
-HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1262,7 +1285,7 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) OverloadableAttr(Attr.getLoc(), S.Context));
}
-static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "blocks" << 1;
@@ -1283,10 +1306,10 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type));
+ D->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type));
}
-static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 2) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2;
@@ -1333,7 +1356,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
}
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
const FunctionType *FT = FD->getType()->getAs<FunctionType>();
assert(FT && "FunctionDecl has non-function type?");
@@ -1346,19 +1369,19 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
- } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (!MD->isVariadic()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
- } else if (isa<BlockDecl>(d)) {
+ } else if (isa<BlockDecl>(D)) {
// Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
// caller.
;
- } else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
+ } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
+ const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(D)
: Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
@@ -1375,16 +1398,14 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
- d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel,
+ D->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel,
nullPos));
}
-static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -1407,36 +1428,35 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context));
}
-static void HandleWeakAttr(Decl *d, const AttributeList &attr, Sema &S) {
+static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (attr.hasParameterOrArguments()) {
- S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (Attr.hasParameterOrArguments()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedVariableOrFunction;
+ if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedVariableOrFunction;
return;
}
- NamedDecl *nd = cast<NamedDecl>(d);
+ NamedDecl *nd = cast<NamedDecl>(D);
// 'weak' only applies to declarations with external linkage.
if (hasEffectivelyInternalLinkage(nd)) {
- S.Diag(attr.getLoc(), diag::err_attribute_weak_static);
+ S.Diag(Attr.getLoc(), diag::err_attribute_weak_static);
return;
}
- nd->addAttr(::new (S.Context) WeakAttr(attr.getLoc(), S.Context));
+ nd->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context));
}
-static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
+
// weak_import only applies to variable & function declarations.
bool isDef = false;
@@ -1459,13 +1479,11 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) WeakImportAttr(Attr.getLoc(), S.Context));
}
-static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
- Sema &S) {
+static void handleReqdWorkGroupSize(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// Attribute has 3 arguments.
- if (Attr.getNumArgs() != 3) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 3))
return;
- }
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
@@ -1484,12 +1502,10 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
WGSize[2]));
}
-static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Attribute has no arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
// Make sure that there is a string literal as the sections's single
// argument.
@@ -1519,37 +1535,45 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
-static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
- d->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context));
+
+ if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) {
+ if (Existing->getLocation().isInvalid())
+ Existing->setLocation(Attr.getLoc());
+ } else {
+ D->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context));
+ }
}
-static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- d->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context));
+ if (ConstAttr *Existing = D->getAttr<ConstAttr>()) {
+ if (Existing->getLocation().isInvalid())
+ Existing->setLocation(Attr.getLoc());
+ } else {
+ D->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context));
+ }
}
-static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- d->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context));
}
-static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1560,7 +1584,7 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- VarDecl *VD = dyn_cast<VarDecl>(d);
+ VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD || !VD->hasLocalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
@@ -1605,18 +1629,17 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD));
+ D->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD));
S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD);
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
- if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
+
+ if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
@@ -1624,8 +1647,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
unsigned FirstIdx = 1;
// checks for the 2nd argument
@@ -1656,7 +1679,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// make sure the format string is really a string
- QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
+ QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
bool not_nsstring_type = !isNSStringType(Ty, S.Context);
if (not_nsstring_type &&
@@ -1669,7 +1692,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< IdxExpr->getSourceRange();
return;
}
- Ty = getFunctionOrMethodResultType(d);
+ Ty = getFunctionOrMethodResultType(D);
if (!isNSStringType(Ty, S.Context) &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
@@ -1681,7 +1704,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context,
Idx.getZExtValue()));
}
@@ -1722,19 +1745,19 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
/// Handle __attribute__((init_priority(priority))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html
-static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleInitPriorityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
if (!S.getLangOptions().CPlusPlus) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
return;
}
- if (!isa<VarDecl>(d) || S.getCurFunctionOrMethodDecl()) {
+ if (!isa<VarDecl>(D) || S.getCurFunctionOrMethodDecl()) {
S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr);
Attr.setInvalid();
return;
}
- QualType T = dyn_cast<VarDecl>(d)->getType();
+ QualType T = dyn_cast<VarDecl>(D)->getType();
if (S.Context.getAsArrayType(T))
T = S.Context.getBaseElementType(T);
if (!T->getAs<RecordType>()) {
@@ -1765,13 +1788,13 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr,
Attr.setInvalid();
return;
}
- d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context,
prioritynum));
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
@@ -1784,7 +1807,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
+ if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
@@ -1792,8 +1815,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
- bool HasImplicitThisParam = isInstanceMethod(d);
- unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
unsigned FirstIdx = 1;
llvm::StringRef Format = Attr.getParameterName()->getName();
@@ -1844,7 +1867,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// make sure the format string is really a string
- QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
+ QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
if (Kind == CFStringFormat) {
if (!isCFStringType(Ty, S.Context)) {
@@ -1881,10 +1904,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check if the function is variadic if the 3rd argument non-zero
if (FirstArg != 0) {
- if (isFunctionOrMethodVariadic(d)) {
+ if (isFunctionOrMethodVariadic(D)) {
++NumArgs; // +1 for ...
} else {
- S.Diag(d->getLocation(), diag::err_format_attribute_requires_variadic);
+ S.Diag(D->getLocation(), diag::err_format_attribute_requires_variadic);
return;
}
}
@@ -1904,26 +1927,42 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format,
+ // Check whether we already have an equivalent format attribute.
+ for (specific_attr_iterator<FormatAttr>
+ i = D->specific_attr_begin<FormatAttr>(),
+ e = D->specific_attr_end<FormatAttr>();
+ i != e ; ++i) {
+ FormatAttr *f = *i;
+ if (f->getType() == Format &&
+ f->getFormatIdx() == (int)Idx.getZExtValue() &&
+ f->getFirstArg() == (int)FirstArg.getZExtValue()) {
+ // If we don't have a valid location for this attribute, adopt the
+ // location.
+ if (f->getLocation().isInvalid())
+ f->setLocation(Attr.getLoc());
+ return;
+ }
+ }
+
+ D->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format,
Idx.getZExtValue(),
FirstArg.getZExtValue()));
}
-static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleTransparentUnionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
+
// Try to find the underlying union declaration.
RecordDecl *RD = 0;
- TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(d);
+ TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
if (TD && TD->getUnderlyingType()->isUnionType())
RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
else
- RD = dyn_cast<RecordDecl>(d);
+ RD = dyn_cast<RecordDecl>(D);
if (!RD || !RD->isUnion()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -1977,12 +2016,11 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getLoc(), S.Context));
}
-static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
+
Expr *ArgExpr = Attr.getArg(0);
StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
@@ -1992,11 +2030,11 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
- d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context,
SE->getString()));
}
-static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -2045,21 +2083,20 @@ void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *TS) {
return;
}
-/// HandleModeAttr - This attribute modifies the width of a decl with primitive
+/// handleModeAttr - This attribute modifies the width of a decl with primitive
/// type.
///
/// Despite what would be logical, the mode attribute is a decl attribute, not a
/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
/// HImode, not an intermediate pointer.
-static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// This attribute isn't documented, but glibc uses it. It changes
// the width of an int or unsigned int to the specified size.
// Check that there aren't any arguments
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
+
IdentifierInfo *Name = Attr.getParameterName();
if (!Name) {
@@ -2216,57 +2253,53 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
cast<ValueDecl>(D)->setType(NewTy);
}
-static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() > 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isFunctionOrMethod(d)) {
+ if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context));
}
-static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr,
- Sema &S) {
+static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(),
S.Context));
}
-static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
@@ -2274,19 +2307,19 @@ static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isa<VarDecl>(d)) {
+ if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
return;
}
- d->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant";
}
}
-static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -2294,33 +2327,31 @@ static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isa<FunctionDecl>(d) && !isa<VarDecl>(d)) {
+ if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableOrFunction;
return;
}
- d->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device";
}
}
-static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- FunctionDecl *FD = cast<FunctionDecl>(d);
+ FunctionDecl *FD = cast<FunctionDecl>(D);
if (!FD->getResultType()->isVoidType()) {
TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
if (FunctionTypeLoc* FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
@@ -2335,60 +2366,56 @@ static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global";
}
}
-static void HandleHostAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<FunctionDecl>(d)) {
+
+ if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- d->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host";
}
}
-static void HandleSharedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- if (!isa<VarDecl>(d)) {
+
+ if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
return;
}
- d->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared";
}
}
-static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (!checkAttributeNumArgs(S, Attr, 0))
return;
- }
- FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
if (Fn == 0) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
@@ -2400,47 +2427,47 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
- if (hasDeclarator(d)) return;
+static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (hasDeclarator(D)) return;
- // Diagnostic is emitted elsewhere: here we store the (valid) attr
+ // Diagnostic is emitted elsewhere: here we store the (valid) Attr
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
CallingConv CC;
- if (S.CheckCallingConvAttr(attr, CC))
+ if (S.CheckCallingConvAttr(Attr, CC))
return;
- if (!isa<ObjCMethodDecl>(d)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedFunctionOrMethod;
+ if (!isa<ObjCMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
return;
}
- switch (attr.getKind()) {
+ switch (Attr.getKind()) {
case AttributeList::AT_fastcall:
- d->addAttr(::new (S.Context) FastCallAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_stdcall:
- d->addAttr(::new (S.Context) StdCallAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_thiscall:
- d->addAttr(::new (S.Context) ThisCallAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_cdecl:
- d->addAttr(::new (S.Context) CDeclAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_pascal:
- d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context));
return;
case AttributeList::AT_pcs: {
- Expr *Arg = attr.getArg(0);
+ Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (Str == 0 || Str->isWide()) {
- S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "pcs" << 1;
- attr.setInvalid();
+ Attr.setInvalid();
return;
}
@@ -2451,12 +2478,12 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
else if (StrRef == "aapcs-vfp")
PCS = PcsAttr::AAPCS_VFP;
else {
- S.Diag(attr.getLoc(), diag::err_invalid_pcs);
- attr.setInvalid();
+ S.Diag(Attr.getLoc(), diag::err_invalid_pcs);
+ Attr.setInvalid();
return;
}
- d->addAttr(::new (S.Context) PcsAttr(attr.getLoc(), S.Context, PCS));
+ D->addAttr(::new (S.Context) PcsAttr(Attr.getLoc(), S.Context, PCS));
}
default:
llvm_unreachable("unexpected attribute kind");
@@ -2464,9 +2491,9 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
}
}
-static void HandleOpenCLKernelAttr(Decl *d, const AttributeList &Attr, Sema &S){
- assert(Attr.isInvalid() == false);
- d->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context));
+static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){
+ assert(!Attr.isInvalid());
+ D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context));
}
bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
@@ -2515,63 +2542,63 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
return false;
}
-static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) {
- if (hasDeclarator(d)) return;
+static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (hasDeclarator(D)) return;
unsigned numParams;
- if (S.CheckRegparmAttr(attr, numParams))
+ if (S.CheckRegparmAttr(Attr, numParams))
return;
- if (!isa<ObjCMethodDecl>(d)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedFunctionOrMethod;
+ if (!isa<ObjCMethodDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
return;
}
- d->addAttr(::new (S.Context) RegparmAttr(attr.getLoc(), S.Context, numParams));
+ D->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, numParams));
}
/// Checks a regparm attribute, returning true if it is ill-formed and
/// otherwise setting numParams to the appropriate value.
-bool Sema::CheckRegparmAttr(const AttributeList &attr, unsigned &numParams) {
- if (attr.isInvalid())
+bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
+ if (Attr.isInvalid())
return true;
- if (attr.getNumArgs() != 1) {
- Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- attr.setInvalid();
+ if (Attr.getNumArgs() != 1) {
+ Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return true;
}
- Expr *NumParamsExpr = attr.getArg(0);
+ Expr *NumParamsExpr = Attr.getArg(0);
llvm::APSInt NumParams(32);
if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
!NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) {
- Diag(attr.getLoc(), diag::err_attribute_argument_not_int)
+ Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "regparm" << NumParamsExpr->getSourceRange();
- attr.setInvalid();
+ Attr.setInvalid();
return true;
}
if (Context.Target.getRegParmMax() == 0) {
- Diag(attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
+ Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
<< NumParamsExpr->getSourceRange();
- attr.setInvalid();
+ Attr.setInvalid();
return true;
}
numParams = NumParams.getZExtValue();
if (numParams > Context.Target.getRegParmMax()) {
- Diag(attr.getLoc(), diag::err_attribute_regparm_invalid_number)
+ Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
<< Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
- attr.setInvalid();
+ Attr.setInvalid();
return true;
}
return false;
}
-static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
+static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) {
@@ -2580,7 +2607,7 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
return;
}
- if (!isFunctionOrMethod(d)) {
+ if (!isFunctionOrMethod(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
@@ -2608,7 +2635,7 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
}
}
- d->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context,
MaxThreads.getZExtValue(),
MinBlocks.getZExtValue()));
} else {
@@ -2627,16 +2654,16 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
return type->isPointerType() || isValidSubjectOfNSAttribute(S, type);
}
-static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) {
- ParmVarDecl *param = dyn_cast<ParmVarDecl>(d);
+static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ ParmVarDecl *param = dyn_cast<ParmVarDecl>(D);
if (!param) {
- S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName() << ExpectedParameter;
+ S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedParameter;
return;
}
bool typeOK, cf;
- if (attr.getKind() == AttributeList::AT_ns_consumed) {
+ if (Attr.getKind() == AttributeList::AT_ns_consumed) {
typeOK = isValidSubjectOfNSAttribute(S, param->getType());
cf = false;
} else {
@@ -2645,47 +2672,52 @@ static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) {
}
if (!typeOK) {
- S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
- << SourceRange(attr.getLoc()) << attr.getName() << cf;
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName() << cf;
return;
}
if (cf)
- param->addAttr(::new (S.Context) CFConsumedAttr(attr.getLoc(), S.Context));
+ param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getLoc(), S.Context));
else
- param->addAttr(::new (S.Context) NSConsumedAttr(attr.getLoc(), S.Context));
+ param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getLoc(), S.Context));
}
-static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr,
- Sema &S) {
- if (!isa<ObjCMethodDecl>(d)) {
- S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName() << ExpectedMethod;
+static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<ObjCMethodDecl>(D)) {
+ S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedMethod;
return;
}
- d->addAttr(::new (S.Context) NSConsumesSelfAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getLoc(), S.Context));
}
-static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr,
- Sema &S) {
+static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
QualType returnType;
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
returnType = MD->getResultType();
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
+ else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
+ returnType = PD->getType();
+ else if (S.getLangOptions().ObjCAutoRefCount && hasDeclarator(D) &&
+ (Attr.getKind() == AttributeList::AT_ns_returns_retained))
+ return; // ignore: was handled as a type attribute
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
returnType = FD->getResultType();
else {
- S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName()
+ S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(Attr.getLoc()) << Attr.getName()
<< ExpectedFunctionOrMethod;
return;
}
bool typeOK;
bool cf;
- switch (attr.getKind()) {
+ switch (Attr.getKind()) {
default: llvm_unreachable("invalid ownership attribute"); return;
case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_retained:
@@ -2702,39 +2734,95 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr,
}
if (!typeOK) {
- S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
- << SourceRange(attr.getLoc())
- << attr.getName() << isa<ObjCMethodDecl>(d) << cf;
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(Attr.getLoc())
+ << Attr.getName() << isa<ObjCMethodDecl>(D) << cf;
return;
}
- switch (attr.getKind()) {
+ switch (Attr.getKind()) {
default:
assert(0 && "invalid ownership attribute");
return;
case AttributeList::AT_ns_returns_autoreleased:
- d->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_cf_returns_not_retained:
- d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_ns_returns_not_retained:
- d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_cf_returns_retained:
- d->addAttr(::new (S.Context) CFReturnsRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(),
S.Context));
return;
case AttributeList::AT_ns_returns_retained:
- d->addAttr(::new (S.Context) NSReturnsRetainedAttr(attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(),
S.Context));
return;
};
}
+static void handleObjCOwnershipAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (hasDeclarator(D)) return;
+
+ SourceLocation L = Attr.getLoc();
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(L, L) << Attr.getName() << 12 /* variable */;
+}
+
+static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) {
+ SourceLocation L = Attr.getLoc();
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(L, L) << Attr.getName() << 12 /* variable */;
+ return;
+ }
+
+ ValueDecl *vd = cast<ValueDecl>(D);
+ QualType type = vd->getType();
+
+ if (!type->isDependentType() &&
+ !type->isObjCLifetimeType()) {
+ S.Diag(Attr.getLoc(), diag::err_objc_precise_lifetime_bad_type)
+ << type;
+ return;
+ }
+
+ Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime();
+
+ // If we have no lifetime yet, check the lifetime we're presumably
+ // going to infer.
+ if (lifetime == Qualifiers::OCL_None && !type->isDependentType())
+ lifetime = type->getObjCARCImplicitLifetime();
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None:
+ assert(type->isDependentType() &&
+ "didn't infer lifetime for non-dependent type?");
+ break;
+
+ case Qualifiers::OCL_Weak: // meaningful
+ case Qualifiers::OCL_Strong: // meaningful
+ break;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ S.Diag(Attr.getLoc(), diag::warn_objc_precise_lifetime_meaningless)
+ << (lifetime == Qualifiers::OCL_Autoreleasing);
+ break;
+ }
+
+ D->addAttr(::new (S.Context)
+ ObjCPreciseLifetimeAttr(Attr.getLoc(), S.Context));
+}
+
static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
return Attr.getKind() == AttributeList::AT_dllimport ||
Attr.getKind() == AttributeList::AT_dllexport ||
@@ -2745,13 +2833,12 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
-static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.Microsoft || S.LangOpts.Borland) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- }
+
Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (Str == 0 || Str->isWide()) {
@@ -2794,7 +2881,7 @@ static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) {
I++;
}
- d->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context,
Str->getString()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
@@ -2804,24 +2891,24 @@ static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
-static void ProcessNonInheritableDeclAttr(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) {
+static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_device: HandleDeviceAttr (D, Attr, S); break;
- case AttributeList::AT_host: HandleHostAttr (D, Attr, S); break;
- case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
+ case AttributeList::AT_device: handleDeviceAttr (S, D, Attr); break;
+ case AttributeList::AT_host: handleHostAttr (S, D, Attr); break;
+ case AttributeList::AT_overloadable:handleOverloadableAttr(S, D, Attr); break;
default:
break;
}
}
-static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) {
+static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break;
- case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
+ case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
+ case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
case AttributeList::AT_IBOutletCollection:
- HandleIBOutletCollection(D, Attr, S); break;
+ handleIBOutletCollection(S, D, Attr); break;
case AttributeList::AT_address_space:
case AttributeList::AT_opencl_image_access:
case AttributeList::AT_objc_gc:
@@ -2837,100 +2924,108 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
// Ignore, this is a non-inheritable attribute, handled
// by ProcessNonInheritableDeclAttr.
break;
- case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
- case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
+ case AttributeList::AT_alias: handleAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_aligned: handleAlignedAttr (S, D, Attr); break;
case AttributeList::AT_always_inline:
- HandleAlwaysInlineAttr (D, Attr, S); break;
+ handleAlwaysInlineAttr (S, D, Attr); break;
case AttributeList::AT_analyzer_noreturn:
- HandleAnalyzerNoReturnAttr (D, Attr, S); break;
- case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
- case AttributeList::AT_availability:HandleAvailabilityAttr(D, Attr, S); break;
+ handleAnalyzerNoReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_annotate: handleAnnotateAttr (S, D, Attr); break;
+ case AttributeList::AT_availability:handleAvailabilityAttr(S, D, Attr); break;
case AttributeList::AT_carries_dependency:
- HandleDependencyAttr (D, Attr, S); break;
- case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break;
- case AttributeList::AT_constant: HandleConstantAttr (D, Attr, S); break;
- case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
- case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
- case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
+ handleDependencyAttr (S, D, Attr); break;
+ case AttributeList::AT_common: handleCommonAttr (S, D, Attr); break;
+ case AttributeList::AT_constant: handleConstantAttr (S, D, Attr); break;
+ case AttributeList::AT_constructor: handleConstructorAttr (S, D, Attr); break;
+ case AttributeList::AT_deprecated: handleDeprecatedAttr (S, D, Attr); break;
+ case AttributeList::AT_destructor: handleDestructorAttr (S, D, Attr); break;
case AttributeList::AT_ext_vector_type:
- HandleExtVectorTypeAttr(scope, D, Attr, S);
+ handleExtVectorTypeAttr(S, scope, D, Attr);
break;
- case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
- case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
- case AttributeList::AT_global: HandleGlobalAttr (D, Attr, S); break;
- case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break;
+ case AttributeList::AT_format: handleFormatAttr (S, D, Attr); break;
+ case AttributeList::AT_format_arg: handleFormatArgAttr (S, D, Attr); break;
+ case AttributeList::AT_global: handleGlobalAttr (S, D, Attr); break;
+ case AttributeList::AT_gnu_inline: handleGNUInlineAttr (S, D, Attr); break;
case AttributeList::AT_launch_bounds:
- HandleLaunchBoundsAttr(D, Attr, S);
+ handleLaunchBoundsAttr(S, D, Attr);
break;
- case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
- case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
- case AttributeList::AT_may_alias: HandleMayAliasAttr (D, Attr, S); break;
- case AttributeList::AT_nocommon: HandleNoCommonAttr (D, Attr, S); break;
- case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
+ case AttributeList::AT_mode: handleModeAttr (S, D, Attr); break;
+ case AttributeList::AT_malloc: handleMallocAttr (S, D, Attr); break;
+ case AttributeList::AT_may_alias: handleMayAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_nocommon: handleNoCommonAttr (S, D, Attr); break;
+ case AttributeList::AT_nonnull: handleNonNullAttr (S, D, Attr); break;
case AttributeList::AT_ownership_returns:
case AttributeList::AT_ownership_takes:
case AttributeList::AT_ownership_holds:
- HandleOwnershipAttr (D, Attr, S); break;
- case AttributeList::AT_naked: HandleNakedAttr (D, Attr, S); break;
- case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
- case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
- case AttributeList::AT_shared: HandleSharedAttr (D, Attr, S); break;
- case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break;
+ handleOwnershipAttr (S, D, Attr); break;
+ case AttributeList::AT_naked: handleNakedAttr (S, D, Attr); break;
+ case AttributeList::AT_noreturn: handleNoReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_nothrow: handleNothrowAttr (S, D, Attr); break;
+ case AttributeList::AT_shared: handleSharedAttr (S, D, Attr); break;
+ case AttributeList::AT_vecreturn: handleVecReturnAttr (S, D, Attr); break;
+
+ case AttributeList::AT_objc_ownership:
+ handleObjCOwnershipAttr(S, D, Attr); break;
+ case AttributeList::AT_objc_precise_lifetime:
+ handleObjCPreciseLifetimeAttr(S, D, Attr); break;
// Checker-specific.
case AttributeList::AT_cf_consumed:
- case AttributeList::AT_ns_consumed: HandleNSConsumedAttr (D, Attr, S); break;
+ case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;
case AttributeList::AT_ns_consumes_self:
- HandleNSConsumesSelfAttr(D, Attr, S); break;
+ handleNSConsumesSelfAttr(S, D, Attr); break;
case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_not_retained:
case AttributeList::AT_cf_returns_not_retained:
case AttributeList::AT_ns_returns_retained:
case AttributeList::AT_cf_returns_retained:
- HandleNSReturnsRetainedAttr(D, Attr, S); break;
+ handleNSReturnsRetainedAttr(S, D, Attr); break;
case AttributeList::AT_reqd_wg_size:
- HandleReqdWorkGroupSize(D, Attr, S); break;
+ handleReqdWorkGroupSize(S, D, Attr); break;
case AttributeList::AT_init_priority:
- HandleInitPriorityAttr(D, Attr, S); break;
+ handleInitPriorityAttr(S, D, Attr); break;
- case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
- case AttributeList::AT_MsStruct: HandleMsStructAttr (D, Attr, S); break;
- case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
- case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
- case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
- case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
- case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break;
- case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
+ case AttributeList::AT_packed: handlePackedAttr (S, D, Attr); break;
+ case AttributeList::AT_MsStruct: handleMsStructAttr (S, D, Attr); break;
+ case AttributeList::AT_section: handleSectionAttr (S, D, Attr); break;
+ case AttributeList::AT_unavailable: handleUnavailableAttr (S, D, Attr); break;
+ case AttributeList::AT_arc_weakref_unavailable:
+ handleArcWeakrefUnavailableAttr (S, D, Attr);
break;
- case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
- case AttributeList::AT_weakref: HandleWeakRefAttr (D, Attr, S); break;
- case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break;
+ case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break;
+ case AttributeList::AT_used: handleUsedAttr (S, D, Attr); break;
+ case AttributeList::AT_visibility: handleVisibilityAttr (S, D, Attr); break;
+ case AttributeList::AT_warn_unused_result: handleWarnUnusedResult(S, D, Attr);
+ break;
+ case AttributeList::AT_weak: handleWeakAttr (S, D, Attr); break;
+ case AttributeList::AT_weakref: handleWeakRefAttr (S, D, Attr); break;
+ case AttributeList::AT_weak_import: handleWeakImportAttr (S, D, Attr); break;
case AttributeList::AT_transparent_union:
- HandleTransparentUnionAttr(D, Attr, S);
+ handleTransparentUnionAttr(S, D, Attr);
break;
case AttributeList::AT_objc_exception:
- HandleObjCExceptionAttr(D, Attr, S);
+ handleObjCExceptionAttr(S, D, Attr);
break;
case AttributeList::AT_objc_method_family:
- HandleObjCMethodFamilyAttr(D, Attr, S);
+ handleObjCMethodFamilyAttr(S, D, Attr);
break;
- case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
- case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
- case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
- case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
- case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
- case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
- case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break;
- case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break;
- case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
+ case AttributeList::AT_nsobject: handleObjCNSObject (S, D, Attr); break;
+ case AttributeList::AT_blocks: handleBlocksAttr (S, D, Attr); break;
+ case AttributeList::AT_sentinel: handleSentinelAttr (S, D, Attr); break;
+ case AttributeList::AT_const: handleConstAttr (S, D, Attr); break;
+ case AttributeList::AT_pure: handlePureAttr (S, D, Attr); break;
+ case AttributeList::AT_cleanup: handleCleanupAttr (S, D, Attr); break;
+ case AttributeList::AT_nodebug: handleNoDebugAttr (S, D, Attr); break;
+ case AttributeList::AT_noinline: handleNoInlineAttr (S, D, Attr); break;
+ case AttributeList::AT_regparm: handleRegparmAttr (S, D, Attr); break;
case AttributeList::IgnoredAttribute:
// Just ignore
break;
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
- HandleNoInstrumentFunctionAttr(D, Attr, S);
+ handleNoInstrumentFunctionAttr(S, D, Attr);
break;
case AttributeList::AT_stdcall:
case AttributeList::AT_cdecl:
@@ -2938,13 +3033,13 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
case AttributeList::AT_thiscall:
case AttributeList::AT_pascal:
case AttributeList::AT_pcs:
- HandleCallConvAttr(D, Attr, S);
+ handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_opencl_kernel_function:
- HandleOpenCLKernelAttr(D, Attr, S);
+ handleOpenCLKernelAttr(S, D, Attr);
break;
case AttributeList::AT_uuid:
- HandleUuidAttr(D, Attr, S);
+ handleUuidAttr(S, D, Attr);
break;
default:
// Ask target about the attribute.
@@ -2960,8 +3055,8 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
/// the attribute applies to decls. If the attribute is a type attribute, just
/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
-static void ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S,
+static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr,
bool NonInheritable, bool Inheritable) {
if (Attr.isInvalid())
return;
@@ -2971,10 +3066,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
return;
if (NonInheritable)
- ProcessNonInheritableDeclAttr(scope, D, Attr, S);
+ ProcessNonInheritableDeclAttr(S, scope, D, Attr);
if (Inheritable)
- ProcessInheritableDeclAttr(scope, D, Attr, S);
+ ProcessInheritableDeclAttr(S, scope, D, Attr);
}
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
@@ -2983,7 +3078,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
const AttributeList *AttrList,
bool NonInheritable, bool Inheritable) {
for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- ProcessDeclAttribute(S, D, *l, *this, NonInheritable, Inheritable);
+ ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable);
}
// GCC accepts
@@ -3085,6 +3180,32 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
}
+/// Is the given declaration allowed to use a forbidden type?
+static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) {
+ // Private ivars are always okay. Unfortunately, people don't
+ // always properly make their ivars private, even in system headers.
+ // Plus we need to make fields okay, too.
+ if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl))
+ return false;
+
+ // Require it to be declared in a system header.
+ return S.Context.getSourceManager().isInSystemHeader(decl->getLocation());
+}
+
+/// Handle a delayed forbidden-type diagnostic.
+static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
+ Decl *decl) {
+ if (decl && isForbiddenTypeAllowed(S, decl)) {
+ decl->addAttr(new (S.Context) UnavailableAttr(diag.Loc, S.Context,
+ "this system declaration uses an unsupported type"));
+ return;
+ }
+
+ S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
+ << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument();
+ diag.Triggered = true;
+}
+
// This duplicates a vector push_back but hides the need to know the
// size of the type.
void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) {
@@ -3126,7 +3247,7 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
// We only want to actually emit delayed diagnostics when we
// successfully parsed a decl.
- if (decl) {
+ if (decl && !decl->isInvalidDecl()) {
// We emit all the active diagnostics, not just those starting
// from the saved state. The idea is this: we get one push for a
// decl spec and another for each declarator; in a decl group like:
@@ -3147,6 +3268,10 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
case DelayedDiagnostic::Access:
S.HandleDelayedAccessCheck(diag, decl);
break;
+
+ case DelayedDiagnostic::ForbiddenType:
+ handleDelayedForbiddenType(S, diag, decl);
+ break;
}
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ce99efb..d793daf 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -185,9 +185,9 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
// FIXME:
//
// C++0x [except.spec]p14:
- // [An] implicit exception-specification specifies the type-id T if and
- // only if T is allowed by the exception-specification of a function directly
- // invoked by f’s implicit definition; f shall allow all exceptions if any
+ // [An] implicit exception-specification specifies the type-id T if and
+ // only if T is allowed by the exception-specification of a function directly
+ // invoked by f's implicit definition; f shall allow all exceptions if any
// function it directly invokes allows all exceptions, and f shall allow no
// exceptions if every function it directly invokes allows no exceptions.
//
@@ -762,13 +762,6 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getLocalUnqualifiedType();
- if (!Class->hasObjectMember()) {
- if (const RecordType *FDTTy =
- NewBaseType.getTypePtr()->getAs<RecordType>())
- if (FDTTy->getDecl()->hasObjectMember())
- Class->setHasObjectMember(true);
- }
-
if (KnownBaseTypes[NewBaseType]) {
// C++ [class.mi]p3:
// A class shall not be specified as a direct base class of a
@@ -1086,14 +1079,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
assert(!DS.isFriendSpecified());
assert(!Init || !HasDeferredInit);
- bool isFunc = false;
- if (D.isFunctionDeclarator())
- isFunc = true;
- else if (D.getNumTypeObjects() == 0 &&
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_typename) {
- QualType TDType = GetTypeFromParser(DS.getRepAsType());
- isFunc = TDType->isFunctionType();
- }
+ bool isFunc = D.isDeclarationOfFunction();
// C++ 9.2p6: A member shall not be declared to have automatic storage
// duration (auto, register) or with the extern storage-class-specifier.
@@ -1440,25 +1426,27 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
}
// If no results were found, try to correct typos.
+ TypoCorrection Corr;
if (R.empty() && BaseType.isNull() &&
- CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) &&
- R.isSingleResult()) {
- if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
+ (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
+ ClassDecl, false, CTC_NoKeywords))) {
+ std::string CorrectedStr(Corr.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corr.getQuoted(getLangOptions()));
+ if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
if (Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl)) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
// member.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << true << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << MemberOrBase << true << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
Diag(Member->getLocation(), diag::note_previous_decl)
- << Member->getDeclName();
+ << CorrectedQuotedStr;
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
LParenLoc, RParenLoc);
}
- } else if (TypeDecl *Type = R.getAsSingle<TypeDecl>()) {
+ } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
const CXXBaseSpecifier *VirtualBaseSpec;
if (FindBaseInitializer(*this, ClassDecl,
@@ -1468,9 +1456,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
// similar name to what was typed; complain and initialize
// that base class.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << false << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << MemberOrBase << false << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
: VirtualBaseSpec;
@@ -1617,14 +1604,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
// Can't check initialization for a member of dependent type or when
// any of the arguments are type-dependent expressions.
Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc);
-
- // Erase any temporaries within this evaluation context; we're not
- // going to track them in the AST, since we'll be rebuilding the
- // ASTs during template instantiation.
- ExprTemporaries.erase(
- ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
- ExprTemporaries.end());
+ RParenLoc,
+ Member->getType().getNonReferenceType());
+
+ DiscardCleanupsInEvaluationContext();
} else {
// Initialize the member.
InitializedEntity MemberEntity =
@@ -1658,8 +1641,9 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
// initializer. However, deconstructing the ASTs is a dicey process,
// and this approach is far more likely to get the corner cases right.
if (CurContext->isDependentContext())
- Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc);
+ Init = new (Context) ParenListExpr(
+ Context, LParenLoc, Args, NumArgs, RParenLoc,
+ Member->getType().getNonReferenceType());
else
Init = MemberInit.get();
}
@@ -1715,22 +1699,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
if (DelegationInit.isInvalid())
return true;
- // If we are in a dependent context, template instantiation will
- // perform this type-checking again. Just save the arguments that we
- // received in a ParenListExpr.
- // FIXME: This isn't quite ideal, since our ASTs don't capture all
- // of the information that we have about the base
- // initializer. However, deconstructing the ASTs is a dicey process,
- // and this approach is far more likely to get the corner cases right.
- if (CurContext->isDependentContext()) {
- ExprResult Init
- = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args,
- NumArgs, RParenLoc));
- return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc,
- Constructor, Init.takeAs<Expr>(),
- RParenLoc);
- }
-
+ assert(!CurContext->isDependentContext());
return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor,
DelegationInit.takeAs<Expr>(),
RParenLoc);
@@ -1815,14 +1784,9 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// any of the arguments are type-dependent expressions.
ExprResult BaseInit
= Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc));
+ RParenLoc, BaseType));
- // Erase any temporaries within this evaluation context; we're not
- // going to track them in the AST, since we'll be rebuilding the
- // ASTs during template instantiation.
- ExprTemporaries.erase(
- ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
- ExprTemporaries.end());
+ DiscardCleanupsInEvaluationContext();
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
/*IsVirtual=*/false,
@@ -1878,7 +1842,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (CurContext->isDependentContext()) {
ExprResult Init
= Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc));
+ RParenLoc, BaseType));
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
BaseSpec->isVirtual(),
LParenLoc,
@@ -1989,6 +1953,11 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
if (ImplicitInitKind == IIK_Copy) {
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
+
+ // Suppress copying zero-width bitfields.
+ if (const Expr *Width = Field->getBitWidth())
+ if (Width->EvaluateAsInt(SemaRef.Context) == 0)
+ return false;
Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
@@ -2134,6 +2103,20 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
}
+ if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ FieldBaseElementType->isObjCRetainableType() &&
+ FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
+ FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+ // Instant objects:
+ // Default-initialize Objective-C pointers to NULL.
+ CXXMemberInit
+ = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ Loc, Loc,
+ new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()),
+ Loc);
+ return false;
+ }
+
// Nothing to initialize.
CXXMemberInit = 0;
return false;
@@ -2207,11 +2190,8 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
}
}
- // Fallthrough and construct a default initializer for the union as
- // a whole, which can call its default constructor if such a thing exists
- // (C++0x perhaps). FIXME: It's not clear that this is the correct
- // behavior going forward with C++0x, when anonymous unions there are
- // finalized, we should revisit this.
+ // FIXME: C++0x unrestricted unions might call a default constructor here.
+ return false;
} else {
// For structs, we simply descend through to initialize all members where
// necessary.
@@ -2259,11 +2239,10 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
return false;
}
-bool
-Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
- CXXCtorInitializer **Initializers,
- unsigned NumInitializers,
- bool AnyErrors) {
+bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
+ CXXCtorInitializer **Initializers,
+ unsigned NumInitializers,
+ bool AnyErrors) {
if (Constructor->getDeclContext()->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
@@ -3405,7 +3384,7 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *RD = CD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = CD->getLocation();
@@ -3586,7 +3565,7 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *RD = CD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = CD->getLocation();
@@ -3636,7 +3615,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
// resolution, as applied to B's [copy] constructor, results in an
// ambiguity or a function that is deleted or inaccessible from the
// defaulted constructor
- CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals);
if (!BaseCtor || BaseCtor->isDeleted())
return true;
if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
@@ -3664,7 +3643,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
// resolution, as applied to B's [copy] constructor, results in an
// ambiguity or a function that is deleted or inaccessible from the
// defaulted constructor
- CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals);
if (!BaseCtor || BaseCtor->isDeleted())
return true;
if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
@@ -3726,8 +3705,8 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
// cannot be [copied] because overload resolution, as applied to B's
// [copy] constructor, results in an ambiguity or a function that is
// deleted or inaccessible from the defaulted constructor
- CXXConstructorDecl *FieldCtor = LookupCopyConstructor(FieldRecord,
- ArgQuals);
+ CXXConstructorDecl *FieldCtor = LookupCopyingConstructor(FieldRecord,
+ ArgQuals);
if (!FieldCtor || FieldCtor->isDeleted())
return true;
if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
@@ -3742,7 +3721,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = MD->getLocation();
@@ -3752,19 +3731,15 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
bool Union = RD->isUnion();
- bool ConstArg =
- MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified();
+ unsigned ArgQuals =
+ MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
+ Qualifiers::Const : 0;
// We do this because we should never actually use an anonymous
// union's constructor.
if (Union && RD->isAnonymousStructOrUnion())
return false;
- DeclarationName OperatorName =
- Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- LookupResult R(*this, OperatorName, Loc, LookupOrdinaryName);
- R.suppressDiagnostics();
-
// FIXME: We should put some diagnostic logic right into this function.
// C++0x [class.copy]/11
@@ -3786,37 +3761,11 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
// resolution, as applied to B's [copy] assignment operator, results in
// an ambiguity or a function that is deleted or inaccessible from the
// assignment operator
-
- LookupQualifiedName(R, BaseDecl, false);
-
- // Filter out any result that isn't a copy-assignment operator.
- LookupResult::Filter F = R.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator())
- continue;
-
- F.erase();
- }
- F.done();
-
- // Build a fake argument expression
- QualType ArgType = BaseType;
- QualType ThisType = BaseType;
- if (ConstArg)
- ArgType.addConst();
- Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
- , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
- };
-
- OverloadCandidateSet OCS((Loc));
- OverloadCandidateSet::iterator Best;
-
- AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
-
- if (OCS.BestViableFunction(*this, Loc, Best, false) !=
- OR_Success)
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
+ 0);
+ if (!CopyOper || CopyOper->isDeleted())
+ return true;
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
return true;
}
@@ -3831,37 +3780,11 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
// resolution, as applied to B's [copy] assignment operator, results in
// an ambiguity or a function that is deleted or inaccessible from the
// assignment operator
-
- LookupQualifiedName(R, BaseDecl, false);
-
- // Filter out any result that isn't a copy-assignment operator.
- LookupResult::Filter F = R.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator())
- continue;
-
- F.erase();
- }
- F.done();
-
- // Build a fake argument expression
- QualType ArgType = BaseType;
- QualType ThisType = BaseType;
- if (ConstArg)
- ArgType.addConst();
- Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
- , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
- };
-
- OverloadCandidateSet OCS((Loc));
- OverloadCandidateSet::iterator Best;
-
- AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
-
- if (OCS.BestViableFunction(*this, Loc, Best, false) !=
- OR_Success)
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
+ 0);
+ if (!CopyOper || CopyOper->isDeleted())
+ return true;
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
return true;
}
@@ -3908,37 +3831,12 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
return true;
}
- LookupQualifiedName(R, FieldRecord, false);
-
- // Filter out any result that isn't a copy-assignment operator.
- LookupResult::Filter F = R.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator())
- continue;
-
- F.erase();
- }
- F.done();
-
- // Build a fake argument expression
- QualType ArgType = FieldType;
- QualType ThisType = FieldType;
- if (ConstArg)
- ArgType.addConst();
- Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
- , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
- };
-
- OverloadCandidateSet OCS((Loc));
- OverloadCandidateSet::iterator Best;
-
- AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
-
- if (OCS.BestViableFunction(*this, Loc, Best, false) !=
- OR_Success)
- return true;
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals,
+ false, 0);
+ if (!CopyOper || CopyOper->isDeleted())
+ return false;
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
+ return false;
}
}
@@ -3948,7 +3846,7 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) {
CXXRecordDecl *RD = DD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
SourceLocation Loc = DD->getLocation();
@@ -4806,6 +4704,13 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// Make our StdNamespace cache point at the first real definition of the
// "std" namespace.
StdNamespace = Namespc;
+
+ // Add this instance of "std" to the set of known namespaces
+ KnownNamespaces[Namespc] = false;
+ } else if (!Namespc->isInline()) {
+ // Since this is an "original" namespace, add it to the known set of
+ // namespaces if it is not an inline namespace.
+ KnownNamespaces[Namespc] = false;
}
PushOnScopeChains(Namespc, DeclRegionScope);
@@ -4941,6 +4846,39 @@ static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
}
}
+static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
+ CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *Ident) {
+ R.clear();
+ if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), Sc, &SS, NULL,
+ false, S.CTC_NoKeywords, NULL)) {
+ if (Corrected.getCorrectionDeclAs<NamespaceDecl>() ||
+ Corrected.getCorrectionDeclAs<NamespaceAliasDecl>()) {
+ std::string CorrectedStr(Corrected.getAsString(S.getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOptions()));
+ if (DeclContext *DC = S.computeDeclContext(SS, false))
+ S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
+ << Ident << DC << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ else
+ S.Diag(IdentLoc, diag::err_using_directive_suggest)
+ << Ident << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+
+ S.Diag(Corrected.getCorrectionDecl()->getLocation(),
+ diag::note_namespace_defined_here) << CorrectedQuotedStr;
+
+ Ident = Corrected.getCorrectionAsIdentifierInfo();
+ R.addDecl(Corrected.getCorrectionDecl());
+ return true;
+ }
+ R.setLookupName(Ident);
+ }
+ return false;
+}
+
Decl *Sema::ActOnUsingDirective(Scope *S,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
@@ -4969,6 +4907,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
return 0;
if (R.empty()) {
+ R.clear();
// Allow "using namespace std;" or "using namespace ::std;" even if
// "std" hasn't been defined yet, for GCC compatibility.
if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) &&
@@ -4978,27 +4917,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
R.resolveKind();
}
// Otherwise, attempt typo correction.
- else if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false,
- CTC_NoKeywords, 0)) {
- if (R.getAsSingle<NamespaceDecl>() ||
- R.getAsSingle<NamespaceAliasDecl>()) {
- if (DeclContext *DC = computeDeclContext(SS, false))
- Diag(IdentLoc, diag::err_using_directive_member_suggest)
- << NamespcName << DC << Corrected << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
- else
- Diag(IdentLoc, diag::err_using_directive_suggest)
- << NamespcName << Corrected
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
- Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here)
- << Corrected;
-
- NamespcName = Corrected.getAsIdentifierInfo();
- } else {
- R.clear();
- R.setLookupName(NamespcName);
- }
- }
+ else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName);
}
if (!R.empty()) {
@@ -5065,6 +4984,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
switch (Name.getKind()) {
+ case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
@@ -5916,30 +5836,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
return 0;
if (R.empty()) {
- if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false,
- CTC_NoKeywords, 0)) {
- if (R.getAsSingle<NamespaceDecl>() ||
- R.getAsSingle<NamespaceAliasDecl>()) {
- if (DeclContext *DC = computeDeclContext(SS, false))
- Diag(IdentLoc, diag::err_using_directive_member_suggest)
- << Ident << DC << Corrected << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
- else
- Diag(IdentLoc, diag::err_using_directive_suggest)
- << Ident << Corrected
- << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
-
- Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here)
- << Corrected;
-
- Ident = Corrected.getAsIdentifierInfo();
- } else {
- R.clear();
- R.setLookupName(Ident);
- }
- }
-
- if (R.empty()) {
+ if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
return 0;
}
@@ -5982,6 +5879,8 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
ImplicitExceptionSpecification ExceptSpec(Context);
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
// Direct base-class constructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
@@ -6355,7 +6254,9 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// An implicitly declared special member function (Clause 12) shall have
// an exception-specification.
ImplicitExceptionSpecification ExceptSpec(Context);
-
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
+
// Direct base-class destructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
BEnd = ClassDecl->bases_end();
@@ -6687,61 +6588,12 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
Loc, Copy.take());
}
-/// \brief Determine whether the given class has a copy assignment operator
-/// that accepts a const-qualified argument.
-static bool hasConstCopyAssignment(Sema &S, const CXXRecordDecl *CClass) {
- CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(CClass);
-
- if (!Class->hasDeclaredCopyAssignment())
- S.DeclareImplicitCopyAssignment(Class);
-
- QualType ClassType = S.Context.getCanonicalType(S.Context.getTypeDeclType(Class));
- DeclarationName OpName
- = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
-
- DeclContext::lookup_const_iterator Op, OpEnd;
- for (llvm::tie(Op, OpEnd) = Class->lookup(OpName); Op != OpEnd; ++Op) {
- // C++ [class.copy]p9:
- // A user-declared copy assignment operator is a non-static non-template
- // member function of class X with exactly one parameter of type X, X&,
- // const X&, volatile X& or const volatile X&.
- const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
- if (!Method)
- continue;
-
- if (Method->isStatic())
- continue;
- if (Method->getPrimaryTemplate())
- continue;
- const FunctionProtoType *FnType =
- Method->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no prototype.");
- // Don't assert on this; an invalid decl might have been left in the AST.
- if (FnType->getNumArgs() != 1 || FnType->isVariadic())
- continue;
- bool AcceptsConst = true;
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()){
- ArgType = Ref->getPointeeType();
- // Is it a non-const lvalue reference?
- if (!ArgType.isConstQualified())
- AcceptsConst = false;
- }
- if (!S.Context.hasSameUnqualifiedType(ArgType, ClassType))
- continue;
-
- // We have a single argument of type cv X or cv X&, i.e. we've found the
- // copy assignment operator. Return whether it accepts const arguments.
- return AcceptsConst;
- }
- assert(Class->isInvalidDecl() &&
- "No copy assignment operator declared in valid code.");
- return false;
-}
-
std::pair<Sema::ImplicitExceptionSpecification, bool>
Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
CXXRecordDecl *ClassDecl) {
+ if (ClassDecl->isInvalidDecl())
+ return std::make_pair(ImplicitExceptionSpecification(Context), false);
+
// C++ [class.copy]p10:
// If the class definition does not explicitly declare a copy
// assignment operator, one is declared implicitly.
@@ -6759,11 +6611,28 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
HasConstCopyAssignment && Base != BaseEnd; ++Base) {
+ // We'll handle this below
+ if (LangOpts.CPlusPlus0x && Base->isVirtual())
+ continue;
+
assert(!Base->getType()->isDependentType() &&
"Cannot generate implicit members for class with dependent bases.");
- const CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- HasConstCopyAssignment = hasConstCopyAssignment(*this, BaseClassDecl);
+ CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
+ LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0,
+ &HasConstCopyAssignment);
+ }
+
+ // In C++0x, the above citation has "or virtual added"
+ if (LangOpts.CPlusPlus0x) {
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
+ BaseEnd = ClassDecl->vbases_end();
+ HasConstCopyAssignment && Base != BaseEnd; ++Base) {
+ assert(!Base->getType()->isDependentType() &&
+ "Cannot generate implicit members for class with dependent bases.");
+ CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
+ LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0,
+ &HasConstCopyAssignment);
+ }
}
// -- for all the nonstatic data members of X that are of a class
@@ -6775,10 +6644,9 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
HasConstCopyAssignment && Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- const CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- HasConstCopyAssignment = hasConstCopyAssignment(*this, FieldClassDecl);
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, false, 0,
+ &HasConstCopyAssignment);
}
}
@@ -6790,36 +6658,48 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
+
+ // It is unspecified whether or not an implicit copy assignment operator
+ // attempts to deduplicate calls to assignment operators of virtual bases are
+ // made. As such, this exception specification is effectively unspecified.
+ // Based on a similar decision made for constness in C++0x, we're erring on
+ // the side of assuming such calls to be made regardless of whether they
+ // actually happen.
ImplicitExceptionSpecification ExceptSpec(Context);
+ unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
Base != BaseEnd; ++Base) {
+ if (Base->isVirtual())
+ continue;
+
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (!BaseClassDecl->hasDeclaredCopyAssignment())
- DeclareImplicitCopyAssignment(BaseClassDecl);
+ if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
+ ArgQuals, false, 0))
+ ExceptSpec.CalledDecl(CopyAssign);
+ }
- if (CXXMethodDecl *CopyAssign
- = BaseClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment))
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
+ BaseEnd = ClassDecl->vbases_end();
+ Base != BaseEnd; ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
+ ArgQuals, false, 0))
ExceptSpec.CalledDecl(CopyAssign);
}
+
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
-
- if (!FieldClassDecl->hasDeclaredCopyAssignment())
- DeclareImplicitCopyAssignment(FieldClassDecl);
-
- if (CXXMethodDecl *CopyAssign
- = FieldClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment))
- ExceptSpec.CalledDecl(CopyAssign);
- }
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ if (CXXMethodDecl *CopyAssign =
+ LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))
+ ExceptSpec.CalledDecl(CopyAssign);
+ }
}
return std::make_pair(ExceptSpec, HasConstCopyAssignment);
@@ -6875,7 +6755,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
PushOnScopeChains(CopyAssignment, S, false);
ClassDecl->addDecl(CopyAssignment);
- if (ShouldDeleteCopyAssignmentOperator(CopyAssignment))
+ // C++0x [class.copy]p18:
+ // ... If the class definition declares a move constructor or move
+ // assignment operator, the implicitly declared copy assignment operator is
+ // defined as deleted; ...
+ if (ClassDecl->hasUserDeclaredMoveConstructor() ||
+ ClassDecl->hasUserDeclaredMoveAssignment() ||
+ ShouldDeleteCopyAssignmentOperator(CopyAssignment))
CopyAssignment->setDeletedAsWritten();
AddOverriddenMethods(ClassDecl, CopyAssignment);
@@ -7014,6 +6900,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Invalid = true;
continue;
}
+
+ // Suppress assigning zero-width bitfields.
+ if (const Expr *Width = Field->getBitWidth())
+ if (Width->EvaluateAsInt(Context) == 0)
+ continue;
QualType FieldType = Field->getType().getNonReferenceType();
if (FieldType->isIncompleteArrayType()) {
@@ -7041,10 +6932,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// explicit assignments, do so. This optimization only applies for arrays
// of scalars and arrays of class type with trivial copy-assignment
// operators.
- if (FieldType->isArrayType() &&
- (!BaseType->isRecordType() ||
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl())
- ->hasTrivialCopyAssignment())) {
+ if (FieldType->isArrayType() &&
+ BaseType.hasTrivialCopyAssignment(Context)) {
// Compute the size of the memory buffer to be copied.
QualType SizeType = Context.getSizeType();
llvm::APInt Size(Context.getTypeSize(SizeType),
@@ -7179,6 +7068,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
std::pair<Sema::ImplicitExceptionSpecification, bool>
Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
+ if (ClassDecl->isInvalidDecl())
+ return std::make_pair(ImplicitExceptionSpecification(Context), false);
+
// C++ [class.copy]p5:
// The implicitly-declared copy constructor for a class X will
// have the form
@@ -7202,8 +7094,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
- &HasConstCopyConstructor);
+ LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -7212,8 +7104,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
++Base) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
- &HasConstCopyConstructor);
+ LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
// -- for all the nonstatic data members of X that are of a
@@ -7226,8 +7118,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- LookupCopyConstructor(FieldClassDecl, Qualifiers::Const,
- &HasConstCopyConstructor);
+ LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
}
// Otherwise, the implicitly declared copy constructor will have
@@ -7251,7 +7143,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyConstructor(BaseClassDecl, Quals))
+ LookupCopyingConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -7261,7 +7153,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyConstructor(BaseClassDecl, Quals))
+ LookupCopyingConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -7271,7 +7163,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyConstructor(FieldClassDecl, Quals))
+ LookupCopyingConstructor(FieldClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
}
@@ -7334,7 +7226,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
PushOnScopeChains(CopyConstructor, S, false);
ClassDecl->addDecl(CopyConstructor);
- if (ShouldDeleteCopyConstructor(CopyConstructor))
+ // C++0x [class.copy]p7:
+ // ... If the class definition declares a move constructor or move
+ // assignment operator, the implicitly declared constructor is defined as
+ // deleted; ...
+ if (ClassDecl->hasUserDeclaredMoveConstructor() ||
+ ClassDecl->hasUserDeclaredMoveAssignment() ||
+ ShouldDeleteCopyConstructor(CopyConstructor))
CopyConstructor->setDeletedAsWritten();
return CopyConstructor;
@@ -7523,6 +7421,10 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
VDecl->setTypeSourceInfo(DeducedType);
VDecl->setType(DeducedType->getType());
+ // In ARC, infer lifetime.
+ if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+ VDecl->setInvalidDecl();
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDeclaration())
@@ -7605,9 +7507,9 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
// Store the initialization expressions as a ParenListExpr.
unsigned NumExprs = Exprs.size();
- VDecl->setInit(new (Context) ParenListExpr(Context, LParenLoc,
- (Expr **)Exprs.release(),
- NumExprs, RParenLoc));
+ VDecl->setInit(new (Context) ParenListExpr(
+ Context, LParenLoc, (Expr **)Exprs.release(), NumExprs, RParenLoc,
+ VDecl->getType().getNonReferenceType()));
return;
}
@@ -8143,10 +8045,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Diag(Loc, diag::err_objc_object_catch);
Invalid = true;
} else if (T->isObjCObjectPointerType()) {
- if (!getLangOptions().ObjCNonFragileABI) {
- Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile);
- Invalid = true;
- }
+ if (!getLangOptions().ObjCNonFragileABI)
+ Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile);
}
}
@@ -8154,7 +8054,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
ExDeclType, TInfo, SC_None, SC_None);
ExDecl->setExceptionVariable(true);
- if (!Invalid) {
+ if (!Invalid && !ExDeclType->isDependentType()) {
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
// C++ [except.handle]p16:
// The object declared in an exception-declaration or, if the
@@ -9020,25 +8920,16 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
// new class or enumeration.
assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class of condition decl.");
-
- TagDecl *OwnedTag = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedTag);
- QualType Ty = TInfo->getType();
-
- if (Ty->isFunctionType()) { // The declarator shall not specify a function...
- // We exit without creating a CXXConditionDeclExpr because a FunctionDecl
- // would be created and CXXConditionDeclExpr wants a VarDecl.
- Diag(D.getIdentifierLoc(), diag::err_invalid_use_of_function_type)
- << D.getSourceRange();
- return DeclResult();
- } else if (OwnedTag && OwnedTag->isDefinition()) {
- // The type-specifier-seq shall not declare a new class or enumeration.
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition);
- }
-
+
Decl *Dcl = ActOnDeclarator(S, D);
if (!Dcl)
- return DeclResult();
+ return true;
+
+ if (isa<FunctionDecl>(Dcl)) { // The declarator shall not specify a function.
+ Diag(Dcl->getLocation(), diag::err_invalid_use_of_function_type)
+ << D.getSourceRange();
+ return true;
+ }
return Dcl;
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index de9097e..aa8152b 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -16,14 +16,96 @@
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/DenseSet.h"
using namespace clang;
+/// Check whether the given method, which must be in the 'init'
+/// family, is a valid member of that family.
+///
+/// \param receiverTypeIfCall - if null, check this as if declaring it;
+/// if non-null, check this as if making a call to it with the given
+/// receiver type
+///
+/// \return true to indicate that there was an error and appropriate
+/// actions were taken
+bool Sema::checkInitMethod(ObjCMethodDecl *method,
+ QualType receiverTypeIfCall) {
+ if (method->isInvalidDecl()) return true;
+
+ // This castAs is safe: methods that don't return an object
+ // pointer won't be inferred as inits and will reject an explicit
+ // objc_method_family(init).
+
+ // We ignore protocols here. Should we? What about Class?
+
+ const ObjCObjectType *result = method->getResultType()
+ ->castAs<ObjCObjectPointerType>()->getObjectType();
+
+ if (result->isObjCId()) {
+ return false;
+ } else if (result->isObjCClass()) {
+ // fall through: always an error
+ } else {
+ ObjCInterfaceDecl *resultClass = result->getInterface();
+ assert(resultClass && "unexpected object type!");
+
+ // It's okay for the result type to still be a forward declaration
+ // if we're checking an interface declaration.
+ if (resultClass->isForwardDecl()) {
+ if (receiverTypeIfCall.isNull() &&
+ !isa<ObjCImplementationDecl>(method->getDeclContext()))
+ return false;
+
+ // Otherwise, we try to compare class types.
+ } else {
+ // If this method was declared in a protocol, we can't check
+ // anything unless we have a receiver type that's an interface.
+ const ObjCInterfaceDecl *receiverClass = 0;
+ if (isa<ObjCProtocolDecl>(method->getDeclContext())) {
+ if (receiverTypeIfCall.isNull())
+ return false;
+
+ receiverClass = receiverTypeIfCall->castAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+
+ // This can be null for calls to e.g. id<Foo>.
+ if (!receiverClass) return false;
+ } else {
+ receiverClass = method->getClassInterface();
+ assert(receiverClass && "method not associated with a class!");
+ }
+
+ // If either class is a subclass of the other, it's fine.
+ if (receiverClass->isSuperClassOf(resultClass) ||
+ resultClass->isSuperClassOf(receiverClass))
+ return false;
+ }
+ }
+
+ SourceLocation loc = method->getLocation();
+
+ // If we're in a system header, and this is not a call, just make
+ // the method unusable.
+ if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) {
+ method->addAttr(new (Context) UnavailableAttr(loc, Context,
+ "init method returns a type unrelated to its receiver type"));
+ return true;
+ }
+
+ // Otherwise, it's an error.
+ Diag(loc, diag::err_arc_init_method_unrelated_result_type);
+ method->setInvalidDecl();
+ return true;
+}
+
bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
const ObjCMethodDecl *Overridden,
bool IsImplementation) {
@@ -36,7 +118,7 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
QualType ResultType = NewMethod->getResultType();
SourceRange ResultTypeRange;
if (const TypeSourceInfo *ResultTypeInfo
- = NewMethod->getResultTypeSourceInfo())
+ = NewMethod->getResultTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
// Figure out which class this method is part of, if any.
@@ -73,7 +155,15 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
return false;
}
-
+/// \brief Check for consistency between a given method declaration and the
+/// methods it overrides within the class hierarchy.
+///
+/// This method walks the inheritance hierarchy starting at the given
+/// declaration context (\p DC), invoking Sema::CheckObjCMethodOverride() with
+/// the given new method (\p NewMethod) and any method it directly overrides
+/// in the hierarchy. Sema::CheckObjCMethodOverride() is responsible for
+/// checking consistency, e.g., among return types for methods that return a
+/// related result type.
static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
DeclContext *DC,
bool SkipCurrent = true) {
@@ -99,10 +189,10 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
return true;
}
-
+
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
- IEnd = Class->protocol_end();
+ IEnd = Class->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -115,7 +205,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
- IEnd = Category->protocol_end();
+ IEnd = Category->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -126,7 +216,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
- IEnd = Protocol->protocol_end();
+ IEnd = Protocol->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -141,13 +231,13 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
DeclContext *DC) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
-
+
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
-
+
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
-
+
if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod,
Impl->getClassInterface());
@@ -159,6 +249,55 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
}
+/// \brief Check a method declaration for compatibility with the Objective-C
+/// ARC conventions.
+static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+ ObjCMethodFamily family = method->getMethodFamily();
+ switch (family) {
+ case OMF_None:
+ case OMF_dealloc:
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ case OMF_self:
+ return false;
+
+ case OMF_init:
+ // If the method doesn't obey the init rules, don't bother annotating it.
+ if (S.checkInitMethod(method, QualType()))
+ return true;
+
+ method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
+ S.Context));
+
+ // Don't add a second copy of this attribute, but otherwise don't
+ // let it be suppressed.
+ if (method->hasAttr<NSReturnsRetainedAttr>())
+ return false;
+ break;
+
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ if (method->hasAttr<NSReturnsRetainedAttr>() ||
+ method->hasAttr<NSReturnsNotRetainedAttr>() ||
+ method->hasAttr<NSReturnsAutoreleasedAttr>())
+ return false;
+ break;
+
+ case OMF_performSelector:
+ // we don't annotate performSelector's
+ return true;
+
+ }
+
+ method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
+ S.Context));
+ return false;
+}
+
static void DiagnoseObjCImplementedDeprecations(Sema &S,
NamedDecl *ND,
SourceLocation ImplLoc,
@@ -212,6 +351,31 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
if ((*PI)->getIdentifier())
PushOnScopeChains(*PI, FnBodyScope);
}
+
+ // In ARC, disallow definition of retain/release/autorelease/retainCount
+ if (getLangOptions().ObjCAutoRefCount) {
+ switch (MDecl->getMethodFamily()) {
+ case OMF_retain:
+ case OMF_retainCount:
+ case OMF_release:
+ case OMF_autorelease:
+ Diag(MDecl->getLocation(), diag::err_arc_illegal_method_def)
+ << MDecl->getSelector();
+ break;
+
+ case OMF_None:
+ case OMF_dealloc:
+ case OMF_alloc:
+ case OMF_init:
+ case OMF_mutableCopy:
+ case OMF_copy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_performSelector:
+ break;
+ }
+ }
+
// Warn on implementating deprecated methods under
// -Wdeprecated-implementations flag.
if (ObjCInterfaceDecl *IC = MDecl->getClassInterface())
@@ -284,9 +448,10 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!PrevDecl) {
// Try to correct for a typo in the superclass name.
- LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
+ NULL, NULL, false, CTC_NoKeywords);
+ if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
Diag(SuperLoc, diag::err_undef_superclass_suggest)
<< SuperName << ClassName << PrevDecl->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_previous_decl)
@@ -333,10 +498,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!SuperClassDecl)
Diag(SuperLoc, diag::err_undef_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
- else if (SuperClassDecl->isForwardDecl())
- Diag(SuperLoc, diag::err_undef_superclass)
+ else if (SuperClassDecl->isForwardDecl()) {
+ Diag(SuperLoc, diag::err_forward_superclass)
<< SuperClassDecl->getDeclName() << ClassName
<< SourceRange(AtInterfaceLoc, ClassLoc);
+ Diag(SuperClassDecl->getLocation(), diag::note_forward_class);
+ SuperClassDecl = 0;
+ }
}
IDecl->setSuperClass(SuperClassDecl);
IDecl->setSuperClassLoc(SuperLoc);
@@ -494,12 +662,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
if (!PDecl) {
- LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
- LookupObjCProtocolName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
+ LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords);
+ if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
- << ProtocolId[i].first << R.getLookupName();
+ << ProtocolId[i].first << Corrected.getCorrection();
Diag(PDecl->getLocation(), diag::note_previous_decl)
<< PDecl->getDeclName();
}
@@ -736,20 +904,20 @@ Decl *Sema::ActOnStartClassImplementation(
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
- LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
+ NULL, NULL, false, CTC_NoKeywords);
+ if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
// Suggest the (potentially) correct interface name. However, put the
// fix-it hint itself in a separate note, since changing the name in
// the warning would make the fix-it change semantics.However, don't
// provide a code-modification hint or use the typo name for recovery,
// because this is just a warning. The program may actually be correct.
+ DeclarationName CorrectedName = Corrected.getCorrection();
Diag(ClassLoc, diag::warn_undef_interface_suggest)
- << ClassName << R.getLookupName();
- Diag(IDecl->getLocation(), diag::note_previous_decl)
- << R.getLookupName()
- << FixItHint::CreateReplacement(ClassLoc,
- R.getLookupName().getAsString());
+ << ClassName << CorrectedName;
+ Diag(IDecl->getLocation(), diag::note_previous_decl) << CorrectedName
+ << FixItHint::CreateReplacement(ClassLoc, CorrectedName.getAsString());
IDecl = 0;
} else {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
@@ -915,6 +1083,9 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
bool &IncompleteImpl, unsigned DiagID) {
+ // No point warning no definition of method which is 'unavailable'.
+ if (method->hasAttr<UnavailableAttr>())
+ return;
if (!IncompleteImpl) {
Diag(ImpLoc, diag::warn_incomplete_impl);
IncompleteImpl = true;
@@ -1091,11 +1262,84 @@ static void CheckMethodOverrideParam(Sema &S,
S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
<< getTypeRange(IfaceVar->getTypeSourceInfo());
}
-
+
+/// In ARC, check whether the conventional meanings of the two methods
+/// match. If they don't, it's a hard error.
+static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
+ ObjCMethodDecl *decl) {
+ ObjCMethodFamily implFamily = impl->getMethodFamily();
+ ObjCMethodFamily declFamily = decl->getMethodFamily();
+ if (implFamily == declFamily) return false;
+
+ // Since conventions are sorted by selector, the only possibility is
+ // that the types differ enough to cause one selector or the other
+ // to fall out of the family.
+ assert(implFamily == OMF_None || declFamily == OMF_None);
+
+ // No further diagnostics required on invalid declarations.
+ if (impl->isInvalidDecl() || decl->isInvalidDecl()) return true;
+
+ const ObjCMethodDecl *unmatched = impl;
+ ObjCMethodFamily family = declFamily;
+ unsigned errorID = diag::err_arc_lost_method_convention;
+ unsigned noteID = diag::note_arc_lost_method_convention;
+ if (declFamily == OMF_None) {
+ unmatched = decl;
+ family = implFamily;
+ errorID = diag::err_arc_gained_method_convention;
+ noteID = diag::note_arc_gained_method_convention;
+ }
+
+ // Indexes into a %select clause in the diagnostic.
+ enum FamilySelector {
+ F_alloc, F_copy, F_mutableCopy = F_copy, F_init, F_new
+ };
+ FamilySelector familySelector = FamilySelector();
+
+ switch (family) {
+ case OMF_None: llvm_unreachable("logic error, no method convention");
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_dealloc:
+ case OMF_retainCount:
+ case OMF_self:
+ case OMF_performSelector:
+ // Mismatches for these methods don't change ownership
+ // conventions, so we don't care.
+ return false;
+
+ case OMF_init: familySelector = F_init; break;
+ case OMF_alloc: familySelector = F_alloc; break;
+ case OMF_copy: familySelector = F_copy; break;
+ case OMF_mutableCopy: familySelector = F_mutableCopy; break;
+ case OMF_new: familySelector = F_new; break;
+ }
+
+ enum ReasonSelector { R_NonObjectReturn, R_UnrelatedReturn };
+ ReasonSelector reasonSelector;
+
+ // The only reason these methods don't fall within their families is
+ // due to unusual result types.
+ if (unmatched->getResultType()->isObjCObjectPointerType()) {
+ reasonSelector = R_UnrelatedReturn;
+ } else {
+ reasonSelector = R_NonObjectReturn;
+ }
+
+ S.Diag(impl->getLocation(), errorID) << familySelector << reasonSelector;
+ S.Diag(decl->getLocation(), noteID) << familySelector << reasonSelector;
+
+ return true;
+}
void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl))
+ return;
+
CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
IsProtocolMethodDecl);
@@ -1204,7 +1448,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl);
}
-/// MatchAllMethodDeclarations - Check methods declaraed in interface or
+/// MatchAllMethodDeclarations - Check methods declared in interface
/// or protocol against those declared in their implementations.
///
void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
@@ -1422,48 +1666,117 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
return CDecl;
}
+static bool tryMatchRecordTypes(ASTContext &Context,
+ Sema::MethodMatchStrategy strategy,
+ const Type *left, const Type *right);
+
+static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy,
+ QualType leftQT, QualType rightQT) {
+ const Type *left =
+ Context.getCanonicalType(leftQT).getUnqualifiedType().getTypePtr();
+ const Type *right =
+ Context.getCanonicalType(rightQT).getUnqualifiedType().getTypePtr();
+
+ if (left == right) return true;
+
+ // If we're doing a strict match, the types have to match exactly.
+ if (strategy == Sema::MMS_strict) return false;
+
+ if (left->isIncompleteType() || right->isIncompleteType()) return false;
+
+ // Otherwise, use this absurdly complicated algorithm to try to
+ // validate the basic, low-level compatibility of the two types.
+
+ // As a minimum, require the sizes and alignments to match.
+ if (Context.getTypeInfo(left) != Context.getTypeInfo(right))
+ return false;
+
+ // Consider all the kinds of non-dependent canonical types:
+ // - functions and arrays aren't possible as return and parameter types
+
+ // - vector types of equal size can be arbitrarily mixed
+ if (isa<VectorType>(left)) return isa<VectorType>(right);
+ if (isa<VectorType>(right)) return false;
+
+ // - references should only match references of identical type
+ // - structs, unions, and Objective-C objects must match more-or-less
+ // exactly
+ // - everything else should be a scalar
+ if (!left->isScalarType() || !right->isScalarType())
+ return tryMatchRecordTypes(Context, strategy, left, right);
+
+ // Make scalars agree in kind, except count bools as chars.
+ Type::ScalarTypeKind leftSK = left->getScalarTypeKind();
+ Type::ScalarTypeKind rightSK = right->getScalarTypeKind();
+ if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral;
+ if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral;
+
+ // Note that data member pointers and function member pointers don't
+ // intermix because of the size differences.
+
+ return (leftSK == rightSK);
+}
+
+static bool tryMatchRecordTypes(ASTContext &Context,
+ Sema::MethodMatchStrategy strategy,
+ const Type *lt, const Type *rt) {
+ assert(lt && rt && lt != rt);
+
+ if (!isa<RecordType>(lt) || !isa<RecordType>(rt)) return false;
+ RecordDecl *left = cast<RecordType>(lt)->getDecl();
+ RecordDecl *right = cast<RecordType>(rt)->getDecl();
+
+ // Require union-hood to match.
+ if (left->isUnion() != right->isUnion()) return false;
+
+ // Require an exact match if either is non-POD.
+ if ((isa<CXXRecordDecl>(left) && !cast<CXXRecordDecl>(left)->isPOD()) ||
+ (isa<CXXRecordDecl>(right) && !cast<CXXRecordDecl>(right)->isPOD()))
+ return false;
+
+ // Require size and alignment to match.
+ if (Context.getTypeInfo(lt) != Context.getTypeInfo(rt)) return false;
+
+ // Require fields to match.
+ RecordDecl::field_iterator li = left->field_begin(), le = left->field_end();
+ RecordDecl::field_iterator ri = right->field_begin(), re = right->field_end();
+ for (; li != le && ri != re; ++li, ++ri) {
+ if (!matchTypes(Context, strategy, li->getType(), ri->getType()))
+ return false;
+ }
+ return (li == le && ri == re);
+}
/// MatchTwoMethodDeclarations - Checks that two methods have matching type and
/// returns true, or false, accordingly.
/// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
-bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
- const ObjCMethodDecl *PrevMethod,
- bool matchBasedOnSizeAndAlignment,
- bool matchBasedOnStrictEqulity) {
- QualType T1 = Context.getCanonicalType(Method->getResultType());
- QualType T2 = Context.getCanonicalType(PrevMethod->getResultType());
-
- if (T1 != T2) {
- // The result types are different.
- if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
- return false;
- // Incomplete types don't have a size and alignment.
- if (T1->isIncompleteType() || T2->isIncompleteType())
- return false;
- // Check is based on size and alignment.
- if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
- return false;
- }
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
+ const ObjCMethodDecl *right,
+ MethodMatchStrategy strategy) {
+ if (!matchTypes(Context, strategy,
+ left->getResultType(), right->getResultType()))
+ return false;
- ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
- E = Method->param_end();
- ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin();
+ if (getLangOptions().ObjCAutoRefCount &&
+ (left->hasAttr<NSReturnsRetainedAttr>()
+ != right->hasAttr<NSReturnsRetainedAttr>() ||
+ left->hasAttr<NSConsumesSelfAttr>()
+ != right->hasAttr<NSConsumesSelfAttr>()))
+ return false;
- for (; ParamI != E; ++ParamI, ++PrevI) {
- assert(PrevI != PrevMethod->param_end() && "Param mismatch");
- T1 = Context.getCanonicalType((*ParamI)->getType());
- T2 = Context.getCanonicalType((*PrevI)->getType());
- if (T1 != T2) {
- // The result types are different.
- if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
- return false;
- // Incomplete types don't have a size and alignment.
- if (T1->isIncompleteType() || T2->isIncompleteType())
- return false;
- // Check is based on size and alignment.
- if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
- return false;
- }
+ ObjCMethodDecl::param_iterator
+ li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
+
+ for (; li != le; ++li, ++ri) {
+ assert(ri != right->param_end() && "Param mismatch");
+ ParmVarDecl *lparm = *li, *rparm = *ri;
+
+ if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType()))
+ return false;
+
+ if (getLangOptions().ObjCAutoRefCount &&
+ lparm->hasAttr<NSConsumedAttr>() != rparm->hasAttr<NSConsumedAttr>())
+ return false;
}
return true;
}
@@ -1505,8 +1818,10 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
// We've seen a method with this name, see if we have already seen this type
// signature.
- for (ObjCMethodList *List = &Entry; List; List = List->Next)
- if (MatchTwoMethodDeclarations(Method, List->Method)) {
+ for (ObjCMethodList *List = &Entry; List; List = List->Next) {
+ bool match = MatchTwoMethodDeclarations(Method, List->Method);
+
+ if (match) {
ObjCMethodDecl *PrevObjCMethod = List->Method;
PrevObjCMethod->setDefined(impl);
// If a method is deprecated, push it in the global pool.
@@ -1523,6 +1838,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
}
return;
}
+ }
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1530,6 +1846,25 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
}
+/// Determines if this is an "acceptable" loose mismatch in the global
+/// method pool. This exists mostly as a hack to get around certain
+/// global mismatches which we can't afford to make warnings / errors.
+/// Really, what we want is a way to take a method out of the global
+/// method pool.
+static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
+ ObjCMethodDecl *other) {
+ if (!chosen->isInstanceMethod())
+ return false;
+
+ Selector sel = chosen->getSelector();
+ if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
+ return false;
+
+ // Don't complain about mismatches for -length if the method we
+ // chose has an integral result type.
+ return (chosen->getResultType()->isIntegerType());
+}
+
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
bool warn, bool instance) {
@@ -1543,32 +1878,52 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
- bool strictSelectorMatch = receiverIdOrClass && warn &&
- (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
- R.getBegin()) !=
- Diagnostic::Ignored);
if (warn && MethList.Method && MethList.Next) {
- bool issueWarning = false;
+ bool issueDiagnostic = false, issueError = false;
+
+ // We support a warning which complains about *any* difference in
+ // method signature.
+ bool strictSelectorMatch =
+ (receiverIdOrClass && warn &&
+ (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+ R.getBegin()) !=
+ Diagnostic::Ignored));
if (strictSelectorMatch)
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ in type mismatch.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, false, true))
- issueWarning = true;
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+ MMS_strict)) {
+ issueDiagnostic = true;
+ break;
+ }
}
- if (!issueWarning)
+ // If we didn't see any strict differences, we won't see any loose
+ // differences. In ARC, however, we also need to check for loose
+ // mismatches, because most of them are errors.
+ if (!strictSelectorMatch ||
+ (issueDiagnostic && getLangOptions().ObjCAutoRefCount))
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ by size & alignment.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
- issueWarning = true;
+ // This checks if the methods differ in type mismatch.
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+ MMS_loose) &&
+ !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
+ issueDiagnostic = true;
+ if (getLangOptions().ObjCAutoRefCount)
+ issueError = true;
+ break;
+ }
}
- if (issueWarning) {
- if (strictSelectorMatch)
+ if (issueDiagnostic) {
+ if (issueError)
+ Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+ else if (strictSelectorMatch)
Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
else
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
- Diag(MethList.Method->getLocStart(), diag::note_using)
+
+ Diag(MethList.Method->getLocStart(),
+ issueError ? diag::note_possibility : diag::note_using)
<< MethList.Method->getSourceRange();
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
Diag(Next->Method->getLocStart(), diag::note_also_found)
@@ -1796,6 +2151,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
DefaultSynthesizeProperties(S, IC, IDecl);
ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
+ DiagnoseOwningPropertyGetterSynthesis(IC);
if (LangOpts.ObjCNonFragileABI2)
while (IDecl->getSuperClass()) {
@@ -1968,7 +2324,7 @@ Decl *Sema::ActOnMethodDeclaration(
} else {
ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI);
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = adjustParameterType(ArgType);
+ ArgType = Context.getAdjustedParameterType(ArgType);
}
LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc,
@@ -2015,7 +2371,7 @@ Decl *Sema::ActOnMethodDeclaration(
ArgType = Context.getObjCIdType();
else
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = adjustParameterType(ArgType);
+ ArgType = Context.getAdjustedParameterType(ArgType);
if (ArgType->isObjCObjectType()) {
Diag(Param->getLocation(),
diag::err_object_cannot_be_passed_returned_by_value)
@@ -2104,7 +2460,11 @@ Decl *Sema::ActOnMethodDeclaration(
mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
}
- if (!ObjCMethod->hasRelatedResultType() &&
+ bool ARCError = false;
+ if (getLangOptions().ObjCAutoRefCount)
+ ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+
+ if (!ObjCMethod->hasRelatedResultType() && !ARCError &&
getLangOptions().ObjCInferRelatedResultType) {
bool InferRelatedResultType = false;
switch (ObjCMethod->getMethodFamily()) {
@@ -2114,6 +2474,7 @@ Decl *Sema::ActOnMethodDeclaration(
case OMF_mutableCopy:
case OMF_release:
case OMF_retainCount:
+ case OMF_performSelector:
break;
case OMF_alloc:
@@ -2255,15 +2616,8 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
- TagDecl *OwnedDecl = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType ExceptionType = TInfo->getType();
-
- if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
- // Objective-C++: Types shall not be defined in exception types.
- Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
- << Context.getTypeDeclType(OwnedDecl);
- }
VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType,
D.getSourceRange().getBegin(),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0549e94..5efc365 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -87,7 +87,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
Diag(Loc, diag::err_deleted_function_use);
- Diag(D->getLocation(), diag::note_unavailable_here) << true;
+ Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true;
return true;
}
}
@@ -104,17 +104,20 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
break;
case AR_Unavailable:
- if (Message.empty()) {
- if (!UnknownObjCClass)
- Diag(Loc, diag::err_unavailable) << D->getDeclName();
- else
- Diag(Loc, diag::warn_unavailable_fwdclass_message)
- << D->getDeclName();
+ if (cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) {
+ if (Message.empty()) {
+ if (!UnknownObjCClass)
+ Diag(Loc, diag::err_unavailable) << D->getDeclName();
+ else
+ Diag(Loc, diag::warn_unavailable_fwdclass_message)
+ << D->getDeclName();
+ }
+ else
+ Diag(Loc, diag::err_unavailable_message)
+ << D->getDeclName() << Message;
+ Diag(D->getLocation(), diag::note_unavailable_here)
+ << isa<FunctionDecl>(D) << false;
}
- else
- Diag(Loc, diag::err_unavailable_message)
- << D->getDeclName() << Message;
- Diag(D->getLocation(), diag::note_unavailable_here) << 0;
break;
}
@@ -437,8 +440,12 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
/// will warn if the resulting type is not a POD type, and rejects ObjC
/// interfaces passed by value.
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
- FunctionDecl *FDecl) {
- ExprResult ExprRes = DefaultArgumentPromotion(E);
+ FunctionDecl *FDecl) {
+ ExprResult ExprRes = CheckPlaceholderExpr(E);
+ if (ExprRes.isInvalid())
+ return ExprError();
+
+ ExprRes = DefaultArgumentPromotion(E);
if (ExprRes.isInvalid())
return ExprError();
E = ExprRes.take();
@@ -456,7 +463,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
<< E->getType() << CT))
return ExprError();
- if (!E->getType()->isPODType()) {
+ if (!E->getType().isPODType(Context)) {
// C++0x [expr.call]p7:
// Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor,
@@ -471,6 +478,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
TrivialEnough = true;
}
}
+
+ if (!TrivialEnough &&
+ getLangOptions().ObjCAutoRefCount &&
+ E->getType()->isObjCLifetimeType())
+ TrivialEnough = true;
if (TrivialEnough) {
// Nothing to diagnose. This is okay.
@@ -1004,7 +1016,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
return Owned(StringLiteral::Create(Context, Literal.GetString(),
- Literal.GetStringLength(),
Literal.AnyWide, Literal.Pascal, StrTy,
&StringTokLocs[0],
StringTokLocs.size()));
@@ -1271,125 +1282,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
return Owned(E);
}
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo);
-
-ExprResult
-Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
- SourceLocation loc,
- IndirectFieldDecl *indirectField,
- Expr *baseObjectExpr,
- SourceLocation opLoc) {
- // First, build the expression that refers to the base object.
-
- bool baseObjectIsPointer = false;
- Qualifiers baseQuals;
-
- // Case 1: the base of the indirect field is not a field.
- VarDecl *baseVariable = indirectField->getVarDecl();
- CXXScopeSpec EmptySS;
- if (baseVariable) {
- assert(baseVariable->getType()->isRecordType());
-
- // In principle we could have a member access expression that
- // accesses an anonymous struct/union that's a static member of
- // the base object's class. However, under the current standard,
- // static data members cannot be anonymous structs or unions.
- // Supporting this is as easy as building a MemberExpr here.
- assert(!baseObjectExpr && "anonymous struct/union is static data member?");
-
- DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
-
- ExprResult result =
- BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
- if (result.isInvalid()) return ExprError();
-
- baseObjectExpr = result.take();
- baseObjectIsPointer = false;
- baseQuals = baseObjectExpr->getType().getQualifiers();
-
- // Case 2: the base of the indirect field is a field and the user
- // wrote a member expression.
- } else if (baseObjectExpr) {
- // The caller provided the base object expression. Determine
- // whether its a pointer and whether it adds any qualifiers to the
- // anonymous struct/union fields we're looking into.
- QualType objectType = baseObjectExpr->getType();
-
- if (const PointerType *ptr = objectType->getAs<PointerType>()) {
- baseObjectIsPointer = true;
- objectType = ptr->getPointeeType();
- } else {
- baseObjectIsPointer = false;
- }
- baseQuals = objectType.getQualifiers();
-
- // Case 3: the base of the indirect field is a field and we should
- // build an implicit member access.
- } else {
- // We've found a member of an anonymous struct/union that is
- // inside a non-anonymous struct/union, so in a well-formed
- // program our base object expression is "this".
- QualType ThisTy = getAndCaptureCurrentThisType();
- if (ThisTy.isNull()) {
- Diag(loc, diag::err_invalid_member_use_in_static_method)
- << indirectField->getDeclName();
- return ExprError();
- }
-
- // Our base object expression is "this".
- baseObjectExpr =
- new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
- baseObjectIsPointer = true;
- baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
- }
-
- // Build the implicit member references to the field of the
- // anonymous struct/union.
- Expr *result = baseObjectExpr;
- IndirectFieldDecl::chain_iterator
- FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
-
- // Build the first member access in the chain with full information.
- if (!baseVariable) {
- FieldDecl *field = cast<FieldDecl>(*FI);
-
- // FIXME: use the real found-decl info!
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- // Make a nameInfo that properly uses the anonymous name.
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
-
- result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
- EmptySS, field, foundDecl,
- memberNameInfo).take();
- baseObjectIsPointer = false;
-
- // FIXME: check qualified member access
- }
-
- // In all cases, we should now skip the first declaration in the chain.
- ++FI;
-
- while (FI != FEnd) {
- FieldDecl *field = cast<FieldDecl>(*FI++);
-
- // FIXME: these are somewhat meaningless
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
- (FI == FEnd? SS : EmptySS), field,
- foundDecl, memberNameInfo)
- .take();
- }
-
- return Owned(result);
-}
-
/// Decomposes the given name into a DeclarationNameInfo, its location, and
/// possibly a list of template arguments.
///
@@ -1399,215 +1291,30 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
/// This actually loses a lot of source location information for
/// non-standard name kinds; we should consider preserving that in
/// some way.
-static void DecomposeUnqualifiedId(Sema &SemaRef,
- const UnqualifiedId &Id,
- TemplateArgumentListInfo &Buffer,
- DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *&TemplateArgs) {
+void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
+ TemplateArgumentListInfo &Buffer,
+ DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *&TemplateArgs) {
if (Id.getKind() == UnqualifiedId::IK_TemplateId) {
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(SemaRef,
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
Id.TemplateId->getTemplateArgs(),
Id.TemplateId->NumArgs);
- SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer);
+ translateTemplateArguments(TemplateArgsPtr, Buffer);
TemplateArgsPtr.release();
TemplateName TName = Id.TemplateId->Template.get();
SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc;
- NameInfo = SemaRef.Context.getNameForTemplate(TName, TNameLoc);
+ NameInfo = Context.getNameForTemplate(TName, TNameLoc);
TemplateArgs = &Buffer;
} else {
- NameInfo = SemaRef.GetNameFromUnqualifiedId(Id);
+ NameInfo = GetNameFromUnqualifiedId(Id);
TemplateArgs = 0;
}
}
-/// Determines if the given class is provably not derived from all of
-/// the prospective base classes.
-static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
- CXXRecordDecl *Record,
- const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
- if (Bases.count(Record->getCanonicalDecl()))
- return false;
-
- RecordDecl *RD = Record->getDefinition();
- if (!RD) return false;
- Record = cast<CXXRecordDecl>(RD);
-
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
- CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
- if (!BaseRT) return false;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
- return false;
- }
-
- return true;
-}
-
-enum IMAKind {
- /// The reference is definitely not an instance member access.
- IMA_Static,
-
- /// The reference may be an implicit instance member access.
- IMA_Mixed,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is not an instance method.
- IMA_Mixed_StaticContext,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is from an unrelated class.
- IMA_Mixed_Unrelated,
-
- /// The reference is definitely an implicit instance member access.
- IMA_Instance,
-
- /// The reference may be to an unresolved using declaration.
- IMA_Unresolved,
-
- /// The reference may be to an unresolved using declaration and the
- /// context is not an instance method.
- IMA_Unresolved_StaticContext,
-
- /// All possible referrents are instance members and the current
- /// context is not an instance method.
- IMA_Error_StaticContext,
-
- /// All possible referrents are instance members of an unrelated
- /// class.
- IMA_Error_Unrelated
-};
-
-/// The given lookup names class member(s) and is not being used for
-/// an address-of-member expression. Classify the type of access
-/// according to whether it's possible that this reference names an
-/// instance member. This is best-effort; it is okay to
-/// conservatively answer "yes", in which case some errors will simply
-/// not be caught until template-instantiation.
-static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
- Scope *CurScope,
- const LookupResult &R) {
- assert(!R.empty() && (*R.begin())->isCXXClassMember());
-
- DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
-
- bool isStaticContext =
- (!isa<CXXMethodDecl>(DC) ||
- cast<CXXMethodDecl>(DC)->isStatic());
-
- // C++0x [expr.prim]p4:
- // Otherwise, if a member-declarator declares a non-static data member
- // of a class X, the expression this is a prvalue of type "pointer to X"
- // within the optional brace-or-equal-initializer.
- if (CurScope->getFlags() & Scope::ThisScope)
- isStaticContext = false;
-
- if (R.isUnresolvableResult())
- return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
-
- // Collect all the declaring classes of instance members we find.
- bool hasNonInstance = false;
- bool hasField = false;
- llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = *I;
-
- if (D->isCXXInstanceMember()) {
- if (dyn_cast<FieldDecl>(D))
- hasField = true;
-
- CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
- Classes.insert(R->getCanonicalDecl());
- }
- else
- hasNonInstance = true;
- }
-
- // If we didn't find any instance members, it can't be an implicit
- // member reference.
- if (Classes.empty())
- return IMA_Static;
-
- // If the current context is not an instance method, it can't be
- // an implicit member reference.
- if (isStaticContext) {
- if (hasNonInstance)
- return IMA_Mixed_StaticContext;
-
- if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
- // C++0x [expr.prim.general]p10:
- // An id-expression that denotes a non-static data member or non-static
- // member function of a class can only be used:
- // (...)
- // - if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
- const Sema::ExpressionEvaluationContextRecord& record = SemaRef.ExprEvalContexts.back();
- bool isUnevaluatedExpression = record.Context == Sema::Unevaluated;
- if (isUnevaluatedExpression)
- return IMA_Mixed_StaticContext;
- }
-
- return IMA_Error_StaticContext;
- }
-
- CXXRecordDecl *contextClass;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
- contextClass = MD->getParent()->getCanonicalDecl();
- else
- contextClass = cast<CXXRecordDecl>(DC);
-
- // [class.mfct.non-static]p3:
- // ...is used in the body of a non-static member function of class X,
- // if name lookup (3.4.1) resolves the name in the id-expression to a
- // non-static non-type member of some class C [...]
- // ...if C is not X or a base class of X, the class member access expression
- // is ill-formed.
- if (R.getNamingClass() &&
- contextClass != R.getNamingClass()->getCanonicalDecl() &&
- contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- // If we can prove that the current context is unrelated to all the
- // declaring classes, it can't be an implicit member reference (in
- // which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- return (hasNonInstance ? IMA_Mixed : IMA_Instance);
-}
-
-/// Diagnose a reference to a field with no object available.
-static void DiagnoseInstanceReference(Sema &SemaRef,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- SourceLocation Loc = nameInfo.getLoc();
- SourceRange Range(Loc);
- if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
-
- if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
- if (MD->isStatic()) {
- // "invalid use of member 'x' in static member function"
- SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
- << Range << nameInfo.getName();
- return;
- }
- }
-
- SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
- << nameInfo.getName() << Range;
- return;
- }
-
- SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
-}
-
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
@@ -1690,39 +1397,43 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
}
// We didn't find anything, so try to correct for a typo.
- DeclarationName Corrected;
- if (S && (Corrected = CorrectTypo(R, S, &SS, 0, false, CTC))) {
- if (!R.empty()) {
- if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
+ TypoCorrection Corrected;
+ if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
+ S, &SS, NULL, false, CTC))) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ R.setLookupName(Corrected.getCorrection());
+
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ R.addDecl(ND);
+ if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ if (ND)
Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
+ << CorrectedQuotedStr;
// Tell the callee to try to recover.
return false;
}
- if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
+ if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) {
// FIXME: If we ended up with a typo for a type name or
// Objective-C class name, we're in trouble because the parser
// is in the wrong place to recover. Suggest the typo
// correction, but don't make it a fix-it since we're not going
// to recover well anyway.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange();
// Don't try to recover; it won't work.
@@ -1732,15 +1443,15 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// FIXME: We found a keyword. Suggest it, but don't provide a fix-it
// because we aren't able to recover.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected;
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << Corrected
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange();
return true;
}
- R.clear();
}
+ R.clear();
// Emit a special diagnostic for failed member lookups.
// FIXME: computing the declaration context might fail here (?)
@@ -1856,7 +1567,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// Decompose the UnqualifiedId into the following data.
DeclarationNameInfo NameInfo;
const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
+ DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
DeclarationName Name = NameInfo.getName();
IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -1892,7 +1603,9 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
bool IvarLookupFollowUp = false;
// Perform the required lookup.
- LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ LookupResult R(*this, NameInfo,
+ (Id.getKind() == UnqualifiedId::IK_ImplicitSelfParam)
+ ? LookupObjCImplicitSelfParam : LookupOrdinaryName);
if (TemplateArgs) {
// Lookup the template name again to correctly establish the context in
// which it was found. This is really unfortunate as we already did the
@@ -2032,38 +1745,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
return BuildDeclarationNameExpr(SS, R, ADL);
}
-/// Builds an expression which might be an implicit member expression.
-ExprResult
-Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
- case IMA_Instance:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
-
- case IMA_Mixed:
- case IMA_Mixed_Unrelated:
- case IMA_Unresolved:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
-
- case IMA_Static:
- case IMA_Mixed_StaticContext:
- case IMA_Unresolved_StaticContext:
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
- return BuildDeclarationNameExpr(SS, R, false);
-
- case IMA_Error_StaticContext:
- case IMA_Error_Unrelated:
- DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return ExprError();
- }
-
- llvm_unreachable("unexpected instance member access kind");
- return ExprError();
-}
-
/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
/// declaration name, generally during template instantiation.
/// There's a large number of things which don't need to be done along
@@ -2155,6 +1836,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IdentifierInfo &II = Context.Idents.get("self");
UnqualifiedId SelfName;
SelfName.setIdentifier(&II, SourceLocation());
+ SelfName.setKind(UnqualifiedId::IK_ImplicitSelfParam);
CXXScopeSpec SelfScopeSpec;
ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
SelfName, false, false);
@@ -2166,27 +1848,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return ExprError();
MarkDeclarationReferenced(Loc, IV);
- Expr *base = SelfExpr.take();
- base = base->IgnoreParenImpCasts();
- if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(base)) {
- const NamedDecl *ND = DE->getDecl();
- if (!isa<ImplicitParamDecl>(ND)) {
- // relax the rule such that it is allowed to have a shadow 'self'
- // where stand-alone ivar can be found in this 'self' object.
- // This is to match gcc's behavior.
- ObjCInterfaceDecl *selfIFace = 0;
- if (const ObjCObjectPointerType *OPT =
- base->getType()->getAsObjCInterfacePointerType())
- selfIFace = OPT->getInterfaceDecl();
- if (!selfIFace ||
- !selfIFace->lookupInstanceVariable(IV->getIdentifier())) {
- Diag(Loc, diag::error_implicit_ivar_access)
- << IV->getDeclName();
- Diag(ND->getLocation(), diag::note_declared_at);
- return ExprError();
- }
- }
- }
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.take(), true, true));
@@ -2385,120 +2046,6 @@ Sema::PerformObjectMemberConversion(Expr *From,
VK, &BasePath);
}
-/// \brief Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS, ValueDecl *Member,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo,
- QualType Ty,
- ExprValueKind VK, ExprObjectKind OK,
- const TemplateArgumentListInfo *TemplateArgs = 0) {
- return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
- Member, FoundDecl, MemberNameInfo,
- TemplateArgs, Ty, VK, OK);
-}
-
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo) {
- // x.a is an l-value if 'a' has a reference type. Otherwise:
- // x.a is an l-value/x-value/pr-value if the base is (and note
- // that *x is always an l-value), except that if the base isn't
- // an ordinary object then we must have an rvalue.
- ExprValueKind VK = VK_LValue;
- ExprObjectKind OK = OK_Ordinary;
- if (!IsArrow) {
- if (BaseExpr->getObjectKind() == OK_Ordinary)
- VK = BaseExpr->getValueKind();
- else
- VK = VK_RValue;
- }
- if (VK != VK_RValue && Field->isBitField())
- OK = OK_BitField;
-
- // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
- QualType MemberType = Field->getType();
- if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
- MemberType = Ref->getPointeeType();
- VK = VK_LValue;
- } else {
- QualType BaseType = BaseExpr->getType();
- if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
-
- Qualifiers BaseQuals = BaseType.getQualifiers();
-
- // GC attributes are never picked up by members.
- BaseQuals.removeObjCGCAttr();
-
- // CVR attributes from the base are picked up by members,
- // except that 'mutable' members don't pick up 'const'.
- if (Field->isMutable()) BaseQuals.removeConst();
-
- Qualifiers MemberQuals
- = S.Context.getCanonicalType(MemberType).getQualifiers();
-
- // TR 18037 does not allow fields to be declared with address spaces.
- assert(!MemberQuals.hasAddressSpace());
-
- Qualifiers Combined = BaseQuals + MemberQuals;
- if (Combined != MemberQuals)
- MemberType = S.Context.getQualifiedType(MemberType, Combined);
- }
-
- S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
- ExprResult Base =
- S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
- FoundDecl, Field);
- if (Base.isInvalid())
- return ExprError();
- return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
- Field, FoundDecl, MemberNameInfo,
- MemberType, VK, OK));
-}
-
-/// Builds an implicit member access expression. The current context
-/// is known to be an instance method, and the given unqualified lookup
-/// set is known to contain only instance members, at least one of which
-/// is from an appropriate type.
-ExprResult
-Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool IsKnownInstance) {
- assert(!R.empty() && !R.isAmbiguous());
-
- SourceLocation loc = R.getNameLoc();
-
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- // FIXME: template-ids inside anonymous structs?
- if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
- return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
-
- // If this is known to be an instance access, go ahead and build an
- // implicit 'this' expression now.
- // 'this' expression now.
- QualType ThisTy = getAndCaptureCurrentThisType();
- assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
-
- Expr *baseExpr = 0; // null signifies implicit access
- if (IsKnownInstance) {
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
- }
-
- return BuildMemberReferenceExpr(baseExpr, ThisTy,
- /*OpLoc*/ SourceLocation(),
- /*IsArrow*/ true,
- SS,
- /*FirstQualifierInScope*/ 0,
- R, TemplateArgs);
-}
-
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
const LookupResult &R,
bool HasTrailingLParen) {
@@ -3160,6 +2707,20 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
Op->getSourceRange(), ExprKind))
return true;
+ if (ExprKind == UETT_SizeOf) {
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(Op->IgnoreParens())) {
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) {
+ QualType OType = PVD->getOriginalType();
+ QualType Type = PVD->getType();
+ if (Type->isPointerType() && OType->isArrayType()) {
+ Diag(Op->getExprLoc(), diag::warn_sizeof_array_param)
+ << Type << OType;
+ Diag(PVD->getLocation(), diag::note_declared_at);
+ }
+ }
+ }
+ }
+
return false;
}
@@ -3274,6 +2835,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind) {
+ ExprResult PE = CheckPlaceholderExpr(E);
+ if (PE.isInvalid())
+ return ExprError();
+
+ E = PE.get();
+
// Verify that the operand is valid.
bool isInvalid = false;
if (E->isTypeDependent()) {
@@ -3285,10 +2852,6 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
} else if (E->getBitField()) { // C99 6.5.3.4p1.
Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0;
isInvalid = true;
- } else if (E->getType()->isPlaceholderType()) {
- ExprResult PE = CheckPlaceholderExpr(E);
- if (PE.isInvalid()) return ExprError();
- return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind);
} else {
isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf);
}
@@ -3372,19 +2935,6 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
-/// Expressions of certain arbitrary types are forbidden by C from
-/// having l-value type. These are:
-/// - 'void', but not qualified void
-/// - function types
-///
-/// The exact rule here is C99 6.3.2.1:
-/// An lvalue is an expression with an object type or an incomplete
-/// type other than void.
-static bool IsCForbiddenLValueType(ASTContext &C, QualType T) {
- return ((T->isVoidType() && !T.hasQualifiers()) ||
- T->isFunctionType());
-}
-
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@@ -3528,7 +3078,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) {
// GNU extension: subscripting on pointer to void
- Diag(LLoc, diag::ext_gnu_void_ptr)
+ Diag(LLoc, diag::ext_gnu_subscript_void_type)
<< BaseExpr->getSourceRange();
// C forbids expressions of unqualified void type from being l-values.
@@ -3548,1109 +3098,12 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
}
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
- !IsCForbiddenLValueType(Context, ResultType));
+ !ResultType.isCForbiddenLValueType());
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
ResultType, VK, OK, RLoc));
}
-/// Check an ext-vector component access expression.
-///
-/// VK should be set in advance to the value kind of the base
-/// expression.
-static QualType
-CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
- SourceLocation OpLoc, const IdentifierInfo *CompName,
- SourceLocation CompLoc) {
- // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
- // see FIXME there.
- //
- // FIXME: This logic can be greatly simplified by splitting it along
- // halving/not halving and reworking the component checking.
- const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
-
- // The vector accessor can't exceed the number of elements.
- const char *compStr = CompName->getNameStart();
-
- // This flag determines whether or not the component is one of the four
- // special names that indicate a subset of exactly half the elements are
- // to be selected.
- bool HalvingSwizzle = false;
-
- // This flag determines whether or not CompName has an 's' char prefix,
- // indicating that it is a string of hex values to be used as vector indices.
- bool HexSwizzle = *compStr == 's' || *compStr == 'S';
-
- bool HasRepeated = false;
- bool HasIndex[16] = {};
-
- int Idx;
-
- // Check that we've found one of the special components, or that the component
- // names must come from the same set.
- if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
- !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
- HalvingSwizzle = true;
- } else if (!HexSwizzle &&
- (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
- do {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
- } else {
- if (HexSwizzle) compStr++;
- while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- }
- }
-
- if (!HalvingSwizzle && *compStr) {
- // We didn't get to the end of the string. This means the component names
- // didn't come from the same set *or* we encountered an illegal name.
- S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
- << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
- return QualType();
- }
-
- // Ensure no component accessor exceeds the width of the vector type it
- // operates on.
- if (!HalvingSwizzle) {
- compStr = CompName->getNameStart();
-
- if (HexSwizzle)
- compStr++;
-
- while (*compStr) {
- if (!vecType->isAccessorWithinNumElements(*compStr++)) {
- S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
- << baseType << SourceRange(CompLoc);
- return QualType();
- }
- }
- }
-
- // The component accessor looks fine - now we need to compute the actual type.
- // The vector type is implied by the component accessor. For example,
- // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
- // vec4.s0 is a float, vec4.s23 is a vec3, etc.
- // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
- unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
- : CompName->getLength();
- if (HexSwizzle)
- CompSize--;
-
- if (CompSize == 1)
- return vecType->getElementType();
-
- if (HasRepeated) VK = VK_RValue;
-
- QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
- // Now look up the TypeDefDecl from the vector type. Without this,
- // diagostics look bad. We want extended vector types to appear built-in.
- for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
- if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
- return S.Context.getTypedefType(S.ExtVectorDecls[i]);
- }
- return VT; // should never get here (a typedef type should always be found).
-}
-
-static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
- IdentifierInfo *Member,
- const Selector &Sel,
- ASTContext &Context) {
- if (Member)
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
- return PD;
- if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
- return OMD;
-
- for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); I != E; ++I) {
- if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context))
- return D;
- }
- return 0;
-}
-
-static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
- IdentifierInfo *Member,
- const Selector &Sel,
- ASTContext &Context) {
- // Check protocols on qualified interfaces.
- Decl *GDecl = 0;
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- if (Member)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
- GDecl = PD;
- break;
- }
- // Also must look for a getter or setter name which uses property syntax.
- if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
- GDecl = OMD;
- break;
- }
- }
- if (!GDecl) {
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- // Search in the protocol-qualifier list of current protocol.
- GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context);
- if (GDecl)
- return GDecl;
- }
- }
- return GDecl;
-}
-
-ExprResult
-Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
- bool IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- // Even in dependent contexts, try to diagnose base expressions with
- // obviously wrong types, e.g.:
- //
- // T* t;
- // t.f;
- //
- // In Obj-C++, however, the above expression is valid, since it could be
- // accessing the 'f' property if T is an Obj-C interface. The extra check
- // allows this, while still reporting an error if T is a struct pointer.
- if (!IsArrow) {
- const PointerType *PT = BaseType->getAs<PointerType>();
- if (PT && (!getLangOptions().ObjC1 ||
- PT->getPointeeType()->isRecordType())) {
- assert(BaseExpr && "cannot happen with implicit member accesses");
- Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr->getSourceRange();
- return ExprError();
- }
- }
-
- assert(BaseType->isDependentType() ||
- NameInfo.getName().isDependentName() ||
- isDependentScopeSpecifier(SS));
-
- // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
- // must have pointer type, and the accessed type is the pointee.
- return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- FirstQualifierInScope,
- NameInfo, TemplateArgs));
-}
-
-/// We know that the given qualified member reference points only to
-/// declarations which do not belong to the static type of the base
-/// expression. Diagnose the problem.
-static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
- Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- // If this is an implicit member access, use a different set of
- // diagnostics.
- if (!BaseExpr)
- return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
-
- SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
- << SS.getRange() << rep << BaseType;
-}
-
-// Check whether the declarations we found through a nested-name
-// specifier in a member expression are actually members of the base
-// type. The restriction here is:
-//
-// C++ [expr.ref]p2:
-// ... In these cases, the id-expression shall name a
-// member of the class or of one of its base classes.
-//
-// So it's perfectly legitimate for the nested-name specifier to name
-// an unrelated class, and for us to find an overload set including
-// decls from classes which are not superclasses, as long as the decl
-// we actually pick through overload resolution is from a superclass.
-bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- const LookupResult &R) {
- const RecordType *BaseRT = BaseType->getAs<RecordType>();
- if (!BaseRT) {
- // We can't check this yet because the base type is still
- // dependent.
- assert(BaseType->isDependentType());
- return false;
- }
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
-
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- // If this is an implicit member reference and we find a
- // non-instance member, it's not an error.
- if (!BaseExpr && !(*I)->isCXXInstanceMember())
- return false;
-
- // Note that we use the DC of the decl, not the underlying decl.
- DeclContext *DC = (*I)->getDeclContext();
- while (DC->isTransparentContext())
- DC = DC->getParent();
-
- if (!DC->isRecord())
- continue;
-
- llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
- MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
-
- if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
- return false;
- }
-
- DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
- R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return true;
-}
-
-static bool
-LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- SourceRange BaseRange, const RecordType *RTy,
- SourceLocation OpLoc, CXXScopeSpec &SS,
- bool HasTemplateArgs) {
- RecordDecl *RDecl = RTy->getDecl();
- if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
- << BaseRange))
- return true;
-
- if (HasTemplateArgs) {
- // LookupTemplateName doesn't expect these both to exist simultaneously.
- QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
-
- bool MOUS;
- SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
- return false;
- }
-
- DeclContext *DC = RDecl;
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = SemaRef.computeDeclContext(SS, false);
-
- if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
- SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
- << SS.getRange() << DC;
- return true;
- }
-
- assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-
- if (!isa<TypeDecl>(DC)) {
- SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
- return true;
- }
- }
-
- // The record definition is complete, now look up the member.
- SemaRef.LookupQualifiedName(R, DC);
-
- if (!R.empty())
- return false;
-
- // We didn't find anything with the given name, so try to correct
- // for typos.
- DeclarationName Name = R.getLookupName();
- if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
- !R.empty() &&
- (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
- SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << DC << R.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
- SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
- return false;
- } else {
- R.clear();
- R.setLookupName(Name);
- }
-
- return false;
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
- SourceLocation OpLoc, bool IsArrow,
- CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- if (BaseType->isDependentType() ||
- (SS.isSet() && isDependentScopeSpecifier(SS)))
- return ActOnDependentMemberExpr(Base, BaseType,
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
-
- LookupResult R(*this, NameInfo, LookupMemberName);
-
- // Implicit member accesses.
- if (!Base) {
- QualType RecordTy = BaseType;
- if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(*this, R, SourceRange(),
- RecordTy->getAs<RecordType>(),
- OpLoc, SS, TemplateArgs != 0))
- return ExprError();
-
- // Explicit member accesses.
- } else {
- ExprResult BaseResult = Owned(Base);
- ExprResult Result =
- LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
-
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get())
- return move(Result);
-
- // LookupMemberExpr can modify Base, and thus change BaseType
- BaseType = Base->getType();
- }
-
- return BuildMemberReferenceExpr(Base, BaseType,
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
- SourceLocation OpLoc, bool IsArrow,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool SuppressQualifierCheck) {
- QualType BaseType = BaseExprType;
- if (IsArrow) {
- assert(BaseType->isPointerType());
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
- }
- R.setBaseObjectType(BaseType);
-
- const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
- DeclarationName MemberName = MemberNameInfo.getName();
- SourceLocation MemberLoc = MemberNameInfo.getLoc();
-
- if (R.isAmbiguous())
- return ExprError();
-
- if (R.empty()) {
- // Rederive where we looked up.
- DeclContext *DC = (SS.isSet()
- ? computeDeclContext(SS, false)
- : BaseType->getAs<RecordType>()->getDecl());
-
- Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC
- << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
- return ExprError();
- }
-
- // Diagnose lookups that find only declarations from a non-base
- // type. This is possible for either qualified lookups (which may
- // have been qualified with an unrelated type) or implicit member
- // expressions (which were found with unqualified lookup and thus
- // may have come from an enclosing scope). Note that it's okay for
- // lookup to find declarations from a non-base type as long as those
- // aren't the ones picked by overload resolution.
- if ((SS.isSet() || !BaseExpr ||
- (isa<CXXThisExpr>(BaseExpr) &&
- cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
- !SuppressQualifierCheck &&
- CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
- return ExprError();
-
- // Construct an unresolved result if we in fact got an unresolved
- // result.
- if (R.isOverloadedResult() || R.isUnresolvableResult()) {
- // Suppress any lookup-related diagnostics; we'll do these when we
- // pick a member.
- R.suppressDiagnostics();
-
- UnresolvedMemberExpr *MemExpr
- = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
- BaseExpr, BaseExprType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- MemberNameInfo,
- TemplateArgs, R.begin(), R.end());
-
- return Owned(MemExpr);
- }
-
- assert(R.isSingleResult());
- DeclAccessPair FoundDecl = R.begin().getPair();
- NamedDecl *MemberDecl = R.getFoundDecl();
-
- // FIXME: diagnose the presence of template arguments now.
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (MemberDecl->isInvalidDecl())
- return ExprError();
-
- // Handle the implicit-member-access case.
- if (!BaseExpr) {
- // If this is not an instance member, convert to a non-member access.
- if (!MemberDecl->isCXXInstanceMember())
- return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
-
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
- }
-
- bool ShouldCheckUse = true;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- // Don't diagnose the use of a virtual member function unless it's
- // explicitly qualified.
- if (MD->isVirtual() && !SS.isSet())
- ShouldCheckUse = false;
- }
-
- // Check the use of this member.
- if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
- Owned(BaseExpr);
- return ExprError();
- }
-
- // Perform a property load on the base regardless of whether we
- // actually need it for the declaration.
- if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(BaseExpr);
- if (Result.isInvalid())
- return ExprError();
- BaseExpr = Result.take();
- }
-
- if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
- return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
- SS, FD, FoundDecl, MemberNameInfo);
-
- if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
- BaseExpr, OpLoc);
-
- if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, Var);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Var, FoundDecl, MemberNameInfo,
- Var->getType().getNonReferenceType(),
- VK_LValue, OK_Ordinary));
- }
-
- if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- ExprValueKind valueKind;
- QualType type;
- if (MemberFn->isInstance()) {
- valueKind = VK_RValue;
- type = Context.BoundMemberTy;
- } else {
- valueKind = VK_LValue;
- type = MemberFn->getType();
- }
-
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- MemberFn, FoundDecl, MemberNameInfo,
- type, valueKind, OK_Ordinary));
- }
- assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
-
- if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Enum, FoundDecl, MemberNameInfo,
- Enum->getType(), VK_RValue, OK_Ordinary));
- }
-
- Owned(BaseExpr);
-
- // We found something that we didn't expect. Complain.
- if (isa<TypeDecl>(MemberDecl))
- Diag(MemberLoc, diag::err_typecheck_member_reference_type)
- << MemberName << BaseType << int(IsArrow);
- else
- Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
- << MemberName << BaseType << int(IsArrow);
-
- Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
- << MemberName;
- R.suppressDiagnostics();
- return ExprError();
-}
-
-/// Given that normal member access failed on the given expression,
-/// and given that the expression's type involves builtin-id or
-/// builtin-Class, decide whether substituting in the redefinition
-/// types would be profitable. The redefinition type is whatever
-/// this translation unit tried to typedef to id/Class; we store
-/// it to the side and then re-use it in places like this.
-static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
- const ObjCObjectPointerType *opty
- = base.get()->getType()->getAs<ObjCObjectPointerType>();
- if (!opty) return false;
-
- const ObjCObjectType *ty = opty->getObjectType();
-
- QualType redef;
- if (ty->isObjCId()) {
- redef = S.Context.ObjCIdRedefinitionType;
- } else if (ty->isObjCClass()) {
- redef = S.Context.ObjCClassRedefinitionType;
- } else {
- return false;
- }
-
- // Do the substitution as long as the redefinition type isn't just a
- // possibly-qualified pointer to builtin-id or builtin-Class again.
- opty = redef->getAs<ObjCObjectPointerType>();
- if (opty && !opty->getObjectType()->getInterface() != 0)
- return false;
-
- base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
- return true;
-}
-
-/// Look up the given member of the given non-type-dependent
-/// expression. This can return in one of two ways:
-/// * If it returns a sentinel null-but-valid result, the caller will
-/// assume that lookup was performed and the results written into
-/// the provided structure. It will take over from there.
-/// * Otherwise, the returned expression will be produced in place of
-/// an ordinary member expression.
-///
-/// The ObjCImpDecl bit is a gross hack that will need to be properly
-/// fixed for ObjC++.
-ExprResult
-Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
- bool &IsArrow, SourceLocation OpLoc,
- CXXScopeSpec &SS,
- Decl *ObjCImpDecl, bool HasTemplateArgs) {
- assert(BaseExpr.get() && "no base expression");
-
- // Perform default conversions.
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
-
- if (IsArrow) {
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
- }
-
- QualType BaseType = BaseExpr.get()->getType();
- assert(!BaseType->isDependentType());
-
- DeclarationName MemberName = R.getLookupName();
- SourceLocation MemberLoc = R.getNameLoc();
-
- // For later type-checking purposes, turn arrow accesses into dot
- // accesses. The only access type we support that doesn't follow
- // the C equivalence "a->b === (*a).b" is ObjC property accesses,
- // and those never use arrows, so this is unaffected.
- if (IsArrow) {
- if (const PointerType *Ptr = BaseType->getAs<PointerType>())
- BaseType = Ptr->getPointeeType();
- else if (const ObjCObjectPointerType *Ptr
- = BaseType->getAs<ObjCObjectPointerType>())
- BaseType = Ptr->getPointeeType();
- else if (BaseType->isRecordType()) {
- // Recover from arrow accesses to records, e.g.:
- // struct MyRecord foo;
- // foo->bar
- // This is actually well-formed in C++ if MyRecord has an
- // overloaded operator->, but that should have been dealt with
- // by now.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
- IsArrow = false;
- } else if (BaseType == Context.BoundMemberTy) {
- goto fail;
- } else {
- Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // Handle field access to simple records.
- if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
- RTy, OpLoc, SS, HasTemplateArgs))
- return ExprError();
-
- // Returning valid-but-null is how we indicate to the caller that
- // the lookup result was filled in.
- return Owned((Expr*) 0);
- }
-
- // Handle ivar access to Objective-C objects.
- if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- // There are three cases for the base type:
- // - builtin id (qualified or unqualified)
- // - builtin Class (qualified or unqualified)
- // - an interface
- ObjCInterfaceDecl *IDecl = OTy->getInterface();
- if (!IDecl) {
- // There's an implicit 'isa' ivar on all objects.
- // But we only actually find it this way on objects of type 'id',
- // apparently.
- if (OTy->isObjCId() && Member->isStr("isa"))
- return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
- Context.getObjCClassType()));
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- goto fail;
- }
-
- ObjCInterfaceDecl *ClassDeclared;
- ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
-
- if (!IV) {
- // Attempt to correct for typos in ivar names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupMemberName);
- if (CorrectTypo(Res, 0, 0, IDecl, false,
- IsArrow ? CTC_ObjCIvarLookup
- : CTC_ObjCPropertyLookup) &&
- (IV = Res.getAsSingle<ObjCIvarDecl>())) {
- Diag(R.getNameLoc(),
- diag::err_typecheck_member_reference_ivar_suggest)
- << IDecl->getDeclName() << MemberName << IV->getDeclName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- IV->getNameAsString());
- Diag(IV->getLocation(), diag::note_previous_decl)
- << IV->getDeclName();
- } else {
- Res.clear();
- Res.setLookupName(Member);
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IDecl->getDeclName() << MemberName
- << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (IV->isInvalidDecl())
- return ExprError();
-
- // Check whether we can reference this field.
- if (DiagnoseUseOfDecl(IV, MemberLoc))
- return ExprError();
- if (IV->getAccessControl() != ObjCIvarDecl::Public &&
- IV->getAccessControl() != ObjCIvarDecl::Package) {
- ObjCInterfaceDecl *ClassOfMethodDecl = 0;
- if (ObjCMethodDecl *MD = getCurMethodDecl())
- ClassOfMethodDecl = MD->getClassInterface();
- else if (ObjCImpDecl && getCurFunctionDecl()) {
- // Case of a c-function declared inside an objc implementation.
- // FIXME: For a c-style function nested inside an objc implementation
- // class, there is no implementation context available, so we pass
- // down the context as argument to this routine. Ideally, this context
- // need be passed down in the AST node and somehow calculated from the
- // AST for a function decl.
- if (ObjCImplementationDecl *IMPD =
- dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
- ClassOfMethodDecl = IMPD->getClassInterface();
- else if (ObjCCategoryImplDecl* CatImplClass =
- dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
- ClassOfMethodDecl = CatImplClass->getClassInterface();
- }
-
- if (IV->getAccessControl() == ObjCIvarDecl::Private) {
- if (ClassDeclared != IDecl ||
- ClassOfMethodDecl != ClassDeclared)
- Diag(MemberLoc, diag::error_private_ivar_access)
- << IV->getDeclName();
- } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
- // @protected
- Diag(MemberLoc, diag::error_protected_ivar_access)
- << IV->getDeclName();
- }
-
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr.take(),
- IsArrow));
- }
-
- // Objective-C property access.
- const ObjCObjectPointerType *OPT;
- if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
- // This actually uses the base as an r-value.
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
-
- assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
-
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- const ObjCObjectType *OT = OPT->getObjectType();
-
- // id, with and without qualifiers.
- if (OT->isObjCId()) {
- // Check protocols on qualified interfaces.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) {
- if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
- // Check the use of this declaration
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(BaseType, Getter, false, false);
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
- VK_LValue,
- OK_ObjCProperty,
- MemberLoc,
- BaseExpr.take()));
- }
-
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(OMD, MemberLoc))
- return ExprError();
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *SMD = 0;
- if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
- SetterSel, Context))
- SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = getMessageSendResultType(BaseType, OMD, false,
- false);
-
- ExprValueKind VK = VK_LValue;
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
- VK, OK,
- MemberLoc, BaseExpr.take()));
- }
- }
- // Use of id.member can only be for a property reference. Do not
- // use the 'id' redefinition in this case.
- if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // 'Class', unqualified only.
- if (OT->isObjCClass()) {
- // Only works in a method declaration (??!).
- ObjCMethodDecl *MD = getCurMethodDecl();
- if (!MD) {
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- goto fail;
- }
-
- // Also must look for a getter name which uses property syntax.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCInterfaceDecl *IFace = MD->getClassInterface();
- ObjCMethodDecl *Getter;
- if ((Getter = IFace->lookupClassMethod(Sel))) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- } else
- Getter = IFace->lookupPrivateMethod(Sel, false);
- // If we found a getter then this may be a valid dot-reference, we
- // will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = IFace->lookupPrivateMethod(SetterSel, false);
- }
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryClassMethod(SetterSel);
-
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
-
- if (Getter || Setter) {
- QualType PType;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
- false);
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- } else {
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- }
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- // FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
- MemberLoc, BaseExpr.take()));
- }
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // Normal property access.
- return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc,
- SourceLocation(), QualType(), false);
- }
-
- // Handle 'field access' to vectors, such as 'V.xx'.
- if (BaseType->isExtVectorType()) {
- // FIXME: this expr should store IsArrow.
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
- QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
- Member, MemberLoc);
- if (ret.isNull())
- return ExprError();
-
- return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
- *Member, MemberLoc));
- }
-
- // Adjust builtin-sel to the appropriate redefinition type if that's
- // not just a pointer to builtin-sel again.
- if (IsArrow &&
- BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
- !Context.ObjCSelRedefinitionType->isObjCSelType()) {
- BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
- CK_BitCast);
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
-
- // Failure cases.
- fail:
-
- // Recover from dot accesses to pointers, e.g.:
- // type *foo;
- // foo.bar
- // This is actually well-formed in two cases:
- // - 'type' is an Objective C type
- // - 'bar' is a pseudo-destructor name which happens to refer to
- // the appropriate pointer type
- if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
- MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, "->");
-
- // Recurse as an -> access.
- IsArrow = true;
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- // If the user is trying to apply -> or . to a function name, it's probably
- // because they forgot parentheses to call that function.
- QualType ZeroArgCallTy;
- UnresolvedSet<4> Overloads;
- if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
- if (ZeroArgCallTy.isNull()) {
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
- UnresolvedSet<2> PlausibleOverloads;
- for (OverloadExpr::decls_iterator It = Overloads.begin(),
- DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
- QualType OverloadResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && OverloadResultTy->isRecordType()) ||
- (IsArrow && OverloadResultTy->isPointerType() &&
- OverloadResultTy->getPointeeType()->isRecordType()))
- PlausibleOverloads.addDecl(It.getDecl());
- }
- NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
- return ExprError();
- }
- if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
- (IsArrow && ZeroArgCallTy->isPointerType() &&
- ZeroArgCallTy->getPointeeType()->isRecordType())) {
- // At this point, we know BaseExpr looks like it's potentially callable
- // with 0 arguments, and that it returns something of a reasonable type,
- // so we can emit a fixit and carry on pretending that BaseExpr was
- // actually a CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- // FIXME: Try this before emitting the fixit, and suppress diagnostics
- // while doing so.
- ExprResult NewBase =
- ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc.getFileLocWithOffset(1));
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr.get()->getSourceRange();
-
- return ExprError();
-}
-
-/// The main callback when the parser finds something like
-/// expression . [nested-name-specifier] identifier
-/// expression -> [nested-name-specifier] identifier
-/// where 'identifier' encompasses a fairly broad spectrum of
-/// possibilities, including destructor and operator references.
-///
-/// \param OpKind either tok::arrow or tok::period
-/// \param HasTrailingLParen whether the next token is '(', which
-/// is used to diagnose mis-uses of special members that can
-/// only be called
-/// \param ObjCImpDecl the current ObjC @implementation decl;
-/// this is an ugly hack around the fact that ObjC @implementations
-/// aren't properly put in the context chain
-ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
- SourceLocation OpLoc,
- tok::TokenKind OpKind,
- CXXScopeSpec &SS,
- UnqualifiedId &Id,
- Decl *ObjCImpDecl,
- bool HasTrailingLParen) {
- if (SS.isSet() && SS.isInvalid())
- return ExprError();
-
- // Warn about the explicit constructor calls Microsoft extension.
- if (getLangOptions().Microsoft &&
- Id.getKind() == UnqualifiedId::IK_ConstructorName)
- Diag(Id.getSourceRange().getBegin(),
- diag::ext_ms_explicit_constructor_call);
-
- TemplateArgumentListInfo TemplateArgsBuffer;
-
- // Decompose the name into its component parts.
- DeclarationNameInfo NameInfo;
- const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer,
- NameInfo, TemplateArgs);
-
- DeclarationName Name = NameInfo.getName();
- bool IsArrow = (OpKind == tok::arrow);
-
- NamedDecl *FirstQualifierInScope
- = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
- static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
-
- // This is a postfix expression, so get rid of ParenListExprs.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
- if (Result.isInvalid()) return ExprError();
- Base = Result.take();
-
- if (Base->getType()->isDependentType() || Name.isDependentName() ||
- isDependentScopeSpecifier(SS)) {
- Result = ActOnDependentMemberExpr(Base, Base->getType(),
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
- } else {
- LookupResult R(*this, NameInfo, LookupMemberName);
- ExprResult BaseResult = Owned(Base);
- Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, ObjCImpDecl, TemplateArgs != 0);
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get()) {
- // The only way a reference to a destructor can be used is to
- // immediately call it, which falls into this case. If the
- // next token is not a '(', produce a diagnostic and build the
- // call now.
- if (!HasTrailingLParen &&
- Id.getKind() == UnqualifiedId::IK_DestructorName)
- return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
-
- return move(Result);
- }
-
- Result = BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
- }
-
- return move(Result);
-}
-
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD,
ParmVarDecl *Param) {
@@ -4716,6 +3169,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(),
const_cast<CXXDestructorDecl*>(Temporary->getDestructor()));
ExprTemporaries.push_back(Temporary);
+ ExprNeedsCleanups = true;
}
// We already type-checked the argument, so we know it works.
@@ -4834,7 +3288,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
InitializedEntity Entity =
Param? InitializedEntity::InitializeParameter(Context, Param)
- : InitializedEntity::InitializeParameter(Context, ProtoArgType);
+ : InitializedEntity::InitializeParameter(Context, ProtoArgType,
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg));
@@ -5157,7 +3612,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (Proto && i < Proto->getNumArgs()) {
InitializedEntity Entity
= InitializedEntity::InitializeParameter(Context,
- Proto->getArgType(i));
+ Proto->getArgType(i),
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg));
@@ -5248,8 +3704,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
InitializedEntity Entity
= InitializedEntity::InitializeTemporary(literalType);
InitializationKind Kind
- = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
- /*IsCStyleCast=*/true);
+ = InitializationKind::CreateCStyleCast(LParenLoc,
+ SourceRange(LParenLoc, RParenLoc));
InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
MultiExprArg(*this, &literalExpr, 1),
@@ -5267,8 +3723,9 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
// In C, compound literals are l-values for some reason.
ExprValueKind VK = getLangOptions().CPlusPlus ? VK_RValue : VK_LValue;
- return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
- VK, literalExpr, isFileScope));
+ return MaybeBindToTemporary(
+ new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
+ VK, literalExpr, isFileScope));
}
ExprResult
@@ -5426,14 +3883,15 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
}
/// CheckCastTypes - Check type constraints for casting between types.
-ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
- Expr *castExpr, CastKind& Kind, ExprValueKind &VK,
+ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR,
+ QualType castType, Expr *castExpr,
+ CastKind& Kind, ExprValueKind &VK,
CXXCastPath &BasePath, bool FunctionalStyle) {
if (castExpr->getType() == Context.UnknownAnyTy)
return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath);
if (getLangOptions().CPlusPlus)
- return CXXCheckCStyleCast(SourceRange(TyR.getBegin(),
+ return CXXCheckCStyleCast(SourceRange(CastStartLoc,
castExpr->getLocEnd()),
castType, VK, castExpr, Kind, BasePath,
FunctionalStyle);
@@ -5551,8 +4009,8 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
// If either type is a pointer, the other type has to be either an
// integer or a pointer.
+ QualType castExprType = castExpr->getType();
if (!castType->isArithmeticType()) {
- QualType castExprType = castExpr->getType();
if (!castExprType->isIntegralType(Context) &&
castExprType->isArithmeticType()) {
Diag(castExpr->getLocStart(),
@@ -5568,6 +4026,36 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
}
}
+ if (getLangOptions().ObjCAutoRefCount) {
+ // Diagnose problems with Objective-C casts involving lifetime qualifiers.
+ CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()),
+ castType, castExpr, CCK_CStyleCast);
+
+ if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
+ if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) {
+ Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
+ Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
+ if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
+ ExprPtr->getPointeeType()->isObjCLifetimeType() &&
+ !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
+ Diag(castExpr->getLocStart(),
+ diag::err_typecheck_incompatible_ownership)
+ << castExprType << castType << AA_Casting
+ << castExpr->getSourceRange();
+
+ return ExprError();
+ }
+ }
+ }
+ else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) {
+ Diag(castExpr->getLocStart(),
+ diag::err_arc_convesion_of_weak_unavailable) << 1
+ << castExprType << castType
+ << castExpr->getSourceRange();
+ return ExprError();
+ }
+ }
+
castExprRes = Owned(castExpr);
Kind = PrepareScalarCast(*this, castExprRes, castType);
if (castExprRes.isInvalid())
@@ -5638,20 +4126,57 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
}
ExprResult
-Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty,
+Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ Declarator &D, ParsedType &Ty,
SourceLocation RParenLoc, Expr *castExpr) {
- assert((Ty != 0) && (castExpr != 0) &&
+ assert(!D.isInvalidType() && (castExpr != 0) &&
"ActOnCastExpr(): missing type or expr");
- TypeSourceInfo *castTInfo;
- QualType castType = GetTypeFromParser(Ty, &castTInfo);
- if (!castTInfo)
- castTInfo = Context.getTrivialTypeSourceInfo(castType);
+ TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ if (getLangOptions().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ QualType castType = castTInfo->getType();
+ Ty = CreateParsedType(castType, castTInfo);
+
+ bool isVectorLiteral = false;
+
+ // Check for an altivec or OpenCL literal,
+ // i.e. all the elements are integer constants.
+ ParenExpr *PE = dyn_cast<ParenExpr>(castExpr);
+ ParenListExpr *PLE = dyn_cast<ParenListExpr>(castExpr);
+ if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) {
+ if (PLE && PLE->getNumExprs() == 0) {
+ Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer);
+ return ExprError();
+ }
+ if (PE || PLE->getNumExprs() == 1) {
+ Expr *E = (PE ? PE->getSubExpr() : PLE->getExpr(0));
+ if (!E->getType()->isVectorType())
+ isVectorLiteral = true;
+ }
+ else
+ isVectorLiteral = true;
+ }
+
+ // If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
+ // then handle it as such.
+ if (isVectorLiteral)
+ return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo);
// If the Expr being casted is a ParenListExpr, handle it specially.
- if (isa<ParenListExpr>(castExpr))
- return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, castExpr,
- castTInfo);
+ // This is not an AltiVec-style cast, so turn the ParenListExpr into a
+ // sequence of BinOp comma operators.
+ if (isa<ParenListExpr>(castExpr)) {
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr);
+ if (Result.isInvalid()) return ExprError();
+ castExpr = Result.take();
+ }
return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr);
}
@@ -5663,8 +4188,8 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
ExprResult CastResult =
- CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
- Kind, VK, BasePath);
+ CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(),
+ castExpr, Kind, VK, BasePath);
if (CastResult.isInvalid())
return ExprError();
castExpr = CastResult.take();
@@ -5675,6 +4200,80 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
LParenLoc, RParenLoc));
}
+ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
+ SourceLocation RParenLoc, Expr *E,
+ TypeSourceInfo *TInfo) {
+ assert((isa<ParenListExpr>(E) || isa<ParenExpr>(E)) &&
+ "Expected paren or paren list expression");
+
+ Expr **exprs;
+ unsigned numExprs;
+ Expr *subExpr;
+ if (ParenListExpr *PE = dyn_cast<ParenListExpr>(E)) {
+ exprs = PE->getExprs();
+ numExprs = PE->getNumExprs();
+ } else {
+ subExpr = cast<ParenExpr>(E)->getSubExpr();
+ exprs = &subExpr;
+ numExprs = 1;
+ }
+
+ QualType Ty = TInfo->getType();
+ assert(Ty->isVectorType() && "Expected vector type");
+
+ llvm::SmallVector<Expr *, 8> initExprs;
+ const VectorType *VTy = Ty->getAs<VectorType>();
+ unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
+
+ // '(...)' form of vector initialization in AltiVec: the number of
+ // initializers must be one or must match the size of the vector.
+ // If a single value is specified in the initializer then it will be
+ // replicated to all the components of the vector
+ if (VTy->getVectorKind() == VectorType::AltiVecVector) {
+ // The number of initializers must be one or must match the size of the
+ // vector. If a single value is specified in the initializer then it will
+ // be replicated to all the components of the vector
+ if (numExprs == 1) {
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ ExprResult Literal = Owned(exprs[0]);
+ Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ PrepareScalarCast(*this, Literal, ElemTy));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ }
+ else if (numExprs < numElems) {
+ Diag(E->getExprLoc(),
+ diag::err_incorrect_number_of_vector_initializers);
+ return ExprError();
+ }
+ else
+ for (unsigned i = 0, e = numExprs; i != e; ++i)
+ initExprs.push_back(exprs[i]);
+ }
+ else {
+ // For OpenCL, when the number of initializers is a single value,
+ // it will be replicated to all components of the vector.
+ if (getLangOptions().OpenCL &&
+ VTy->getVectorKind() == VectorType::GenericVector &&
+ numExprs == 1) {
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ ExprResult Literal = Owned(exprs[0]);
+ Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ PrepareScalarCast(*this, Literal, ElemTy));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ }
+
+ for (unsigned i = 0, e = numExprs; i != e; ++i)
+ initExprs.push_back(exprs[i]);
+ }
+ // FIXME: This means that pretty-printing the final AST will produce curly
+ // braces instead of the original commas.
+ InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc,
+ &initExprs[0],
+ initExprs.size(), RParenLoc);
+ initE->setType(Ty);
+ return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
+}
+
/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
/// of comma binary operators.
ExprResult
@@ -5694,91 +4293,18 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) {
return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get());
}
-ExprResult
-Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
- SourceLocation RParenLoc, Expr *Op,
- TypeSourceInfo *TInfo) {
- ParenListExpr *PE = cast<ParenListExpr>(Op);
- QualType Ty = TInfo->getType();
- bool isVectorLiteral = false;
-
- // Check for an altivec or OpenCL literal,
- // i.e. all the elements are integer constants.
- if (getLangOptions().AltiVec && Ty->isVectorType()) {
- if (PE->getNumExprs() == 0) {
- Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer);
- return ExprError();
- }
- if (PE->getNumExprs() == 1) {
- if (!PE->getExpr(0)->getType()->isVectorType())
- isVectorLiteral = true;
- }
- else
- isVectorLiteral = true;
- }
-
- // If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
- // then handle it as such.
- if (isVectorLiteral) {
- llvm::SmallVector<Expr *, 8> initExprs;
- // '(...)' form of vector initialization in AltiVec: the number of
- // initializers must be one or must match the size of the vector.
- // If a single value is specified in the initializer then it will be
- // replicated to all the components of the vector
- if (Ty->getAs<VectorType>()->getVectorKind() ==
- VectorType::AltiVecVector) {
- unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
- // The number of initializers must be one or must match the size of the
- // vector. If a single value is specified in the initializer then it will
- // be replicated to all the components of the vector
- if (PE->getNumExprs() == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
- ExprResult Literal = Owned(PE->getExpr(0));
- Literal = ImpCastExprToType(Literal.take(), ElemTy,
- PrepareScalarCast(*this, Literal, ElemTy));
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
- }
- else if (PE->getNumExprs() < numElems) {
- Diag(PE->getExprLoc(),
- diag::err_incorrect_number_of_vector_initializers);
- return ExprError();
- }
- else
- for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
- initExprs.push_back(PE->getExpr(i));
- }
- else
- for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
- initExprs.push_back(PE->getExpr(i));
-
- // FIXME: This means that pretty-printing the final AST will produce curly
- // braces instead of the original commas.
- InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc,
- &initExprs[0],
- initExprs.size(), RParenLoc);
- E->setType(Ty);
- return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, E);
- } else {
- // This is not an AltiVec-style cast, so turn the ParenListExpr into a
- // sequence of BinOp comma operators.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Op);
- if (Result.isInvalid()) return ExprError();
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Result.take());
- }
-}
-
ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
SourceLocation R,
- MultiExprArg Val,
- ParsedType TypeOfCast) {
+ MultiExprArg Val) {
unsigned nexprs = Val.size();
Expr **exprs = reinterpret_cast<Expr**>(Val.release());
assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
Expr *expr;
- if (nexprs == 1 && TypeOfCast && !TypeIsVectorType(TypeOfCast))
+ if (nexprs == 1)
expr = new (Context) ParenExpr(L, R, exprs[0]);
else
- expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R,
+ exprs[nexprs-1]->getType());
return Owned(expr);
}
@@ -5876,7 +4402,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
// Now check the two expressions.
if (LHSTy->isVectorType() || RHSTy->isVectorType())
- return CheckVectorOperands(QuestionLoc, LHS, RHS);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
// OpenCL: If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
@@ -6203,43 +4729,21 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
-/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
+/// SuggestParentheses - Emit a note with a fixit hint that wraps
/// ParenRange in parentheses.
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
- const PartialDiagnostic &PD,
- const PartialDiagnostic &FirstNote,
- SourceRange FirstParenRange,
- const PartialDiagnostic &SecondNote,
- SourceRange SecondParenRange) {
- Self.Diag(Loc, PD);
-
- if (!FirstNote.getDiagID())
- return;
-
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
- if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just return.
- return;
- }
-
- Self.Diag(Loc, FirstNote)
- << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
-
- if (!SecondNote.getDiagID())
- return;
-
- EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
- if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just dig the
- // warning/error and return.
- Self.Diag(Loc, SecondNote);
- return;
+ const PartialDiagnostic &Note,
+ SourceRange ParenRange) {
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
+ if (ParenRange.getBegin().isFileID() && ParenRange.getEnd().isFileID() &&
+ EndLoc.isValid()) {
+ Self.Diag(Loc, Note)
+ << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ } else {
+ // We can't display the parentheses, so just show the bare note.
+ Self.Diag(Loc, Note) << ParenRange;
}
-
- Self.Diag(Loc, SecondNote)
- << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
}
static bool IsArithmeticOp(BinaryOperatorKind Opc) {
@@ -6312,13 +4816,13 @@ static bool ExprLooksBoolean(Expr *E) {
/// "int x = a + someBinaryCondition ? 1 : 2".
static void DiagnoseConditionalPrecedence(Sema &Self,
SourceLocation OpLoc,
- Expr *cond,
- Expr *lhs,
- Expr *rhs) {
+ Expr *Condition,
+ Expr *LHS,
+ Expr *RHS) {
BinaryOperatorKind CondOpcode;
Expr *CondRHS;
- if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS))
+ if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS))
return;
if (!ExprLooksBoolean(CondRHS))
return;
@@ -6326,25 +4830,18 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
// The condition is an arithmetic binary expression, with a right-
// hand side that looks boolean, so warn.
- PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional)
- << cond->getSourceRange()
- << BinaryOperator::getOpcodeStr(CondOpcode);
-
- PartialDiagnostic FirstNote =
- Self.PDiag(diag::note_precedence_conditional_silence)
+ Self.Diag(OpLoc, diag::warn_precedence_conditional)
+ << Condition->getSourceRange()
<< BinaryOperator::getOpcodeStr(CondOpcode);
- SourceRange FirstParenRange(cond->getLocStart(),
- cond->getLocEnd());
-
- PartialDiagnostic SecondNote =
- Self.PDiag(diag::note_precedence_conditional_first);
-
- SourceRange SecondParenRange(CondRHS->getLocStart(),
- rhs->getLocEnd());
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_conditional_silence)
+ << BinaryOperator::getOpcodeStr(CondOpcode),
+ SourceRange(Condition->getLocStart(), Condition->getLocEnd()));
- SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange,
- SecondNote, SecondParenRange);
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_conditional_first),
+ SourceRange(CondRHS->getLocStart(), RHS->getLocEnd()));
}
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
@@ -6427,17 +4924,31 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
// qualifiers of the type *pointed to* by the right;
Qualifiers lq;
+ // As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay.
+ if (lhq.getObjCLifetime() != rhq.getObjCLifetime() &&
+ lhq.compatiblyIncludesObjCLifetime(rhq)) {
+ // Ignore lifetime for further calculation.
+ lhq.removeObjCLifetime();
+ rhq.removeObjCLifetime();
+ }
+
if (!lhq.compatiblyIncludes(rhq)) {
// Treat address-space mismatches as fatal. TODO: address subspaces
if (lhq.getAddressSpace() != rhq.getAddressSpace())
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
- // It's okay to add or remove GC qualifiers when converting to
+ // It's okay to add or remove GC or lifetime qualifiers when converting to
// and from void*.
- else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr())
+ else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime()
+ .compatiblyIncludes(
+ rhq.withoutObjCGCAttr().withoutObjCGLifetime())
&& (lhptee->isVoidType() || rhptee->isVoidType()))
; // keep old
+ // Treat lifetime mismatches as fatal.
+ else if (lhq.getObjCLifetime() != rhq.getObjCLifetime())
+ ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
+
// For GCC compatibility, other qualifier mismatches are treated
// as still compatible in C.
else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
@@ -6614,6 +5125,7 @@ Sema::AssignConvertType
Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
CastKind &Kind) {
QualType rhsType = rhs.get()->getType();
+ QualType origLhsType = lhsType;
// Get canonical types. We're not formatting these types, just comparing
// them.
@@ -6768,7 +5280,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
// A* -> B*
if (rhsType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
- return checkObjCPointerTypesForAssignment(*this, lhsType, rhsType);
+ Sema::AssignConvertType result =
+ checkObjCPointerTypesForAssignment(*this, lhsType, rhsType);
+ if (getLangOptions().ObjCAutoRefCount &&
+ result == Compatible &&
+ !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType))
+ result = IncompatibleObjCWeakRef;
+ return result;
}
// int or null -> A*
@@ -6936,8 +5454,12 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) {
AA_Assigning);
if (Res.isInvalid())
return Incompatible;
+ Sema::AssignConvertType result = Compatible;
+ if (getLangOptions().ObjCAutoRefCount &&
+ !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType()))
+ result = IncompatibleObjCWeakRef;
rExpr = move(Res);
- return Compatible;
+ return result;
}
// FIXME: Currently, we fall through and treat C++ classes like C
@@ -6989,7 +5511,8 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &
return QualType();
}
-QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) {
+QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex,
+ SourceLocation Loc, bool isCompAssign) {
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhsType =
@@ -7001,42 +5524,33 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
if (lhsType == rhsType)
return lhsType;
- // Handle the case of a vector & extvector type of the same size and element
- // type. It would be nice if we only had one vector type someday.
- if (getLangOptions().LaxVectorConversions) {
- if (const VectorType *LV = lhsType->getAs<VectorType>()) {
- if (const VectorType *RV = rhsType->getAs<VectorType>()) {
- if (LV->getElementType() == RV->getElementType() &&
- LV->getNumElements() == RV->getNumElements()) {
- if (lhsType->isExtVectorType()) {
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
- }
-
- lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
- return rhsType;
- } else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){
- // If we are allowing lax vector conversions, and LHS and RHS are both
- // vectors, the total size only needs to be the same. This is a
- // bitcast; no bits are changed but the result type is different.
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
- }
- }
- }
- }
-
// Handle the case of equivalent AltiVec and GCC vector types
if (lhsType->isVectorType() && rhsType->isVectorType() &&
Context.areCompatibleVectorTypes(lhsType, rhsType)) {
- lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
+ if (lhsType->isExtVectorType()) {
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
+ return lhsType;
+ }
+
+ if (!isCompAssign)
+ lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
return rhsType;
}
+ if (getLangOptions().LaxVectorConversions &&
+ Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) {
+ // If we are allowing lax vector conversions, and LHS and RHS are both
+ // vectors, the total size only needs to be the same. This is a
+ // bitcast; no bits are changed but the result type is different.
+ // FIXME: Should we really be allowing this?
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
+ return lhsType;
+ }
+
// Canonicalize the ExtVector to the LHS, remember if we swapped so we can
// swap back (so that we don't reverse the inputs to a subtract, for instance.
bool swapped = false;
- if (rhsType->isExtVectorType()) {
+ if (rhsType->isExtVectorType() && !isCompAssign) {
swapped = true;
std::swap(rex, lex);
std::swap(rhsType, lhsType);
@@ -7069,6 +5583,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
}
// Vectors of different size or scalar and non-ext-vector are errors.
+ if (swapped) std::swap(rex, lex);
Diag(Loc, diag::err_typecheck_vector_not_convertable)
<< lex.get()->getType() << rex.get()->getType()
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
@@ -7078,7 +5593,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
QualType Sema::CheckMultiplyDivideOperands(
ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
if (lex.isInvalid() || rex.isInvalid())
@@ -7102,7 +5617,7 @@ QualType Sema::CheckRemainderOperands(
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
if (lex.get()->getType()->hasIntegerRepresentation() &&
rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
return InvalidOperands(Loc, lex, rex);
}
@@ -7121,10 +5636,149 @@ QualType Sema::CheckRemainderOperands(
return compType;
}
+/// \brief Diagnose invalid arithmetic on two void pointers.
+static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_void_type
+ : diag::ext_gnu_void_ptr)
+ << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on a void pointer.
+static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer) {
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_void_type
+ : diag::ext_gnu_void_ptr)
+ << 0 /* one pointer */ << Pointer->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on two function pointers.
+static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ assert(LHS->getType()->isAnyPointerType());
+ assert(RHS->getType()->isAnyPointerType());
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_function_type
+ : diag::ext_gnu_ptr_func_arith)
+ << 1 /* two pointers */ << LHS->getType()->getPointeeType()
+ // We only show the second type if it differs from the first.
+ << (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(),
+ RHS->getType())
+ << RHS->getType()->getPointeeType()
+ << LHS->getSourceRange() << RHS->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on a function pointer.
+static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer) {
+ assert(Pointer->getType()->isAnyPointerType());
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_function_type
+ : diag::ext_gnu_ptr_func_arith)
+ << 0 /* one pointer */ << Pointer->getType()->getPointeeType()
+ << 0 /* one pointer, so only one type */
+ << Pointer->getSourceRange();
+}
+
+/// \brief Check the validity of an arithmetic pointer operand.
+///
+/// If the operand has pointer type, this code will check for pointer types
+/// which are invalid in arithmetic operations. These will be diagnosed
+/// appropriately, including whether or not the use is supported as an
+/// extension.
+///
+/// \returns True when the operand is valid to use (even if as an extension).
+static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
+ Expr *Operand) {
+ if (!Operand->getType()->isAnyPointerType()) return true;
+
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (PointeeTy->isVoidType()) {
+ diagnoseArithmeticOnVoidPointer(S, Loc, Operand);
+ return !S.getLangOptions().CPlusPlus;
+ }
+ if (PointeeTy->isFunctionType()) {
+ diagnoseArithmeticOnFunctionPointer(S, Loc, Operand);
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ if ((Operand->getType()->isPointerType() &&
+ !Operand->getType()->isDependentType()) ||
+ Operand->getType()->isObjCObjectPointerType()) {
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (S.RequireCompleteType(
+ Loc, PointeeTy,
+ S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PointeeTy << Operand->getSourceRange()))
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer
+/// operands.
+///
+/// This routine will diagnose any invalid arithmetic on pointer operands much
+/// like \see checkArithmeticOpPointerOperand. However, it has special logic
+/// for emitting a single diagnostic even for operations where both LHS and RHS
+/// are (potentially problematic) pointers.
+///
+/// \returns True when the operand is valid to use (even if as an extension).
+static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ bool isLHSPointer = LHS->getType()->isAnyPointerType();
+ bool isRHSPointer = RHS->getType()->isAnyPointerType();
+ if (!isLHSPointer && !isRHSPointer) return true;
+
+ QualType LHSPointeeTy, RHSPointeeTy;
+ if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType();
+ if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType();
+
+ // Check for arithmetic on pointers to incomplete types.
+ bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType();
+ bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType();
+ if (isLHSVoidPtr || isRHSVoidPtr) {
+ if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS);
+ else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS);
+ else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS);
+
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType();
+ bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType();
+ if (isLHSFuncPtr || isRHSFuncPtr) {
+ if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS);
+ else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS);
+ else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS);
+
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ Expr *Operands[] = { LHS, RHS };
+ for (unsigned i = 0; i < 2; ++i) {
+ Expr *Operand = Operands[i];
+ if ((Operand->getType()->isPointerType() &&
+ !Operand->getType()->isDependentType()) ||
+ Operand->getType()->isObjCObjectPointerType()) {
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (S.RequireCompleteType(
+ Loc, PointeeTy,
+ S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PointeeTy << Operand->getSourceRange()))
+ return false;
+ }
+ }
+ return true;
+}
+
QualType Sema::CheckAdditionOperands( // C99 6.5.6
ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(Loc, lex, rex);
+ QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
@@ -7146,42 +5800,12 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
std::swap(PExp, IExp);
if (PExp->getType()->isAnyPointerType()) {
-
if (IExp->getType()->isIntegerType()) {
- QualType PointeeTy = PExp->getType()->getPointeeType();
-
- // Check for arithmetic on pointers to incomplete types.
- if (PointeeTy->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
+ if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
+ return QualType();
- // GNU extension: arithmetic on pointer to void
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- } else if (PointeeTy->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex.get()->getType() << lex.get()->getSourceRange();
- return QualType();
- }
+ QualType PointeeTy = PExp->getType()->getPointeeType();
- // GNU extension: arithmetic on pointer to function
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << lex.get()->getType() << lex.get()->getSourceRange();
- } else {
- // Check if we require a complete type.
- if (((PExp->getType()->isPointerType() &&
- !PExp->getType()->isDependentType()) ||
- PExp->getType()->isObjCObjectPointerType()) &&
- RequireCompleteType(Loc, PointeeTy,
- PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << PExp->getSourceRange()
- << PExp->getType()))
- return QualType();
- }
// Diagnose bad cases where we step over interface counts.
if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@@ -7209,7 +5833,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
SourceLocation Loc, QualType* CompLHSTy) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(Loc, lex, rex);
+ QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
@@ -7231,35 +5855,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (lex.get()->getType()->isAnyPointerType()) {
QualType lpointee = lex.get()->getType()->getPointeeType();
- // The LHS must be an completely-defined object type.
-
- bool ComplainAboutVoid = false;
- Expr *ComplainAboutFunc = 0;
- if (lpointee->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU C extension: arithmetic on pointer to void
- ComplainAboutVoid = true;
- } else if (lpointee->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex.get()->getType() << lex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU C extension: arithmetic on pointer to function
- ComplainAboutFunc = lex.get();
- } else if (!lpointee->isDependentType() &&
- RequireCompleteType(Loc, lpointee,
- PDiag(diag::err_typecheck_sub_ptr_object)
- << lex.get()->getSourceRange()
- << lex.get()->getType()))
- return QualType();
-
// Diagnose bad cases where we step over interface counts.
if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@@ -7269,13 +5864,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
// The result type of a pointer-int computation is the pointer type.
if (rex.get()->getType()->isIntegerType()) {
- if (ComplainAboutVoid)
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- if (ComplainAboutFunc)
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
- << ComplainAboutFunc->getSourceRange();
+ if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get()))
+ return QualType();
if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return lex.get()->getType();
@@ -7285,33 +5875,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
- // RHS must be a completely-type object type.
- // Handle the GNU void* extension.
- if (rpointee->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
-
- ComplainAboutVoid = true;
- } else if (rpointee->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << rex.get()->getType() << rex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU extension: arithmetic on pointer to function
- if (!ComplainAboutFunc)
- ComplainAboutFunc = rex.get();
- } else if (!rpointee->isDependentType() &&
- RequireCompleteType(Loc, rpointee,
- PDiag(diag::err_typecheck_sub_ptr_object)
- << rex.get()->getSourceRange()
- << rex.get()->getType()))
- return QualType();
-
if (getLangOptions().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
@@ -7332,13 +5895,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
}
}
- if (ComplainAboutVoid)
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- if (ComplainAboutFunc)
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
- << ComplainAboutFunc->getSourceRange();
+ if (!checkArithmeticBinOpPointerOperands(*this, Loc,
+ lex.get(), rex.get()))
+ return QualType();
if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return Context.getPointerDiffType();
@@ -7394,19 +5953,24 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex,
llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue());
Result = Result.shl(Right);
+ // Print the bit representation of the signed integer as an unsigned
+ // hexadecimal number.
+ llvm::SmallString<40> HexResult;
+ Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true);
+
// If we are only missing a sign bit, this is less likely to result in actual
// bugs -- if the result is cast back to an unsigned type, it will have the
// expected value. Thus we place this behind a different warning that can be
// turned off separately if needed.
if (LeftBits == ResultBits - 1) {
- S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit)
- << Result.toString(10) << LHSTy
+ S.Diag(Loc, diag::warn_shift_result_sets_sign_bit)
+ << HexResult.str() << LHSTy
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
return;
}
S.Diag(Loc, diag::warn_shift_result_gt_typewidth)
- << Result.toString(10) << Result.getMinSignedBits() << LHSTy
+ << HexResult.str() << Result.getMinSignedBits() << LHSTy
<< Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
@@ -7427,7 +5991,7 @@ QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocati
// Vector shifts promote their scalar inputs to vector type.
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
@@ -7720,7 +6284,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
// comparisons of member pointers to null pointer constants.
if (RHSIsNull &&
((lType->isAnyPointerType() || lType->isNullPtrType()) ||
- (!isRelational && lType->isMemberPointerType()))) {
+ (!isRelational &&
+ (lType->isMemberPointerType() || lType->isBlockPointerType())))) {
rex = ImpCastExprToType(rex.take(), lType,
lType->isMemberPointerType()
? CK_NullToMemberPointer
@@ -7729,7 +6294,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
}
if (LHSIsNull &&
((rType->isAnyPointerType() || rType->isNullPtrType()) ||
- (!isRelational && rType->isMemberPointerType()))) {
+ (!isRelational &&
+ (rType->isMemberPointerType() || rType->isBlockPointerType())))) {
lex = ImpCastExprToType(lex.take(), rType,
rType->isMemberPointerType()
? CK_NullToMemberPointer
@@ -7894,7 +6460,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
bool isRelational) {
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
- QualType vType = CheckVectorOperands(Loc, lex, rex);
+ QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false);
if (vType.isNull())
return vType;
@@ -7949,7 +6515,7 @@ inline QualType Sema::CheckBitwiseOperands(
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
if (lex.get()->getType()->hasIntegerRepresentation() &&
rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
return InvalidOperands(Loc, lex, rex);
}
@@ -7975,8 +6541,8 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// is a constant.
if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() &&
rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() &&
- // Don't warn in macros.
- !Loc.isMacroID()) {
+ // Don't warn in macros or template instantiations.
+ !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) {
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
@@ -8099,7 +6665,43 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
unsigned Diag = 0;
bool NeedType = false;
switch (IsLV) { // C99 6.5.16p2
- case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
+ case Expr::MLV_ConstQualified:
+ Diag = diag::err_typecheck_assign_const;
+
+ // In ARC, use some specialized diagnostics for occasions where we
+ // infer 'const'. These are always pseudo-strong variables.
+ if (S.getLangOptions().ObjCAutoRefCount) {
+ DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
+ if (declRef && isa<VarDecl>(declRef->getDecl())) {
+ VarDecl *var = cast<VarDecl>(declRef->getDecl());
+
+ // Use the normal diagnostic if it's pseudo-__strong but the
+ // user actually wrote 'const'.
+ if (var->isARCPseudoStrong() &&
+ (!var->getTypeSourceInfo() ||
+ !var->getTypeSourceInfo()->getType().isConstQualified())) {
+ // There are two pseudo-strong cases:
+ // - self
+ ObjCMethodDecl *method = S.getCurMethodDecl();
+ if (method && var == method->getSelfDecl())
+ Diag = diag::err_typecheck_arr_assign_self;
+
+ // - fast enumeration variables
+ else
+ Diag = diag::err_typecheck_arr_assign_enumeration;
+
+ SourceRange Assign;
+ if (Loc != OrigLoc)
+ Assign = SourceRange(OrigLoc, OrigLoc);
+ S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ // We need to preserve the AST regardless, so migration tool
+ // can do its job.
+ return false;
+ }
+ }
+ }
+
+ break;
case Expr::MLV_ArrayType:
Diag = diag::err_typecheck_array_not_modifiable_lvalue;
NeedType = true;
@@ -8214,6 +6816,13 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
<< SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc());
}
}
+
+ if (ConvTy == Compatible) {
+ if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
+ checkRetainCycles(LHS, RHS.get());
+ else if (getLangOptions().ObjCAutoRefCount)
+ checkUnsafeExprAssigns(Loc, LHS, RHS.get());
+ }
} else {
// Compound assignment "x += y"
ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType);
@@ -8295,29 +6904,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
QualType PointeeTy = ResType->getPointeeType();
// C99 6.5.2.4p2, 6.5.6p2
- if (PointeeTy->isVoidType()) {
- if (S.getLangOptions().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
- << Op->getSourceRange();
- return QualType();
- }
-
- // Pointer to void is a GNU extension in C.
- S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
- } else if (PointeeTy->isFunctionType()) {
- if (S.getLangOptions().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
- << Op->getType() << Op->getSourceRange();
- return QualType();
- }
-
- S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
- << ResType << Op->getSourceRange();
- } else if (S.RequireCompleteType(OpLoc, PointeeTy,
- S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << Op->getSourceRange()
- << ResType))
+ if (!checkArithmeticOpPointerOperand(S, OpLoc, Op))
return QualType();
+
// Diagnose bad cases where we step over interface counts.
else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) {
S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
@@ -8400,6 +6989,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
LHS.get()->getObjectKind() == OK_ObjCProperty);
const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
+ bool Consumed = false;
+
if (PropRef->isImplicitProperty()) {
// If using property-dot syntax notation for assignment, and there is a
// setter, RHS expression is being passed to the setter argument. So,
@@ -8407,6 +6998,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
LHSTy = (*P)->getType();
+ Consumed = (getLangOptions().ObjCAutoRefCount &&
+ (*P)->hasAttr<NSConsumedAttr>());
// Otherwise, if the getter returns an l-value, just call that.
} else {
@@ -8418,14 +7011,26 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
return;
}
}
+ } else if (getLangOptions().ObjCAutoRefCount) {
+ const ObjCMethodDecl *setter
+ = PropRef->getExplicitProperty()->getSetterMethodDecl();
+ if (setter) {
+ ObjCMethodDecl::param_iterator P = setter->param_begin();
+ LHSTy = (*P)->getType();
+ Consumed = (*P)->hasAttr<NSConsumedAttr>();
+ }
}
- if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) {
+ if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) ||
+ getLangOptions().ObjCAutoRefCount) {
InitializedEntity Entity =
- InitializedEntity::InitializeParameter(Context, LHSTy);
+ InitializedEntity::InitializeParameter(Context, LHSTy, Consumed);
ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
- if (!ArgE.isInvalid())
+ if (!ArgE.isInvalid()) {
RHS = ArgE;
+ if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver())
+ checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get());
+ }
}
}
@@ -8682,8 +7287,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
VK = VK_LValue;
// ...except that certain expressions are never l-values in C.
- if (!S.getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(S.Context, Result))
+ if (!S.getLangOptions().CPlusPlus && Result.isCForbiddenLValueType())
VK = VK_RValue;
return Result;
@@ -8815,6 +7419,53 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
rhs = move(resolvedRHS);
}
+ // The canonical way to check for a GNU null is with isNullPointerConstant,
+ // but we use a bit of a hack here for speed; this is a relatively
+ // hot path, and isNullPointerConstant is slow.
+ bool LeftNull = isa<GNUNullExpr>(lhs.get()->IgnoreParenImpCasts());
+ bool RightNull = isa<GNUNullExpr>(rhs.get()->IgnoreParenImpCasts());
+
+ // Detect when a NULL constant is used improperly in an expression. These
+ // are mainly cases where the null pointer is used as an integer instead
+ // of a pointer.
+ if (LeftNull || RightNull) {
+ // Avoid analyzing cases where the result will either be invalid (and
+ // diagnosed as such) or entirely valid and not something to warn about.
+ QualType LeftType = lhs.get()->getType();
+ QualType RightType = rhs.get()->getType();
+ if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() &&
+ !LeftType->isFunctionType() &&
+ !RightType->isBlockPointerType() &&
+ !RightType->isMemberPointerType() &&
+ !RightType->isFunctionType()) {
+ if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add ||
+ Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And ||
+ Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign ||
+ Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign ||
+ Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign ||
+ Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) {
+ // These are the operations that would not make sense with a null pointer
+ // no matter what the other expression is.
+ Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
+ << (LeftNull ? lhs.get()->getSourceRange() : SourceRange())
+ << (RightNull ? rhs.get()->getSourceRange() : SourceRange());
+ } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT ||
+ Opc == BO_EQ || Opc == BO_NE) {
+ // These are the operations that would not make sense with a null pointer
+ // if the other expression the other expression is not a pointer.
+ if (LeftNull != RightNull &&
+ !LeftType->isAnyPointerType() &&
+ !LeftType->canDecayToPointerType() &&
+ !RightType->isAnyPointerType() &&
+ !RightType->canDecayToPointerType()) {
+ Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
+ << (LeftNull ? lhs.get()->getSourceRange()
+ : rhs.get()->getSourceRange());
+ }
+ }
+ }
+ }
+
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType());
@@ -8953,28 +7604,46 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
(BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc)))
return;
- if (BinOp::isComparisonOp(lhsopc))
+ if (BinOp::isComparisonOp(lhsopc)) {
+ Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
+ << SourceRange(lhs->getLocStart(), OpLoc)
+ << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::warn_precedence_bitwise_rel)
- << SourceRange(lhs->getLocStart(), OpLoc)
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
Self.PDiag(diag::note_precedence_bitwise_silence)
<< BinOp::getOpcodeStr(lhsopc),
- lhs->getSourceRange(),
+ lhs->getSourceRange());
+ SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
- else if (BinOp::isComparisonOp(rhsopc))
+ } else if (BinOp::isComparisonOp(rhsopc)) {
+ Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
+ << SourceRange(OpLoc, rhs->getLocEnd())
+ << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::warn_precedence_bitwise_rel)
- << SourceRange(OpLoc, rhs->getLocEnd())
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
Self.PDiag(diag::note_precedence_bitwise_silence)
<< BinOp::getOpcodeStr(rhsopc),
- rhs->getSourceRange(),
+ rhs->getSourceRange());
+ SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ SourceRange(lhs->getLocStart(),
+ cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ }
+}
+
+/// \brief It accepts a '&' expr that is inside a '|' one.
+/// Emit a diagnostic together with a fixit hint that wraps the '&' expression
+/// in parentheses.
+static void
+EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc,
+ BinaryOperator *Bop) {
+ assert(Bop->getOpcode() == BO_And);
+ Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or)
+ << Bop->getSourceRange() << OpLoc;
+ SuggestParentheses(Self, Bop->getOperatorLoc(),
+ Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence),
+ Bop->getSourceRange());
}
/// \brief It accepts a '&&' expr that is inside a '||' one.
@@ -8984,12 +7653,11 @@ static void
EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
BinaryOperator *Bop) {
assert(Bop->getOpcode() == BO_LAnd);
+ Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or)
+ << Bop->getSourceRange() << OpLoc;
SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::warn_logical_and_in_logical_or)
- << Bop->getSourceRange() << OpLoc,
Self.PDiag(diag::note_logical_and_in_logical_or_silence),
- Bop->getSourceRange(),
- Self.PDiag(0), SourceRange());
+ Bop->getSourceRange());
}
/// \brief Returns true if the given expression can be evaluated as a constant
@@ -9043,13 +7711,28 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
}
}
+/// \brief Look for '&' in the left or right hand of a '|' expr.
+static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
+ Expr *OrArg) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrArg)) {
+ if (Bop->getOpcode() == BO_And)
+ return EmitDiagnosticForBitwiseAndInBitwiseOr(S, OpLoc, Bop);
+ }
+}
+
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
/// precedence.
static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
SourceLocation OpLoc, Expr *lhs, Expr *rhs){
// Diagnose "arg1 'bitwise' arg2 'eq' arg3".
if (BinaryOperator::isBitwiseOp(Opc))
- return DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
+ DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
+
+ // Diagnose "arg1 & arg2 | arg3"
+ if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) {
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs);
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs);
+ }
// Warn about arg1 || arg2 && arg3, as GCC 4.3+ does.
// We don't warn for 'assert(a || b && "bad")' since this is safe.
@@ -9274,6 +7957,29 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
Context.getPointerType(Context.VoidTy)));
}
+/// Given the last statement in a statement-expression, check whether
+/// the result is a producing expression (like a call to an
+/// ns_returns_retained function) and, if so, rebuild it to hoist the
+/// release out of the full-expression. Otherwise, return null.
+/// Cannot fail.
+static Expr *maybeRebuildARCConsumingStmt(Stmt *s) {
+ // Should always be wrapped with one of these.
+ ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s);
+ if (!cleanups) return 0;
+
+ ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr());
+ if (!cast || cast->getCastKind() != CK_ObjCConsumeObject)
+ return 0;
+
+ // Splice out the cast. This shouldn't modify any interesting
+ // features of the statement.
+ Expr *producer = cast->getSubExpr();
+ assert(producer->getType() == cast->getType());
+ assert(producer->getValueKind() == cast->getValueKind());
+ cleanups->setSubExpr(producer);
+ return cleanups;
+}
+
ExprResult
Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc) { // "({..})"
@@ -9301,6 +8007,7 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
LastLabelStmt = Label;
LastStmt = Label->getSubStmt();
}
+
if (Expr *LastE = dyn_cast<Expr>(LastStmt)) {
// Do function/array conversion on the last expression, but not
// lvalue-to-rvalue. However, initialize an unqualified type.
@@ -9310,12 +8017,24 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
Ty = LastExpr.get()->getType().getUnqualifiedType();
if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) {
- LastExpr = PerformCopyInitialization(
+ // In ARC, if the final expression ends in a consume, splice
+ // the consume out and bind it later. In the alternate case
+ // (when dealing with a retainable type), the result
+ // initialization will create a produce. In both cases the
+ // result will be +1, and we'll need to balance that out with
+ // a bind.
+ if (Expr *rebuiltLastStmt
+ = maybeRebuildARCConsumingStmt(LastExpr.get())) {
+ LastExpr = rebuiltLastStmt;
+ } else {
+ LastExpr = PerformCopyInitialization(
InitializedEntity::InitializeResult(LPLoc,
Ty,
false),
SourceLocation(),
- LastExpr);
+ LastExpr);
+ }
+
if (LastExpr.isInvalid())
return ExprError();
if (LastExpr.get() != 0) {
@@ -9757,7 +8476,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If we don't have a function type, just build one from nothing.
} else {
FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default);
+ EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
}
@@ -9766,15 +8485,25 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BlockTy = Context.getBlockPointerType(BlockTy);
// If needed, diagnose invalid gotos and switches in the block.
- if (getCurFunction()->NeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+ if (getCurFunction()->NeedsScopeChecking() &&
+ !hasAnyUnrecoverableErrorsInThisFunction())
DiagnoseInvalidJumps(cast<CompoundStmt>(Body));
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
- BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
+ for (BlockDecl::capture_const_iterator ci = BSI->TheDecl->capture_begin(),
+ ce = BSI->TheDecl->capture_end(); ci != ce; ++ci) {
+ const VarDecl *variable = ci->getVariable();
+ QualType T = variable->getType();
+ QualType::DestructionKind destructKind = T.isDestructedType();
+ if (destructKind != QualType::DK_none)
+ getCurFunction()->setHasBranchProtectedScope();
+ }
+ BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
+
return Owned(Result);
}
@@ -9818,8 +8547,41 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
<< OrigExpr->getType() << E->getSourceRange());
}
- // FIXME: Check that type is complete/non-abstract
- // FIXME: Warn if a non-POD type is passed in.
+ if (!TInfo->getType()->isDependentType()) {
+ if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(),
+ PDiag(diag::err_second_parameter_to_va_arg_incomplete)
+ << TInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
+ if (RequireNonAbstractType(TInfo->getTypeLoc().getBeginLoc(),
+ TInfo->getType(),
+ PDiag(diag::err_second_parameter_to_va_arg_abstract)
+ << TInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
+ if (!TInfo->getType().isPODType(Context))
+ Diag(TInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_second_parameter_to_va_arg_not_pod)
+ << TInfo->getType()
+ << TInfo->getTypeLoc().getSourceRange();
+
+ // Check for va_arg where arguments of the given type will be promoted
+ // (i.e. this va_arg is guaranteed to have undefined behavior).
+ QualType PromoteType;
+ if (TInfo->getType()->isPromotableIntegerType()) {
+ PromoteType = Context.getPromotedIntegerType(TInfo->getType());
+ if (Context.typesAreCompatible(PromoteType, TInfo->getType()))
+ PromoteType = QualType();
+ }
+ if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float))
+ PromoteType = Context.DoubleTy;
+ if (!PromoteType.isNull())
+ Diag(TInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_second_parameter_to_va_arg_never_compatible)
+ << TInfo->getType()
+ << PromoteType
+ << TInfo->getTypeLoc().getSourceRange();
+ }
QualType T = TInfo->getType().getNonLValueExprType(Context);
return Owned(new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T));
@@ -9913,6 +8675,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (lhq.getAddressSpace() != rhq.getAddressSpace()) {
DiagKind = diag::err_typecheck_incompatible_address_space;
break;
+
+
+ } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) {
+ DiagKind = diag::err_typecheck_incompatible_ownership;
+ break;
}
llvm_unreachable("unknown error case for discarding qualifiers!");
@@ -9950,6 +8717,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleVectors:
DiagKind = diag::warn_incompatible_vectors;
break;
+ case IncompatibleObjCWeakRef:
+ DiagKind = diag::err_arc_weak_unavailable_assign;
+ break;
case Incompatible:
DiagKind = diag::err_typecheck_convert_incompatible;
isInvalid = true;
@@ -10027,7 +8797,10 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
void
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
ExprEvalContexts.push_back(
- ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size()));
+ ExpressionEvaluationContextRecord(NewContext,
+ ExprTemporaries.size(),
+ ExprNeedsCleanups));
+ ExprNeedsCleanups = false;
}
void
@@ -10062,15 +8835,27 @@ Sema::PopExpressionEvaluationContext() {
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
// will never be constructed.
- if (Rec.Context == Unevaluated &&
- ExprTemporaries.size() > Rec.NumTemporaries)
+ if (Rec.Context == Unevaluated) {
ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
ExprTemporaries.end());
+ ExprNeedsCleanups = Rec.ParentNeedsCleanups;
+
+ // Otherwise, merge the contexts together.
+ } else {
+ ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
+ }
// Destroy the popped expression evaluation record.
Rec.Destroy();
}
+void Sema::DiscardCleanupsInEvaluationContext() {
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+ ExprNeedsCleanups = false;
+}
+
/// \brief Note that the given declaration was referenced in the source code.
///
/// This routine should be invoke whenever a given declaration is referenced
@@ -10364,7 +9149,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) {
/// during overload resolution or within sizeof/alignof/typeof/typeid.
bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
const PartialDiagnostic &PD) {
- switch (ExprEvalContexts.back().Context ) {
+ switch (ExprEvalContexts.back().Context) {
case Unevaluated:
// The argument will never be evaluated, so don't complain.
break;
@@ -10780,9 +9565,6 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
}
ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
- ObjCMethodDecl *method = msg->getMethodDecl();
- assert(method && "__unknown_anytype message without result type?");
-
// Verify that this is a legal result type of a call.
if (DestType->isArrayType() || DestType->isFunctionType()) {
S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function)
@@ -10790,8 +9572,11 @@ ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
return ExprError();
}
- assert(method->getResultType() == S.Context.UnknownAnyTy);
- method->setResultType(DestType);
+ // Rewrite the method result type if available.
+ if (ObjCMethodDecl *method = msg->getMethodDecl()) {
+ assert(method->getResultType() == S.Context.UnknownAnyTy);
+ method->setResultType(DestType);
+ }
// Change the type of the message.
msg->setType(DestType.getNonReferenceType());
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 2f5a890..e804fcd 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -480,23 +480,63 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
/// ActOnCXXThrow - Parse throw expressions.
ExprResult
-Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) {
+Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) {
+ bool IsThrownVarInScope = false;
+ if (Ex) {
+ // C++0x [class.copymove]p31:
+ // When certain criteria are met, an implementation is allowed to omit the
+ // copy/move construction of a class object [...]
+ //
+ // - in a throw-expression, when the operand is the name of a
+ // non-volatile automatic object (other than a function or catch-
+ // clause parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
+ // exception object
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens()))
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) {
+ for( ; S; S = S->getParent()) {
+ if (S->isDeclScope(Var)) {
+ IsThrownVarInScope = true;
+ break;
+ }
+
+ if (S->getFlags() &
+ (Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
+ Scope::FunctionPrototypeScope | Scope::ObjCMethodScope |
+ Scope::TryScope))
+ break;
+ }
+ }
+ }
+ }
+
+ return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope);
+}
+
+ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
+ bool IsThrownVarInScope) {
// Don't report an error if 'throw' is used in system headers.
if (!getLangOptions().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
-
+
if (Ex && !Ex->isTypeDependent()) {
- ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex);
+ ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
if (ExRes.isInvalid())
return ExprError();
Ex = ExRes.take();
}
- return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc));
+
+ return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc,
+ IsThrownVarInScope));
}
/// CheckCXXThrowOperand - Validate the operand of a throw.
-ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
+ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
+ bool IsThrownVarInScope) {
// C++ [except.throw]p3:
// A throw-expression initializes a temporary object, called the exception
// object, the type of which is determined by removing any top-level
@@ -535,14 +575,28 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
// Initialize the exception result. This implicitly weeds out
// abstract types or types with inaccessible copy constructors.
- const VarDecl *NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
-
- // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p32.
+
+ // C++0x [class.copymove]p31:
+ // When certain criteria are met, an implementation is allowed to omit the
+ // copy/move construction of a class object [...]
+ //
+ // - in a throw-expression, when the operand is the name of a
+ // non-volatile automatic object (other than a function or catch-clause
+ // parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
+ // exception object
+ const VarDecl *NRVOVariable = 0;
+ if (IsThrownVarInScope)
+ NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
+
InitializedEntity Entity =
InitializedEntity::InitializeException(ThrowLoc, E->getType(),
- /*NRVO=*/false);
+ /*NRVO=*/NRVOVariable != 0);
Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
- QualType(), E);
+ QualType(), E,
+ IsThrownVarInScope);
if (Res.isInvalid())
return ExprError();
E = Res.take();
@@ -691,7 +745,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
ExprResult CastExpr =
- CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
+ CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(),
+ TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
Kind, VK, BasePath,
/*FunctionalStyle=*/true);
if (CastExpr.isInvalid())
@@ -827,8 +882,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0, /*OwnedDecl=*/0,
- /*AllowAuto=*/true);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0);
QualType AllocType = TInfo->getType();
if (D.isInvalidType())
return ExprError();
@@ -902,8 +956,16 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
- QualType ResultType = Context.getPointerType(AllocType);
+ // In ARC, infer 'retaining' for the allocated
+ if (getLangOptions().ObjCAutoRefCount &&
+ AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+ AllocType->isObjCLifetimeType()) {
+ AllocType = Context.getLifetimeQualifiedType(AllocType,
+ AllocType->getObjCARCImplicitLifetime());
+ }
+ QualType ResultType = Context.getPointerType(AllocType);
+
// C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
// or enumeration type with a non-negative value."
if (ArraySize && !ArraySize->isTypeDependent()) {
@@ -964,6 +1026,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
+ // ARC: warn about ABI issues.
+ if (getLangOptions().ObjCAutoRefCount) {
+ QualType BaseAllocType = Context.getBaseElementType(AllocType);
+ if (BaseAllocType.hasStrongOrWeakObjCLifetime())
+ Diag(StartLoc, diag::warn_err_new_delete_object_array)
+ << 0 << BaseAllocType;
+ }
+
// Note that we do *not* convert the argument in any way. It can
// be signed, larger than size_t, whatever.
}
@@ -1078,7 +1148,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (OperatorDelete)
MarkDeclarationReferenced(StartLoc, OperatorDelete);
- // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
+ // C++0x [expr.new]p17:
+ // If the new expression creates an array of objects of class type,
+ // access and ambiguity control are done for the destructor.
+ if (ArraySize && Constructor) {
+ if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) {
+ MarkDeclarationReferenced(StartLoc, dtor);
+ CheckDestructorAccess(StartLoc, dtor,
+ PDiag(diag::err_access_dtor)
+ << Context.getBaseElementType(AllocType));
+ }
+ }
PlacementArgs.release();
ConstructorArgs.release();
@@ -1122,6 +1202,15 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (unsigned AddressSpace = AllocType.getAddressSpace())
return Diag(Loc, diag::err_address_space_qualified_new)
<< AllocType.getUnqualifiedType() << AddressSpace;
+ else if (getLangOptions().ObjCAutoRefCount) {
+ if (const ArrayType *AT = Context.getAsArrayType(AllocType)) {
+ QualType BaseAllocType = Context.getBaseElementType(AT);
+ if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+ BaseAllocType->isObjCLifetimeType())
+ return Diag(Loc, diag::err_arc_new_array_without_ownership)
+ << BaseAllocType;
+ }
+ }
return false;
}
@@ -1774,8 +1863,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// delete-expression; it is not necessary to cast away the constness
// (5.2.11) of the pointer expression before it is used as the operand
// of the delete-expression. ]
- Ex = ImpCastExprToType(Ex.take(), Context.getPointerType(Context.VoidTy),
- CK_NoOp);
+ if (!Context.hasSameType(Ex.get()->getType(), Context.VoidPtrTy))
+ Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy, CK_NoOp,
+ Ex.take(), 0, VK_RValue));
if (Pointee->isArrayType() && !ArrayForm) {
Diag(StartLoc, diag::warn_delete_array_type)
@@ -1830,6 +1920,14 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (!dtor || !dtor->isVirtual())
Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
}
+
+ } else if (getLangOptions().ObjCAutoRefCount &&
+ PointeeElem->isObjCLifetimeType() &&
+ (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong ||
+ PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) &&
+ ArrayForm) {
+ Diag(StartLoc, diag::warn_err_new_delete_object_array)
+ << 1 << PointeeElem;
}
if (!OperatorDelete) {
@@ -1988,11 +2086,12 @@ static ExprResult BuildCXXCastArgument(Sema &S,
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence &ICS,
- AssignmentAction Action, bool CStyle) {
+ AssignmentAction Action,
+ CheckedConversionKind CCK) {
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion: {
ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard,
- Action, CStyle);
+ Action, CCK);
if (Res.isInvalid())
return ExprError();
From = Res.take();
@@ -2027,7 +2126,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprResult Res =
PerformImplicitConversion(From, BeforeToType,
ICS.UserDefined.Before, AA_Converting,
- CStyle);
+ CCK);
if (Res.isInvalid())
return ExprError();
From = Res.take();
@@ -2047,7 +2146,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = CastArg.take();
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
- AA_Converting, CStyle);
+ AA_Converting, CCK);
}
case ImplicitConversionSequence::AmbiguousConversion:
@@ -2076,13 +2175,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence& SCS,
- AssignmentAction Action, bool CStyle) {
+ AssignmentAction Action,
+ CheckedConversionKind CCK) {
+ bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast);
+
// Overall FIXME: we are recomputing too many types here and doing far too
// much extra work. What this means is that we need to keep track of more
// information that is computed when we try the implicit conversion initially,
// so that we don't need to recompute anything here.
QualType FromType = From->getType();
-
+
if (SCS.CopyConstructor) {
// FIXME: When can ToType be a reference type?
assert(!ToType->isReferenceType());
@@ -2149,12 +2251,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
- From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay).take();
+ From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Function_To_Pointer:
FromType = Context.getPointerType(FromType);
- From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay).take();
+ From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
default:
@@ -2178,17 +2282,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
- From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+ From = ImpCastExprToType(From, ToType, CK_NoOp,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
- From = ImpCastExprToType(From, ToType, CK_IntegralCast).take();
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Floating_Promotion:
case ICK_Floating_Conversion:
- From = ImpCastExprToType(From, ToType, CK_FloatingCast).take();
+ From = ImpCastExprToType(From, ToType, CK_FloatingCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Complex_Promotion:
@@ -2206,21 +2313,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
} else {
CK = CK_IntegralComplexCast;
}
- From = ImpCastExprToType(From, ToType, CK).take();
+ From = ImpCastExprToType(From, ToType, CK,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
}
case ICK_Floating_Integral:
if (ToType->isRealFloatingType())
- From = ImpCastExprToType(From, ToType, CK_IntegralToFloating).take();
+ From = ImpCastExprToType(From, ToType, CK_IntegralToFloating,
+ VK_RValue, /*BasePath=*/0, CCK).take();
else
- From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral).take();
+ From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Compatible_Conversion:
- From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+ From = ImpCastExprToType(From, ToType, CK_NoOp,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
+ case ICK_Writeback_Conversion:
case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC && Action != AA_Casting) {
// Diagnose incompatible Objective-C conversions
@@ -2234,17 +2346,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
<< From->getSourceRange();
-
+
if (From->getType()->isObjCObjectPointerType() &&
ToType->isObjCObjectPointerType())
EmitRelatedResultTypeNote(From);
- }
-
+ }
+ else if (getLangOptions().ObjCAutoRefCount &&
+ !CheckObjCARCUnavailableWeakConversion(ToType,
+ From->getType())) {
+ if (Action == AA_Initializing)
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_weak_unavailable_assign);
+ else
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_convesion_of_weak_unavailable)
+ << (Action == AA_Casting) << From->getType() << ToType
+ << From->getSourceRange();
+ }
+
CastKind Kind = CK_Invalid;
CXXCastPath BasePath;
if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
return ExprError();
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ .take();
break;
}
@@ -2255,13 +2380,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ .take();
break;
}
case ICK_Boolean_Conversion:
From = ImpCastExprToType(From, Context.BoolTy,
- ScalarTypeToBooleanCastKind(FromType)).take();
+ ScalarTypeToBooleanCastKind(FromType),
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Derived_To_Base: {
@@ -2276,16 +2403,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = ImpCastExprToType(From, ToType.getNonReferenceType(),
CK_DerivedToBase, CastCategory(From),
- &BasePath).take();
+ &BasePath, CCK).take();
break;
}
case ICK_Vector_Conversion:
- From = ImpCastExprToType(From, ToType, CK_BitCast).take();
+ From = ImpCastExprToType(From, ToType, CK_BitCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Vector_Splat:
- From = ImpCastExprToType(From, ToType, CK_VectorSplat).take();
+ From = ImpCastExprToType(From, ToType, CK_VectorSplat,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Complex_Real:
@@ -2321,27 +2450,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// _Complex x -> x
From = ImpCastExprToType(From, ElType,
isFloatingComplex ? CK_FloatingComplexToReal
- : CK_IntegralComplexToReal).take();
+ : CK_IntegralComplexToReal,
+ VK_RValue, /*BasePath=*/0, CCK).take();
// x -> y
if (Context.hasSameUnqualifiedType(ElType, ToType)) {
// do nothing
} else if (ToType->isRealFloatingType()) {
From = ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating).take();
+ isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating,
+ VK_RValue, /*BasePath=*/0, CCK).take();
} else {
assert(ToType->isIntegerType());
From = ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast).take();
+ isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
}
}
break;
case ICK_Block_Pointer_Conversion: {
- From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
- VK_RValue).take();
- break;
- }
+ From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
+ break;
+ }
case ICK_TransparentUnionConversion: {
ExprResult FromRes = Owned(From);
@@ -2376,7 +2508,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprValueKind VK = ToType->isReferenceType() ?
CastCategory(From) : VK_RValue;
From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
- CK_NoOp, VK).take();
+ CK_NoOp, VK, /*BasePath=*/0, CCK).take();
if (SCS.DeprecatedStringLiteralToCharPtr &&
!getLangOptions().WritableStrings)
@@ -2553,6 +2685,23 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsObject:
return T->isObjectType();
case UTT_IsScalar:
+ // Note: semantic analysis depends on Objective-C lifetime types to be
+ // considered scalar types. However, such types do not actually behave
+ // like scalar types at run time (since they may require retain/release
+ // operations), so we report them as non-scalar.
+ if (T->isObjCLifetimeType()) {
+ switch (T.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+ }
+ }
+
return T->isScalarType();
case UTT_IsCompound:
return T->isCompoundType();
@@ -2566,13 +2715,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsVolatile:
return T.isVolatileQualified();
case UTT_IsTrivial:
- return T->isTrivialType();
+ return T.isTrivialType(Self.Context);
case UTT_IsTriviallyCopyable:
- return T->isTriviallyCopyableType();
+ return T.isTriviallyCopyableType(Self.Context);
case UTT_IsStandardLayout:
return T->isStandardLayoutType();
case UTT_IsPOD:
- return T->isPODType();
+ return T.isPODType(Self.Context);
case UTT_IsLiteral:
return T->isLiteralType();
case UTT_IsEmpty:
@@ -2605,7 +2754,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// If __is_pod (type) is true then the trait is true, else if type is
// a cv class or union type (or array thereof) with a trivial default
// constructor ([class.ctor]) then the trait is true, else it is false.
- if (T->isPODType())
+ if (T.isPODType(Self.Context))
return true;
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
@@ -2617,7 +2766,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// the trait is true, else if type is a cv class or union type
// with a trivial copy constructor ([class.copy]) then the trait
// is true, else it is false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(Self.Context) || T->isReferenceType())
return true;
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
@@ -2637,7 +2786,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (C.getBaseElementType(T).isConstQualified())
return false;
- if (T->isPODType())
+ if (T.isPODType(Self.Context))
return true;
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
@@ -2649,8 +2798,14 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// type (or array thereof) with a trivial destructor
// ([class.dtor]) then the trait is true, else it is
// false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(Self.Context) || T->isReferenceType())
+ return true;
+
+ // Objective-C++ ARC: autorelease types don't require destruction.
+ if (T->isObjCLifetimeType() &&
+ T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
return true;
+
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
@@ -2668,8 +2823,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return false;
if (T->isReferenceType())
return false;
- if (T->isPODType())
- return true;
+ if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
+ return true;
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialCopyAssignment())
@@ -2704,7 +2859,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// if type is a cv class or union type with copy constructors that are
// known not to throw an exception then the trait is true, else it is
// false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
return true;
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -2744,7 +2899,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// true, else if type is a cv class or union type (or array
// thereof) with a default constructor that is known not to
// throw an exception then the trait is true, else it is false.
- if (T->isPODType())
+ if (T.isPODType(C) || T->isObjCLifetimeType())
return true;
if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -3089,6 +3244,20 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
ExprValueKind &VK,
SourceLocation Loc,
bool isIndirect) {
+ assert(!lex.get()->getType()->isPlaceholderType() &&
+ !rex.get()->getType()->isPlaceholderType() &&
+ "placeholders should have been weeded out by now");
+
+ // The LHS undergoes lvalue conversions if this is ->*.
+ if (isIndirect) {
+ lex = DefaultLvalueConversion(lex.take());
+ if (lex.isInvalid()) return QualType();
+ }
+
+ // The RHS always undergoes lvalue conversions.
+ rex = DefaultLvalueConversion(rex.take());
+ if (rex.isInvalid()) return QualType();
+
const char *OpSpelling = isIndirect ? "->*" : ".*";
// C++ 5.5p2
// The binary operator .* [p3: ->*] binds its second operand, which shall
@@ -3556,7 +3725,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
// Extension: conditional operator involving vector types.
if (LTy->isVectorType() || RTy->isVectorType())
- return CheckVectorOperands(QuestionLoc, LHS, RHS);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
// -- The second and third operands have arithmetic or enumeration type;
// the usual arithmetic conversions are performed to bring them to a
@@ -3828,17 +3997,83 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (!E)
return ExprError();
- if (!Context.getLangOptions().CPlusPlus)
+ assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+
+ // If the result is a glvalue, we shouldn't bind it.
+ if (!E->isRValue())
return Owned(E);
- assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+ // In ARC, calls that return a retainable type can return retained,
+ // in which case we have to insert a consuming cast.
+ if (getLangOptions().ObjCAutoRefCount &&
+ E->getType()->isObjCRetainableType()) {
+
+ bool ReturnsRetained;
+
+ // For actual calls, we compute this by examining the type of the
+ // called value.
+ if (CallExpr *Call = dyn_cast<CallExpr>(E)) {
+ Expr *Callee = Call->getCallee()->IgnoreParens();
+ QualType T = Callee->getType();
+
+ if (T == Context.BoundMemberTy) {
+ // Handle pointer-to-members.
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Callee))
+ T = BinOp->getRHS()->getType();
+ else if (MemberExpr *Mem = dyn_cast<MemberExpr>(Callee))
+ T = Mem->getMemberDecl()->getType();
+ }
+
+ if (const PointerType *Ptr = T->getAs<PointerType>())
+ T = Ptr->getPointeeType();
+ else if (const BlockPointerType *Ptr = T->getAs<BlockPointerType>())
+ T = Ptr->getPointeeType();
+ else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>())
+ T = MemPtr->getPointeeType();
+
+ const FunctionType *FTy = T->getAs<FunctionType>();
+ assert(FTy && "call to value not of function type?");
+ ReturnsRetained = FTy->getExtInfo().getProducesResult();
+
+ // ActOnStmtExpr arranges things so that StmtExprs of retainable
+ // type always produce a +1 object.
+ } else if (isa<StmtExpr>(E)) {
+ ReturnsRetained = true;
+
+ // For message sends and property references, we try to find an
+ // actual method. FIXME: we should infer retention by selector in
+ // cases where we don't have an actual method.
+ } else {
+ Decl *D = 0;
+ if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
+ D = Send->getMethodDecl();
+ } else {
+ CastExpr *CE = cast<CastExpr>(E);
+ // FIXME. What other cast kinds to check for?
+ if (CE->getCastKind() == CK_ObjCProduceObject ||
+ CE->getCastKind() == CK_LValueToRValue)
+ return MaybeBindToTemporary(CE->getSubExpr());
+ assert(CE->getCastKind() == CK_GetObjCProperty);
+ const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty();
+ D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0);
+ }
- const RecordType *RT = E->getType()->getAs<RecordType>();
- if (!RT)
+ ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
+ }
+
+ ExprNeedsCleanups = true;
+
+ CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject
+ : CK_ObjCReclaimReturnedObject);
+ return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0,
+ VK_RValue));
+ }
+
+ if (!getLangOptions().CPlusPlus)
return Owned(E);
- // If the result is a glvalue, we shouldn't bind it.
- if (E->Classify(Context).isGLValue())
+ const RecordType *RT = E->getType()->getAs<RecordType>();
+ if (!RT)
return Owned(E);
// That should be enough to guarantee that this type is complete.
@@ -3847,15 +4082,18 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (RD->isInvalidDecl() || RD->hasTrivialDestructor())
return Owned(E);
- CXXTemporary *Temp = CXXTemporary::Create(Context, LookupDestructor(RD));
- ExprTemporaries.push_back(Temp);
- if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
+ CXXDestructorDecl *Destructor = LookupDestructor(RD);
+
+ CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
+ if (Destructor) {
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_temp)
<< E->getType());
+
+ ExprTemporaries.push_back(Temp);
+ ExprNeedsCleanups = true;
}
- // FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
@@ -3864,14 +4102,16 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
assert(ExprTemporaries.size() >= FirstTemporary);
- if (ExprTemporaries.size() == FirstTemporary)
+ assert(ExprNeedsCleanups || ExprTemporaries.size() == FirstTemporary);
+ if (!ExprNeedsCleanups)
return SubExpr;
Expr *E = ExprWithCleanups::Create(Context, SubExpr,
- &ExprTemporaries[FirstTemporary],
+ ExprTemporaries.begin() + FirstTemporary,
ExprTemporaries.size() - FirstTemporary);
ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
ExprTemporaries.end());
+ ExprNeedsCleanups = false;
return E;
}
@@ -3887,9 +4127,7 @@ Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) {
Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
assert(SubStmt && "sub statement can't be null!");
- unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
- assert(ExprTemporaries.size() >= FirstTemporary);
- if (ExprTemporaries.size() == FirstTemporary)
+ if (!ExprNeedsCleanups)
return SubStmt;
// FIXME: In order to attach the temporaries, wrap the statement into
@@ -4047,17 +4285,35 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
QualType DestructedType = DestructedTypeInfo->getType();
SourceLocation DestructedTypeStart
= DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
- if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
- !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
- Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
- << ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
-
- // Recover by setting the destructed type to the object type.
- DestructedType = ObjectType;
- DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
+ if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ DestructedTypeStart);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ } else if (DestructedType.getObjCLifetime() !=
+ ObjectType.getObjCLifetime()) {
+
+ if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) {
+ // Okay: just pretend that the user provided the correctly-qualified
+ // type.
+ } else {
+ Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ }
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
DestructedTypeStart);
- Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
}
}
@@ -4293,7 +4549,16 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the
// designated object (and is no longer an lvalue).
- if (E->isRValue()) return Owned(E);
+ if (E->isRValue()) {
+ // In C, function designators (i.e. expressions of function type)
+ // are r-values, but we still want to do function-to-pointer decay
+ // on them. This is both technically correct and convenient for
+ // some clients.
+ if (!getLangOptions().CPlusPlus && E->getType()->isFunctionType())
+ return DefaultFunctionArrayConversion(E);
+
+ return Owned(E);
+ }
// We always want to do this on ObjC property references.
if (E->getObjectKind() == OK_ObjCProperty) {
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
new file mode 100644
index 0000000..2488dc8
--- /dev/null
+++ b/lib/Sema/SemaExprMember.cpp
@@ -0,0 +1,1594 @@
+//===--- SemaExprMember.cpp - Semantic Analysis for Expressions -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis member access expressions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+using namespace sema;
+
+/// Determines if the given class is provably not derived from all of
+/// the prospective base classes.
+static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
+ CXXRecordDecl *Record,
+ const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
+ if (Bases.count(Record->getCanonicalDecl()))
+ return false;
+
+ RecordDecl *RD = Record->getDefinition();
+ if (!RD) return false;
+ Record = cast<CXXRecordDecl>(RD);
+
+ for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
+ E = Record->bases_end(); I != E; ++I) {
+ CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
+ CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
+ if (!BaseRT) return false;
+
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
+ return false;
+ }
+
+ return true;
+}
+
+enum IMAKind {
+ /// The reference is definitely not an instance member access.
+ IMA_Static,
+
+ /// The reference may be an implicit instance member access.
+ IMA_Mixed,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is not an instance method.
+ IMA_Mixed_StaticContext,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is from an unrelated class.
+ IMA_Mixed_Unrelated,
+
+ /// The reference is definitely an implicit instance member access.
+ IMA_Instance,
+
+ /// The reference may be to an unresolved using declaration.
+ IMA_Unresolved,
+
+ /// The reference may be to an unresolved using declaration and the
+ /// context is not an instance method.
+ IMA_Unresolved_StaticContext,
+
+ /// All possible referrents are instance members and the current
+ /// context is not an instance method.
+ IMA_Error_StaticContext,
+
+ /// All possible referrents are instance members of an unrelated
+ /// class.
+ IMA_Error_Unrelated
+};
+
+/// The given lookup names class member(s) and is not being used for
+/// an address-of-member expression. Classify the type of access
+/// according to whether it's possible that this reference names an
+/// instance member. This is best-effort; it is okay to
+/// conservatively answer "yes", in which case some errors will simply
+/// not be caught until template-instantiation.
+static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ Scope *CurScope,
+ const LookupResult &R) {
+ assert(!R.empty() && (*R.begin())->isCXXClassMember());
+
+ DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
+
+ bool isStaticContext =
+ (!isa<CXXMethodDecl>(DC) ||
+ cast<CXXMethodDecl>(DC)->isStatic());
+
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ if (CurScope->getFlags() & Scope::ThisScope)
+ isStaticContext = false;
+
+ if (R.isUnresolvableResult())
+ return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
+
+ // Collect all the declaring classes of instance members we find.
+ bool hasNonInstance = false;
+ bool hasField = false;
+ llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+
+ if (D->isCXXInstanceMember()) {
+ if (dyn_cast<FieldDecl>(D))
+ hasField = true;
+
+ CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
+ Classes.insert(R->getCanonicalDecl());
+ }
+ else
+ hasNonInstance = true;
+ }
+
+ // If we didn't find any instance members, it can't be an implicit
+ // member reference.
+ if (Classes.empty())
+ return IMA_Static;
+
+ // If the current context is not an instance method, it can't be
+ // an implicit member reference.
+ if (isStaticContext) {
+ if (hasNonInstance)
+ return IMA_Mixed_StaticContext;
+
+ if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
+ // C++0x [expr.prim.general]p10:
+ // An id-expression that denotes a non-static data member or non-static
+ // member function of a class can only be used:
+ // (...)
+ // - if that id-expression denotes a non-static data member and it
+ // appears in an unevaluated operand.
+ const Sema::ExpressionEvaluationContextRecord& record
+ = SemaRef.ExprEvalContexts.back();
+ bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated);
+ if (isUnevaluatedExpression)
+ return IMA_Mixed_StaticContext;
+ }
+
+ return IMA_Error_StaticContext;
+ }
+
+ CXXRecordDecl *contextClass;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ contextClass = MD->getParent()->getCanonicalDecl();
+ else
+ contextClass = cast<CXXRecordDecl>(DC);
+
+ // [class.mfct.non-static]p3:
+ // ...is used in the body of a non-static member function of class X,
+ // if name lookup (3.4.1) resolves the name in the id-expression to a
+ // non-static non-type member of some class C [...]
+ // ...if C is not X or a base class of X, the class member access expression
+ // is ill-formed.
+ if (R.getNamingClass() &&
+ contextClass != R.getNamingClass()->getCanonicalDecl() &&
+ contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ // If we can prove that the current context is unrelated to all the
+ // declaring classes, it can't be an implicit member reference (in
+ // which case it's an error if any of those members are selected).
+ if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ return (hasNonInstance ? IMA_Mixed : IMA_Instance);
+}
+
+/// Diagnose a reference to a field with no object available.
+static void DiagnoseInstanceReference(Sema &SemaRef,
+ const CXXScopeSpec &SS,
+ NamedDecl *rep,
+ const DeclarationNameInfo &nameInfo) {
+ SourceLocation Loc = nameInfo.getLoc();
+ SourceRange Range(Loc);
+ if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
+
+ if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
+ if (MD->isStatic()) {
+ // "invalid use of member 'x' in static member function"
+ SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
+ << Range << nameInfo.getName();
+ return;
+ }
+ }
+
+ SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
+ << nameInfo.getName() << Range;
+ return;
+ }
+
+ SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
+}
+
+/// Builds an expression which might be an implicit member expression.
+ExprResult
+Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
+ case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+
+ case IMA_Mixed:
+ case IMA_Mixed_Unrelated:
+ case IMA_Unresolved:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+
+ case IMA_Static:
+ case IMA_Mixed_StaticContext:
+ case IMA_Unresolved_StaticContext:
+ if (TemplateArgs)
+ return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
+ return BuildDeclarationNameExpr(SS, R, false);
+
+ case IMA_Error_StaticContext:
+ case IMA_Error_Unrelated:
+ DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
+ R.getLookupNameInfo());
+ return ExprError();
+ }
+
+ llvm_unreachable("unexpected instance member access kind");
+ return ExprError();
+}
+
+/// Check an ext-vector component access expression.
+///
+/// VK should be set in advance to the value kind of the base
+/// expression.
+static QualType
+CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
+ SourceLocation OpLoc, const IdentifierInfo *CompName,
+ SourceLocation CompLoc) {
+ // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
+ // see FIXME there.
+ //
+ // FIXME: This logic can be greatly simplified by splitting it along
+ // halving/not halving and reworking the component checking.
+ const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
+
+ // The vector accessor can't exceed the number of elements.
+ const char *compStr = CompName->getNameStart();
+
+ // This flag determines whether or not the component is one of the four
+ // special names that indicate a subset of exactly half the elements are
+ // to be selected.
+ bool HalvingSwizzle = false;
+
+ // This flag determines whether or not CompName has an 's' char prefix,
+ // indicating that it is a string of hex values to be used as vector indices.
+ bool HexSwizzle = *compStr == 's' || *compStr == 'S';
+
+ bool HasRepeated = false;
+ bool HasIndex[16] = {};
+
+ int Idx;
+
+ // Check that we've found one of the special components, or that the component
+ // names must come from the same set.
+ if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
+ !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
+ HalvingSwizzle = true;
+ } else if (!HexSwizzle &&
+ (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
+ do {
+ if (HasIndex[Idx]) HasRepeated = true;
+ HasIndex[Idx] = true;
+ compStr++;
+ } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
+ } else {
+ if (HexSwizzle) compStr++;
+ while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
+ if (HasIndex[Idx]) HasRepeated = true;
+ HasIndex[Idx] = true;
+ compStr++;
+ }
+ }
+
+ if (!HalvingSwizzle && *compStr) {
+ // We didn't get to the end of the string. This means the component names
+ // didn't come from the same set *or* we encountered an illegal name.
+ S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
+ << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
+ return QualType();
+ }
+
+ // Ensure no component accessor exceeds the width of the vector type it
+ // operates on.
+ if (!HalvingSwizzle) {
+ compStr = CompName->getNameStart();
+
+ if (HexSwizzle)
+ compStr++;
+
+ while (*compStr) {
+ if (!vecType->isAccessorWithinNumElements(*compStr++)) {
+ S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
+ << baseType << SourceRange(CompLoc);
+ return QualType();
+ }
+ }
+ }
+
+ // The component accessor looks fine - now we need to compute the actual type.
+ // The vector type is implied by the component accessor. For example,
+ // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
+ // vec4.s0 is a float, vec4.s23 is a vec3, etc.
+ // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
+ unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
+ : CompName->getLength();
+ if (HexSwizzle)
+ CompSize--;
+
+ if (CompSize == 1)
+ return vecType->getElementType();
+
+ if (HasRepeated) VK = VK_RValue;
+
+ QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
+ // Now look up the TypeDefDecl from the vector type. Without this,
+ // diagostics look bad. We want extended vector types to appear built-in.
+ for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
+ if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
+ return S.Context.getTypedefType(S.ExtVectorDecls[i]);
+ }
+ return VT; // should never get here (a typedef type should always be found).
+}
+
+static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
+ IdentifierInfo *Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+ if (Member)
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
+ return PD;
+ if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
+ return OMD;
+
+ for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); I != E; ++I) {
+ if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
+ Context))
+ return D;
+ }
+ return 0;
+}
+
+static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
+ IdentifierInfo *Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+ // Check protocols on qualified interfaces.
+ Decl *GDecl = 0;
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ if (Member)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ GDecl = PD;
+ break;
+ }
+ // Also must look for a getter or setter name which uses property syntax.
+ if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
+ GDecl = OMD;
+ break;
+ }
+ }
+ if (!GDecl) {
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ // Search in the protocol-qualifier list of current protocol.
+ GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
+ Context);
+ if (GDecl)
+ return GDecl;
+ }
+ }
+ return GDecl;
+}
+
+ExprResult
+Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
+ bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ // Even in dependent contexts, try to diagnose base expressions with
+ // obviously wrong types, e.g.:
+ //
+ // T* t;
+ // t.f;
+ //
+ // In Obj-C++, however, the above expression is valid, since it could be
+ // accessing the 'f' property if T is an Obj-C interface. The extra check
+ // allows this, while still reporting an error if T is a struct pointer.
+ if (!IsArrow) {
+ const PointerType *PT = BaseType->getAs<PointerType>();
+ if (PT && (!getLangOptions().ObjC1 ||
+ PT->getPointeeType()->isRecordType())) {
+ assert(BaseExpr && "cannot happen with implicit member accesses");
+ Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ assert(BaseType->isDependentType() ||
+ NameInfo.getName().isDependentName() ||
+ isDependentScopeSpecifier(SS));
+
+ // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
+ // must have pointer type, and the accessed type is the pointee.
+ return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
+ IsArrow, OpLoc,
+ SS.getWithLocInContext(Context),
+ FirstQualifierInScope,
+ NameInfo, TemplateArgs));
+}
+
+/// We know that the given qualified member reference points only to
+/// declarations which do not belong to the static type of the base
+/// expression. Diagnose the problem.
+static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
+ Expr *BaseExpr,
+ QualType BaseType,
+ const CXXScopeSpec &SS,
+ NamedDecl *rep,
+ const DeclarationNameInfo &nameInfo) {
+ // If this is an implicit member access, use a different set of
+ // diagnostics.
+ if (!BaseExpr)
+ return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
+
+ SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
+ << SS.getRange() << rep << BaseType;
+}
+
+// Check whether the declarations we found through a nested-name
+// specifier in a member expression are actually members of the base
+// type. The restriction here is:
+//
+// C++ [expr.ref]p2:
+// ... In these cases, the id-expression shall name a
+// member of the class or of one of its base classes.
+//
+// So it's perfectly legitimate for the nested-name specifier to name
+// an unrelated class, and for us to find an overload set including
+// decls from classes which are not superclasses, as long as the decl
+// we actually pick through overload resolution is from a superclass.
+bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
+ QualType BaseType,
+ const CXXScopeSpec &SS,
+ const LookupResult &R) {
+ const RecordType *BaseRT = BaseType->getAs<RecordType>();
+ if (!BaseRT) {
+ // We can't check this yet because the base type is still
+ // dependent.
+ assert(BaseType->isDependentType());
+ return false;
+ }
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ // If this is an implicit member reference and we find a
+ // non-instance member, it's not an error.
+ if (!BaseExpr && !(*I)->isCXXInstanceMember())
+ return false;
+
+ // Note that we use the DC of the decl, not the underlying decl.
+ DeclContext *DC = (*I)->getDeclContext();
+ while (DC->isTransparentContext())
+ DC = DC->getParent();
+
+ if (!DC->isRecord())
+ continue;
+
+ llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
+ MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
+
+ if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ return false;
+ }
+
+ DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
+ R.getRepresentativeDecl(),
+ R.getLookupNameInfo());
+ return true;
+}
+
+static bool
+LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+ SourceRange BaseRange, const RecordType *RTy,
+ SourceLocation OpLoc, CXXScopeSpec &SS,
+ bool HasTemplateArgs) {
+ RecordDecl *RDecl = RTy->getDecl();
+ if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+ SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseRange))
+ return true;
+
+ if (HasTemplateArgs) {
+ // LookupTemplateName doesn't expect these both to exist simultaneously.
+ QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
+
+ bool MOUS;
+ SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
+ return false;
+ }
+
+ DeclContext *DC = RDecl;
+ if (SS.isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = SemaRef.computeDeclContext(SS, false);
+
+ if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
+ SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
+ << SS.getRange() << DC;
+ return true;
+ }
+
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+
+ if (!isa<TypeDecl>(DC)) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
+ << DC << SS.getRange();
+ return true;
+ }
+ }
+
+ // The record definition is complete, now look up the member.
+ SemaRef.LookupQualifiedName(R, DC);
+
+ if (!R.empty())
+ return false;
+
+ // We didn't find anything with the given name, so try to correct
+ // for typos.
+ DeclarationName Name = R.getLookupName();
+ TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), NULL,
+ &SS, DC, false,
+ Sema::CTC_MemberLookup);
+ NamedDecl *ND = Corrected.getCorrectionDecl();
+ R.clear();
+ if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) {
+ std::string CorrectedStr(
+ Corrected.getAsString(SemaRef.getLangOptions()));
+ std::string CorrectedQuotedStr(
+ Corrected.getQuoted(SemaRef.getLangOptions()));
+ R.setLookupName(Corrected.getCorrection());
+ R.addDecl(ND);
+ SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << DC << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
+ }
+
+ return false;
+}
+
+ExprResult
+Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
+ SourceLocation OpLoc, bool IsArrow,
+ CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ if (BaseType->isDependentType() ||
+ (SS.isSet() && isDependentScopeSpecifier(SS)))
+ return ActOnDependentMemberExpr(Base, BaseType,
+ IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
+
+ LookupResult R(*this, NameInfo, LookupMemberName);
+
+ // Implicit member accesses.
+ if (!Base) {
+ QualType RecordTy = BaseType;
+ if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
+ if (LookupMemberExprInRecord(*this, R, SourceRange(),
+ RecordTy->getAs<RecordType>(),
+ OpLoc, SS, TemplateArgs != 0))
+ return ExprError();
+
+ // Explicit member accesses.
+ } else {
+ ExprResult BaseResult = Owned(Base);
+ ExprResult Result =
+ LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
+ SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
+
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
+
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get())
+ return move(Result);
+
+ // LookupMemberExpr can modify Base, and thus change BaseType
+ BaseType = Base->getType();
+ }
+
+ return BuildMemberReferenceExpr(Base, BaseType,
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
+}
+
+static ExprResult
+BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
+ const CXXScopeSpec &SS, FieldDecl *Field,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo);
+
+ExprResult
+Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
+ SourceLocation loc,
+ IndirectFieldDecl *indirectField,
+ Expr *baseObjectExpr,
+ SourceLocation opLoc) {
+ // First, build the expression that refers to the base object.
+
+ bool baseObjectIsPointer = false;
+ Qualifiers baseQuals;
+
+ // Case 1: the base of the indirect field is not a field.
+ VarDecl *baseVariable = indirectField->getVarDecl();
+ CXXScopeSpec EmptySS;
+ if (baseVariable) {
+ assert(baseVariable->getType()->isRecordType());
+
+ // In principle we could have a member access expression that
+ // accesses an anonymous struct/union that's a static member of
+ // the base object's class. However, under the current standard,
+ // static data members cannot be anonymous structs or unions.
+ // Supporting this is as easy as building a MemberExpr here.
+ assert(!baseObjectExpr && "anonymous struct/union is static data member?");
+
+ DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
+
+ ExprResult result
+ = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
+ if (result.isInvalid()) return ExprError();
+
+ baseObjectExpr = result.take();
+ baseObjectIsPointer = false;
+ baseQuals = baseObjectExpr->getType().getQualifiers();
+
+ // Case 2: the base of the indirect field is a field and the user
+ // wrote a member expression.
+ } else if (baseObjectExpr) {
+ // The caller provided the base object expression. Determine
+ // whether its a pointer and whether it adds any qualifiers to the
+ // anonymous struct/union fields we're looking into.
+ QualType objectType = baseObjectExpr->getType();
+
+ if (const PointerType *ptr = objectType->getAs<PointerType>()) {
+ baseObjectIsPointer = true;
+ objectType = ptr->getPointeeType();
+ } else {
+ baseObjectIsPointer = false;
+ }
+ baseQuals = objectType.getQualifiers();
+
+ // Case 3: the base of the indirect field is a field and we should
+ // build an implicit member access.
+ } else {
+ // We've found a member of an anonymous struct/union that is
+ // inside a non-anonymous struct/union, so in a well-formed
+ // program our base object expression is "this".
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) {
+ Diag(loc, diag::err_invalid_member_use_in_static_method)
+ << indirectField->getDeclName();
+ return ExprError();
+ }
+
+ // Our base object expression is "this".
+ baseObjectExpr
+ = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
+ baseObjectIsPointer = true;
+ baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
+ }
+
+ // Build the implicit member references to the field of the
+ // anonymous struct/union.
+ Expr *result = baseObjectExpr;
+ IndirectFieldDecl::chain_iterator
+ FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
+
+ // Build the first member access in the chain with full information.
+ if (!baseVariable) {
+ FieldDecl *field = cast<FieldDecl>(*FI);
+
+ // FIXME: use the real found-decl info!
+ DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
+
+ // Make a nameInfo that properly uses the anonymous name.
+ DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
+
+ result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
+ EmptySS, field, foundDecl,
+ memberNameInfo).take();
+ baseObjectIsPointer = false;
+
+ // FIXME: check qualified member access
+ }
+
+ // In all cases, we should now skip the first declaration in the chain.
+ ++FI;
+
+ while (FI != FEnd) {
+ FieldDecl *field = cast<FieldDecl>(*FI++);
+
+ // FIXME: these are somewhat meaningless
+ DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
+ DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
+
+ result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
+ (FI == FEnd? SS : EmptySS), field,
+ foundDecl, memberNameInfo).take();
+ }
+
+ return Owned(result);
+}
+
+/// \brief Build a MemberExpr AST node.
+static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec &SS, ValueDecl *Member,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo,
+ QualType Ty,
+ ExprValueKind VK, ExprObjectKind OK,
+ const TemplateArgumentListInfo *TemplateArgs = 0) {
+ return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
+ Member, FoundDecl, MemberNameInfo,
+ TemplateArgs, Ty, VK, OK);
+}
+
+ExprResult
+Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
+ SourceLocation OpLoc, bool IsArrow,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck) {
+ QualType BaseType = BaseExprType;
+ if (IsArrow) {
+ assert(BaseType->isPointerType());
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ }
+ R.setBaseObjectType(BaseType);
+
+ const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
+ DeclarationName MemberName = MemberNameInfo.getName();
+ SourceLocation MemberLoc = MemberNameInfo.getLoc();
+
+ if (R.isAmbiguous())
+ return ExprError();
+
+ if (R.empty()) {
+ // Rederive where we looked up.
+ DeclContext *DC = (SS.isSet()
+ ? computeDeclContext(SS, false)
+ : BaseType->getAs<RecordType>()->getDecl());
+
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+ return ExprError();
+ }
+
+ // Diagnose lookups that find only declarations from a non-base
+ // type. This is possible for either qualified lookups (which may
+ // have been qualified with an unrelated type) or implicit member
+ // expressions (which were found with unqualified lookup and thus
+ // may have come from an enclosing scope). Note that it's okay for
+ // lookup to find declarations from a non-base type as long as those
+ // aren't the ones picked by overload resolution.
+ if ((SS.isSet() || !BaseExpr ||
+ (isa<CXXThisExpr>(BaseExpr) &&
+ cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
+ !SuppressQualifierCheck &&
+ CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
+ return ExprError();
+
+ // Construct an unresolved result if we in fact got an unresolved
+ // result.
+ if (R.isOverloadedResult() || R.isUnresolvableResult()) {
+ // Suppress any lookup-related diagnostics; we'll do these when we
+ // pick a member.
+ R.suppressDiagnostics();
+
+ UnresolvedMemberExpr *MemExpr
+ = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
+ BaseExpr, BaseExprType,
+ IsArrow, OpLoc,
+ SS.getWithLocInContext(Context),
+ MemberNameInfo,
+ TemplateArgs, R.begin(), R.end());
+
+ return Owned(MemExpr);
+ }
+
+ assert(R.isSingleResult());
+ DeclAccessPair FoundDecl = R.begin().getPair();
+ NamedDecl *MemberDecl = R.getFoundDecl();
+
+ // FIXME: diagnose the presence of template arguments now.
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (MemberDecl->isInvalidDecl())
+ return ExprError();
+
+ // Handle the implicit-member-access case.
+ if (!BaseExpr) {
+ // If this is not an instance member, convert to a non-member access.
+ if (!MemberDecl->isCXXInstanceMember())
+ return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
+
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
+ }
+
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && !SS.isSet())
+ ShouldCheckUse = false;
+ }
+
+ // Check the use of this member.
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
+ Owned(BaseExpr);
+ return ExprError();
+ }
+
+ // Perform a property load on the base regardless of whether we
+ // actually need it for the declaration.
+ if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(BaseExpr);
+ if (Result.isInvalid())
+ return ExprError();
+ BaseExpr = Result.take();
+ }
+
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
+ return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
+ SS, FD, FoundDecl, MemberNameInfo);
+
+ if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
+ BaseExpr, OpLoc);
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, Var);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Var, FoundDecl, MemberNameInfo,
+ Var->getType().getNonReferenceType(),
+ VK_LValue, OK_Ordinary));
+ }
+
+ if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ ExprValueKind valueKind;
+ QualType type;
+ if (MemberFn->isInstance()) {
+ valueKind = VK_RValue;
+ type = Context.BoundMemberTy;
+ } else {
+ valueKind = VK_LValue;
+ type = MemberFn->getType();
+ }
+
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ MemberFn, FoundDecl, MemberNameInfo,
+ type, valueKind, OK_Ordinary));
+ }
+ assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
+
+ if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Enum, FoundDecl, MemberNameInfo,
+ Enum->getType(), VK_RValue, OK_Ordinary));
+ }
+
+ Owned(BaseExpr);
+
+ // We found something that we didn't expect. Complain.
+ if (isa<TypeDecl>(MemberDecl))
+ Diag(MemberLoc, diag::err_typecheck_member_reference_type)
+ << MemberName << BaseType << int(IsArrow);
+ else
+ Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
+ << MemberName << BaseType << int(IsArrow);
+
+ Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
+ << MemberName;
+ R.suppressDiagnostics();
+ return ExprError();
+}
+
+/// Given that normal member access failed on the given expression,
+/// and given that the expression's type involves builtin-id or
+/// builtin-Class, decide whether substituting in the redefinition
+/// types would be profitable. The redefinition type is whatever
+/// this translation unit tried to typedef to id/Class; we store
+/// it to the side and then re-use it in places like this.
+static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
+ const ObjCObjectPointerType *opty
+ = base.get()->getType()->getAs<ObjCObjectPointerType>();
+ if (!opty) return false;
+
+ const ObjCObjectType *ty = opty->getObjectType();
+
+ QualType redef;
+ if (ty->isObjCId()) {
+ redef = S.Context.ObjCIdRedefinitionType;
+ } else if (ty->isObjCClass()) {
+ redef = S.Context.ObjCClassRedefinitionType;
+ } else {
+ return false;
+ }
+
+ // Do the substitution as long as the redefinition type isn't just a
+ // possibly-qualified pointer to builtin-id or builtin-Class again.
+ opty = redef->getAs<ObjCObjectPointerType>();
+ if (opty && !opty->getObjectType()->getInterface() != 0)
+ return false;
+
+ base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
+ return true;
+}
+
+/// Look up the given member of the given non-type-dependent
+/// expression. This can return in one of two ways:
+/// * If it returns a sentinel null-but-valid result, the caller will
+/// assume that lookup was performed and the results written into
+/// the provided structure. It will take over from there.
+/// * Otherwise, the returned expression will be produced in place of
+/// an ordinary member expression.
+///
+/// The ObjCImpDecl bit is a gross hack that will need to be properly
+/// fixed for ObjC++.
+ExprResult
+Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
+ bool &IsArrow, SourceLocation OpLoc,
+ CXXScopeSpec &SS,
+ Decl *ObjCImpDecl, bool HasTemplateArgs) {
+ assert(BaseExpr.get() && "no base expression");
+
+ // Perform default conversions.
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+
+ if (IsArrow) {
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+ }
+
+ QualType BaseType = BaseExpr.get()->getType();
+ assert(!BaseType->isDependentType());
+
+ DeclarationName MemberName = R.getLookupName();
+ SourceLocation MemberLoc = R.getNameLoc();
+
+ // For later type-checking purposes, turn arrow accesses into dot
+ // accesses. The only access type we support that doesn't follow
+ // the C equivalence "a->b === (*a).b" is ObjC property accesses,
+ // and those never use arrows, so this is unaffected.
+ if (IsArrow) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (const ObjCObjectPointerType *Ptr
+ = BaseType->getAs<ObjCObjectPointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (BaseType->isRecordType()) {
+ // Recover from arrow accesses to records, e.g.:
+ // struct MyRecord foo;
+ // foo->bar
+ // This is actually well-formed in C++ if MyRecord has an
+ // overloaded operator->, but that should have been dealt with
+ // by now.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ IsArrow = false;
+ } else if (BaseType == Context.BoundMemberTy) {
+ goto fail;
+ } else {
+ Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr.get()->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ // Handle field access to simple records.
+ if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
+ if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
+ RTy, OpLoc, SS, HasTemplateArgs))
+ return ExprError();
+
+ // Returning valid-but-null is how we indicate to the caller that
+ // the lookup result was filled in.
+ return Owned((Expr*) 0);
+ }
+
+ // Handle ivar access to Objective-C objects.
+ if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ // There are three cases for the base type:
+ // - builtin id (qualified or unqualified)
+ // - builtin Class (qualified or unqualified)
+ // - an interface
+ ObjCInterfaceDecl *IDecl = OTy->getInterface();
+ if (!IDecl) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ (OTy->isObjCId() || OTy->isObjCClass()))
+ goto fail;
+ // There's an implicit 'isa' ivar on all objects.
+ // But we only actually find it this way on objects of type 'id',
+ // apparently.
+ if (OTy->isObjCId() && Member->isStr("isa"))
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
+ Context.getObjCClassType()));
+
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ goto fail;
+ }
+
+ ObjCInterfaceDecl *ClassDeclared;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
+
+ if (!IV) {
+ // Attempt to correct for typos in ivar names.
+ LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
+ LookupMemberName);
+ TypoCorrection Corrected = CorrectTypo(
+ R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false,
+ IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup);
+ if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) {
+ Diag(R.getNameLoc(),
+ diag::err_typecheck_member_reference_ivar_suggest)
+ << IDecl->getDeclName() << MemberName << IV->getDeclName()
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ IV->getNameAsString());
+ Diag(IV->getLocation(), diag::note_previous_decl)
+ << IV->getDeclName();
+ } else {
+ if (IsArrow && IDecl->FindPropertyDeclaration(Member)) {
+ Diag(MemberLoc,
+ diag::err_property_found_suggest)
+ << Member << BaseExpr.get()->getType()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ return ExprError();
+ }
+ Res.clear();
+ Res.setLookupName(Member);
+
+ Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IDecl->getDeclName() << MemberName
+ << BaseExpr.get()->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check whether we can reference this field.
+ if (DiagnoseUseOfDecl(IV, MemberLoc))
+ return ExprError();
+ if (IV->getAccessControl() != ObjCIvarDecl::Public &&
+ IV->getAccessControl() != ObjCIvarDecl::Package) {
+ ObjCInterfaceDecl *ClassOfMethodDecl = 0;
+ if (ObjCMethodDecl *MD = getCurMethodDecl())
+ ClassOfMethodDecl = MD->getClassInterface();
+ else if (ObjCImpDecl && getCurFunctionDecl()) {
+ // Case of a c-function declared inside an objc implementation.
+ // FIXME: For a c-style function nested inside an objc implementation
+ // class, there is no implementation context available, so we pass
+ // down the context as argument to this routine. Ideally, this context
+ // need be passed down in the AST node and somehow calculated from the
+ // AST for a function decl.
+ if (ObjCImplementationDecl *IMPD =
+ dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
+ ClassOfMethodDecl = IMPD->getClassInterface();
+ else if (ObjCCategoryImplDecl* CatImplClass =
+ dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
+ ClassOfMethodDecl = CatImplClass->getClassInterface();
+ }
+
+ if (IV->getAccessControl() == ObjCIvarDecl::Private) {
+ if (ClassDeclared != IDecl ||
+ ClassOfMethodDecl != ClassDeclared)
+ Diag(MemberLoc, diag::error_private_ivar_access)
+ << IV->getDeclName();
+ } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
+ // @protected
+ Diag(MemberLoc, diag::error_protected_ivar_access)
+ << IV->getDeclName();
+ }
+ if (getLangOptions().ObjCAutoRefCount) {
+ Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
+ if (UO->getOpcode() == UO_Deref)
+ BaseExp = UO->getSubExpr()->IgnoreParenCasts();
+
+ if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp))
+ if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ Diag(DE->getLocation(), diag::error_arc_weak_ivar_access);
+ }
+
+ return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc, BaseExpr.take(),
+ IsArrow));
+ }
+
+ // Objective-C property access.
+ const ObjCObjectPointerType *OPT;
+ if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
+ // This actually uses the base as an r-value.
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+
+ assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
+
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ const ObjCObjectType *OT = OPT->getObjectType();
+
+ // id, with and without qualifiers.
+ if (OT->isObjCId()) {
+ // Check protocols on qualified interfaces.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) {
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
+ // Check the use of this declaration
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(BaseType, Getter, false, false);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ VK_LValue,
+ OK_ObjCProperty,
+ MemberLoc,
+ BaseExpr.take()));
+ }
+
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(OMD, MemberLoc))
+ return ExprError();
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *SMD = 0;
+ if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
+ SetterSel, Context))
+ SMD = dyn_cast<ObjCMethodDecl>(SDecl);
+ QualType PType = getMessageSendResultType(BaseType, OMD, false,
+ false);
+
+ ExprValueKind VK = VK_LValue;
+ if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
+ VK = VK_RValue;
+ ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
+ VK, OK,
+ MemberLoc, BaseExpr.take()));
+ }
+ }
+ // Use of id.member can only be for a property reference. Do not
+ // use the 'id' redefinition in this case.
+ if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+
+ // 'Class', unqualified only.
+ if (OT->isObjCClass()) {
+ // Only works in a method declaration (??!).
+ ObjCMethodDecl *MD = getCurMethodDecl();
+ if (!MD) {
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ goto fail;
+ }
+
+ // Also must look for a getter name which uses property syntax.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ ObjCMethodDecl *Getter;
+ if ((Getter = IFace->lookupClassMethod(Sel))) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ } else
+ Getter = IFace->lookupPrivateMethod(Sel, false);
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = IFace->lookupPrivateMethod(SetterSel, false);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter)
+ Setter = IFace->getCategoryClassMethod(SetterSel);
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ ExprValueKind VK = VK_LValue;
+ if (Getter) {
+ PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
+ false);
+ if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
+ VK = VK_RValue;
+ } else {
+ // Get the expression type from Setter's incoming parameter.
+ PType = (*(Setter->param_end() -1))->getType();
+ }
+ ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+
+ // FIXME: we must check that the setter has property type.
+ return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
+ PType, VK, OK,
+ MemberLoc, BaseExpr.take()));
+ }
+
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+
+ // Normal property access.
+ return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), OpLoc,
+ MemberName, MemberLoc,
+ SourceLocation(), QualType(), false);
+ }
+
+ // Handle 'field access' to vectors, such as 'V.xx'.
+ if (BaseType->isExtVectorType()) {
+ // FIXME: this expr should store IsArrow.
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
+ QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
+ Member, MemberLoc);
+ if (ret.isNull())
+ return ExprError();
+
+ return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
+ *Member, MemberLoc));
+ }
+
+ // Adjust builtin-sel to the appropriate redefinition type if that's
+ // not just a pointer to builtin-sel again.
+ if (IsArrow &&
+ BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
+ !Context.ObjCSelRedefinitionType->isObjCSelType()) {
+ BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
+ CK_BitCast);
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+
+ // Failure cases.
+ fail:
+
+ // Recover from dot accesses to pointers, e.g.:
+ // type *foo;
+ // foo.bar
+ // This is actually well-formed in two cases:
+ // - 'type' is an Objective C type
+ // - 'bar' is a pseudo-destructor name which happens to refer to
+ // the appropriate pointer type
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
+ if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
+ MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, "->");
+
+ // Recurse as an -> access.
+ IsArrow = true;
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+ }
+
+ // If the user is trying to apply -> or . to a function name, it's probably
+ // because they forgot parentheses to call that function.
+ QualType ZeroArgCallTy;
+ UnresolvedSet<4> Overloads;
+ if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
+ if (ZeroArgCallTy.isNull()) {
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
+ UnresolvedSet<2> PlausibleOverloads;
+ for (OverloadExpr::decls_iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
+ QualType OverloadResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && OverloadResultTy->isRecordType()) ||
+ (IsArrow && OverloadResultTy->isPointerType() &&
+ OverloadResultTy->getPointeeType()->isRecordType()))
+ PlausibleOverloads.addDecl(It.getDecl());
+ }
+ NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
+ return ExprError();
+ }
+ if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
+ (IsArrow && ZeroArgCallTy->isPointerType() &&
+ ZeroArgCallTy->getPointeeType()->isRecordType())) {
+ // At this point, we know BaseExpr looks like it's potentially callable
+ // with 0 arguments, and that it returns something of a reasonable type,
+ // so we can emit a fixit and carry on pretending that BaseExpr was
+ // actually a CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ // FIXME: Try this before emitting the fixit, and suppress diagnostics
+ // while doing so.
+ ExprResult NewBase =
+ ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc.getFileLocWithOffset(1));
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase;
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+ }
+
+ Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr.get()->getSourceRange();
+
+ return ExprError();
+}
+
+/// The main callback when the parser finds something like
+/// expression . [nested-name-specifier] identifier
+/// expression -> [nested-name-specifier] identifier
+/// where 'identifier' encompasses a fairly broad spectrum of
+/// possibilities, including destructor and operator references.
+///
+/// \param OpKind either tok::arrow or tok::period
+/// \param HasTrailingLParen whether the next token is '(', which
+/// is used to diagnose mis-uses of special members that can
+/// only be called
+/// \param ObjCImpDecl the current ObjC @implementation decl;
+/// this is an ugly hack around the fact that ObjC @implementations
+/// aren't properly put in the context chain
+ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ CXXScopeSpec &SS,
+ UnqualifiedId &Id,
+ Decl *ObjCImpDecl,
+ bool HasTrailingLParen) {
+ if (SS.isSet() && SS.isInvalid())
+ return ExprError();
+
+ // Warn about the explicit constructor calls Microsoft extension.
+ if (getLangOptions().Microsoft &&
+ Id.getKind() == UnqualifiedId::IK_ConstructorName)
+ Diag(Id.getSourceRange().getBegin(),
+ diag::ext_ms_explicit_constructor_call);
+
+ TemplateArgumentListInfo TemplateArgsBuffer;
+
+ // Decompose the name into its component parts.
+ DeclarationNameInfo NameInfo;
+ const TemplateArgumentListInfo *TemplateArgs;
+ DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
+ NameInfo, TemplateArgs);
+
+ DeclarationName Name = NameInfo.getName();
+ bool IsArrow = (OpKind == tok::arrow);
+
+ NamedDecl *FirstQualifierInScope
+ = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
+
+ // This is a postfix expression, so get rid of ParenListExprs.
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
+ if (Result.isInvalid()) return ExprError();
+ Base = Result.take();
+
+ if (Base->getType()->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS)) {
+ Result = ActOnDependentMemberExpr(Base, Base->getType(),
+ IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
+ } else {
+ LookupResult R(*this, NameInfo, LookupMemberName);
+ ExprResult BaseResult = Owned(Base);
+ Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
+ SS, ObjCImpDecl, TemplateArgs != 0);
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
+
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get()) {
+ // The only way a reference to a destructor can be used is to
+ // immediately call it, which falls into this case. If the
+ // next token is not a '(', produce a diagnostic and build the
+ // call now.
+ if (!HasTrailingLParen &&
+ Id.getKind() == UnqualifiedId::IK_DestructorName)
+ return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
+
+ return move(Result);
+ }
+
+ Result = BuildMemberReferenceExpr(Base, Base->getType(),
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
+ }
+
+ return move(Result);
+}
+
+static ExprResult
+BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
+ const CXXScopeSpec &SS, FieldDecl *Field,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo) {
+ // x.a is an l-value if 'a' has a reference type. Otherwise:
+ // x.a is an l-value/x-value/pr-value if the base is (and note
+ // that *x is always an l-value), except that if the base isn't
+ // an ordinary object then we must have an rvalue.
+ ExprValueKind VK = VK_LValue;
+ ExprObjectKind OK = OK_Ordinary;
+ if (!IsArrow) {
+ if (BaseExpr->getObjectKind() == OK_Ordinary)
+ VK = BaseExpr->getValueKind();
+ else
+ VK = VK_RValue;
+ }
+ if (VK != VK_RValue && Field->isBitField())
+ OK = OK_BitField;
+
+ // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
+ QualType MemberType = Field->getType();
+ if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
+ MemberType = Ref->getPointeeType();
+ VK = VK_LValue;
+ } else {
+ QualType BaseType = BaseExpr->getType();
+ if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+
+ // GC attributes are never picked up by members.
+ BaseQuals.removeObjCGCAttr();
+
+ // CVR attributes from the base are picked up by members,
+ // except that 'mutable' members don't pick up 'const'.
+ if (Field->isMutable()) BaseQuals.removeConst();
+
+ Qualifiers MemberQuals
+ = S.Context.getCanonicalType(MemberType).getQualifiers();
+
+ // TR 18037 does not allow fields to be declared with address spaces.
+ assert(!MemberQuals.hasAddressSpace());
+
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ MemberType = S.Context.getQualifiedType(MemberType, Combined);
+ }
+
+ S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
+ ExprResult Base =
+ S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
+ FoundDecl, Field);
+ if (Base.isInvalid())
+ return ExprError();
+ return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
+ Field, FoundDecl, MemberNameInfo,
+ MemberType, VK, OK));
+}
+
+/// Builds an implicit member access expression. The current context
+/// is known to be an instance method, and the given unqualified lookup
+/// set is known to contain only instance members, at least one of which
+/// is from an appropriate type.
+ExprResult
+Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsKnownInstance) {
+ assert(!R.empty() && !R.isAmbiguous());
+
+ SourceLocation loc = R.getNameLoc();
+
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ // FIXME: template-ids inside anonymous structs?
+ if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
+ return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
+
+ // If this is known to be an instance access, go ahead and build an
+ // implicit 'this' expression now.
+ // 'this' expression now.
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
+
+ Expr *baseExpr = 0; // null signifies implicit access
+ if (IsKnownInstance) {
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
+ }
+
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ true,
+ SS,
+ /*FirstQualifierInScope*/ 0,
+ R, TemplateArgs);
+}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index cb5c1e0..02a4682 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/SmallString.h"
#include "clang/Lex/Preprocessor.h"
@@ -62,7 +63,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// Create the aggregate string with the appropriate content and location
// information.
- S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(),
+ S = StringLiteral::Create(Context, StrBuf,
/*Wide=*/false, /*Pascal=*/false,
Context.getPointerType(Context.CharTy),
&StrLocs[0], StrLocs.size());
@@ -127,7 +128,8 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
else {
- if (!EncodedType->getAsArrayTypeUnsafe()) // Incomplete array is handled.
+ if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled.
+ !EncodedType->isVoidType()) // void is handled too.
if (RequireCompleteType(AtLoc, EncodedType,
PDiag(diag::err_incomplete_type_objc_at_encode)
<< EncodedTypeInfo->getTypeLoc().getSourceRange()))
@@ -176,12 +178,39 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
SourceRange(LParenLoc, RParenLoc));
if (!Method)
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
+
+ if (!Method ||
+ Method->getImplementationControl() != ObjCMethodDecl::Optional) {
+ llvm::DenseMap<Selector, SourceLocation>::iterator Pos
+ = ReferencedSelectors.find(Sel);
+ if (Pos == ReferencedSelectors.end())
+ ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
+ }
- llvm::DenseMap<Selector, SourceLocation>::iterator Pos
- = ReferencedSelectors.find(Sel);
- if (Pos == ReferencedSelectors.end())
- ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
-
+ // In ARC, forbid the user from using @selector for
+ // retain/release/autorelease/dealloc/retainCount.
+ if (getLangOptions().ObjCAutoRefCount) {
+ switch (Sel.getMethodFamily()) {
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ case OMF_dealloc:
+ Diag(AtLoc, diag::err_arc_illegal_selector) <<
+ Sel << SourceRange(LParenLoc, RParenLoc);
+ break;
+
+ case OMF_None:
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_init:
+ case OMF_mutableCopy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_performSelector:
+ break;
+ }
+ }
QualType Ty = Context.getObjCSelType();
return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
}
@@ -321,11 +350,22 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
Args[i] = Result.take();
}
- unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
- diag::warn_inst_method_not_found;
+ unsigned DiagID;
+ if (getLangOptions().ObjCAutoRefCount)
+ DiagID = diag::err_arc_method_not_found;
+ else
+ DiagID = isClassMessage ? diag::warn_class_method_not_found
+ : diag::warn_inst_method_not_found;
Diag(lbrac, DiagID)
<< Sel << isClassMessage << SourceRange(lbrac, rbrac);
- ReturnType = Context.getObjCIdType();
+
+ // In debuggers, we want to use __unknown_anytype for these
+ // results so that clients can cast them.
+ if (getLangOptions().DebuggerSupport) {
+ ReturnType = Context.UnknownAnyTy;
+ } else {
+ ReturnType = Context.getObjCIdType();
+ }
VK = VK_RValue;
return false;
}
@@ -404,17 +444,15 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
return IsError;
}
-bool Sema::isSelfExpr(Expr *RExpr) {
+bool Sema::isSelfExpr(Expr *receiver) {
// 'self' is objc 'self' in an objc method only.
DeclContext *DC = CurContext;
while (isa<BlockDecl>(DC))
DC = DC->getParent();
if (DC && !isa<ObjCMethodDecl>(DC))
return false;
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr))
- if (ICE->getCastKind() == CK_LValueToRValue)
- RExpr = ICE->getSubExpr();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr))
+ receiver = receiver->IgnoreParenLValueCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))
if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self"))
return true;
return false;
@@ -489,7 +527,8 @@ ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
/// objective C interface. This is a property reference expression.
ExprResult Sema::
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
- Expr *BaseExpr, DeclarationName MemberName,
+ Expr *BaseExpr, SourceLocation OpLoc,
+ DeclarationName MemberName,
SourceLocation MemberLoc,
SourceLocation SuperLoc, QualType SuperType,
bool Super) {
@@ -635,17 +674,19 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
// Attempt to correct for typos in property names.
- LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName);
- if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) &&
- Res.getAsSingle<ObjCPropertyDecl>()) {
- DeclarationName TypoResult = Res.getLookupName();
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
+ NULL, IFace, false, CTC_NoKeywords, OPT);
+ if (ObjCPropertyDecl *Property =
+ Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) {
+ DeclarationName TypoResult = Corrected.getCorrection();
Diag(MemberLoc, diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0) << TypoResult
<< FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
- ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
Diag(Property->getLocation(), diag::note_previous_decl)
<< Property->getDeclName();
- return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc,
+ return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
+ TypoResult, MemberLoc,
SuperLoc, SuperType, Super);
}
ObjCInterfaceDecl *ClassDeclared;
@@ -663,6 +704,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
return ExprError();
}
}
+ Diag(MemberLoc,
+ diag::err_ivar_access_using_property_syntax_suggest)
+ << MemberName << QualType(OPT, 0) << Ivar->getDeclName()
+ << FixItHint::CreateReplacement(OpLoc, "->");
+ return ExprError();
}
Diag(MemberLoc, diag::err_property_not_found)
@@ -699,7 +745,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
T = Context.getObjCObjectPointerType(T);
return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
- /*BaseExpr*/0, &propertyName,
+ /*BaseExpr*/0,
+ SourceLocation()/*OpLoc*/,
+ &propertyName,
propertyNameLoc,
receiverNameLoc, T, true);
}
@@ -862,29 +910,30 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
Method->getClassInterface()->getSuperClass())
CTC = CTC_ObjCMessageReceiver;
- if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) {
- if (Result.isSingleResult()) {
+ if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
+ Result.getLookupKind(), S, NULL,
+ NULL, false, CTC)) {
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
// If we found a declaration, correct when it refers to an Objective-C
// class.
- NamedDecl *ND = Result.getFoundDecl();
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Result.getLookupName()
+ << Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc),
ND->getNameAsString());
Diag(ND->getLocation(), diag::note_previous_decl)
- << Corrected;
+ << Corrected.getCorrection();
QualType T = Context.getObjCInterfaceType(Class);
TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
ReceiverType = CreateParsedType(T, TSInfo);
return ObjCClassMessage;
}
- } else if (Result.empty() && Corrected.getAsIdentifierInfo() &&
- Corrected.getAsIdentifierInfo()->isStr("super")) {
+ } else if (Corrected.isKeyword() &&
+ Corrected.getCorrectionAsIdentifierInfo()->isStr("super")) {
// If we've found the keyword "super", this is a send to super.
Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Corrected
+ << Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
return ObjCSuperMessage;
}
@@ -1013,11 +1062,16 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
// Find the method we are messaging.
if (!Method) {
if (Class->isForwardDecl()) {
+ if (getLangOptions().ObjCAutoRefCount) {
+ Diag(Loc, diag::err_arc_receiver_forward_class) << ReceiverType;
+ } else {
+ Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
+ }
+
// A forward class used in messaging is treated as a 'Class'
- Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
- if (Method)
+ if (Method && !getLangOptions().ObjCAutoRefCount)
Diag(Method->getLocation(), diag::note_method_sent_forward_class)
<< Method->getDeclName();
}
@@ -1236,6 +1290,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
= ReceiverType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
ClassDecl = OCIType->getInterfaceDecl();
+
+ if (ClassDecl->isForwardDecl() && getLangOptions().ObjCAutoRefCount) {
+ Diag(Loc, diag::err_arc_receiver_forward_instance)
+ << OCIType->getPointeeType()
+ << (Receiver ? Receiver->getSourceRange() : SourceRange(SuperLoc));
+ return ExprError();
+ }
+
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to MethodPool.
@@ -1250,6 +1312,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+ if (!Method && getLangOptions().ObjCAutoRefCount) {
+ Diag(Loc, diag::err_arc_may_not_respond)
+ << OCIType->getPointeeType() << Sel;
+ return ExprError();
+ }
+
if (!Method && (!Receiver || !isSelfExpr(Receiver))) {
// If we still haven't found a method, look in the global pool. This
// behavior isn't very desirable, however we need it for GCC
@@ -1267,10 +1335,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass))
return ExprError();
- } else if (!Context.getObjCIdType().isNull() &&
+ } else if (!getLangOptions().ObjCAutoRefCount &&
+ !Context.getObjCIdType().isNull() &&
(ReceiverType->isPointerType() ||
ReceiverType->isIntegerType())) {
// Implicitly convert integers and pointers to 'id' but emit a warning.
+ // But not in ARC.
Diag(Loc, diag::warn_bad_receiver_type)
<< ReceiverType
<< Receiver->getSourceRange();
@@ -1332,8 +1402,84 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
diag::err_illegal_message_expr_incomplete_type))
return ExprError();
+ // In ARC, forbid the user from sending messages to
+ // retain/release/autorelease/dealloc/retainCount explicitly.
+ if (getLangOptions().ObjCAutoRefCount) {
+ ObjCMethodFamily family =
+ (Method ? Method->getMethodFamily() : Sel.getMethodFamily());
+ switch (family) {
+ case OMF_init:
+ if (Method)
+ checkInitMethod(Method, ReceiverType);
+
+ case OMF_None:
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ case OMF_self:
+ break;
+
+ case OMF_dealloc:
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ Diag(Loc, diag::err_arc_illegal_explicit_message)
+ << Sel << SelectorLoc;
+ break;
+
+ case OMF_performSelector:
+ if (Method && NumArgs >= 1) {
+ if (ObjCSelectorExpr *SelExp = dyn_cast<ObjCSelectorExpr>(Args[0])) {
+ Selector ArgSel = SelExp->getSelector();
+ ObjCMethodDecl *SelMethod =
+ LookupInstanceMethodInGlobalPool(ArgSel,
+ SelExp->getSourceRange());
+ if (!SelMethod)
+ SelMethod =
+ LookupFactoryMethodInGlobalPool(ArgSel,
+ SelExp->getSourceRange());
+ if (SelMethod) {
+ ObjCMethodFamily SelFamily = SelMethod->getMethodFamily();
+ switch (SelFamily) {
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_init:
+ // Issue error, unless ns_returns_not_retained.
+ if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
+ // selector names a +1 method
+ Diag(SelectorLoc,
+ diag::err_arc_perform_selector_retains);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ }
+ break;
+ default:
+ // +0 call. OK. unless ns_returns_retained.
+ if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) {
+ // selector names a +1 method
+ Diag(SelectorLoc,
+ diag::err_arc_perform_selector_retains);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ }
+ break;
+ }
+ }
+ } else {
+ // error (may leak).
+ Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks);
+ Diag(Args[0]->getExprLoc(), diag::note_used_here);
+ }
+ }
+ break;
+ }
+ }
+
// Construct the appropriate ObjCMessageExpr instance.
- Expr *Result;
+ ObjCMessageExpr *Result;
if (SuperLoc.isValid())
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
SuperLoc, /*IsInstanceSuper=*/true,
@@ -1343,6 +1489,27 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
Receiver, Sel, SelectorLoc, Method,
Args, NumArgs, RBracLoc);
+
+ if (getLangOptions().ObjCAutoRefCount) {
+ // In ARC, annotate delegate init calls.
+ if (Result->getMethodFamily() == OMF_init &&
+ (SuperLoc.isValid() || isSelfExpr(Receiver))) {
+ // Only consider init calls *directly* in init implementations,
+ // not within blocks.
+ ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CurContext);
+ if (method && method->getMethodFamily() == OMF_init) {
+ // The implicit assignment to self means we also don't want to
+ // consume the result.
+ Result->setDelegateInitCall(true);
+ return Owned(Result);
+ }
+ }
+
+ // In ARC, check for message sends which are likely to introduce
+ // retain cycles.
+ checkRetainCycles(Result);
+ }
+
return MaybeBindToTemporary(Result);
}
@@ -1364,3 +1531,393 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
LBracLoc, SelectorLoc, RBracLoc, move(Args));
}
+enum ARCConversionTypeClass {
+ ACTC_none,
+ ACTC_retainable,
+ ACTC_indirectRetainable
+};
+static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) {
+ ARCConversionTypeClass ACTC = ACTC_retainable;
+
+ // Ignore an outermost reference type.
+ if (const ReferenceType *ref = type->getAs<ReferenceType>())
+ type = ref->getPointeeType();
+
+ // Drill through pointers and arrays recursively.
+ while (true) {
+ if (const PointerType *ptr = type->getAs<PointerType>()) {
+ type = ptr->getPointeeType();
+ } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) {
+ type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0);
+ } else {
+ break;
+ }
+ ACTC = ACTC_indirectRetainable;
+ }
+
+ if (!type->isObjCRetainableType()) return ACTC_none;
+ return ACTC;
+}
+
+namespace {
+ /// Return true if the given expression can be reasonably converted
+ /// between a retainable pointer type and a C pointer type.
+ struct ARCCastChecker : StmtVisitor<ARCCastChecker, bool> {
+ ASTContext &Context;
+ ARCCastChecker(ASTContext &Context) : Context(Context) {}
+ bool VisitStmt(Stmt *s) {
+ return false;
+ }
+ bool VisitExpr(Expr *e) {
+ return e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
+ }
+
+ bool VisitParenExpr(ParenExpr *e) {
+ return Visit(e->getSubExpr());
+ }
+ bool VisitCastExpr(CastExpr *e) {
+ switch (e->getCastKind()) {
+ case CK_NullToPointer:
+ return true;
+ case CK_NoOp:
+ case CK_LValueToRValue:
+ case CK_BitCast:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ return Visit(e->getSubExpr());
+ default:
+ return false;
+ }
+ }
+ bool VisitUnaryExtension(UnaryOperator *e) {
+ return Visit(e->getSubExpr());
+ }
+ bool VisitBinComma(BinaryOperator *e) {
+ return Visit(e->getRHS());
+ }
+ bool VisitConditionalOperator(ConditionalOperator *e) {
+ // Conditional operators are okay if both sides are okay.
+ return Visit(e->getTrueExpr()) && Visit(e->getFalseExpr());
+ }
+ bool VisitObjCStringLiteral(ObjCStringLiteral *e) {
+ // Always white-list Objective-C string literals.
+ return true;
+ }
+ bool VisitStmtExpr(StmtExpr *e) {
+ return Visit(e->getSubStmt()->body_back());
+ }
+ bool VisitDeclRefExpr(DeclRefExpr *e) {
+ // White-list references to global extern strings from system
+ // headers.
+ if (VarDecl *var = dyn_cast<VarDecl>(e->getDecl()))
+ if (var->getStorageClass() == SC_Extern &&
+ var->getType().isConstQualified() &&
+ Context.getSourceManager().isInSystemHeader(var->getLocation()))
+ return true;
+ return false;
+ }
+ };
+}
+
+bool
+Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) {
+ Expr *NewExp = Exp->IgnoreParenCasts();
+
+ if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp)
+ && !isa<CallExpr>(NewExp))
+ return false;
+ ObjCMethodDecl *method = 0;
+ bool MethodReturnsPlusOne = false;
+
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) {
+ method = PRE->getExplicitProperty()->getGetterMethodDecl();
+ }
+ else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(NewExp))
+ method = ME->getMethodDecl();
+ else {
+ CallExpr *CE = cast<CallExpr>(NewExp);
+ Decl *CallDecl = CE->getCalleeDecl();
+ if (!CallDecl)
+ return false;
+ if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>())
+ return true;
+ MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>();
+ if (!MethodReturnsPlusOne) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl))
+ if (const IdentifierInfo *Id = ND->getIdentifier())
+ if (Id->isStr("__builtin___CFStringMakeConstantString"))
+ return true;
+ }
+ }
+
+ if (!MethodReturnsPlusOne) {
+ if (!method)
+ return false;
+ if (method->hasAttr<CFReturnsNotRetainedAttr>())
+ return true;
+ MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>();
+ if (!MethodReturnsPlusOne) {
+ ObjCMethodFamily family = method->getSelector().getMethodFamily();
+ switch (family) {
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ MethodReturnsPlusOne = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (MethodReturnsPlusOne) {
+ TypeSourceInfo *TSInfo =
+ Context.getTrivialTypeSourceInfo(castType, SourceLocation());
+ ExprResult ExpRes = BuildObjCBridgedCast(SourceLocation(), OBC_BridgeTransfer,
+ SourceLocation(), TSInfo, Exp);
+ Exp = ExpRes.take();
+ }
+ return true;
+}
+
+void
+Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
+ Expr *&castExpr, CheckedConversionKind CCK) {
+ QualType castExprType = castExpr->getType();
+
+ ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
+ ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
+ if (exprACTC == castACTC) return;
+ if (exprACTC && castType->isIntegralType(Context)) return;
+
+ // Allow casts between pointers to lifetime types (e.g., __strong id*)
+ // and pointers to void (e.g., cv void *). Casting from void* to lifetime*
+ // must be explicit.
+ if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
+ if (const PointerType *CastExprPtr = castExprType->getAs<PointerType>()) {
+ QualType CastPointee = CastPtr->getPointeeType();
+ QualType CastExprPointee = CastExprPtr->getPointeeType();
+ if ((CCK != CCK_ImplicitConversion &&
+ CastPointee->isObjCIndirectLifetimeType() &&
+ CastExprPointee->isVoidType()) ||
+ (CastPointee->isVoidType() &&
+ CastExprPointee->isObjCIndirectLifetimeType()))
+ return;
+ }
+ }
+
+ if (ARCCastChecker(Context).Visit(castExpr))
+ return;
+
+ SourceLocation loc =
+ (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
+
+ if (makeUnavailableInSystemHeader(loc,
+ "converts between Objective-C and C pointers in -fobjc-arc"))
+ return;
+
+ unsigned srcKind = 0;
+ switch (exprACTC) {
+ case ACTC_none:
+ srcKind = (castExprType->isPointerType() ? 1 : 0);
+ break;
+ case ACTC_retainable:
+ srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
+ break;
+ case ACTC_indirectRetainable:
+ srcKind = 4;
+ break;
+ }
+
+ if (CCK == CCK_CStyleCast) {
+ // Check whether this could be fixed with a bridge cast.
+ SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin());
+ SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc;
+
+ if (castType->isObjCARCBridgableType() &&
+ castExprType->isCARCBridgableType()) {
+ // explicit unbridged casts are allowed if the source of the cast is a
+ // message sent to an objc method (or property access)
+ if (ValidObjCARCNoBridgeCastExpr(castExpr, castType))
+ return;
+ Diag(loc, diag::err_arc_cast_requires_bridge)
+ << 2
+ << castExprType
+ << (castType->isBlockPointerType()? 1 : 0)
+ << castType
+ << castRange
+ << castExpr->getSourceRange();
+ Diag(NoteLoc, diag::note_arc_bridge)
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
+ Diag(NoteLoc, diag::note_arc_bridge_transfer)
+ << castExprType
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge_transfer ");
+
+ return;
+ }
+
+ if (castType->isCARCBridgableType() &&
+ castExprType->isObjCARCBridgableType()){
+ Diag(loc, diag::err_arc_cast_requires_bridge)
+ << (castExprType->isBlockPointerType()? 1 : 0)
+ << castExprType
+ << 2
+ << castType
+ << castRange
+ << castExpr->getSourceRange();
+
+ Diag(NoteLoc, diag::note_arc_bridge)
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
+ Diag(NoteLoc, diag::note_arc_bridge_retained)
+ << castType
+ << FixItHint::CreateInsertion(AfterLParen, "__bridge_retained ");
+ return;
+ }
+ }
+
+ Diag(loc, diag::err_arc_mismatched_cast)
+ << (CCK != CCK_ImplicitConversion) << srcKind << castExprType << castType
+ << castRange << castExpr->getSourceRange();
+}
+
+bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
+ QualType exprType) {
+ QualType canCastType =
+ Context.getCanonicalType(castType).getUnqualifiedType();
+ QualType canExprType =
+ Context.getCanonicalType(exprType).getUnqualifiedType();
+ if (isa<ObjCObjectPointerType>(canCastType) &&
+ castType.getObjCLifetime() == Qualifiers::OCL_Weak &&
+ canExprType->isObjCObjectPointerType()) {
+ if (const ObjCObjectPointerType *ObjT =
+ canExprType->getAs<ObjCObjectPointerType>())
+ if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable())
+ return false;
+ }
+ return true;
+}
+
+/// Look for an ObjCReclaimReturnedObject cast and destroy it.
+static Expr *maybeUndoReclaimObject(Expr *e) {
+ // For now, we just undo operands that are *immediately* reclaim
+ // expressions, which prevents the vast majority of potential
+ // problems here. To catch them all, we'd need to rebuild arbitrary
+ // value-propagating subexpressions --- we can't reliably rebuild
+ // in-place because of expression sharing.
+ if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
+ if (ice->getCastKind() == CK_ObjCReclaimReturnedObject)
+ return ice->getSubExpr();
+
+ return e;
+}
+
+ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
+ ObjCBridgeCastKind Kind,
+ SourceLocation BridgeKeywordLoc,
+ TypeSourceInfo *TSInfo,
+ Expr *SubExpr) {
+ QualType T = TSInfo->getType();
+ QualType FromType = SubExpr->getType();
+
+ bool MustConsume = false;
+ if (T->isDependentType() || SubExpr->isTypeDependent()) {
+ // Okay: we'll build a dependent expression type.
+ } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) {
+ // Casting CF -> id
+ switch (Kind) {
+ case OBC_Bridge:
+ break;
+
+ case OBC_BridgeRetained:
+ Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
+ << 2
+ << FromType
+ << (T->isBlockPointerType()? 1 : 0)
+ << T
+ << SubExpr->getSourceRange()
+ << Kind;
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge)
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge");
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer)
+ << FromType
+ << FixItHint::CreateReplacement(BridgeKeywordLoc,
+ "__bridge_transfer ");
+
+ Kind = OBC_Bridge;
+ break;
+
+ case OBC_BridgeTransfer:
+ // We must consume the Objective-C object produced by the cast.
+ MustConsume = true;
+ break;
+ }
+ } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) {
+ // Okay: id -> CF
+ switch (Kind) {
+ case OBC_Bridge:
+ // Reclaiming a value that's going to be __bridge-casted to CF
+ // is very dangerous, so we don't do it.
+ SubExpr = maybeUndoReclaimObject(SubExpr);
+ break;
+
+ case OBC_BridgeRetained:
+ // Produce the object before casting it.
+ SubExpr = ImplicitCastExpr::Create(Context, FromType,
+ CK_ObjCProduceObject,
+ SubExpr, 0, VK_RValue);
+ break;
+
+ case OBC_BridgeTransfer:
+ Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
+ << (FromType->isBlockPointerType()? 1 : 0)
+ << FromType
+ << 2
+ << T
+ << SubExpr->getSourceRange()
+ << Kind;
+
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge)
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge ");
+ Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained)
+ << T
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge_retained ");
+
+ Kind = OBC_Bridge;
+ break;
+ }
+ } else {
+ Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible)
+ << FromType << T << Kind
+ << SubExpr->getSourceRange()
+ << TSInfo->getTypeLoc().getSourceRange();
+ return ExprError();
+ }
+
+ Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind,
+ BridgeKeywordLoc,
+ TSInfo, SubExpr);
+
+ if (MustConsume) {
+ ExprNeedsCleanups = true;
+ Result = ImplicitCastExpr::Create(Context, T, CK_ObjCConsumeObject, Result,
+ 0, VK_RValue);
+ }
+
+ return Result;
+}
+
+ExprResult Sema::ActOnObjCBridgedCast(Scope *S,
+ SourceLocation LParenLoc,
+ ObjCBridgeCastKind Kind,
+ SourceLocation BridgeKeywordLoc,
+ ParsedType Type,
+ SourceLocation RParenLoc,
+ Expr *SubExpr) {
+ TypeSourceInfo *TSInfo = 0;
+ QualType T = GetTypeFromParser(Type, &TSInfo);
+ if (!TSInfo)
+ TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc);
+ return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo,
+ SubExpr);
+}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index a33f5d0..9fbcbab 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -769,7 +769,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// subaggregate, brace elision is assumed and the initializer is
// considered for the initialization of the first member of
// the subaggregate.
- if (ElemType->isAggregateType() || ElemType->isVectorType()) {
+ if (!SemaRef.getLangOptions().OpenCL &&
+ (ElemType->isAggregateType() || ElemType->isVectorType())) {
CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
@@ -1184,6 +1185,15 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
continue;
}
+ // Make sure we can use this declaration.
+ if (SemaRef.DiagnoseUseOfDecl(*Field,
+ IList->getInit(Index)->getLocStart())) {
+ ++Index;
+ ++Field;
+ hadError = true;
+ continue;
+ }
+
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
@@ -1443,19 +1453,23 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// was a typo for another field name.
LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
Sema::LookupMemberName);
- if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false,
- Sema::CTC_NoKeywords) &&
- (ReplacementField = R.getAsSingle<FieldDecl>()) &&
+ TypoCorrection Corrected = SemaRef.CorrectTypo(
+ DeclarationNameInfo(FieldName, D->getFieldLoc()),
+ Sema::LookupMemberName, /*Scope=*/NULL, /*SS=*/NULL,
+ RT->getDecl(), false, Sema::CTC_NoKeywords);
+ if ((ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>()) &&
ReplacementField->getDeclContext()->getRedeclContext()
->Equals(RT->getDecl())) {
+ std::string CorrectedStr(
+ Corrected.getAsString(SemaRef.getLangOptions()));
+ std::string CorrectedQuotedStr(
+ Corrected.getQuoted(SemaRef.getLangOptions()));
SemaRef.Diag(D->getFieldLoc(),
diag::err_field_designator_unknown_suggest)
- << FieldName << CurrentObjectType << R.getLookupName()
- << FixItHint::CreateReplacement(D->getFieldLoc(),
- R.getLookupName().getAsString());
+ << FieldName << CurrentObjectType << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr);
SemaRef.Diag(ReplacementField->getLocation(),
- diag::note_previous_decl)
- << ReplacementField->getDeclName();
+ diag::note_previous_decl) << CorrectedQuotedStr;
} else {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
@@ -1499,6 +1513,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
StructuredList->setInitializedFieldInUnion(*Field);
}
+ // Make sure we can use this declaration.
+ if (SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc())) {
+ ++Index;
+ return true;
+ }
+
// Update the designator with the field declaration.
D->setField(*Field);
@@ -2029,10 +2049,10 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
DeclarationName InitializedEntity::getName() const {
switch (getKind()) {
- case EK_Parameter:
- if (!VariableOrMember)
- return DeclarationName();
- // Fall through
+ case EK_Parameter: {
+ ParmVarDecl *D = reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
+ return (D ? D->getDeclName() : DeclarationName());
+ }
case EK_Variable:
case EK_Member:
@@ -2057,10 +2077,12 @@ DeclarationName InitializedEntity::getName() const {
DeclaratorDecl *InitializedEntity::getDecl() const {
switch (getKind()) {
case EK_Variable:
- case EK_Parameter:
case EK_Member:
return VariableOrMember;
+ case EK_Parameter:
+ return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
+
case EK_Result:
case EK_Exception:
case EK_New:
@@ -2123,6 +2145,9 @@ void InitializationSequence::Step::Destroy() {
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayInit:
+ case SK_PassByIndirectCopyRestore:
+ case SK_PassByIndirectRestore:
+ case SK_ProduceObjCObject:
break;
case SK_ConversionSequence:
@@ -2131,7 +2156,7 @@ void InitializationSequence::Step::Destroy() {
}
bool InitializationSequence::isDirectReferenceBinding() const {
- return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference;
+ return !Steps.empty() && Steps.back().Kind == SK_BindReference;
}
bool InitializationSequence::isAmbiguous() const {
@@ -2306,6 +2331,22 @@ void InitializationSequence::AddArrayInitStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddPassByIndirectCopyRestoreStep(QualType type,
+ bool shouldCopy) {
+ Step s;
+ s.Kind = (shouldCopy ? SK_PassByIndirectCopyRestore
+ : SK_PassByIndirectRestore);
+ s.Type = type;
+ Steps.push_back(s);
+}
+
+void InitializationSequence::AddProduceObjCObjectStep(QualType T) {
+ Step S;
+ S.Kind = SK_ProduceObjCObject;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
setSequenceKind(FailedSequence);
@@ -2317,6 +2358,33 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure,
// Attempt initialization
//===----------------------------------------------------------------------===//
+static void MaybeProduceObjCObject(Sema &S,
+ InitializationSequence &Sequence,
+ const InitializedEntity &Entity) {
+ if (!S.getLangOptions().ObjCAutoRefCount) return;
+
+ /// When initializing a parameter, produce the value if it's marked
+ /// __attribute__((ns_consumed)).
+ if (Entity.getKind() == InitializedEntity::EK_Parameter) {
+ if (!Entity.isParameterConsumed())
+ return;
+
+ assert(Entity.getType()->isObjCRetainableType() &&
+ "consuming an object of unretainable type?");
+ Sequence.AddProduceObjCObjectStep(Entity.getType());
+
+ /// When initializing a return value, if the return type is a
+ /// retainable type, then returns need to immediately retain the
+ /// object. If an autorelease is required, it will be done at the
+ /// last instant.
+ } else if (Entity.getKind() == InitializedEntity::EK_Result) {
+ if (!Entity.getType()->isObjCRetainableType())
+ return;
+
+ Sequence.AddProduceObjCObjectStep(Entity.getType());
+ }
+}
+
/// \brief Attempt list initialization (C++0x [dcl.init.list])
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -2380,13 +2448,16 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
bool DerivedToBase;
bool ObjCConversion;
+ bool ObjCLifetimeConversion;
assert(!S.CompareReferenceRelationship(Initializer->getLocStart(),
T1, T2, DerivedToBase,
- ObjCConversion) &&
+ ObjCConversion,
+ ObjCLifetimeConversion) &&
"Must have incompatible references when binding via conversion");
(void)DerivedToBase;
(void)ObjCConversion;
-
+ (void)ObjCLifetimeConversion;
+
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -2513,10 +2584,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
bool NewDerivedToBase = false;
bool NewObjCConversion = false;
+ bool NewObjCLifetimeConversion = false;
Sema::ReferenceCompareResult NewRefRelationship
= S.CompareReferenceRelationship(DeclLoc, T1,
T2.getNonLValueExprType(S.Context),
- NewDerivedToBase, NewObjCConversion);
+ NewDerivedToBase, NewObjCConversion,
+ NewObjCLifetimeConversion);
if (NewRefRelationship == Sema::Ref_Incompatible) {
// If the type we've converted to is not reference-related to the
// type we're looking for, then there is another conversion step
@@ -2550,8 +2623,6 @@ static void TryReferenceInitialization(Sema &S,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::ReferenceBinding);
-
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
@@ -2584,10 +2655,11 @@ static void TryReferenceInitialization(Sema &S,
bool isRValueRef = !isLValueRef;
bool DerivedToBase = false;
bool ObjCConversion = false;
+ bool ObjCLifetimeConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
- ObjCConversion);
+ ObjCConversion, ObjCLifetimeConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -2746,11 +2818,15 @@ static void TryReferenceInitialization(Sema &S,
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
- if (S.TryImplicitConversion(Sequence, TempEntity, Initializer,
+ ImplicitConversionSequence ICS
+ = S.TryImplicitConversion(Initializer, TempEntity.getType(),
/*SuppressUserConversions*/ false,
AllowExplicit,
/*FIXME:InOverloadResolution=*/false,
- /*CStyle=*/Kind.isCStyleOrFunctionalCast())) {
+ /*CStyle=*/Kind.isCStyleOrFunctionalCast(),
+ /*AllowObjCWritebackConversion=*/false);
+
+ if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
// this into an overloading ambiguity diagnostic. However, we need
// to keep that set as an OverloadCandidateSet rather than as some
@@ -2764,6 +2840,8 @@ static void TryReferenceInitialization(Sema &S,
else
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
return;
+ } else {
+ Sequence.AddConversionSequenceStep(ICS, TempEntity.getType());
}
// [...] If T1 is reference-related to T2, cv1 must be the
@@ -2953,10 +3031,8 @@ static void TryDefaultInitialization(Sema &S,
// C++ [dcl.init]p6:
// To default-initialize an object of type T means:
// - if T is an array type, each element is default-initialized;
- QualType DestType = Entity.getType();
- while (const ArrayType *Array = S.Context.getAsArrayType(DestType))
- DestType = Array->getElementType();
-
+ QualType DestType = S.Context.getBaseElementType(Entity.getType());
+
// - if T is a (possibly cv-qualified) class type (Clause 9), the default
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
@@ -2970,8 +3046,16 @@ static void TryDefaultInitialization(Sema &S,
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
// default constructor.
- if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus)
+ if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) {
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
+
+ // If the destination type has a lifetime property, zero-initialize it.
+ if (DestType.getQualifiers().hasObjCLifetime()) {
+ Sequence.AddZeroInitializationStep(Entity.getType());
+ return;
+ }
}
/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
@@ -3125,6 +3209,86 @@ static void TryUserDefinedConversion(Sema &S,
}
}
+/// The non-zero enum values here are indexes into diagnostic alternatives.
+enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
+
+/// Determines whether this expression is an acceptable ICR source.
+static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
+ bool isAddressOf) {
+ // Skip parens.
+ e = e->IgnoreParens();
+
+ // Skip address-of nodes.
+ if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
+ if (op->getOpcode() == UO_AddrOf)
+ return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true);
+
+ // Skip certain casts.
+ } else if (CastExpr *ce = dyn_cast<CastExpr>(e)) {
+ switch (ce->getCastKind()) {
+ case CK_Dependent:
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_NoOp:
+ return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf);
+
+ case CK_ArrayToPointerDecay:
+ return IIK_nonscalar;
+
+ case CK_NullToPointer:
+ return IIK_okay;
+
+ default:
+ break;
+ }
+
+ // If we have a declaration reference, it had better be a local variable.
+ } else if (isa<DeclRefExpr>(e) || isa<BlockDeclRefExpr>(e)) {
+ if (!isAddressOf) return IIK_nonlocal;
+
+ VarDecl *var;
+ if (isa<DeclRefExpr>(e)) {
+ var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
+ if (!var) return IIK_nonlocal;
+ } else {
+ var = cast<BlockDeclRefExpr>(e)->getDecl();
+ }
+
+ return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal);
+
+ // If we have a conditional operator, check both sides.
+ } else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) {
+ if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf))
+ return iik;
+
+ return isInvalidICRSource(C, cond->getRHS(), isAddressOf);
+
+ // These are never scalar.
+ } else if (isa<ArraySubscriptExpr>(e)) {
+ return IIK_nonscalar;
+
+ // Otherwise, it needs to be a null pointer constant.
+ } else {
+ return (e->isNullPointerConstant(C, Expr::NPC_ValueDependentIsNull)
+ ? IIK_okay : IIK_nonlocal);
+ }
+
+ return IIK_nonlocal;
+}
+
+/// Check whether the given expression is a valid operand for an
+/// indirect copy/restore.
+static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
+ assert(src->isRValue());
+
+ InvalidICRKind iik = isInvalidICRSource(S.Context, src, false);
+ if (iik == IIK_okay) return;
+
+ S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)
+ << ((unsigned) iik - 1) // shift index into diagnostic explanations
+ << src->getSourceRange();
+}
+
/// \brief Determine whether we have compatible array types for the
/// purposes of GNU by-copy array initialization.
static bool hasCompatibleArrayTypes(ASTContext &Context,
@@ -3144,6 +3308,53 @@ static bool hasCompatibleArrayTypes(ASTContext &Context,
return Source->isConstantArrayType() && Dest->isIncompleteArrayType();
}
+static bool tryObjCWritebackConversion(Sema &S,
+ InitializationSequence &Sequence,
+ const InitializedEntity &Entity,
+ Expr *Initializer) {
+ bool ArrayDecay = false;
+ QualType ArgType = Initializer->getType();
+ QualType ArgPointee;
+ if (const ArrayType *ArgArrayType = S.Context.getAsArrayType(ArgType)) {
+ ArrayDecay = true;
+ ArgPointee = ArgArrayType->getElementType();
+ ArgType = S.Context.getPointerType(ArgPointee);
+ }
+
+ // Handle write-back conversion.
+ QualType ConvertedArgType;
+ if (!S.isObjCWritebackConversion(ArgType, Entity.getType(),
+ ConvertedArgType))
+ return false;
+
+ // We should copy unless we're passing to an argument explicitly
+ // marked 'out'.
+ bool ShouldCopy = true;
+ if (ParmVarDecl *param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
+ ShouldCopy = (param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
+
+ // Do we need an lvalue conversion?
+ if (ArrayDecay || Initializer->isGLValue()) {
+ ImplicitConversionSequence ICS;
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+
+ QualType ResultType;
+ if (ArrayDecay) {
+ ICS.Standard.First = ICK_Array_To_Pointer;
+ ResultType = S.Context.getPointerType(ArgPointee);
+ } else {
+ ICS.Standard.First = ICK_Lvalue_To_Rvalue;
+ ResultType = Initializer->getType().getNonLValueExprType(S.Context);
+ }
+
+ Sequence.AddConversionSequenceStep(ICS, ResultType);
+ }
+
+ Sequence.AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+ return true;
+}
+
InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -3255,12 +3466,28 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
- // Handle initialization in C
+ // Determine whether we should consider writeback conversions for
+ // Objective-C ARC.
+ bool allowObjCWritebackConversion = S.getLangOptions().ObjCAutoRefCount &&
+ Entity.getKind() == InitializedEntity::EK_Parameter;
+
+ // We're at the end of the line for C: it's either a write-back conversion
+ // or it's a C assignment. There's no need to check anything else.
if (!S.getLangOptions().CPlusPlus) {
+ // If allowed, check whether this is an Objective-C writeback conversion.
+ if (allowObjCWritebackConversion &&
+ tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
+ return;
+ }
+
+ // Handle initialization in C
AddCAssignmentStep(DestType);
+ MaybeProduceObjCObject(S, *this, Entity);
return;
}
+ assert(S.getLangOptions().CPlusPlus);
+
// - If the destination type is a (possibly cv-qualified) class type:
if (DestType->isRecordType()) {
// - If the initialization is direct-initialization, or if it is
@@ -3294,6 +3521,7 @@ InitializationSequence::InitializationSequence(Sema &S,
// type, conversion functions are considered.
if (!SourceType.isNull() && SourceType->isRecordType()) {
TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
+ MaybeProduceObjCObject(S, *this, Entity);
return;
}
@@ -3302,12 +3530,38 @@ InitializationSequence::InitializationSequence(Sema &S,
// conversions (Clause 4) will be used, if necessary, to convert the
// initializer expression to the cv-unqualified version of the
// destination type; no user-defined conversions are considered.
- if (S.TryImplicitConversion(*this, Entity, Initializer,
- /*SuppressUserConversions*/ true,
+
+ ImplicitConversionSequence ICS
+ = S.TryImplicitConversion(Initializer, Entity.getType(),
+ /*SuppressUserConversions*/true,
/*AllowExplicitConversions*/ false,
/*InOverloadResolution*/ false,
- /*CStyle=*/Kind.isCStyleOrFunctionalCast()))
- {
+ /*CStyle=*/Kind.isCStyleOrFunctionalCast(),
+ allowObjCWritebackConversion);
+
+ if (ICS.isStandard() &&
+ ICS.Standard.Second == ICK_Writeback_Conversion) {
+ // Objective-C ARC writeback conversion.
+
+ // We should copy unless we're passing to an argument explicitly
+ // marked 'out'.
+ bool ShouldCopy = true;
+ if (ParmVarDecl *Param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
+ ShouldCopy = (Param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
+
+ // If there was an lvalue adjustment, add it as a separate conversion.
+ if (ICS.Standard.First == ICK_Array_To_Pointer ||
+ ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
+ ImplicitConversionSequence LvalueICS;
+ LvalueICS.setStandard();
+ LvalueICS.Standard.setAsIdentityConversion();
+ LvalueICS.Standard.setAllToTypes(ICS.Standard.getToType(0));
+ LvalueICS.Standard.First = ICS.Standard.First;
+ AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
+ }
+
+ AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+ } else if (ICS.isBad()) {
DeclAccessPair dap;
if (Initializer->getType() == Context.OverloadTy &&
!S.ResolveAddressOfOverloadedFunction(Initializer
@@ -3315,6 +3569,10 @@ InitializationSequence::InitializationSequence(Sema &S,
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else
SetFailed(InitializationSequence::FK_ConversionFailed);
+ } else {
+ AddConversionSequenceStep(ICS, Entity.getType());
+
+ MaybeProduceObjCObject(S, *this, Entity);
}
}
@@ -3560,7 +3818,7 @@ static ExprResult CopyObject(Sema &S,
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << Best->Function->isDeleted();
+ << 1 << Best->Function->isDeleted();
return ExprError();
}
@@ -3633,6 +3891,11 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
}
}
+static bool isReferenceBinding(const InitializationSequence::Step &s) {
+ return s.Kind == InitializationSequence::SK_BindReference ||
+ s.Kind == InitializationSequence::SK_BindReferenceToTemporary;
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -3684,19 +3947,9 @@ InitializationSequence::Perform(Sema &S,
}
}
-
- if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast())
- return ExprResult(Args.release()[0]);
-
- if (Args.size() == 0)
- return S.Owned((Expr *)0);
-
- unsigned NumArgs = Args.size();
- return S.Owned(new (S.Context) ParenListExpr(S.Context,
- SourceLocation(),
- (Expr **)Args.release(),
- NumArgs,
- SourceLocation()));
+ assert(Kind.getKind() == InitializationKind::IK_Copy ||
+ Kind.isExplicitCast());
+ return ExprResult(Args.release()[0]);
}
// No steps means no initialization.
@@ -3733,7 +3986,10 @@ InitializationSequence::Perform(Sema &S,
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
- case SK_ArrayInit: {
+ case SK_ArrayInit:
+ case SK_PassByIndirectCopyRestore:
+ case SK_PassByIndirectRestore:
+ case SK_ProduceObjCObject: {
assert(Args.size() == 1);
CurInit = Args.get()[0];
if (!CurInit.get()) return ExprError();
@@ -3841,12 +4097,22 @@ InitializationSequence::Perform(Sema &S,
break;
case SK_BindReferenceToTemporary:
- // Reference binding does not have any corresponding ASTs.
-
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
+ // Materialize the temporary into memory.
+ CurInit = new (S.Context) MaterializeTemporaryExpr(
+ Entity.getType().getNonReferenceType(),
+ CurInit.get(),
+ Entity.getType()->isLValueReferenceType());
+
+ // If we're binding to an Objective-C object that has lifetime, we
+ // need cleanups.
+ if (S.getLangOptions().ObjCAutoRefCount &&
+ CurInit.get()->getType()->isObjCLifetimeType())
+ S.ExprNeedsCleanups = true;
+
break;
case SK_ExtraneousCopyToTemporary:
@@ -3925,8 +4191,7 @@ InitializationSequence::Perform(Sema &S,
CreatedObject = Conversion->getResultType()->isRecordType();
}
- bool RequiresCopy = !IsCopy &&
- getKind() != InitializationSequence::ReferenceBinding;
+ bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back());
if (RequiresCopy || shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
else if (CreatedObject && shouldDestroyTemporary(Entity)) {
@@ -3969,10 +4234,14 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConversionSequence: {
+ Sema::CheckedConversionKind CCK
+ = Kind.isCStyleCast()? Sema::CCK_CStyleCast
+ : Kind.isFunctionalCast()? Sema::CCK_FunctionalCast
+ : Kind.isExplicitCast()? Sema::CCK_OtherCast
+ : Sema::CCK_ImplicitConversion;
ExprResult CurInitExprRes =
S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
- getAssignmentAction(Entity),
- Kind.isCStyleOrFunctionalCast());
+ getAssignmentAction(Entity), CCK);
if (CurInitExprRes.isInvalid())
return ExprError();
CurInit = move(CurInitExprRes);
@@ -4182,7 +4451,20 @@ InitializationSequence::Perform(Sema &S,
}
}
}
+ break;
+ case SK_PassByIndirectCopyRestore:
+ case SK_PassByIndirectRestore:
+ checkIndirectCopyRestoreSource(S, CurInit.get());
+ CurInit = S.Owned(new (S.Context)
+ ObjCIndirectCopyRestoreExpr(CurInit.take(), Step->Type,
+ Step->Kind == SK_PassByIndirectCopyRestore));
+ break;
+
+ case SK_ProduceObjCObject:
+ CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type,
+ CK_ObjCProduceObject,
+ CurInit.take(), 0, VK_RValue));
break;
}
}
@@ -4278,7 +4560,7 @@ bool InitializationSequence::Diagnose(Sema &S,
true);
if (Ovl == OR_Deleted) {
S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << Best->Function->isDeleted();
+ << 1 << Best->Function->isDeleted();
} else {
llvm_unreachable("Inconsistent overload resolution?");
}
@@ -4443,7 +4725,7 @@ bool InitializationSequence::Diagnose(Sema &S,
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl == OR_Deleted) {
S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << Best->Function->isDeleted();
+ << 1 << Best->Function->isDeleted();
} else {
llvm_unreachable("Inconsistent overload resolution?");
}
@@ -4587,10 +4869,6 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case NormalSequence:
OS << "Normal sequence: ";
break;
-
- case ReferenceBinding:
- OS << "Reference binding: ";
- break;
}
for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
@@ -4674,6 +4952,18 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case SK_ArrayInit:
OS << "array initialization";
break;
+
+ case SK_PassByIndirectCopyRestore:
+ OS << "pass by indirect copy and restore";
+ break;
+
+ case SK_PassByIndirectRestore:
+ OS << "pass by indirect restore";
+ break;
+
+ case SK_ProduceObjCObject:
+ OS << "Objective-C object retension";
+ break;
}
}
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 92ade1e..0e448e3 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -20,6 +20,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/TypoCorrection.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
@@ -42,6 +43,7 @@
#include <iterator>
#include <utility>
#include <algorithm>
+#include <map>
using namespace clang;
using namespace sema;
@@ -207,6 +209,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
bool Redeclaration) {
unsigned IDNS = 0;
switch (NameKind) {
+ case Sema::LookupObjCImplicitSelfParam:
case Sema::LookupOrdinaryName:
case Sema::LookupRedeclarationWithLinkage:
IDNS = Decl::IDNS_Ordinary;
@@ -1095,7 +1098,10 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
if (LeftStartingScope && !((*I)->hasLinkage()))
continue;
}
-
+ else if (NameKind == LookupObjCImplicitSelfParam &&
+ !isa<ImplicitParamDecl>(*I))
+ continue;
+
R.addDecl(*I);
if ((*I)->getAttr<OverloadableAttr>()) {
@@ -1379,6 +1385,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Look for this member in our base classes
CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0;
switch (R.getLookupKind()) {
+ case LookupObjCImplicitSelfParam:
case LookupOrdinaryName:
case LookupMemberName:
case LookupRedeclarationWithLinkage:
@@ -2137,15 +2144,15 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
}
}
-Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
+Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
CXXSpecialMember SM,
bool ConstArg,
bool VolatileArg,
bool RValueThis,
bool ConstThis,
bool VolatileThis) {
- D = D->getDefinition();
- assert((D && !D->isBeingDefined()) &&
+ RD = RD->getDefinition();
+ assert((RD && !RD->isBeingDefined()) &&
"doing special member lookup into record that isn't fully complete");
if (RValueThis || ConstThis || VolatileThis)
assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) &&
@@ -2155,7 +2162,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
"parameter-less special members can't have qualified arguments");
llvm::FoldingSetNodeID ID;
- ID.AddPointer(D);
+ ID.AddPointer(RD);
ID.AddInteger(SM);
ID.AddInteger(ConstArg);
ID.AddInteger(VolatileArg);
@@ -2176,9 +2183,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
- if (!D->hasDeclaredDestructor())
- DeclareImplicitDestructor(D);
- CXXDestructorDecl *DD = D->getDestructor();
+ if (!RD->hasDeclaredDestructor())
+ DeclareImplicitDestructor(RD);
+ CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
Result->setSuccess(DD->isDeleted());
@@ -2188,7 +2195,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
// Prepare for overload resolution. Here we construct a synthetic argument
// if necessary and make sure that implicit functions are declared.
- CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D));
+ CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(RD));
DeclarationName Name;
Expr *Arg = 0;
unsigned NumArgs;
@@ -2196,18 +2203,18 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
if (SM == CXXDefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
- if (D->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(D);
+ if (RD->needsImplicitDefaultConstructor())
+ DeclareImplicitDefaultConstructor(RD);
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
- if (!D->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(D);
+ if (!RD->hasDeclaredCopyConstructor())
+ DeclareImplicitCopyConstructor(RD);
// TODO: Move constructors
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- if (!D->hasDeclaredCopyAssignment())
- DeclareImplicitCopyAssignment(D);
+ if (!RD->hasDeclaredCopyAssignment())
+ DeclareImplicitCopyAssignment(RD);
// TODO: Move assignment
}
@@ -2225,7 +2232,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
// there is no semantic difference for class types in this restricted
// case.
ExprValueKind VK;
- if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ if (SM == CXXCopyConstructor || SM == CXXCopyAssignment)
VK = VK_LValue;
else
VK = VK_RValue;
@@ -2240,7 +2247,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
ThisTy.addConst();
if (VolatileThis)
ThisTy.addVolatile();
- Expr::Classification ObjectClassification =
+ Expr::Classification Classification =
(new (Context) OpaqueValueExpr(SourceLocation(), ThisTy,
RValueThis ? VK_RValue : VK_LValue))->
Classify(Context);
@@ -2252,16 +2259,33 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
DeclContext::lookup_iterator I, E;
Result->setConstParamMatch(false);
- llvm::tie(I, E) = D->lookup(Name);
+ llvm::tie(I, E) = RD->lookup(Name);
assert((I != E) &&
"lookup for a constructor or assignment operator was empty");
for ( ; I != E; ++I) {
- if ((*I)->isInvalidDecl())
+ Decl *Cand = *I;
+
+ if (Cand->isInvalidDecl())
continue;
- if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) {
- AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs,
- OCS, true);
+ if (UsingShadowDecl *U = dyn_cast<UsingShadowDecl>(Cand)) {
+ // FIXME: [namespace.udecl]p15 says that we should only consider a
+ // using declaration here if it does not match a declaration in the
+ // derived class. We do not implement this correctly in other cases
+ // either.
+ Cand = U->getTargetDecl();
+
+ if (Cand->isInvalidDecl())
+ continue;
+ }
+
+ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand)) {
+ if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy,
+ Classification, &Arg, NumArgs, OCS, true);
+ else
+ AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg,
+ NumArgs, OCS, true);
// Here we're looking for a const parameter to speed up creation of
// implicit copy methods.
@@ -2269,13 +2293,21 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
(SM == CXXCopyConstructor &&
cast<CXXConstructorDecl>(M)->isCopyConstructor())) {
QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);
- if (ArgType->getPointeeType().isConstQualified())
+ if (!ArgType->isReferenceType() ||
+ ArgType->getPointeeType().isConstQualified())
Result->setConstParamMatch(true);
}
+ } else if (FunctionTemplateDecl *Tmpl =
+ dyn_cast<FunctionTemplateDecl>(Cand)) {
+ if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
+ RD, 0, ThisTy, Classification, &Arg, NumArgs,
+ OCS, true);
+ else
+ AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
+ 0, &Arg, NumArgs, OCS, true);
} else {
- FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I);
- AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- 0, &Arg, NumArgs, OCS, true);
+ assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl");
}
}
@@ -2310,10 +2342,10 @@ CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) {
return cast_or_null<CXXConstructorDecl>(Result->getMethod());
}
-/// \brief Look up the copy constructor for the given class.
-CXXConstructorDecl *Sema::LookupCopyConstructor(CXXRecordDecl *Class,
- unsigned Quals,
- bool *ConstParamMatch) {
+/// \brief Look up the copying constructor for the given class.
+CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class,
+ unsigned Quals,
+ bool *ConstParamMatch) {
assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy ctor arg");
SpecialMemberOverloadResult *Result =
@@ -2341,6 +2373,27 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
return Class->lookup(Name);
}
+/// \brief Look up the copying assignment operator for the given class.
+CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class,
+ unsigned Quals, bool RValueThis,
+ unsigned ThisQuals,
+ bool *ConstParamMatch) {
+ assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
+ "non-const, non-volatile qualifiers for copy assignment arg");
+ assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
+ "non-const, non-volatile qualifiers for copy assignment this");
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile, RValueThis,
+ ThisQuals & Qualifiers::Const,
+ ThisQuals & Qualifiers::Volatile);
+
+ if (ConstParamMatch)
+ *ConstParamMatch = Result->hasConstParamMatch();
+
+ return Result->getMethod();
+}
+
/// \brief Look for the destructor of the given class.
///
/// During semantic analysis, this routine should be used in lieu of
@@ -2995,6 +3048,12 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
//===----------------------------------------------------------------------===//
namespace {
+
+typedef llvm::StringMap<TypoCorrection, llvm::BumpPtrAllocator> TypoResultsMap;
+typedef std::map<unsigned, TypoResultsMap *> TypoEditDistanceMap;
+
+static const unsigned MaxTypoDistanceResultSets = 5;
+
class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// \brief The name written that is a typo in the source.
llvm::StringRef Typo;
@@ -3002,33 +3061,55 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// \brief The results found that have the smallest edit distance
/// found (so far) with the typo name.
///
- /// The boolean value indicates whether there is a keyword with this name.
- llvm::StringMap<bool, llvm::BumpPtrAllocator> BestResults;
+ /// The pointer value being set to the current DeclContext indicates
+ /// whether there is a keyword with this name.
+ TypoEditDistanceMap BestResults;
+
+ /// \brief The worst of the best N edit distances found so far.
+ unsigned MaxEditDistance;
- /// \brief The best edit distance found so far.
- unsigned BestEditDistance;
+ Sema &SemaRef;
public:
- explicit TypoCorrectionConsumer(IdentifierInfo *Typo)
+ explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo)
: Typo(Typo->getName()),
- BestEditDistance((std::numeric_limits<unsigned>::max)()) { }
+ MaxEditDistance((std::numeric_limits<unsigned>::max)()),
+ SemaRef(SemaRef) { }
+ ~TypoCorrectionConsumer() {
+ for (TypoEditDistanceMap::iterator I = BestResults.begin(),
+ IEnd = BestResults.end();
+ I != IEnd;
+ ++I)
+ delete I->second;
+ }
+
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
void FoundName(llvm::StringRef Name);
- void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword);
-
- typedef llvm::StringMap<bool, llvm::BumpPtrAllocator>::iterator iterator;
- iterator begin() { return BestResults.begin(); }
- iterator end() { return BestResults.end(); }
- void erase(iterator I) { BestResults.erase(I); }
+ void addKeywordResult(llvm::StringRef Keyword);
+ void addName(llvm::StringRef Name, NamedDecl *ND, unsigned Distance,
+ NestedNameSpecifier *NNS=NULL);
+ void addCorrection(TypoCorrection Correction);
+
+ typedef TypoResultsMap::iterator result_iterator;
+ typedef TypoEditDistanceMap::iterator distance_iterator;
+ distance_iterator begin() { return BestResults.begin(); }
+ distance_iterator end() { return BestResults.end(); }
+ void erase(distance_iterator I) { BestResults.erase(I); }
unsigned size() const { return BestResults.size(); }
bool empty() const { return BestResults.empty(); }
- bool &operator[](llvm::StringRef Name) {
- return BestResults[Name];
+ TypoCorrection &operator[](llvm::StringRef Name) {
+ return (*BestResults.begin()->second)[Name];
+ }
+
+ unsigned getMaxEditDistance() const {
+ return MaxEditDistance;
}
- unsigned getBestEditDistance() const { return BestEditDistance; }
+ unsigned getBestEditDistance() {
+ return (BestResults.empty()) ? MaxEditDistance : BestResults.begin()->first;
+ }
};
}
@@ -3053,55 +3134,181 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) {
// Use a simple length-based heuristic to determine the minimum possible
// edit distance. If the minimum isn't good enough, bail out early.
unsigned MinED = abs((int)Name.size() - (int)Typo.size());
- if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3))
+ if (MinED > MaxEditDistance || (MinED && Typo.size() / MinED < 3))
return;
// Compute an upper bound on the allowable edit distance, so that the
// edit-distance algorithm can short-circuit.
unsigned UpperBound =
- std::min(unsigned((Typo.size() + 2) / 3), BestEditDistance);
+ std::min(unsigned((Typo.size() + 2) / 3), MaxEditDistance);
// Compute the edit distance between the typo and the name of this
// entity. If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
unsigned ED = Typo.edit_distance(Name, true, UpperBound);
- if (ED == 0)
- return;
- if (ED < BestEditDistance) {
- // This result is better than any we've seen before; clear out
- // the previous results.
- BestResults.clear();
- BestEditDistance = ED;
- } else if (ED > BestEditDistance) {
+ if (ED > MaxEditDistance) {
// This result is worse than the best results we've seen so far;
// ignore it.
return;
}
- // Add this name to the list of results. By not assigning a value, we
- // keep the current value if we've seen this name before (either as a
- // keyword or as a declaration), or get the default value (not a keyword)
- // if we haven't seen it before.
- (void)BestResults[Name];
+ addName(Name, NULL, ED);
}
-void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
- llvm::StringRef Keyword) {
+void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) {
// Compute the edit distance between the typo and this keyword.
// If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
unsigned ED = Typo.edit_distance(Keyword);
- if (ED < BestEditDistance) {
- BestResults.clear();
- BestEditDistance = ED;
- } else if (ED > BestEditDistance) {
+ if (ED > MaxEditDistance) {
// This result is worse than the best results we've seen so far;
// ignore it.
return;
}
- BestResults[Keyword] = true;
+ addName(Keyword, TypoCorrection::KeywordDecl(), ED);
+}
+
+void TypoCorrectionConsumer::addName(llvm::StringRef Name,
+ NamedDecl *ND,
+ unsigned Distance,
+ NestedNameSpecifier *NNS) {
+ addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name),
+ ND, NNS, Distance));
+}
+
+void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
+ llvm::StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
+ TypoResultsMap *& Map = BestResults[Correction.getEditDistance()];
+ if (!Map)
+ Map = new TypoResultsMap;
+
+ TypoCorrection &CurrentCorrection = (*Map)[Name];
+ if (!CurrentCorrection ||
+ // FIXME: The following should be rolled up into an operator< on
+ // TypoCorrection with a more principled definition.
+ CurrentCorrection.isKeyword() < Correction.isKeyword() ||
+ Correction.getAsString(SemaRef.getLangOptions()) <
+ CurrentCorrection.getAsString(SemaRef.getLangOptions()))
+ CurrentCorrection = Correction;
+
+ while (BestResults.size() > MaxTypoDistanceResultSets) {
+ TypoEditDistanceMap::iterator Last = BestResults.end();
+ --Last;
+ delete Last->second;
+ BestResults.erase(Last);
+ }
+}
+
+namespace {
+
+class SpecifierInfo {
+ public:
+ DeclContext* DeclCtx;
+ NestedNameSpecifier* NameSpecifier;
+ unsigned EditDistance;
+
+ SpecifierInfo(DeclContext *Ctx, NestedNameSpecifier *NNS, unsigned ED)
+ : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {}
+};
+
+typedef llvm::SmallVector<DeclContext*, 4> DeclContextList;
+typedef llvm::SmallVector<SpecifierInfo, 16> SpecifierInfoList;
+
+class NamespaceSpecifierSet {
+ ASTContext &Context;
+ DeclContextList CurContextChain;
+ bool isSorted;
+
+ SpecifierInfoList Specifiers;
+ llvm::SmallSetVector<unsigned, 4> Distances;
+ llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap;
+
+ /// \brief Helper for building the list of DeclContexts between the current
+ /// context and the top of the translation unit
+ static DeclContextList BuildContextChain(DeclContext *Start);
+
+ void SortNamespaces();
+
+ public:
+ explicit NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext)
+ : Context(Context), CurContextChain(BuildContextChain(CurContext)),
+ isSorted(true) {}
+
+ /// \brief Add the namespace to the set, computing the corresponding
+ /// NestedNameSpecifier and its distance in the process.
+ void AddNamespace(NamespaceDecl *ND);
+
+ typedef SpecifierInfoList::iterator iterator;
+ iterator begin() {
+ if (!isSorted) SortNamespaces();
+ return Specifiers.begin();
+ }
+ iterator end() { return Specifiers.end(); }
+};
+
+}
+
+DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) {
+ assert(Start && "Bulding a context chain from a null context");
+ DeclContextList Chain;
+ for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL;
+ DC = DC->getLookupParent()) {
+ NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(DC);
+ if (!DC->isInlineNamespace() && !DC->isTransparentContext() &&
+ !(ND && ND->isAnonymousNamespace()))
+ Chain.push_back(DC->getPrimaryContext());
+ }
+ return Chain;
+}
+
+void NamespaceSpecifierSet::SortNamespaces() {
+ llvm::SmallVector<unsigned, 4> sortedDistances;
+ sortedDistances.append(Distances.begin(), Distances.end());
+
+ if (sortedDistances.size() > 1)
+ std::sort(sortedDistances.begin(), sortedDistances.end());
+
+ Specifiers.clear();
+ for (llvm::SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(),
+ DIEnd = sortedDistances.end();
+ DI != DIEnd; ++DI) {
+ SpecifierInfoList &SpecList = DistanceMap[*DI];
+ Specifiers.append(SpecList.begin(), SpecList.end());
+ }
+
+ isSorted = true;
+}
+
+void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
+ DeclContext *Ctx = cast<DeclContext>(ND);
+ NestedNameSpecifier *NNS = NULL;
+ unsigned NumSpecifiers = 0;
+ DeclContextList NamespaceDeclChain(BuildContextChain(Ctx));
+
+ // Eliminate common elements from the two DeclContext chains
+ for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
+ CEnd = CurContextChain.rend();
+ C != CEnd && !NamespaceDeclChain.empty() &&
+ NamespaceDeclChain.back() == *C; ++C) {
+ NamespaceDeclChain.pop_back();
+ }
+
+ // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
+ for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(),
+ CEnd = NamespaceDeclChain.rend();
+ C != CEnd; ++C) {
+ NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C);
+ if (ND) {
+ NNS = NestedNameSpecifier::Create(Context, NNS, ND);
+ ++NumSpecifiers;
+ }
+ }
+
+ isSorted = false;
+ Distances.insert(NumSpecifiers);
+ DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers));
}
/// \brief Perform name lookup for a possible result for typo correction.
@@ -3155,14 +3362,193 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
}
}
+/// \brief Add keywords to the consumer as possible typo corrections.
+static void AddKeywordsToConsumer(Sema &SemaRef,
+ TypoCorrectionConsumer &Consumer,
+ Scope *S, Sema::CorrectTypoContext CTC) {
+ // Add context-dependent keywords.
+ bool WantTypeSpecifiers = false;
+ bool WantExpressionKeywords = false;
+ bool WantCXXNamedCasts = false;
+ bool WantRemainingKeywords = false;
+ switch (CTC) {
+ case Sema::CTC_Unknown:
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ WantCXXNamedCasts = true;
+ WantRemainingKeywords = true;
+
+ if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
+ if (Method->getClassInterface() &&
+ Method->getClassInterface()->getSuperClass())
+ Consumer.addKeywordResult("super");
+
+ break;
+
+ case Sema::CTC_NoKeywords:
+ break;
+
+ case Sema::CTC_Type:
+ WantTypeSpecifiers = true;
+ break;
+
+ case Sema::CTC_ObjCMessageReceiver:
+ Consumer.addKeywordResult("super");
+ // Fall through to handle message receivers like expressions.
+
+ case Sema::CTC_Expression:
+ if (SemaRef.getLangOptions().CPlusPlus)
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ // Fall through to get C++ named casts.
+
+ case Sema::CTC_CXXCasts:
+ WantCXXNamedCasts = true;
+ break;
+
+ case Sema::CTC_ObjCPropertyLookup:
+ // FIXME: Add "isa"?
+ break;
+
+ case Sema::CTC_MemberLookup:
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult("template");
+ break;
+
+ case Sema::CTC_ObjCIvarLookup:
+ break;
+ }
+
+ if (WantTypeSpecifiers) {
+ // Add type-specifier keywords to the set of results.
+ const char *CTypeSpecs[] = {
+ "char", "const", "double", "enum", "float", "int", "long", "short",
+ "signed", "struct", "union", "unsigned", "void", "volatile",
+ "_Complex", "_Imaginary",
+ // storage-specifiers as well
+ "extern", "inline", "static", "typedef"
+ };
+
+ const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
+ for (unsigned I = 0; I != NumCTypeSpecs; ++I)
+ Consumer.addKeywordResult(CTypeSpecs[I]);
+
+ if (SemaRef.getLangOptions().C99)
+ Consumer.addKeywordResult("restrict");
+ if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult("bool");
+ else if (SemaRef.getLangOptions().C99)
+ Consumer.addKeywordResult("_Bool");
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("class");
+ Consumer.addKeywordResult("typename");
+ Consumer.addKeywordResult("wchar_t");
+
+ if (SemaRef.getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult("char16_t");
+ Consumer.addKeywordResult("char32_t");
+ Consumer.addKeywordResult("constexpr");
+ Consumer.addKeywordResult("decltype");
+ Consumer.addKeywordResult("thread_local");
+ }
+ }
+
+ if (SemaRef.getLangOptions().GNUMode)
+ Consumer.addKeywordResult("typeof");
+ }
+
+ if (WantCXXNamedCasts && SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("const_cast");
+ Consumer.addKeywordResult("dynamic_cast");
+ Consumer.addKeywordResult("reinterpret_cast");
+ Consumer.addKeywordResult("static_cast");
+ }
+
+ if (WantExpressionKeywords) {
+ Consumer.addKeywordResult("sizeof");
+ if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("false");
+ Consumer.addKeywordResult("true");
+ }
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ const char *CXXExprs[] = {
+ "delete", "new", "operator", "throw", "typeid"
+ };
+ const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
+ for (unsigned I = 0; I != NumCXXExprs; ++I)
+ Consumer.addKeywordResult(CXXExprs[I]);
+
+ if (isa<CXXMethodDecl>(SemaRef.CurContext) &&
+ cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
+ Consumer.addKeywordResult("this");
+
+ if (SemaRef.getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult("alignof");
+ Consumer.addKeywordResult("nullptr");
+ }
+ }
+ }
+
+ if (WantRemainingKeywords) {
+ if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) {
+ // Statements.
+ const char *CStmts[] = {
+ "do", "else", "for", "goto", "if", "return", "switch", "while" };
+ const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
+ for (unsigned I = 0; I != NumCStmts; ++I)
+ Consumer.addKeywordResult(CStmts[I]);
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("catch");
+ Consumer.addKeywordResult("try");
+ }
+
+ if (S && S->getBreakParent())
+ Consumer.addKeywordResult("break");
+
+ if (S && S->getContinueParent())
+ Consumer.addKeywordResult("continue");
+
+ if (!SemaRef.getCurFunction()->SwitchStack.empty()) {
+ Consumer.addKeywordResult("case");
+ Consumer.addKeywordResult("default");
+ }
+ } else {
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("namespace");
+ Consumer.addKeywordResult("template");
+ }
+
+ if (S && S->isClassScope()) {
+ Consumer.addKeywordResult("explicit");
+ Consumer.addKeywordResult("friend");
+ Consumer.addKeywordResult("mutable");
+ Consumer.addKeywordResult("private");
+ Consumer.addKeywordResult("protected");
+ Consumer.addKeywordResult("public");
+ Consumer.addKeywordResult("virtual");
+ }
+ }
+
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult("using");
+
+ if (SemaRef.getLangOptions().CPlusPlus0x)
+ Consumer.addKeywordResult("static_assert");
+ }
+ }
+}
+
/// \brief Try to "correct" a typo in the source code by finding
/// visible declarations whose names are similar to the name that was
/// present in the source code.
///
-/// \param Res the \c LookupResult structure that contains the name
-/// that was present in the source code along with the name-lookup
-/// criteria used to search for the name. On success, this structure
-/// will contain the results of name lookup.
+/// \param TypoName the \c DeclarationNameInfo structure that contains
+/// the name that was present in the source code along with its location.
+///
+/// \param LookupKind the name-lookup criteria used to search for the name.
///
/// \param S the scope in which name lookup occurs.
///
@@ -3181,60 +3567,64 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
/// \param OPT when non-NULL, the search for visible declarations will
/// also walk the protocols in the qualified interfaces of \p OPT.
///
-/// \returns the corrected name if the typo was corrected, otherwise returns an
-/// empty \c DeclarationName. When a typo was corrected, the result structure
-/// may contain the results of name lookup for the correct name or it may be
-/// empty.
-DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
- DeclContext *MemberContext,
- bool EnteringContext,
- CorrectTypoContext CTC,
- const ObjCObjectPointerType *OPT) {
+/// \returns a \c TypoCorrection containing the corrected name if the typo
+/// along with information such as the \c NamedDecl where the corrected name
+/// was declared, and any additional \c NestedNameSpecifier needed to access
+/// it (C++ only). The \c TypoCorrection is empty if there is no correction.
+TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
+ Sema::LookupNameKind LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ CorrectTypoContext CTC,
+ const ObjCObjectPointerType *OPT) {
if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking)
- return DeclarationName();
+ return TypoCorrection();
// We only attempt to correct typos for identifiers.
- IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
+ IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
if (!Typo)
- return DeclarationName();
+ return TypoCorrection();
// If the scope specifier itself was invalid, don't try to correct
// typos.
if (SS && SS->isInvalid())
- return DeclarationName();
+ return TypoCorrection();
// Never try to correct typos during template deduction or
// instantiation.
if (!ActiveTemplateInstantiations.empty())
- return DeclarationName();
+ return TypoCorrection();
- TypoCorrectionConsumer Consumer(Typo);
+ NamespaceSpecifierSet Namespaces(Context, CurContext);
+
+ TypoCorrectionConsumer Consumer(*this, Typo);
// Perform name lookup to find visible, similarly-named entities.
bool IsUnqualifiedLookup = false;
if (MemberContext) {
- LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
+ LookupVisibleDecls(MemberContext, LookupKind, Consumer);
// Look in qualified interfaces.
if (OPT) {
for (ObjCObjectPointerType::qual_iterator
I = OPT->qual_begin(), E = OPT->qual_end();
I != E; ++I)
- LookupVisibleDecls(*I, Res.getLookupKind(), Consumer);
+ LookupVisibleDecls(*I, LookupKind, Consumer);
}
} else if (SS && SS->isSet()) {
DeclContext *DC = computeDeclContext(*SS, EnteringContext);
if (!DC)
- return DeclarationName();
+ return TypoCorrection();
// Provide a stop gap for files that are just seriously broken. Trying
// to correct all typos can turn into a HUGE performance penalty, causing
// some files to take minutes to get rejected by the parser.
if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
- return DeclarationName();
+ return TypoCorrection();
++TyposCorrected;
- LookupVisibleDecls(DC, Res.getLookupKind(), Consumer);
+ LookupVisibleDecls(DC, LookupKind, Consumer);
} else {
IsUnqualifiedLookup = true;
UnqualifiedTyposCorrectedMap::iterator Cached
@@ -3244,7 +3634,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
// to correct all typos can turn into a HUGE performance penalty, causing
// some files to take minutes to get rejected by the parser.
if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
- return DeclarationName();
+ return TypoCorrection();
// For unqualified lookup, look through all of the names that we have
// seen in this translation unit.
@@ -3268,313 +3658,225 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
} else {
// Use the cached value, unless it's a keyword. In the keyword case, we'll
// end up adding the keyword below.
- if (Cached->second.first.empty())
- return DeclarationName();
+ if (!Cached->second)
+ return TypoCorrection();
- if (!Cached->second.second)
- Consumer.FoundName(Cached->second.first);
+ if (!Cached->second.isKeyword())
+ Consumer.addCorrection(Cached->second);
}
}
- // Add context-dependent keywords.
- bool WantTypeSpecifiers = false;
- bool WantExpressionKeywords = false;
- bool WantCXXNamedCasts = false;
- bool WantRemainingKeywords = false;
- switch (CTC) {
- case CTC_Unknown:
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- WantCXXNamedCasts = true;
- WantRemainingKeywords = true;
-
- if (ObjCMethodDecl *Method = getCurMethodDecl())
- if (Method->getClassInterface() &&
- Method->getClassInterface()->getSuperClass())
- Consumer.addKeywordResult(Context, "super");
-
- break;
-
- case CTC_NoKeywords:
- break;
-
- case CTC_Type:
- WantTypeSpecifiers = true;
- break;
-
- case CTC_ObjCMessageReceiver:
- Consumer.addKeywordResult(Context, "super");
- // Fall through to handle message receivers like expressions.
-
- case CTC_Expression:
- if (getLangOptions().CPlusPlus)
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- // Fall through to get C++ named casts.
-
- case CTC_CXXCasts:
- WantCXXNamedCasts = true;
- break;
-
- case CTC_ObjCPropertyLookup:
- // FIXME: Add "isa"?
- break;
+ AddKeywordsToConsumer(*this, Consumer, S, CTC);
- case CTC_MemberLookup:
- if (getLangOptions().CPlusPlus)
- Consumer.addKeywordResult(Context, "template");
- break;
+ // If we haven't found anything, we're done.
+ if (Consumer.empty()) {
+ // If this was an unqualified lookup, note that no correction was found.
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
- case CTC_ObjCIvarLookup:
- break;
+ return TypoCorrection();
}
- if (WantTypeSpecifiers) {
- // Add type-specifier keywords to the set of results.
- const char *CTypeSpecs[] = {
- "char", "const", "double", "enum", "float", "int", "long", "short",
- "signed", "struct", "union", "unsigned", "void", "volatile", "_Bool",
- "_Complex", "_Imaginary",
- // storage-specifiers as well
- "extern", "inline", "static", "typedef"
- };
-
- const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
- for (unsigned I = 0; I != NumCTypeSpecs; ++I)
- Consumer.addKeywordResult(Context, CTypeSpecs[I]);
-
- if (getLangOptions().C99)
- Consumer.addKeywordResult(Context, "restrict");
- if (getLangOptions().Bool || getLangOptions().CPlusPlus)
- Consumer.addKeywordResult(Context, "bool");
-
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "class");
- Consumer.addKeywordResult(Context, "typename");
- Consumer.addKeywordResult(Context, "wchar_t");
-
- if (getLangOptions().CPlusPlus0x) {
- Consumer.addKeywordResult(Context, "char16_t");
- Consumer.addKeywordResult(Context, "char32_t");
- Consumer.addKeywordResult(Context, "constexpr");
- Consumer.addKeywordResult(Context, "decltype");
- Consumer.addKeywordResult(Context, "thread_local");
- }
- }
+ // Make sure that the user typed at least 3 characters for each correction
+ // made. Otherwise, we don't even both looking at the results.
+ unsigned ED = Consumer.getBestEditDistance();
+ if (ED > 0 && Typo->getName().size() / ED < 3) {
+ // If this was an unqualified lookup, note that no correction was found.
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
- if (getLangOptions().GNUMode)
- Consumer.addKeywordResult(Context, "typeof");
+ return TypoCorrection();
}
- if (WantCXXNamedCasts && getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "const_cast");
- Consumer.addKeywordResult(Context, "dynamic_cast");
- Consumer.addKeywordResult(Context, "reinterpret_cast");
- Consumer.addKeywordResult(Context, "static_cast");
+ // Build the NestedNameSpecifiers for the KnownNamespaces
+ if (getLangOptions().CPlusPlus) {
+ // Load any externally-known namespaces.
+ if (ExternalSource && !LoadedExternalKnownNamespaces) {
+ llvm::SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces;
+ LoadedExternalKnownNamespaces = true;
+ ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces);
+ for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I)
+ KnownNamespaces[ExternalKnownNamespaces[I]] = true;
+ }
+
+ for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ KNI = KnownNamespaces.begin(),
+ KNIEnd = KnownNamespaces.end();
+ KNI != KNIEnd; ++KNI)
+ Namespaces.AddNamespace(KNI->first);
}
- if (WantExpressionKeywords) {
- Consumer.addKeywordResult(Context, "sizeof");
- if (getLangOptions().Bool || getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "false");
- Consumer.addKeywordResult(Context, "true");
- }
+ // Weed out any names that could not be found by name lookup.
+ llvm::SmallPtrSet<IdentifierInfo*, 16> QualifiedResults;
+ LookupResult TmpRes(*this, TypoName, LookupKind);
+ TmpRes.suppressDiagnostics();
+ while (!Consumer.empty()) {
+ TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
+ unsigned ED = DI->first;
+ for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(),
+ IEnd = DI->second->end();
+ I != IEnd; /* Increment in loop. */) {
+ // If the item already has been looked up or is a keyword, keep it
+ if (I->second.isResolved()) {
+ ++I;
+ continue;
+ }
- if (getLangOptions().CPlusPlus) {
- const char *CXXExprs[] = {
- "delete", "new", "operator", "throw", "typeid"
- };
- const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
- for (unsigned I = 0; I != NumCXXExprs; ++I)
- Consumer.addKeywordResult(Context, CXXExprs[I]);
+ // Perform name lookup on this name.
+ IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo();
+ LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
+ EnteringContext, CTC);
- if (isa<CXXMethodDecl>(CurContext) &&
- cast<CXXMethodDecl>(CurContext)->isInstance())
- Consumer.addKeywordResult(Context, "this");
+ switch (TmpRes.getResultKind()) {
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ QualifiedResults.insert(Name);
+ // We didn't find this name in our scope, or didn't like what we found;
+ // ignore it.
+ {
+ TypoCorrectionConsumer::result_iterator Next = I;
+ ++Next;
+ DI->second->erase(I);
+ I = Next;
+ }
+ break;
- if (getLangOptions().CPlusPlus0x) {
- Consumer.addKeywordResult(Context, "alignof");
- Consumer.addKeywordResult(Context, "nullptr");
+ case LookupResult::Ambiguous:
+ // We don't deal with ambiguities.
+ return TypoCorrection();
+
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
+ // FIXME: This sets the CorrectionDecl to NULL for overloaded functions.
+ // It would be nice to find the right one with overload resolution.
+ ++I;
+ break;
}
}
- }
-
- if (WantRemainingKeywords) {
- if (getCurFunctionOrMethodDecl() || getCurBlock()) {
- // Statements.
- const char *CStmts[] = {
- "do", "else", "for", "goto", "if", "return", "switch", "while" };
- const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
- for (unsigned I = 0; I != NumCStmts; ++I)
- Consumer.addKeywordResult(Context, CStmts[I]);
-
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "catch");
- Consumer.addKeywordResult(Context, "try");
- }
- if (S && S->getBreakParent())
- Consumer.addKeywordResult(Context, "break");
-
- if (S && S->getContinueParent())
- Consumer.addKeywordResult(Context, "continue");
-
- if (!getCurFunction()->SwitchStack.empty()) {
- Consumer.addKeywordResult(Context, "case");
- Consumer.addKeywordResult(Context, "default");
- }
- } else {
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "namespace");
- Consumer.addKeywordResult(Context, "template");
- }
+ if (DI->second->empty())
+ Consumer.erase(DI);
+ else if (!getLangOptions().CPlusPlus || QualifiedResults.empty() || !ED)
+ // If there are results in the closest possible bucket, stop
+ break;
- if (S && S->isClassScope()) {
- Consumer.addKeywordResult(Context, "explicit");
- Consumer.addKeywordResult(Context, "friend");
- Consumer.addKeywordResult(Context, "mutable");
- Consumer.addKeywordResult(Context, "private");
- Consumer.addKeywordResult(Context, "protected");
- Consumer.addKeywordResult(Context, "public");
- Consumer.addKeywordResult(Context, "virtual");
+ // Only perform the qualified lookups for C++
+ if (getLangOptions().CPlusPlus) {
+ TmpRes.suppressDiagnostics();
+ for (llvm::SmallPtrSet<IdentifierInfo*,
+ 16>::iterator QRI = QualifiedResults.begin(),
+ QRIEnd = QualifiedResults.end();
+ QRI != QRIEnd; ++QRI) {
+ for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(),
+ NIEnd = Namespaces.end();
+ NI != NIEnd; ++NI) {
+ DeclContext *Ctx = NI->DeclCtx;
+ unsigned QualifiedED = ED + NI->EditDistance;
+
+ // Stop searching once the namespaces are too far away to create
+ // acceptable corrections for this identifier (since the namespaces
+ // are sorted in ascending order by edit distance)
+ if (QualifiedED > Consumer.getMaxEditDistance()) break;
+
+ TmpRes.clear();
+ TmpRes.setLookupName(*QRI);
+ if (!LookupQualifiedName(TmpRes, Ctx)) continue;
+
+ switch (TmpRes.getResultKind()) {
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(),
+ QualifiedED, NI->NameSpecifier);
+ break;
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::Ambiguous:
+ break;
+ }
+ }
}
}
- if (getLangOptions().CPlusPlus) {
- Consumer.addKeywordResult(Context, "using");
-
- if (getLangOptions().CPlusPlus0x)
- Consumer.addKeywordResult(Context, "static_assert");
- }
+ QualifiedResults.clear();
}
- // If we haven't found anything, we're done.
- if (Consumer.empty()) {
- // If this was an unqualified lookup, note that no correction was found.
- if (IsUnqualifiedLookup)
- (void)UnqualifiedTyposCorrected[Typo];
+ // No corrections remain...
+ if (Consumer.empty()) return TypoCorrection();
- return DeclarationName();
- }
+ TypoResultsMap &BestResults = *Consumer.begin()->second;
+ ED = Consumer.begin()->first;
- // Make sure that the user typed at least 3 characters for each correction
- // made. Otherwise, we don't even both looking at the results.
-
- // We also suppress exact matches; those should be handled by a
- // different mechanism (e.g., one that introduces qualification in
- // C++).
- unsigned ED = Consumer.getBestEditDistance();
if (ED > 0 && Typo->getName().size() / ED < 3) {
// If this was an unqualified lookup, note that no correction was found.
if (IsUnqualifiedLookup)
(void)UnqualifiedTyposCorrected[Typo];
- return DeclarationName();
+ return TypoCorrection();
}
- // Weed out any names that could not be found by name lookup.
- bool LastLookupWasAccepted = false;
- for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
- IEnd = Consumer.end();
- I != IEnd; /* Increment in loop. */) {
- // Keywords are always found.
- if (I->second) {
- ++I;
- continue;
- }
-
- // Perform name lookup on this name.
- IdentifierInfo *Name = &Context.Idents.get(I->getKey());
- LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
- EnteringContext, CTC);
-
- switch (Res.getResultKind()) {
- case LookupResult::NotFound:
- case LookupResult::NotFoundInCurrentInstantiation:
- case LookupResult::Ambiguous:
- // We didn't find this name in our scope, or didn't like what we found;
- // ignore it.
- Res.suppressDiagnostics();
- {
- TypoCorrectionConsumer::iterator Next = I;
- ++Next;
- Consumer.erase(I);
- I = Next;
- }
- LastLookupWasAccepted = false;
- break;
-
- case LookupResult::Found:
- case LookupResult::FoundOverloaded:
- case LookupResult::FoundUnresolvedValue:
- ++I;
- LastLookupWasAccepted = true;
- break;
- }
-
- if (Res.isAmbiguous()) {
- // We don't deal with ambiguities.
- Res.suppressDiagnostics();
- Res.clear();
- return DeclarationName();
+ // If we have multiple possible corrections, eliminate the ones where we
+ // added namespace qualifiers to try to resolve the ambiguity (and to favor
+ // corrections without additional namespace qualifiers)
+ if (getLangOptions().CPlusPlus && BestResults.size() > 1) {
+ TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
+ for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(),
+ IEnd = DI->second->end();
+ I != IEnd; /* Increment in loop. */) {
+ if (I->second.getCorrectionSpecifier() != NULL) {
+ TypoCorrectionConsumer::result_iterator Cur = I;
+ ++I;
+ DI->second->erase(Cur);
+ } else ++I;
}
}
// If only a single name remains, return that result.
- if (Consumer.size() == 1) {
- IdentifierInfo *Name = &Context.Idents.get(Consumer.begin()->getKey());
- if (Consumer.begin()->second) {
- Res.suppressDiagnostics();
- Res.clear();
-
- // Don't correct to a keyword that's the same as the typo; the keyword
- // wasn't actually in scope.
- if (ED == 0) {
- Res.setLookupName(Typo);
- return DeclarationName();
- }
+ if (BestResults.size() == 1) {
+ const llvm::StringMapEntry<TypoCorrection> &Correction = *(BestResults.begin());
+ const TypoCorrection &Result = Correction.second;
- } else if (!LastLookupWasAccepted) {
- // Perform name lookup on this name.
- LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
- EnteringContext, CTC);
- }
+ // Don't correct to a keyword that's the same as the typo; the keyword
+ // wasn't actually in scope.
+ if (ED == 0 && Result.isKeyword()) return TypoCorrection();
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo]
- = std::make_pair(Name->getName(), Consumer.begin()->second);
+ UnqualifiedTyposCorrected[Typo] = Result;
- return &Context.Idents.get(Consumer.begin()->getKey());
+ return Result;
}
- else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver
- && Consumer["super"]) {
- // Prefix 'super' when we're completing in a message-receiver
+ else if (BestResults.size() > 1 && CTC == CTC_ObjCMessageReceiver
+ && BestResults["super"].isKeyword()) {
+ // Prefer 'super' when we're completing in a message-receiver
// context.
- Res.suppressDiagnostics();
- Res.clear();
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
- if (ED == 0) {
- Res.setLookupName(Typo);
- return DeclarationName();
- }
+ if (ED == 0) return TypoCorrection();
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo]
- = std::make_pair("super", Consumer.begin()->second);
+ UnqualifiedTyposCorrected[Typo] = BestResults["super"];
- return &Context.Idents.get("super");
+ return BestResults["super"];
}
- Res.suppressDiagnostics();
- Res.setLookupName(Typo);
- Res.clear();
- // Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
(void)UnqualifiedTyposCorrected[Typo];
- return DeclarationName();
+ return TypoCorrection();
+}
+
+std::string TypoCorrection::getAsString(const LangOptions &LO) const {
+ if (CorrectionNameSpec) {
+ std::string tmpBuffer;
+ llvm::raw_string_ostream PrefixOStream(tmpBuffer);
+ CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO));
+ return PrefixOStream.str() + CorrectionName.getAsString();
+ }
+
+ return CorrectionName.getAsString();
}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 6c4469c..d826ea8 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -24,6 +24,51 @@ using namespace clang;
// Grammar actions.
//===----------------------------------------------------------------------===//
+/// Check the internal consistency of a property declaration.
+static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
+ if (property->isInvalidDecl()) return;
+
+ ObjCPropertyDecl::PropertyAttributeKind propertyKind
+ = property->getPropertyAttributes();
+ Qualifiers::ObjCLifetime propertyLifetime
+ = property->getType().getObjCLifetime();
+
+ // Nothing to do if we don't have a lifetime.
+ if (propertyLifetime == Qualifiers::OCL_None) return;
+
+ Qualifiers::ObjCLifetime expectedLifetime;
+ unsigned selector;
+
+ // Strong properties should have either strong or no lifetime.
+ if (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_copy)) {
+ expectedLifetime = Qualifiers::OCL_Strong;
+ selector = 0;
+ } else if (propertyKind & ObjCPropertyDecl::OBJC_PR_weak) {
+ expectedLifetime = Qualifiers::OCL_Weak;
+ selector = 1;
+ } else if (propertyKind & (ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_unsafe_unretained) &&
+ property->getType()->isObjCRetainableType()) {
+ expectedLifetime = Qualifiers::OCL_ExplicitNone;
+ selector = 2;
+ } else {
+ // We have a lifetime qualifier but no dominating property
+ // attribute. That's okay.
+ return;
+ }
+
+ if (propertyLifetime == expectedLifetime) return;
+
+ property->setInvalidDecl();
+ S.Diag(property->getLocation(),
+ diag::err_arc_inconsistent_property_ownership)
+ << property->getDeclName()
+ << selector
+ << propertyLifetime;
+}
+
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD,
ObjCDeclSpec &ODS,
@@ -34,6 +79,14 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC) {
unsigned Attributes = ODS.getPropertyAttributes();
+ TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
+ QualType T = TSI->getType();
+ if ((getLangOptions().getGCMode() != LangOptions::NonGC &&
+ T.isObjCGCWeak()) ||
+ (getLangOptions().ObjCAutoRefCount &&
+ T.getObjCLifetime() == Qualifiers::OCL_Weak))
+ Attributes |= ObjCDeclSpec::DQ_PR_weak;
+
bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
// default is readwrite!
!(Attributes & ObjCDeclSpec::DQ_PR_readonly));
@@ -42,9 +95,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
(isReadWrite &&
!(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
-
- TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
+ !(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_copy) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_weak)));
// Proceed with constructing the ObjCPropertDecls.
ObjCContainerDecl *ClassDecl =
@@ -58,20 +112,27 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Attributes,
isOverridingProperty, TSI,
MethodImplKind);
- if (Res)
+ if (Res) {
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+ if (getLangOptions().ObjCAutoRefCount)
+ checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
+ }
return Res;
}
- Decl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
- GetterSel, SetterSel,
- isAssign, isReadWrite,
- Attributes, TSI, MethodImplKind);
+ ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
+ GetterSel, SetterSel,
+ isAssign, isReadWrite,
+ Attributes, TSI, MethodImplKind);
if (lexicalDC)
Res->setLexicalDeclContext(lexicalDC);
// Validate the attributes on the @property.
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+
+ if (getLangOptions().ObjCAutoRefCount)
+ checkARCPropertyDecl(*this, Res);
+
return Res;
}
@@ -118,6 +179,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
// Set setter/getter selector name. Needed later.
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
+ ProcessDeclAttributes(S, PDecl, FD.D);
DC->addDecl(PDecl);
// We need to look in the @interface to see if the @property was
@@ -139,10 +201,6 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
CreatePropertyDecl(S, CCPrimary, AtLoc,
FD, GetterSel, SetterSel, isAssign, isReadWrite,
Attributes, T, MethodImplKind, DC);
- // Mark written attribute as having no attribute because
- // this is not a user-written property declaration in primary
- // class.
- PDecl->setPropertyAttributesAsWritten(ObjCPropertyDecl::OBJC_PR_noattr);
// A case of continuation class adding a new property in the class. This
// is not what it was meant for. However, gcc supports it and so should we.
@@ -158,6 +216,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
unsigned retainCopyNonatomic =
(ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
ObjCPropertyDecl::OBJC_PR_copy |
ObjCPropertyDecl::OBJC_PR_nonatomic);
if ((Attributes & retainCopyNonatomic) !=
@@ -189,6 +248,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
PIDecl->makeitReadWriteAttribute();
if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
PIDecl->setSetterName(SetterSel);
@@ -272,6 +333,35 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
+ unsigned attributesAsWritten = 0;
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly;
+ if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite;
+ if (Attributes & ObjCDeclSpec::DQ_PR_getter)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter;
+ if (Attributes & ObjCDeclSpec::DQ_PR_setter)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter;
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign;
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain;
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong;
+ if (Attributes & ObjCDeclSpec::DQ_PR_weak)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak;
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy;
+ if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
+ if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
+
+ PDecl->setPropertyAttributesAsWritten(
+ (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten);
+
if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
@@ -287,9 +377,18 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_weak)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
+
if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+ if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+
if (isAssign)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
@@ -298,8 +397,12 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
else if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
- PDecl->setPropertyAttributesAsWritten(PDecl->getPropertyAttributes());
-
+ // 'unsafe_unretained' is alias for 'assign'.
+ if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+ if (isAssign)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+
if (MethodImplKind == tok::objc_required)
PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
else if (MethodImplKind == tok::objc_optional)
@@ -308,6 +411,93 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
return PDecl;
}
+static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
+ ObjCPropertyDecl *property,
+ ObjCIvarDecl *ivar) {
+ if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
+
+ QualType propertyType = property->getType();
+ Qualifiers::ObjCLifetime propertyLifetime = propertyType.getObjCLifetime();
+ ObjCPropertyDecl::PropertyAttributeKind propertyKind
+ = property->getPropertyAttributes();
+
+ QualType ivarType = ivar->getType();
+ Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
+
+ // Case 1: strong properties.
+ if (propertyLifetime == Qualifiers::OCL_Strong ||
+ (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_copy))) {
+ switch (ivarLifetime) {
+ case Qualifiers::OCL_Strong:
+ // Okay.
+ return;
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_Autoreleasing:
+ // These aren't valid lifetimes for object ivars; don't diagnose twice.
+ return;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Weak:
+ S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
+ << property->getDeclName()
+ << ivar->getDeclName()
+ << ivarLifetime;
+ break;
+ }
+
+ // Case 2: weak properties.
+ } else if (propertyLifetime == Qualifiers::OCL_Weak ||
+ (propertyKind & ObjCPropertyDecl::OBJC_PR_weak)) {
+ switch (ivarLifetime) {
+ case Qualifiers::OCL_Weak:
+ // Okay.
+ return;
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_Autoreleasing:
+ // These aren't valid lifetimes for object ivars; don't diagnose twice.
+ return;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Strong:
+ S.Diag(propertyImplLoc, diag::error_weak_property)
+ << property->getDeclName()
+ << ivar->getDeclName();
+ break;
+ }
+
+ // Case 3: assign properties.
+ } else if ((propertyKind & ObjCPropertyDecl::OBJC_PR_assign) &&
+ propertyType->isObjCRetainableType()) {
+ switch (ivarLifetime) {
+ case Qualifiers::OCL_ExplicitNone:
+ // Okay.
+ return;
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_Autoreleasing:
+ // These aren't valid lifetimes for object ivars; don't diagnose twice.
+ return;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership)
+ << property->getDeclName()
+ << ivar->getDeclName();
+ break;
+ }
+
+ // Any other property should be ignored.
+ } else {
+ return;
+ }
+
+ S.Diag(property->getLocation(), diag::note_property_declare);
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
@@ -396,9 +586,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ObjCIvarDecl *Ivar = 0;
// Check that we have a valid, previously declared ivar for @synthesize
if (Synthesize) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ !property->hasWrittenStorageAttribute() &&
+ property->getType()->isObjCRetainableType()) {
+ Diag(PropertyLoc, diag::err_arc_objc_property_default_assign_on_object);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
+
// @synthesize
if (!PropertyIvar)
PropertyIvar = PropertyId;
+ ObjCPropertyDecl::PropertyAttributeKind kind
+ = property->getPropertyAttributes();
QualType PropType = Context.getCanonicalType(property->getType());
QualType PropertyIvarType = PropType;
if (PropType->isReferenceType())
@@ -407,6 +606,45 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ObjCInterfaceDecl *ClassDeclared;
Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
+ // In ARC, give the ivar a lifetime qualifier based on its
+ // property attributes.
+ if (getLangOptions().ObjCAutoRefCount &&
+ !PropertyIvarType.getObjCLifetime()) {
+
+ // retain/copy have retaining lifetime.
+ if (kind & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_copy)) {
+ Qualifiers qs;
+ qs.addObjCLifetime(Qualifiers::OCL_Strong);
+ PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
+ }
+ else if (kind & ObjCPropertyDecl::OBJC_PR_weak) {
+ if (!getLangOptions().ObjCRuntimeHasWeak) {
+ Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
+ Qualifiers qs;
+ qs.addObjCLifetime(Qualifiers::OCL_Weak);
+ PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
+ }
+ else if (kind & ObjCPropertyDecl::OBJC_PR_assign &&
+ PropertyIvarType->isObjCRetainableType()) {
+ // assume that an 'assign' property synthesizes __unsafe_unretained
+ // ivar
+ Qualifiers qs;
+ qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
+ PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
+ }
+ }
+
+ if (kind & ObjCPropertyDecl::OBJC_PR_weak &&
+ !getLangOptions().ObjCAutoRefCount &&
+ getLangOptions().getGCMode() == LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
+
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
PropertyLoc, PropertyLoc, PropertyIvar,
PropertyIvarType, /*Dinfo=*/0,
@@ -435,7 +673,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (PropertyIvarType != IvarType) {
bool compat = false;
if (isa<ObjCObjectPointerType>(PropertyIvarType)
- && isa<ObjCObjectPointerType>(IvarType))
+ && isa<ObjCObjectPointerType>(IvarType))
compat =
Context.canAssignObjCInterfaces(
PropertyIvarType->getAs<ObjCObjectPointerType>(),
@@ -470,12 +708,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// Fall thru - see previous comment
}
// __weak is explicit. So it works on Canonical type.
- if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC)) {
Diag(PropertyLoc, diag::error_weak_property)
<< property->getDeclName() << Ivar->getDeclName();
// Fall thru - see previous comment
}
+ // Fall thru - see previous comment
if ((property->getType()->isObjCObjectPointerType() ||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
getLangOptions().getGCMode() != LangOptions::NonGC) {
@@ -484,9 +723,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// Fall thru - see previous comment
}
}
+ if (getLangOptions().ObjCAutoRefCount)
+ checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
} else if (PropertyIvar)
// @dynamic
Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
+
assert (property && "ActOnPropertyImplDecl - property declaration missing");
ObjCPropertyImplDecl *PIDecl =
ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
@@ -523,6 +765,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
PIDecl->setGetterCXXConstructor(ResExpr);
}
}
+ if (property->hasAttr<NSReturnsNotRetainedAttr>() &&
+ !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
+ Diag(getterMethod->getLocation(),
+ diag::warn_property_getter_owning_mismatch);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
}
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl);
@@ -632,10 +880,19 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
!= (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "copy" << inheritedName;
- else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "retain" << inheritedName;
+ else {
+ unsigned CAttrRetain =
+ (CAttr &
+ (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+ unsigned SAttrRetain =
+ (SAttr &
+ (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+ bool CStrong = (CAttrRetain != 0);
+ bool SStrong = (SAttrRetain != 0);
+ if (CStrong != SStrong)
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "retain (or strong)" << inheritedName;
+ }
if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
!= (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
@@ -653,13 +910,16 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
QualType RHSType =
Context.getCanonicalType(Property->getType());
- if (!Context.typesAreCompatible(LHSType, RHSType)) {
- // FIXME: Incorporate this test with typesAreCompatible.
- if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
- if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
- return;
- Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
- << Property->getType() << SuperProperty->getType() << inheritedName;
+ if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) {
+ // Do cases not handled in above.
+ // FIXME. For future support of covariant property types, revisit this.
+ bool IncompatibleObjC = false;
+ QualType ConvertedType;
+ if (!isObjCPointerConversion(RHSType, LHSType,
+ ConvertedType, IncompatibleObjC) ||
+ IncompatibleObjC)
+ Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
+ << Property->getType() << SuperProperty->getType() << inheritedName;
}
}
@@ -1050,7 +1310,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// Is there a matching propery synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- PropImplMap.count(Prop))
+ PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>())
continue;
if (!InsMap.count(Prop->getGetterName())) {
Diag(Prop->getLocation(),
@@ -1135,6 +1395,35 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
}
}
+void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
+ if (getLangOptions().getGCMode() == LangOptions::GCOnly)
+ return;
+
+ for (ObjCImplementationDecl::propimpl_iterator
+ i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+ continue;
+
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
+ !D->getInstanceMethod(PD->getGetterName())) {
+ ObjCMethodDecl *method = PD->getGetterMethodDecl();
+ if (!method)
+ continue;
+ ObjCMethodFamily family = method->getMethodFamily();
+ if (family == OMF_alloc || family == OMF_copy ||
+ family == OMF_mutableCopy || family == OMF_new) {
+ if (getLangOptions().ObjCAutoRefCount)
+ Diag(PID->getLocation(), diag::err_ownin_getter_rule);
+ else
+ Diag(PID->getLocation(), diag::warn_ownin_getter_rule);
+ Diag(PD->getLocation(), diag::note_property_declare);
+ }
+ }
+ }
+}
+
/// AddPropertyAttrs - Propagates attributes from a property to the
/// implicitly-declared getter or setter for that property.
static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
@@ -1214,6 +1503,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// and the real context should be the same.
if (lexicalDC)
GetterMethod->setLexicalDeclContext(lexicalDC);
+ if (property->hasAttr<NSReturnsNotRetainedAttr>())
+ GetterMethod->addAttr(
+ ::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
@@ -1245,7 +1537,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
Loc, Loc,
property->getIdentifier(),
- property->getType(),
+ property->getType().getUnqualifiedType(),
/*TInfo=*/0,
SC_None,
SC_None,
@@ -1287,7 +1579,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
SourceLocation Loc,
unsigned &Attributes) {
// FIXME: Improve the reported location.
- if (!PDecl)
+ if (!PDecl || PDecl->isInvalidDecl())
return;
ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
@@ -1297,12 +1589,16 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
(Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain))) {
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong))) {
const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
"readwrite" :
(Attributes & ObjCDeclSpec::DQ_PR_assign) ?
"assign" :
+ (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ?
+ "unsafe_unretained" :
(Attributes & ObjCDeclSpec::DQ_PR_copy) ?
"copy" : "retain";
@@ -1313,14 +1609,15 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
}
// Check for copy or retain on non-object types.
- if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
- !PropertyTy->isObjCObjectPointerType() &&
- !PropertyTy->isBlockPointerType() &&
- !Context.isObjCNSObjectType(PropertyTy) &&
+ if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) &&
+ !PropertyTy->isObjCRetainableType() &&
!PropertyDecl->getAttr<ObjCNSObjectAttr>()) {
Diag(Loc, diag::err_objc_property_requires_object)
- << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
- Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
+ << (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" :
+ Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)");
+ Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong);
}
// Check for more than one of { assign, copy, retain }.
@@ -1335,18 +1632,75 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
<< "assign" << "retain";
Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
}
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "strong";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ }
+ if (getLangOptions().ObjCAutoRefCount &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
+ } else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "copy";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "strong";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ }
+ if (getLangOptions().ObjCAutoRefCount &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "unsafe_unretained" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
} else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "copy" << "retain";
Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
}
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "copy" << "strong";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_weak) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "copy" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
+ }
+ else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "retain" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ }
+ else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "strong" << "weak";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
}
// Warn if user supplied no assignment attribute, property is
// readwrite, and this is an object type.
if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain)) &&
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
+ ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong |
+ ObjCDeclSpec::DQ_PR_weak)) &&
!(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
PropertyTy->isObjCObjectPointerType()) {
// Skip this warning in gc-only mode.
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 4bba6f8..437b2b5 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -38,8 +38,10 @@ using namespace sema;
/// function.
static ExprResult
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn,
- SourceLocation Loc = SourceLocation()) {
- ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc));
+ SourceLocation Loc = SourceLocation(),
+ const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
+ ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(),
+ VK_LValue, Loc, LocInfo));
E = S.DefaultFunctionArrayConversion(E.take());
if (E.isInvalid())
return ExprError();
@@ -49,7 +51,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn,
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
- bool CStyle);
+ bool CStyle,
+ bool AllowObjCWritebackConversion);
static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
@@ -106,6 +109,7 @@ GetConversionCategory(ImplicitConversionKind Kind) {
ICC_Conversion,
ICC_Conversion,
ICC_Conversion,
+ ICC_Conversion,
ICC_Conversion
};
return Category[(int)Kind];
@@ -138,7 +142,8 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Complex_Real_Conversion,
ICR_Conversion,
- ICR_Conversion
+ ICR_Conversion,
+ ICR_Writeback_Conversion
};
return Rank[(int)Kind];
}
@@ -170,6 +175,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Complex-real conversion",
"Block Pointer conversion",
"Transparent Union Conversion"
+ "Writeback conversion"
};
return Name[Kind];
}
@@ -181,12 +187,14 @@ void StandardConversionSequence::setAsIdentityConversion() {
Second = ICK_Identity;
Third = ICK_Identity;
DeprecatedStringLiteralToCharPtr = false;
+ QualificationIncludesObjCLifetime = false;
ReferenceBinding = false;
DirectBinding = false;
IsLvalueReference = true;
BindsToFunctionLvalue = false;
BindsToRvalue = false;
BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ObjCLifetimeConversionBinding = false;
CopyConstructor = 0;
}
@@ -730,6 +738,15 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
return false;
}
+/// \brief Checks availability of the function depending on the current
+/// function context. Inside an unavailable function, unavailability is ignored.
+///
+/// \returns true if \arg FD is unavailable and current context is inside
+/// an available function, false otherwise.
+bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) {
+ return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
+}
+
/// TryImplicitConversion - Attempt to perform an implicit conversion
/// from the given expression (Expr) to the given type (ToType). This
/// function returns an implicit conversion sequence that can be used
@@ -753,15 +770,20 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
/// not permitted.
/// If @p AllowExplicit, then explicit user-defined conversions are
/// permitted.
+///
+/// \param AllowObjCWritebackConversion Whether we allow the Objective-C
+/// writeback conversion, which allows __autoreleasing id* parameters to
+/// be initialized with __strong id* or __weak id* arguments.
static ImplicitConversionSequence
TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
bool AllowExplicit,
bool InOverloadResolution,
- bool CStyle) {
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
ImplicitConversionSequence ICS;
if (IsStandardConversion(S, From, ToType, InOverloadResolution,
- ICS.Standard, CStyle)) {
+ ICS.Standard, CStyle, AllowObjCWritebackConversion)){
ICS.setStandard();
return ICS;
}
@@ -867,24 +889,17 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
return ICS;
}
-bool Sema::TryImplicitConversion(InitializationSequence &Sequence,
- const InitializedEntity &Entity,
- Expr *Initializer,
- bool SuppressUserConversions,
- bool AllowExplicitConversions,
- bool InOverloadResolution,
- bool CStyle) {
- ImplicitConversionSequence ICS
- = clang::TryImplicitConversion(*this, Initializer, Entity.getType(),
- SuppressUserConversions,
- AllowExplicitConversions,
- InOverloadResolution,
- CStyle);
- if (ICS.isBad()) return true;
-
- // Perform the actual conversion.
- Sequence.AddConversionSequenceStep(ICS, Entity.getType());
- return false;
+ImplicitConversionSequence
+Sema::TryImplicitConversion(Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool InOverloadResolution,
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
+ return clang::TryImplicitConversion(*this, From, ToType,
+ SuppressUserConversions, AllowExplicit,
+ InOverloadResolution, CStyle,
+ AllowObjCWritebackConversion);
}
/// PerformImplicitConversion - Perform an implicit conversion of the
@@ -903,18 +918,25 @@ ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
ImplicitConversionSequence& ICS) {
+ // Objective-C ARC: Determine whether we will allow the writeback conversion.
+ bool AllowObjCWritebackConversion
+ = getLangOptions().ObjCAutoRefCount &&
+ (Action == AA_Passing || Action == AA_Sending);
+
+
ICS = clang::TryImplicitConversion(*this, From, ToType,
/*SuppressUserConversions=*/false,
AllowExplicit,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ AllowObjCWritebackConversion);
return PerformImplicitConversion(From, ToType, ICS, Action);
}
/// \brief Determine whether the conversion from FromType to ToType is a valid
/// conversion that strips "noreturn" off the nested function type.
-static bool IsNoReturnConversion(ASTContext &Context, QualType FromType,
- QualType ToType, QualType &ResultTy) {
+bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType,
+ QualType &ResultTy) {
if (Context.hasSameUnqualifiedType(FromType, ToType))
return false;
@@ -1016,7 +1038,8 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
- bool CStyle) {
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
QualType FromType = From->getType();
// Standard conversions (C++ [conv])
@@ -1054,7 +1077,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
QualType resultTy;
// if the function type matches except for [[noreturn]], it's ok
- if (!IsNoReturnConversion(S.Context, FromType,
+ if (!S.IsNoReturnConversion(FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
// otherwise, only a boolean conversion is standard
if (!ToType->isBooleanType())
@@ -1123,6 +1146,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// conversion (4.4). (C++ 4.2p2)
SCS.Second = ICK_Identity;
SCS.Third = ICK_Qualification;
+ SCS.QualificationIncludesObjCLifetime = false;
SCS.setAllToTypes(FromType);
return true;
}
@@ -1199,7 +1223,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
} else if (S.IsBlockPointerConversion(FromType, ToType, FromType)) {
- SCS.Second = ICK_Block_Pointer_Conversion;
+ SCS.Second = ICK_Block_Pointer_Conversion;
+ } else if (AllowObjCWritebackConversion &&
+ S.isObjCWritebackConversion(FromType, ToType, FromType)) {
+ SCS.Second = ICK_Writeback_Conversion;
} else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution,
FromType, IncompatibleObjC)) {
// Pointer conversions (C++ 4.10).
@@ -1218,7 +1245,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType.getUnqualifiedType();
- } else if (IsNoReturnConversion(S.Context, FromType, ToType, FromType)) {
+ } else if (S.IsNoReturnConversion(FromType, ToType, FromType)) {
// Treat a conversion that strips "noreturn" as an identity conversion.
SCS.Second = ICK_NoReturn_Adjustment;
} else if (IsTransparentUnionStandardConversion(S, From, ToType,
@@ -1235,8 +1262,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
QualType CanonFrom;
QualType CanonTo;
// The third conversion can be a qualification conversion (C++ 4p1).
- if (S.IsQualificationConversion(FromType, ToType, CStyle)) {
+ bool ObjCLifetimeConversion;
+ if (S.IsQualificationConversion(FromType, ToType, CStyle,
+ ObjCLifetimeConversion)) {
SCS.Third = ICK_Qualification;
+ SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion;
FromType = ToType;
CanonFrom = S.Context.getCanonicalType(FromType);
CanonTo = S.Context.getCanonicalType(ToType);
@@ -1253,7 +1283,8 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
if (CanonFrom.getLocalUnqualifiedType()
== CanonTo.getLocalUnqualifiedType() &&
(CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()
- || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) {
+ || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr()
+ || CanonFrom.getObjCLifetime() != CanonTo.getObjCLifetime())) {
FromType = ToType;
CanonFrom = CanonTo;
}
@@ -1284,7 +1315,8 @@ IsTransparentUnionStandardConversion(Sema &S, Expr* From,
for (RecordDecl::field_iterator it = UD->field_begin(),
itend = UD->field_end();
it != itend; ++it) {
- if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, CStyle)) {
+ if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS,
+ CStyle, /*ObjCWritebackConversion=*/false)) {
ToType = it->getType();
return true;
}
@@ -1479,16 +1511,18 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
/// same type qualifiers as FromPtr has on its pointee type. ToType,
/// if non-empty, will be a pointer to ToType that may or may not have
/// the right set of qualifiers on its pointee.
+///
static QualType
BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
QualType ToPointee, QualType ToType,
- ASTContext &Context) {
+ ASTContext &Context,
+ bool StripObjCLifetime = false) {
assert((FromPtr->getTypeClass() == Type::Pointer ||
FromPtr->getTypeClass() == Type::ObjCObjectPointer) &&
"Invalid similarly-qualified pointer type");
- /// \brief Conversions to 'id' subsume cv-qualifier conversions.
- if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
+ /// Conversions to 'id' subsume cv-qualifier conversions.
+ if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
return ToType.getUnqualifiedType();
QualType CanonFromPointee
@@ -1496,6 +1530,9 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
QualType CanonToPointee = Context.getCanonicalType(ToPointee);
Qualifiers Quals = CanonFromPointee.getQualifiers();
+ if (StripObjCLifetime)
+ Quals.removeObjCLifetime();
+
// Exact qualifier match -> return the pointer type we're converting to.
if (CanonToPointee.getLocalQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
@@ -1599,7 +1636,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// Beyond this point, both types need to be pointers
// , including objective-c pointers.
QualType ToPointeeType = ToTypePtr->getPointeeType();
- if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) {
+ if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() &&
+ !getLangOptions().ObjCAutoRefCount) {
ConvertedType = BuildSimilarlyQualifiedPointerType(
FromType->getAs<ObjCObjectPointerType>(),
ToPointeeType,
@@ -1624,7 +1662,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
ToPointeeType->isVoidType()) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
- ToType, Context);
+ ToType, Context,
+ /*StripObjCLifetime=*/true);
return true;
}
@@ -1814,6 +1853,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ToPointeeType->getAs<ObjCObjectPointerType>() &&
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
IncompatibleObjC)) {
+
ConvertedType = Context.getPointerType(ConvertedType);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
@@ -1885,6 +1925,73 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
return false;
}
+/// \brief Determine whether this is an Objective-C writeback conversion,
+/// used for parameter passing when performing automatic reference counting.
+///
+/// \param FromType The type we're converting form.
+///
+/// \param ToType The type we're converting to.
+///
+/// \param ConvertedType The type that will be produced after applying
+/// this conversion.
+bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
+ QualType &ConvertedType) {
+ if (!getLangOptions().ObjCAutoRefCount ||
+ Context.hasSameUnqualifiedType(FromType, ToType))
+ return false;
+
+ // Parameter must be a pointer to __autoreleasing (with no other qualifiers).
+ QualType ToPointee;
+ if (const PointerType *ToPointer = ToType->getAs<PointerType>())
+ ToPointee = ToPointer->getPointeeType();
+ else
+ return false;
+
+ Qualifiers ToQuals = ToPointee.getQualifiers();
+ if (!ToPointee->isObjCLifetimeType() ||
+ ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing ||
+ !ToQuals.withoutObjCGLifetime().empty())
+ return false;
+
+ // Argument must be a pointer to __strong to __weak.
+ QualType FromPointee;
+ if (const PointerType *FromPointer = FromType->getAs<PointerType>())
+ FromPointee = FromPointer->getPointeeType();
+ else
+ return false;
+
+ Qualifiers FromQuals = FromPointee.getQualifiers();
+ if (!FromPointee->isObjCLifetimeType() ||
+ (FromQuals.getObjCLifetime() != Qualifiers::OCL_Strong &&
+ FromQuals.getObjCLifetime() != Qualifiers::OCL_Weak))
+ return false;
+
+ // Make sure that we have compatible qualifiers.
+ FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing);
+ if (!ToQuals.compatiblyIncludes(FromQuals))
+ return false;
+
+ // Remove qualifiers from the pointee type we're converting from; they
+ // aren't used in the compatibility check belong, and we'll be adding back
+ // qualifiers (with __autoreleasing) if the compatibility check succeeds.
+ FromPointee = FromPointee.getUnqualifiedType();
+
+ // The unqualified form of the pointee types must be compatible.
+ ToPointee = ToPointee.getUnqualifiedType();
+ bool IncompatibleObjC;
+ if (Context.typesAreCompatible(FromPointee, ToPointee))
+ FromPointee = ToPointee;
+ else if (!isObjCPointerConversion(FromPointee, ToPointee, FromPointee,
+ IncompatibleObjC))
+ return false;
+
+ /// \brief Construct the type we're converting to, which is a pointer to
+ /// __autoreleasing pointee.
+ FromPointee = Context.getQualifiedType(FromPointee, FromQuals);
+ ConvertedType = Context.getPointerType(FromPointee);
+ return true;
+}
+
bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType) {
QualType ToPointeeType;
@@ -2178,12 +2285,17 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
/// IsQualificationConversion - Determines whether the conversion from
/// an rvalue of type FromType to ToType is a qualification conversion
/// (C++ 4.4).
+///
+/// \param ObjCLifetimeConversion Output parameter that will be set to indicate
+/// when the qualification conversion involves a change in the Objective-C
+/// object lifetime.
bool
Sema::IsQualificationConversion(QualType FromType, QualType ToType,
- bool CStyle) {
+ bool CStyle, bool &ObjCLifetimeConversion) {
FromType = Context.getCanonicalType(FromType);
ToType = Context.getCanonicalType(ToType);
-
+ ObjCLifetimeConversion = false;
+
// If FromType and ToType are the same type, this is not a
// qualification conversion.
if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
@@ -2206,6 +2318,21 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
+ // Objective-C ARC:
+ // Check Objective-C lifetime conversions.
+ if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
+ UnwrappedAnyPointer) {
+ if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
+ ObjCLifetimeConversion = true;
+ FromQuals.removeObjCLifetime();
+ ToQuals.removeObjCLifetime();
+ } else {
+ // Qualification conversions cannot cast between different
+ // Objective-C lifetime qualifiers.
+ return false;
+ }
+ }
+
// Allow addition/removal of GC attributes but not changing GC attributes.
if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
(!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
@@ -2713,6 +2840,15 @@ CompareStandardConversionSequences(Sema &S,
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
if (UnqualT1 == UnqualT2) {
+ // Objective-C++ ARC: If the references refer to objects with different
+ // lifetimes, prefer bindings that don't change lifetime.
+ if (SCS1.ObjCLifetimeConversionBinding !=
+ SCS2.ObjCLifetimeConversionBinding) {
+ return SCS1.ObjCLifetimeConversionBinding
+ ? ImplicitConversionSequence::Worse
+ : ImplicitConversionSequence::Better;
+ }
+
// If the type is an array type, promote the element qualifiers to the
// type for comparison.
if (isa<ArrayType>(T1) && T1Quals)
@@ -2722,7 +2858,7 @@ CompareStandardConversionSequences(Sema &S,
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
else if (T1.isMoreQualifiedThan(T2))
- return ImplicitConversionSequence::Worse;
+ return ImplicitConversionSequence::Worse;
}
}
@@ -2770,6 +2906,17 @@ CompareQualificationConversions(Sema &S,
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
+
+ // Objective-C++ ARC:
+ // Prefer qualification conversions not involving a change in lifetime
+ // to qualification conversions that do not change lifetime.
+ if (SCS1.QualificationIncludesObjCLifetime !=
+ SCS2.QualificationIncludesObjCLifetime) {
+ Result = SCS1.QualificationIncludesObjCLifetime
+ ? ImplicitConversionSequence::Worse
+ : ImplicitConversionSequence::Better;
+ }
+
while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) {
// Within each iteration of the loop, we check the qualifiers to
// determine if this still looks like a qualification
@@ -3039,7 +3186,8 @@ Sema::ReferenceCompareResult
Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
bool &DerivedToBase,
- bool &ObjCConversion) {
+ bool &ObjCConversion,
+ bool &ObjCLifetimeConversion) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -3056,6 +3204,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// T1 is a base class of T2.
DerivedToBase = false;
ObjCConversion = false;
+ ObjCLifetimeConversion = false;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
@@ -3090,9 +3239,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// qualifiers when performing these computations, so that e.g., an int in
// address space 1 is not reference-compatible with an int in address
// space 2.
+ if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
+ T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
+ T1Quals.removeObjCLifetime();
+ T2Quals.removeObjCLifetime();
+ ObjCLifetimeConversion = true;
+ }
+
if (T1Quals == T2Quals)
return Ref_Compatible;
- else if (T1.isMoreQualifiedThan(T2))
+ else if (T1Quals.compatiblyIncludes(T2Quals))
return Ref_Compatible_With_Added_Qualification;
else
return Ref_Related;
@@ -3135,13 +3291,14 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (AllowRvalues) {
bool DerivedToBase = false;
bool ObjCConversion = false;
+ bool ObjCLifetimeConversion = false;
if (!ConvTemplate &&
S.CompareReferenceRelationship(
DeclLoc,
Conv->getConversionType().getNonReferenceType()
.getUnqualifiedType(),
DeclType.getNonReferenceType().getUnqualifiedType(),
- DerivedToBase, ObjCConversion) ==
+ DerivedToBase, ObjCConversion, ObjCLifetimeConversion) ==
Sema::Ref_Incompatible)
continue;
} else {
@@ -3242,10 +3399,11 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
bool isRValRef = DeclType->isRValueReferenceType();
bool DerivedToBase = false;
bool ObjCConversion = false;
+ bool ObjCLifetimeConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
- ObjCConversion);
+ ObjCConversion, ObjCLifetimeConversion);
// C++0x [dcl.init.ref]p5:
@@ -3283,6 +3441,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = false;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = 0;
// Nothing more to do: the inaccessibility/ambiguity check for
@@ -3328,7 +3487,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
// -- If the initializer expression
//
// -- is an xvalue, class prvalue, array prvalue or function
- // lvalue and "cv1T1" is reference-compatible with "cv2 T2", or
+ // lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification &&
(InitCategory.isXValue() ||
(InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
@@ -3356,6 +3515,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = InitCategory.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = 0;
return ICS;
}
@@ -3398,7 +3558,17 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
// we would be reference-compatible or reference-compatible with
// added qualification. But that wasn't the case, so the reference
// initialization fails.
- return ICS;
+ //
+ // Note that we only want to check address spaces and cvr-qualifiers here.
+ // ObjC GC and lifetime qualifiers aren't important.
+ Qualifiers T1Quals = T1.getQualifiers();
+ Qualifiers T2Quals = T2.getQualifiers();
+ T1Quals.removeObjCGCAttr();
+ T1Quals.removeObjCLifetime();
+ T2Quals.removeObjCGCAttr();
+ T2Quals.removeObjCLifetime();
+ if (!T1Quals.compatiblyIncludes(T2Quals))
+ return ICS;
}
// If at least one of the types is a class type, the types are not
@@ -3429,7 +3599,8 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions,
/*AllowExplicit=*/false,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
// Of course, that's still a reference binding.
if (ICS.isStandard()) {
@@ -3438,12 +3609,14 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = true;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = false;
} else if (ICS.isUserDefined()) {
ICS.UserDefined.After.ReferenceBinding = true;
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = true;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding = false;
}
return ICS;
@@ -3458,7 +3631,8 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
static ImplicitConversionSequence
TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
- bool InOverloadResolution) {
+ bool InOverloadResolution,
+ bool AllowObjCWritebackConversion) {
if (ToType->isReferenceType())
return TryReferenceInit(S, From, ToType,
/*FIXME:*/From->getLocStart(),
@@ -3469,7 +3643,8 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
SuppressUserConversions,
/*AllowExplicit=*/false,
InOverloadResolution,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ AllowObjCWritebackConversion);
}
/// TryObjectArgumentInitialization - Try to initialize the object
@@ -3659,7 +3834,8 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) {
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/true,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
}
/// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -3686,7 +3862,8 @@ TryContextuallyConvertToObjCId(Sema &S, Expr *From) {
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/true,
/*InOverloadResolution=*/false,
- /*CStyle=*/false);
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
}
/// PerformContextuallyConvertToObjCId - Perform a contextual conversion
@@ -3980,7 +4157,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Candidate.Conversions[ArgIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
- /*InOverloadResolution=*/true);
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4153,7 +4332,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.Conversions[ArgIdx + 1]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
- /*InOverloadResolution=*/true);
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4356,25 +4537,26 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
CK_FunctionToPointerDecay,
&ConversionRef, VK_RValue);
- QualType CallResultType
- = Conversion->getConversionType().getNonLValueExprType(Context);
- if (RequireCompleteType(From->getLocStart(), CallResultType, 0)) {
+ QualType ConversionType = Conversion->getConversionType();
+ if (RequireCompleteType(From->getLocStart(), ConversionType, 0)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
return;
}
- ExprValueKind VK = Expr::getValueKindForType(Conversion->getConversionType());
+ ExprValueKind VK = Expr::getValueKindForType(ConversionType);
// Note that it is safe to allocate CallExpr on the stack here because
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
// allocator).
+ QualType CallResultType = ConversionType.getNonLValueExprType(Context);
CallExpr Call(Context, &ConversionFn, 0, 0, CallResultType, VK,
From->getLocStart());
ImplicitConversionSequence ICS =
TryCopyInitialization(*this, &Call, ToType,
/*SuppressUserConversions=*/true,
- /*InOverloadResolution=*/false);
+ /*InOverloadResolution=*/false,
+ /*AllowObjCWritebackConversion=*/false);
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
@@ -4544,7 +4726,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Conversions[ArgIdx + 1]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
/*SuppressUserConversions=*/false,
- /*InOverloadResolution=*/false);
+ /*InOverloadResolution=*/false,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4662,7 +4846,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Candidate.Conversions[ArgIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx],
ArgIdx == 0 && IsAssignmentOperator,
- /*InOverloadResolution=*/false);
+ /*InOverloadResolution=*/false,
+ /*AllowObjCWritebackConversion=*/
+ getLangOptions().ObjCAutoRefCount);
}
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
@@ -6417,7 +6603,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Best is the best viable function.
if (Best->Function &&
- (Best->Function->isDeleted() || Best->Function->isUnavailable()))
+ (Best->Function->isDeleted() ||
+ S.isFunctionConsideredUnavailable(Best->Function)))
return OR_Deleted;
return OR_Success;
@@ -6619,6 +6806,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
+ if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy
+ << FromQs.getObjCLifetime() << ToQs.getObjCLifetime()
+ << (unsigned) isObjectArgument << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
+ return;
+ }
+
if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc)
<< (unsigned) FnKind << FnDesc
@@ -6901,7 +7099,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
- if (Cand->Viable && (Fn->isDeleted() || Fn->isUnavailable())) {
+ if (Cand->Viable && (Fn->isDeleted() ||
+ S.isFunctionConsideredUnavailable(Fn))) {
std::string FnDesc;
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
@@ -7152,7 +7351,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
= TryCopyInitialization(S, Args[ConvIdx],
Cand->BuiltinTypes.ParamTypes[ConvIdx],
SuppressUserConversions,
- /*InOverloadResolution*/ true);
+ /*InOverloadResolution*/ true,
+ /*AllowObjCWritebackConversion=*/
+ S.getLangOptions().ObjCAutoRefCount);
return;
}
@@ -7163,7 +7364,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
Cand->Conversions[ConvIdx]
= TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx),
SuppressUserConversions,
- /*InOverloadResolution=*/true);
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ S.getLangOptions().ObjCAutoRefCount);
else
Cand->Conversions[ConvIdx].setEllipsis();
}
@@ -7407,8 +7610,8 @@ private:
QualType ResultTy;
if (Context.hasSameUnqualifiedType(TargetFunctionType,
FunDecl->getType()) ||
- IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType,
- ResultTy)) {
+ S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType,
+ ResultTy)) {
Matches.push_back(std::make_pair(CurAccessFunPair,
cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
FoundNonTemplateFunction = true;
@@ -7742,13 +7945,17 @@ static void AddOverloadedCallCandidate(Sema &S,
TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ bool KnownValid) {
NamedDecl *Callee = FoundDecl.getDecl();
if (isa<UsingShadowDecl>(Callee))
Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl();
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
- assert(!ExplicitTemplateArgs && "Explicit template arguments?");
+ if (ExplicitTemplateArgs) {
+ assert(!KnownValid && "Explicit template arguments?");
+ return;
+ }
S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet,
false, PartialOverloading);
return;
@@ -7762,9 +7969,7 @@ static void AddOverloadedCallCandidate(Sema &S,
return;
}
- assert(false && "unhandled case in overloaded call candidate");
-
- // do nothing?
+ assert(!KnownValid && "unhandled case in overloaded call candidate");
}
/// \brief Add the overload candidates named by callee and/or found by argument
@@ -7815,7 +8020,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
E = ULE->decls_end(); I != E; ++I)
AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs,
Args, NumArgs, CandidateSet,
- PartialOverloading);
+ PartialOverloading, /*KnownValid*/ true);
if (ULE->requiresADL())
AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
@@ -7857,13 +8062,15 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
AddOverloadedCallCandidate(SemaRef, I.getPair(),
ExplicitTemplateArgs, Args, NumArgs,
- Candidates, false);
+ Candidates, false, /*KnownValid*/ false);
OverloadCandidateSet::iterator Best;
- if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success)
+ if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success) {
// No viable functions. Don't bother the user with notes for functions
// which don't work and shouldn't be found anyway.
+ R.clear();
return false;
+ }
// Find the namespaces where ADL would have looked, and suggest
// declaring the function there instead.
@@ -8673,7 +8880,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc);
+ DeclarationNameLoc LocInfo;
+ LocInfo.CXXOperatorName.BeginOpNameLoc = LLoc.getRawEncoding();
+ LocInfo.CXXOperatorName.EndOpNameLoc = RLoc.getRawEncoding();
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc, LocInfo);
if (FnExpr.isInvalid())
return ExprError();
@@ -8963,13 +9173,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
TheCall->getMethodDecl()->isPure()) {
const CXXMethodDecl *MD = TheCall->getMethodDecl();
- if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts()))
+ if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts())) {
Diag(MemExpr->getLocStart(),
diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor)
<< MD->getDeclName() << isa<CXXDestructorDecl>(CurContext)
<< MD->getParent()->getDeclName();
Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName();
+ }
}
return MaybeBindToTemporary(TheCall);
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index d7c0a54..65f431d 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -66,8 +66,30 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
// If we have an invalid decl, just return.
if (DG.isNull() || !DG.isSingleDecl()) return;
+ VarDecl *var = cast<VarDecl>(DG.getSingleDecl());
+
// suppress any potential 'unused variable' warning.
- DG.getSingleDecl()->setUsed();
+ var->setUsed();
+
+ // foreach variables are never actually initialized in the way that
+ // the parser came up with.
+ var->setInit(0);
+
+ // In ARC, we don't need to retain the iteration variable of a fast
+ // enumeration loop. Rather than actually trying to catch that
+ // during declaration processing, we remove the consequences here.
+ if (getLangOptions().ObjCAutoRefCount) {
+ QualType type = var->getType();
+
+ // Only do this if we inferred the lifetime. Inferred lifetime
+ // will show up as a local qualifier because explicit lifetime
+ // should have shown up as an AttributedType instead.
+ if (type.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Add 'const' and mark the variable as pseudo-strong.
+ var->setType(type.withConst());
+ var->setARCPseudoStrong(true);
+ }
+ }
}
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
@@ -114,6 +136,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
} else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ if (getLangOptions().ObjCAutoRefCount && ME->isDelegateInitCall()) {
+ Diag(Loc, diag::err_arc_unused_init_message) << R1;
+ return;
+ }
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
@@ -951,14 +977,13 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
return StmtError(Diag((*DS->decl_begin())->getLocation(),
diag::err_toomany_element_decls));
- Decl *D = DS->getSingleDecl();
- FirstType = cast<ValueDecl>(D)->getType();
+ VarDecl *D = cast<VarDecl>(DS->getSingleDecl());
+ FirstType = D->getType();
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
// declare identifiers for objects having storage class 'auto' or
// 'register'.
- VarDecl *VD = cast<VarDecl>(D);
- if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
- return StmtError(Diag(VD->getLocation(),
+ if (!D->hasLocalStorage())
+ return StmtError(Diag(D->getLocation(),
diag::err_non_variable_decl_in_for));
} else {
Expr *FirstE = cast<Expr>(First);
@@ -1047,6 +1072,13 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
Decl->setTypeSourceInfo(InitTSI);
Decl->setType(InitTSI->getType());
+ // In ARC, infer lifetime.
+ // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if
+ // we're doing the equivalent of fast iteration.
+ if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ SemaRef.inferObjCARCLifetime(Decl))
+ Decl->setInvalidDecl();
+
SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false,
/*TypeMayContainAuto=*/false);
SemaRef.FinalizeDeclaration(Decl);
@@ -1374,6 +1406,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
if (LoopVar->isInvalidDecl())
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
}
+ } else {
+ // The range is implicitly used as a placeholder when it is dependent.
+ RangeVar->setUsed();
}
return Owned(new (Context) CXXForRangeStmt(RangeDS,
@@ -1508,7 +1543,8 @@ ExprResult
Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
const VarDecl *NRVOCandidate,
QualType ResultType,
- Expr *Value) {
+ Expr *Value,
+ bool AllowNRVO) {
// C++0x [class.copy]p33:
// When the criteria for elision of a copy operation are met or would
// be met save for the fact that the source object is a function
@@ -1516,7 +1552,8 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// overload resolution to select the constructor for the copy is first
// performed as if the object were designated by an rvalue.
ExprResult Res = ExprError();
- if (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true)) {
+ if (AllowNRVO &&
+ (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) {
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack,
Value->getType(), CK_LValueToRValue,
Value, VK_XValue);
@@ -1726,8 +1763,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (D != diag::ext_return_has_void_expr ||
!getLangOptions().CPlusPlus) {
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+
+ int FunctionKind = 0;
+ if (isa<ObjCMethodDecl>(CurDecl))
+ FunctionKind = 1;
+ else if (isa<CXXConstructorDecl>(CurDecl))
+ FunctionKind = 2;
+ else if (isa<CXXDestructorDecl>(CurDecl))
+ FunctionKind = 3;
+
Diag(ReturnLoc, D)
- << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
+ << CurDecl->getDeclName() << FunctionKind
<< RetValExp->getSourceRange();
}
}
@@ -1756,7 +1802,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
// function return.
- // In C++ the return statement is handled via a copy initialization.
+ // In C++ the return statement is handled via a copy initialization,
// the C version of which boils down to CheckSingleAssignmentConstraints.
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
@@ -1797,7 +1843,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
!CurContext->isDependentContext())
FunctionScopes.back()->Returns.push_back(Result);
-
+
return Owned(Result);
}
@@ -1955,7 +2001,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
llvm::StringRef Clobber = Literal->getString();
- if (!Context.Target.isValidGCCRegisterName(Clobber))
+ if (!Context.Target.isValidClobber(Clobber))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_unknown_register_name) << Clobber);
}
@@ -2179,6 +2225,12 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl,
HandlerBlock));
}
+StmtResult
+Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) {
+ getCurFunction()->setHasBranchProtectedScope();
+ return Owned(new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body));
+}
+
namespace {
class TypeWithHandler {
@@ -2309,4 +2361,3 @@ Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
assert(Block);
return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
}
-
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5d4caac..3ac190e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -294,26 +294,31 @@ void Sema::LookupTemplateName(LookupResult &Found,
if (Found.empty() && !isDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
- if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx,
- false, CTC_CXXCasts)) {
+ Found.clear();
+ if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
+ Found.getLookupKind(), S, &SS,
+ LookupCtx, false,
+ CTC_CXXCasts)) {
+ Found.setLookupName(Corrected.getCorrection());
+ if (Corrected.getCorrectionDecl())
+ Found.addDecl(Corrected.getCorrectionDecl());
FilterAcceptableTemplateNames(Found);
if (!Found.empty()) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
- << Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_no_template_suggest)
- << Name << Found.getLookupName()
- << FixItHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
Diag(Template->getLocation(), diag::note_previous_decl)
- << Template->getDeclName();
+ << CorrectedQuotedStr;
}
} else {
- Found.clear();
Found.setLookupName(Name);
}
}
@@ -1856,7 +1861,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
- DependentTemplateName *DTN = Name.getAsDependentTemplateName();
+ DependentTemplateName *DTN
+ = Name.getUnderlying().getAsDependentTemplateName();
if (DTN && DTN->isIdentifier())
// When building a template-id where the template-name is dependent,
// assume the template is a type template. Either our assumption is
@@ -1892,6 +1898,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType;
+ bool InstantiationDependent = false;
if (TypeAliasTemplateDecl *AliasTemplate
= dyn_cast<TypeAliasTemplateDecl>(Template)) {
// Find the canonical type for this type alias template specialization.
@@ -1917,7 +1924,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs)) {
+ TemplateArgs, InstantiationDependent)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -2357,8 +2364,20 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return true;
// Add the converted template type argument.
- Converted.push_back(
- TemplateArgument(Context.getCanonicalType(Arg.getAsType())));
+ QualType ArgType = Context.getCanonicalType(Arg.getAsType());
+
+ // Objective-C ARC:
+ // If an explicitly-specified template argument type is a lifetime type
+ // with no lifetime qualifier, the __strong lifetime qualifier is inferred.
+ if (getLangOptions().ObjCAutoRefCount &&
+ ArgType->isObjCLifetimeType() &&
+ !ArgType.getObjCLifetime()) {
+ Qualifiers Qs;
+ Qs.setObjCLifetime(Qualifiers::OCL_Strong);
+ ArgType = Context.getQualifiedType(ArgType, Qs);
+ }
+
+ Converted.push_back(TemplateArgument(ArgType));
return false;
}
@@ -2912,16 +2931,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// arguments, just break out now and we'll fill in the argument pack below.
if ((*Param)->isTemplateParameterPack())
break;
-
- // If our template is a template template parameter that hasn't acquired
- // its proper context yet (e.g., because we're using the template template
- // parameter in the signature of a function template, before we've built
- // the function template itself), don't attempt substitution of default
- // template arguments at this point: we don't have enough context to
- // do it properly.
- if (isTemplateTemplateParameter &&
- Template->getDeclContext()->isTranslationUnit())
- break;
// We have a default template argument that we will use.
TemplateArgumentLoc Arg;
@@ -3307,8 +3316,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
QualType ArgType = Arg->getType();
// See through any implicit casts we added to fix the type.
- while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = Cast->getSubExpr();
+ Arg = Arg->IgnoreImpCasts();
// C++ [temp.arg.nontype]p1:
//
@@ -3321,7 +3329,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// expressed as & id-expression where the & is optional if
// the name refers to a function or array, or if the
// corresponding template-parameter is a reference; or
- DeclRefExpr *DRE = 0;
// In C++98/03 mode, give an extension warning on any extra parentheses.
// See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
@@ -3337,29 +3344,30 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Arg = Parens->getSubExpr();
}
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
+
bool AddressTaken = false;
SourceLocation AddrOpLoc;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UO_AddrOf) {
- // Support &__uuidof(class_with_uuid) as a non-type template argument.
- // Very common in Microsoft COM headers.
- if (S.getLangOptions().Microsoft &&
- isa<CXXUuidofExpr>(UnOp->getSubExpr())) {
- Converted = TemplateArgument(ArgIn);
- return false;
- }
-
- DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
+ Arg = UnOp->getSubExpr();
AddressTaken = true;
AddrOpLoc = UnOp->getOperatorLoc();
}
- } else {
- if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
- Converted = TemplateArgument(ArgIn);
- return false;
- }
- DRE = dyn_cast<DeclRefExpr>(Arg);
}
+
+ if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
+ Converted = TemplateArgument(ArgIn);
+ return false;
+ }
+
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
+
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
@@ -3513,9 +3521,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
}
+ bool ObjCLifetimeConversion;
if (ParamType->isPointerType() &&
!ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
- S.IsQualificationConversion(ArgType, ParamType, false)) {
+ S.IsQualificationConversion(ArgType, ParamType, false,
+ ObjCLifetimeConversion)) {
// For pointer-to-object types, qualification conversions are
// permitted.
} else {
@@ -3552,10 +3562,10 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// We can't perform this conversion or binding.
if (ParamType->isReferenceType())
S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
- << ParamType << Arg->getType() << Arg->getSourceRange();
+ << ParamType << ArgIn->getType() << Arg->getSourceRange();
else
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
- << Arg->getType() << ParamType << Arg->getSourceRange();
+ << ArgIn->getType() << ParamType << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -3599,6 +3609,10 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
Arg = Parens->getSubExpr();
}
+ while (SubstNonTypeTemplateParmExpr *subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
+ Arg = subst->getReplacement()->IgnoreImpCasts();
+
// A pointer-to-member constant written &Class::member.
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UO_AddrOf) {
@@ -3875,8 +3889,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Owned(Arg);
}
+ bool ObjCLifetimeConversion;
if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(),
- false)) {
+ false, ObjCLifetimeConversion)) {
Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
} else if (!Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
@@ -3943,9 +3958,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// member, qualification conversions (4.4) are applied.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
+ bool ObjCLifetimeConversion;
if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
// Types match exactly: nothing more to do here.
- } else if (IsQualificationConversion(ArgType, ParamType, false)) {
+ } else if (IsQualificationConversion(ArgType, ParamType, false,
+ ObjCLifetimeConversion)) {
Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
} else {
// We can't perform this conversion.
@@ -4053,8 +4070,10 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
// We might need to perform a trailing qualification conversion, since
// the element type on the parameter could be more qualified than the
// element type in the expression we constructed.
+ bool ObjCLifetimeConversion;
if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
- ParamType.getUnqualifiedType(), false))
+ ParamType.getUnqualifiedType(), false,
+ ObjCLifetimeConversion))
RefExpr = ImpCastExprToType(RefExpr.take(), ParamType.getUnqualifiedType(), CK_NoOp);
assert(!RefExpr.isInvalid() &&
@@ -4818,10 +4837,12 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Converted))
return true;
+ bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs.getArgumentArray(),
- TemplateArgs.size())) {
+ TemplateArgs.size(),
+ InstantiationDependent)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< ClassTemplate->getDeclName();
isPartialSpecialization = false;
@@ -5346,7 +5367,7 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
/// explicitly provided as in, e.g., \c void sort<>(char*, char*);
/// as it anyway contains info on the angle brackets locations.
///
-/// \param PrevDecl the set of declarations that may be specialized by
+/// \param Previous the set of declarations that may be specialized by
/// this function specialization.
bool
Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
@@ -5410,13 +5431,12 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
- {
- // Note: do not overwrite location info if previous template
- // specialization kind was explicit.
- TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
- if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation)
- Specialization->setLocation(FD->getLocation());
- }
+
+ // Note: do not overwrite location info if previous template
+ // specialization kind was explicit.
+ TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
+ if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation)
+ Specialization->setLocation(FD->getLocation());
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 7d0ce8b..dcb4ff2 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -12,7 +12,6 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/SemaDiagnostic.h" // FIXME: temporary!
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/AST/ASTContext.h"
@@ -820,6 +819,11 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
ParamQs.hasAddressSpace())
return true;
+ // Mismatched (but not missing) Objective-C lifetime qualifiers.
+ if (ParamQs.getObjCLifetime() != ArgQs.getObjCLifetime() &&
+ ParamQs.hasObjCLifetime())
+ return true;
+
// CVR qualifier superset.
return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) &&
((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers())
@@ -1010,6 +1014,17 @@ DeduceTemplateArguments(Sema &S,
DeducedQs.removeObjCGCAttr();
if (ParamQs.hasAddressSpace())
DeducedQs.removeAddressSpace();
+ if (ParamQs.hasObjCLifetime())
+ DeducedQs.removeObjCLifetime();
+
+ // Objective-C ARC:
+ // If template deduction would produce an argument type with lifetime type
+ // but no lifetime qualifier, the __strong lifetime qualifier is inferred.
+ if (S.getLangOptions().ObjCAutoRefCount &&
+ DeducedType->isObjCLifetimeType() &&
+ !DeducedQs.hasObjCLifetime())
+ DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong);
+
DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(),
DeducedQs);
@@ -1054,10 +1069,39 @@ DeduceTemplateArguments(Sema &S,
}
switch (Param->getTypeClass()) {
- // No deduction possible for these types
+ // Non-canonical types cannot appear here.
+#define NON_CANONICAL_TYPE(Class, Base) \
+ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
+#define TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+
+ case Type::TemplateTypeParm:
+ case Type::SubstTemplateTypeParmPack:
+ llvm_unreachable("Type nodes handled above");
+
+ // These types cannot be used in templates or cannot be dependent, so
+ // deduction always fails.
case Type::Builtin:
+ case Type::VariableArray:
+ case Type::Vector:
+ case Type::FunctionNoProto:
+ case Type::Record:
+ case Type::Enum:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
return Sema::TDK_NonDeducedMismatch;
+ // _Complex T [placeholder extension]
+ case Type::Complex:
+ if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>())
+ return DeduceTemplateArguments(S, TemplateParams,
+ cast<ComplexType>(Param)->getElementType(),
+ ComplexArg->getElementType(),
+ Info, Deduced, TDF);
+
+ return Sema::TDK_NonDeducedMismatch;
+
// T *
case Type::Pointer: {
QualType PointeeType;
@@ -1361,17 +1405,107 @@ DeduceTemplateArguments(Sema &S,
Deduced, 0);
}
+ // (clang extension)
+ //
+ // T __attribute__(((ext_vector_type(<integral constant>))))
+ case Type::ExtVector: {
+ const ExtVectorType *VectorParam = cast<ExtVectorType>(Param);
+ if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+ // Make sure that the vectors have the same number of elements.
+ if (VectorParam->getNumElements() != VectorArg->getNumElements())
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform deduction on the element types.
+ return DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF);
+ }
+
+ if (const DependentSizedExtVectorType *VectorArg
+ = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+ // We can't check the number of elements, since the argument has a
+ // dependent number of elements. This can only occur during partial
+ // ordering.
+
+ // Perform deduction on the element types.
+ return DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF);
+ }
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
+ // (clang extension)
+ //
+ // T __attribute__(((ext_vector_type(N))))
+ case Type::DependentSizedExtVector: {
+ const DependentSizedExtVectorType *VectorParam
+ = cast<DependentSizedExtVectorType>(Param);
+
+ if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+ // Perform deduction on the element types.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF))
+ return Result;
+
+ // Perform deduction on the vector size, if we can.
+ NonTypeTemplateParmDecl *NTTP
+ = getDeducedParameterFromExpr(VectorParam->getSizeExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
+ ArgSize = VectorArg->getNumElements();
+ return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy,
+ false, Info, Deduced);
+ }
+
+ if (const DependentSizedExtVectorType *VectorArg
+ = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+ // Perform deduction on the element types.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced,
+ TDF))
+ return Result;
+
+ // Perform deduction on the vector size, if we can.
+ NonTypeTemplateParmDecl *NTTP
+ = getDeducedParameterFromExpr(VectorParam->getSizeExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(),
+ Info, Deduced);
+ }
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::DependentName:
+ case Type::UnresolvedUsing:
+ case Type::Decltype:
+ case Type::UnaryTransform:
+ case Type::Auto:
+ case Type::DependentTemplateSpecialization:
+ case Type::PackExpansion:
// No template argument deduction for these types
return Sema::TDK_Success;
-
- default:
- break;
}
- // FIXME: Many more cases to go (to go).
return Sema::TDK_Success;
}
@@ -2189,15 +2323,108 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_Success;
}
+/// \brief Check whether the deduced argument type for a call to a function
+/// template matches the actual argument type per C++ [temp.deduct.call]p4.
+static bool
+CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
+ QualType DeducedA) {
+ ASTContext &Context = S.Context;
+
+ QualType A = OriginalArg.OriginalArgType;
+ QualType OriginalParamType = OriginalArg.OriginalParamType;
+
+ // Check for type equality (top-level cv-qualifiers are ignored).
+ if (Context.hasSameUnqualifiedType(A, DeducedA))
+ return false;
+
+ // Strip off references on the argument types; they aren't needed for
+ // the following checks.
+ if (const ReferenceType *DeducedARef = DeducedA->getAs<ReferenceType>())
+ DeducedA = DeducedARef->getPointeeType();
+ if (const ReferenceType *ARef = A->getAs<ReferenceType>())
+ A = ARef->getPointeeType();
+
+ // C++ [temp.deduct.call]p4:
+ // [...] However, there are three cases that allow a difference:
+ // - If the original P is a reference type, the deduced A (i.e., the
+ // type referred to by the reference) can be more cv-qualified than
+ // the transformed A.
+ if (const ReferenceType *OriginalParamRef
+ = OriginalParamType->getAs<ReferenceType>()) {
+ // We don't want to keep the reference around any more.
+ OriginalParamType = OriginalParamRef->getPointeeType();
+
+ Qualifiers AQuals = A.getQualifiers();
+ Qualifiers DeducedAQuals = DeducedA.getQualifiers();
+ if (AQuals == DeducedAQuals) {
+ // Qualifiers match; there's nothing to do.
+ } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
+ return true;
+ } else {
+ // Qualifiers are compatible, so have the argument type adopt the
+ // deduced argument type's qualifiers as if we had performed the
+ // qualification conversion.
+ A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals);
+ }
+ }
+
+ // - The transformed A can be another pointer or pointer to member
+ // type that can be converted to the deduced A via a qualification
+ // conversion.
+ //
+ // Also allow conversions which merely strip [[noreturn]] from function types
+ // (recursively) as an extension.
+ // FIXME: Currently, this doesn't place nicely with qualfication conversions.
+ bool ObjCLifetimeConversion = false;
+ QualType ResultTy;
+ if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
+ (S.IsQualificationConversion(A, DeducedA, false,
+ ObjCLifetimeConversion) ||
+ S.IsNoReturnConversion(A, DeducedA, ResultTy)))
+ return false;
+
+
+ // - If P is a class and P has the form simple-template-id, then the
+ // transformed A can be a derived class of the deduced A. [...]
+ // [...] Likewise, if P is a pointer to a class of the form
+ // simple-template-id, the transformed A can be a pointer to a
+ // derived class pointed to by the deduced A.
+ if (const PointerType *OriginalParamPtr
+ = OriginalParamType->getAs<PointerType>()) {
+ if (const PointerType *DeducedAPtr = DeducedA->getAs<PointerType>()) {
+ if (const PointerType *APtr = A->getAs<PointerType>()) {
+ if (A->getPointeeType()->isRecordType()) {
+ OriginalParamType = OriginalParamPtr->getPointeeType();
+ DeducedA = DeducedAPtr->getPointeeType();
+ A = APtr->getPointeeType();
+ }
+ }
+ }
+ }
+
+ if (Context.hasSameUnqualifiedType(A, DeducedA))
+ return false;
+
+ if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) &&
+ S.IsDerivedFrom(A, DeducedA))
+ return false;
+
+ return true;
+}
+
/// \brief Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
+///
+/// \param OriginalCallArgs If non-NULL, the original call arguments against
+/// which the deduced argument types should be compared.
Sema::TemplateDeductionResult
Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info) {
+ TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -2351,6 +2578,24 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
!Trap.hasErrorOccurred())
Info.take();
+ if (OriginalCallArgs) {
+ // C++ [temp.deduct.call]p4:
+ // In general, the deduction process attempts to find template argument
+ // values that will make the deduced A identical to A (after the type A
+ // is transformed as described above). [...]
+ for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) {
+ OriginalCallArg OriginalArg = (*OriginalCallArgs)[I];
+ unsigned ParamIdx = OriginalArg.ArgIdx;
+
+ if (ParamIdx >= Specialization->getNumParams())
+ continue;
+
+ QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
+ if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA))
+ return Sema::TDK_SubstitutionFailure;
+ }
+ }
+
// There may have been an error that did not prevent us from constructing a
// declaration. Mark the declaration invalid and return with a substitution
// failure.
@@ -2594,6 +2839,10 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
return false;
}
+static bool hasDeducibleTemplateParameters(Sema &S,
+ FunctionTemplateDecl *FunctionTemplate,
+ QualType T);
+
/// \brief Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
@@ -2675,10 +2924,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Deduce template arguments from the function parameters.
Deduced.resize(TemplateParams->size());
unsigned ArgIdx = 0;
+ llvm::SmallVector<OriginalCallArg, 4> OriginalCallArgs;
for (unsigned ParamIdx = 0, NumParams = ParamTypes.size();
ParamIdx != NumParams; ++ParamIdx) {
- QualType ParamType = ParamTypes[ParamIdx];
-
+ QualType OrigParamType = ParamTypes[ParamIdx];
+ QualType ParamType = OrigParamType;
+
const PackExpansionType *ParamExpansion
= dyn_cast<PackExpansionType>(ParamType);
if (!ParamExpansion) {
@@ -2688,20 +2939,25 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Expr *Arg = Args[ArgIdx++];
QualType ArgType = Arg->getType();
+
unsigned TDF = 0;
if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
ParamType, ArgType, Arg,
TDF))
continue;
+ // Keep track of the argument type and corresponding parameter index,
+ // so we can check for compatibility between the deduced A and A.
+ if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
+ OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1,
+ ArgType));
+
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
- // FIXME: we need to check that the deduced A is the same as A,
- // modulo the various allowed differences.
continue;
}
@@ -2747,9 +3003,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
for (; ArgIdx < NumArgs; ++ArgIdx) {
HasAnyArguments = true;
- ParamType = ParamPattern;
+ QualType OrigParamType = ParamPattern;
+ ParamType = OrigParamType;
Expr *Arg = Args[ArgIdx];
QualType ArgType = Arg->getType();
+
unsigned TDF = 0;
if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
ParamType, ArgType, Arg,
@@ -2760,6 +3018,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
break;
}
+ // Keep track of the argument type and corresponding argument index,
+ // so we can check for compatibility between the deduced A and A.
+ if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
+ OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx,
+ ArgType));
+
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this, TemplateParams,
ParamType, ArgType, Info, Deduced,
@@ -2792,7 +3056,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
NumExplicitlySpecified,
- Specialization, Info);
+ Specialization, Info, &OriginalCallArgs);
}
/// \brief Deduce template arguments when taking the address of a function
@@ -2969,9 +3233,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
P, A, Info, Deduced, TDF))
return Result;
- // FIXME: we need to check that the deduced A is the same as A,
- // modulo the various allowed differences.
-
// Finish template argument deduction.
LocalInstantiationScope InstScope(*this);
FunctionDecl *Spec = 0;
@@ -3099,8 +3360,19 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
QualType DeducedType = Deduced[0].getAsType();
if (DeducedType.isNull())
return false;
-
+
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
+
+ // Check that the deduced argument type is compatible with the original
+ // argument type per C++ [temp.deduct.call]p4.
+ if (Result &&
+ CheckOriginalCallArgDeduction(*this,
+ Sema::OriginalCallArg(FuncParam,0,InitType),
+ Result->getType())) {
+ Result = 0;
+ return false;
+ }
+
return true;
}
@@ -3227,8 +3499,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Other:
// - In other contexts (14.6.6.2) the function template's function type
// is used.
- // FIXME: Don't we actually want to perform the adjustments on the parameter
- // types?
if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(),
FD1->getType(), Info, Deduced, TDF_None,
/*PartialOrdering=*/true, RefParamComparisons))
@@ -4010,3 +4280,23 @@ Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
true, TemplateParams->getDepth(), Deduced);
}
+
+bool hasDeducibleTemplateParameters(Sema &S,
+ FunctionTemplateDecl *FunctionTemplate,
+ QualType T) {
+ if (!T->isDependentType())
+ return false;
+
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ llvm::SmallVector<bool, 4> Deduced;
+ Deduced.resize(TemplateParams->size());
+ ::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(),
+ Deduced);
+
+ for (unsigned I = 0, N = Deduced.size(); I != N; ++I)
+ if (Deduced[I])
+ return true;
+
+ return false;
+}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 3c19641..1988f14 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -62,8 +62,20 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
if (!Ctx) {
Ctx = D->getDeclContext();
- assert((!D->isTemplateParameter() || !Ctx->isTranslationUnit()) &&
- "Template parameter doesn't have its context yet!");
+ // If we have a template template parameter with translation unit context,
+ // then we're performing substitution into a default template argument of
+ // this template template parameter before we've constructed the template
+ // that will own this template template parameter. In this case, we
+ // use empty template parameter lists for all of the outer templates
+ // to avoid performing any substitutions.
+ if (Ctx->isTranslationUnit()) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
+ Result.addOuterTemplateArguments(0, 0);
+ return Result;
+ }
+ }
}
while (!Ctx->isFileContext()) {
@@ -788,6 +800,11 @@ namespace {
getSema().CallsUndergoingInstantiation.pop_back();
return move(Result);
}
+
+ private:
+ ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
+ SourceLocation loc,
+ const TemplateArgument &arg);
};
}
@@ -795,7 +812,7 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) {
if (T.isNull())
return true;
- if (T->isDependentType() || T->isVariablyModifiedType())
+ if (T->isInstantiationDependentType() || T->isVariablyModifiedType())
return false;
getSema().MarkDeclarationsReferencedInType(Loc, T);
@@ -980,13 +997,14 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && "Null template template argument");
-
+
// We don't ever want to substitute for a qualified template name, since
// the qualifier is handled separately. So, look through the qualified
// template name to its underlying declaration.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
-
+
+ Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template);
return Template;
}
}
@@ -1065,46 +1083,65 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
+ return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
+}
+
+ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
+ NonTypeTemplateParmDecl *parm,
+ SourceLocation loc,
+ const TemplateArgument &arg) {
+ ExprResult result;
+ QualType type;
+
// The template argument itself might be an expression, in which
// case we just return that expression.
- if (Arg.getKind() == TemplateArgument::Expression)
- return SemaRef.Owned(Arg.getAsExpr());
+ if (arg.getKind() == TemplateArgument::Expression) {
+ Expr *argExpr = arg.getAsExpr();
+ result = SemaRef.Owned(argExpr);
+ type = argExpr->getType();
- if (Arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+ } else if (arg.getKind() == TemplateArgument::Declaration) {
+ ValueDecl *VD = cast<ValueDecl>(arg.getAsDecl());
// Find the instantiation of the template argument. This is
// required for nested templates.
VD = cast_or_null<ValueDecl>(
- getSema().FindInstantiatedDecl(E->getLocation(),
- VD, TemplateArgs));
+ getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
if (!VD)
return ExprError();
// Derive the type we want the substituted decl to have. This had
// better be non-dependent, or these checks will have serious problems.
- QualType TargetType;
- if (NTTP->isExpandedParameterPack())
- TargetType = NTTP->getExpansionType(
- getSema().ArgumentPackSubstitutionIndex);
- else if (NTTP->isParameterPack() &&
- isa<PackExpansionType>(NTTP->getType())) {
- TargetType = SemaRef.SubstType(
- cast<PackExpansionType>(NTTP->getType())->getPattern(),
- TemplateArgs, E->getLocation(),
- NTTP->getDeclName());
- } else
- TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs,
- E->getLocation(), NTTP->getDeclName());
- assert(!TargetType.isNull() && "type substitution failed for param type");
- assert(!TargetType->isDependentType() && "param type still dependent");
- return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg,
- TargetType,
- E->getLocation());
+ if (parm->isExpandedParameterPack()) {
+ type = parm->getExpansionType(SemaRef.ArgumentPackSubstitutionIndex);
+ } else if (parm->isParameterPack() &&
+ isa<PackExpansionType>(parm->getType())) {
+ type = SemaRef.SubstType(
+ cast<PackExpansionType>(parm->getType())->getPattern(),
+ TemplateArgs, loc, parm->getDeclName());
+ } else {
+ type = SemaRef.SubstType(parm->getType(), TemplateArgs,
+ loc, parm->getDeclName());
+ }
+ assert(!type.isNull() && "type substitution failed for param type");
+ assert(!type->isDependentType() && "param type still dependent");
+ result = SemaRef.BuildExpressionFromDeclTemplateArgument(arg, type, loc);
+
+ if (!result.isInvalid()) type = result.get()->getType();
+ } else {
+ result = SemaRef.BuildExpressionFromIntegralTemplateArgument(arg, loc);
+
+ // Note that this type can be different from the type of 'result',
+ // e.g. if it's an enum type.
+ type = arg.getIntegralType();
}
+ if (result.isInvalid()) return ExprError();
- return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
- E->getSourceRange().getBegin());
+ Expr *resultExpr = result.take();
+ return SemaRef.Owned(new (SemaRef.Context)
+ SubstNonTypeTemplateParmExpr(type,
+ resultExpr->getValueKind(),
+ loc, parm, resultExpr));
}
ExprResult
@@ -1120,36 +1157,9 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
assert(Index < ArgPack.pack_size() && "Substitution index out-of-range");
const TemplateArgument &Arg = ArgPack.pack_begin()[Index];
- if (Arg.getKind() == TemplateArgument::Expression)
- return SemaRef.Owned(Arg.getAsExpr());
-
- if (Arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
-
- // Find the instantiation of the template argument. This is
- // required for nested templates.
- VD = cast_or_null<ValueDecl>(
- getSema().FindInstantiatedDecl(E->getParameterPackLocation(),
- VD, TemplateArgs));
- if (!VD)
- return ExprError();
-
- QualType T;
- NonTypeTemplateParmDecl *NTTP = E->getParameterPack();
- if (NTTP->isExpandedParameterPack())
- T = NTTP->getExpansionType(getSema().ArgumentPackSubstitutionIndex);
- else if (const PackExpansionType *Expansion
- = dyn_cast<PackExpansionType>(NTTP->getType()))
- T = SemaRef.SubstType(Expansion->getPattern(), TemplateArgs,
- E->getParameterPackLocation(), NTTP->getDeclName());
- else
- T = E->getType();
- return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, T,
- E->getParameterPackLocation());
- }
-
- return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
- E->getParameterPackLocation());
+ return transformNonTypeTemplateParmRef(E->getParameterPack(),
+ E->getParameterPackLocation(),
+ Arg);
}
ExprResult
@@ -1327,7 +1337,7 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
"Cannot perform an instantiation without some context on the "
"instantiation stack");
- if (!T->getType()->isDependentType() &&
+ if (!T->getType()->isInstantiationDependentType() &&
!T->getType()->isVariablyModifiedType())
return T;
@@ -1346,7 +1356,7 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL,
if (TL.getType().isNull())
return 0;
- if (!TL.getType()->isDependentType() &&
+ if (!TL.getType()->isInstantiationDependentType() &&
!TL.getType()->isVariablyModifiedType()) {
// FIXME: Make a copy of the TypeLoc data here, so that we can
// return a new TypeSourceInfo. Inefficient!
@@ -1375,7 +1385,7 @@ QualType Sema::SubstType(QualType T,
// If T is not a dependent type or a variably-modified type, there
// is nothing to do.
- if (!T->isDependentType() && !T->isVariablyModifiedType())
+ if (!T->isInstantiationDependentType() && !T->isVariablyModifiedType())
return T;
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
@@ -1383,7 +1393,8 @@ QualType Sema::SubstType(QualType T,
}
static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
- if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType())
+ if (T->getType()->isInstantiationDependentType() ||
+ T->getType()->isVariablyModifiedType())
return true;
TypeLoc TL = T->getTypeLoc().IgnoreParens();
@@ -1397,7 +1408,7 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
// The parameter's type as written might be dependent even if the
// decayed type was not dependent.
if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo())
- if (TSInfo->getType()->isDependentType())
+ if (TSInfo->getType()->isInstantiationDependentType())
return true;
// TODO: currently we always rebuild expressions. When we
@@ -1798,9 +1809,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
// If the initialization is no longer dependent, check it now.
- if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent())
- && !NewField->getType()->isDependentType()
- && !NewInit.get()->isTypeDependent()) {
+ if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent() ||
+ OldInit->isValueDependent()) &&
+ !NewField->getType()->isDependentType() &&
+ !NewInit.get()->isTypeDependent() &&
+ !NewInit.get()->isValueDependent()) {
// FIXME: handle list-initialization
SourceLocation EqualLoc = NewField->getLocation();
NewInit = PerformCopyInitialization(
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e78aa29..29385e5 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -59,7 +59,7 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
// FIXME: Is this still too simple?
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
- Decl *Tmpl, Decl *New) {
+ const Decl *Tmpl, Decl *New) {
for (AttrVec::const_iterator i = Tmpl->attr_begin(), e = Tmpl->attr_end();
i != e; ++i) {
const Attr *TmplAttr = *i;
@@ -132,7 +132,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
bool IsTypeAlias) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType() ||
+ if (DI->getType()->isInstantiationDependentType() ||
DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
@@ -415,8 +415,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
!Var->isCXXForRangeDecl())
SemaRef.ActOnUninitializedDecl(Var, false);
- // Diagnose unused local variables.
- if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed())
+ // Diagnose unused local variables with dependent types, where the diagnostic
+ // will have been deferred.
+ if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed() &&
+ D->getType()->isDependentType())
SemaRef.DiagnoseUnusedDecl(Var);
return Var;
@@ -433,7 +435,7 @@ Decl *TemplateDeclInstantiator::VisitAccessSpecDecl(AccessSpecDecl *D) {
Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType() ||
+ if (DI->getType()->isInstantiationDependentType() ||
DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
@@ -1088,9 +1090,26 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Function->setLexicalDeclContext(LexicalDC);
// Attach the parameters
- for (unsigned P = 0; P < Params.size(); ++P)
- if (Params[P])
- Params[P]->setOwningFunction(Function);
+ if (isa<FunctionProtoType>(Function->getType().IgnoreParens())) {
+ // Adopt the already-instantiated parameters into our own context.
+ for (unsigned P = 0; P < Params.size(); ++P)
+ if (Params[P])
+ Params[P]->setOwningFunction(Function);
+ } else {
+ // Since we were instantiated via a typedef of a function type, create
+ // new parameters.
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "No function prototype in template instantiation?");
+ for (FunctionProtoType::arg_type_iterator AI = Proto->arg_type_begin(),
+ AE = Proto->arg_type_end(); AI != AE; ++AI) {
+ ParmVarDecl *Param
+ = SemaRef.BuildParmVarDeclForTypedef(Function, Function->getLocation(),
+ *AI);
+ Param->setScopeInfo(0, Params.size());
+ Params.push_back(Param);
+ }
+ }
Function->setParams(Params.data(), Params.size());
SourceLocation InstantiateAtPOI;
@@ -2264,7 +2283,12 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI));
}
- SemaRef.InstantiateAttrs(TemplateArgs, Tmpl, New);
+ const FunctionDecl* Definition = Tmpl;
+
+ // Get the definition. Leaves the variable unchanged if undefined.
+ Tmpl->isDefined(Definition);
+
+ SemaRef.InstantiateAttrs(TemplateArgs, Definition, New);
return false;
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 86d3bc1..daa1523 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -716,17 +716,19 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
- if (DeclarationName CorrectedName = CorrectTypo(R, S, 0, 0, false,
- CTC_NoKeywords)) {
- if (NamedDecl *CorrectedResult = R.getAsSingle<NamedDecl>())
+ if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), S, 0, 0,
+ false, CTC_NoKeywords)) {
+ if (NamedDecl *CorrectedResult = Corrected.getCorrectionDecl())
if (CorrectedResult->isParameterPack()) {
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
ParameterPack = CorrectedResult;
Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
- << &Name << CorrectedName
- << FixItHint::CreateReplacement(NameLoc,
- CorrectedName.getAsString());
+ << &Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(
+ NameLoc, Corrected.getAsString(getLangOptions()));
Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
- << CorrectedName;
+ << CorrectedQuotedStr;
}
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 5fd8afa..f3e73ec 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -26,36 +26,11 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/DelayedDiagnostic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
-/// \brief Perform adjustment on the parameter type of a function.
-///
-/// This routine adjusts the given parameter type @p T to the actual
-/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
-/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
-QualType Sema::adjustParameterType(QualType T) {
- // C99 6.7.5.3p7:
- // A declaration of a parameter as "array of type" shall be
- // adjusted to "qualified pointer to type", where the type
- // qualifiers (if any) are those specified within the [ and ] of
- // the array type derivation.
- if (T->isArrayType())
- return Context.getArrayDecayedType(T);
-
- // C99 6.7.5.3p8:
- // A declaration of a parameter as "function returning type"
- // shall be adjusted to "pointer to function returning type", as
- // in 6.3.2.1.
- if (T->isFunctionType())
- return Context.getPointerType(T);
-
- return T;
-}
-
-
-
/// isOmittedBlockReturnType - Return true if this declarator is missing a
/// return type because this is a omitted return type on a block literal.
static bool isOmittedBlockReturnType(const Declarator &D) {
@@ -86,6 +61,11 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
useInstantiationLoc = true;
break;
+ case AttributeList::AT_objc_ownership:
+ diagID = diag::warn_objc_object_attribute_wrong_type;
+ useInstantiationLoc = true;
+ break;
+
default:
// Assume everything else was a function attribute.
diagID = diag::warn_function_attribute_wrong_type;
@@ -110,7 +90,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
// objc_gc applies to Objective-C pointers or, otherwise, to the
// smallest available pointer type (i.e. 'void*' in 'void**').
#define OBJC_POINTER_TYPE_ATTRS_CASELIST \
- case AttributeList::AT_objc_gc
+ case AttributeList::AT_objc_gc: \
+ case AttributeList::AT_objc_ownership
// Function type attributes.
#define FUNCTION_TYPE_ATTRS_CASELIST \
@@ -295,11 +276,15 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
static bool handleObjCGCTypeAttr(TypeProcessingState &state,
AttributeList &attr, QualType &type);
+static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
+ AttributeList &attr, QualType &type);
+
static bool handleObjCPointerTypeAttr(TypeProcessingState &state,
AttributeList &attr, QualType &type) {
- // Right now, we have exactly one of these attributes: objc_gc.
- assert(attr.getKind() == AttributeList::AT_objc_gc);
- return handleObjCGCTypeAttr(state, attr, type);
+ if (attr.getKind() == AttributeList::AT_objc_gc)
+ return handleObjCGCTypeAttr(state, attr, type);
+ assert(attr.getKind() == AttributeList::AT_objc_ownership);
+ return handleObjCOwnershipTypeAttr(state, attr, type);
}
/// Given that an objc_gc attribute was written somewhere on a
@@ -447,7 +432,12 @@ distributeFunctionTypeAttrToInnermost(TypeProcessingState &state,
return true;
}
- return handleFunctionTypeAttr(state, attr, declSpecType);
+ if (handleFunctionTypeAttr(state, attr, declSpecType)) {
+ spliceAttrOutOfList(attr, attrList);
+ return true;
+ }
+
+ return false;
}
/// A function type attribute was written in the decl spec. Try to
@@ -512,6 +502,11 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
+ case AttributeList::AT_ns_returns_retained:
+ if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+ break;
+ // fallthrough
+
FUNCTION_TYPE_ATTRS_CASELIST:
distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
@@ -560,6 +555,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*args*/ 0, 0,
/*type quals*/ 0,
/*ref-qualifier*/true, SourceLocation(),
+ /*mutable qualifier*/SourceLocation(),
/*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0,
/*parens*/ loc, loc,
declarator));
@@ -575,10 +571,11 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/// \param D the declarator containing the declaration specifier.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
-static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
+static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
+ Sema &S = state.getSema();
Declarator &declarator = state.getDeclarator();
const DeclSpec &DS = declarator.getDeclSpec();
SourceLocation DeclLoc = declarator.getIdentifierLoc();
@@ -1017,6 +1014,51 @@ QualType Sema::BuildParenType(QualType T) {
return Context.getParenType(T);
}
+/// Given that we're building a pointer or reference to the given
+static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
+ SourceLocation loc,
+ bool isReference) {
+ // Bail out if retention is unrequired or already specified.
+ if (!type->isObjCLifetimeType() ||
+ type.getObjCLifetime() != Qualifiers::OCL_None)
+ return type;
+
+ Qualifiers::ObjCLifetime implicitLifetime = Qualifiers::OCL_None;
+
+ // If the object type is const-qualified, we can safely use
+ // __unsafe_unretained. This is safe (because there are no read
+ // barriers), and it'll be safe to coerce anything but __weak* to
+ // the resulting type.
+ if (type.isConstQualified()) {
+ implicitLifetime = Qualifiers::OCL_ExplicitNone;
+
+ // Otherwise, check whether the static type does not require
+ // retaining. This currently only triggers for Class (possibly
+ // protocol-qualifed, and arrays thereof).
+ } else if (type->isObjCARCImplicitlyUnretainedType()) {
+ implicitLifetime = Qualifiers::OCL_ExplicitNone;
+
+ // If that failed, give an error and recover using __autoreleasing.
+ } else {
+ // These types can show up in private ivars in system headers, so
+ // we need this to not be an error in those cases. Instead we
+ // want to delay.
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ sema::DelayedDiagnostic::makeForbiddenType(loc,
+ diag::err_arc_indirect_no_ownership, type, isReference));
+ } else {
+ S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference;
+ }
+ implicitLifetime = Qualifiers::OCL_Autoreleasing;
+ }
+ assert(implicitLifetime && "didn't infer any lifetime!");
+
+ Qualifiers qs;
+ qs.addObjCLifetime(implicitLifetime);
+ return S.Context.getQualifiedType(type, qs);
+}
+
/// \brief Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -1041,6 +1083,10 @@ QualType Sema::BuildPointerType(QualType T,
assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
+ // In ARC, it is forbidden to build pointers to unqualified pointers.
+ if (getLangOptions().ObjCAutoRefCount)
+ T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false);
+
// Build the pointer type.
return Context.getPointerType(T);
}
@@ -1094,12 +1140,38 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return QualType();
}
+ // In ARC, it is forbidden to build references to unqualified pointers.
+ if (getLangOptions().ObjCAutoRefCount)
+ T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
+
// Handle restrict on references.
if (LValueRef)
return Context.getLValueReferenceType(T, SpelledAsLValue);
return Context.getRValueReferenceType(T);
}
+/// Check whether the specified array size makes the array type a VLA. If so,
+/// return true, if not, return the size of the array in SizeVal.
+static bool isArraySizeVLA(Expr *ArraySize, llvm::APSInt &SizeVal, Sema &S) {
+ // If the size is an ICE, it certainly isn't a VLA.
+ if (ArraySize->isIntegerConstantExpr(SizeVal, S.Context))
+ return false;
+
+ // If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable
+ // value as an extension.
+ Expr::EvalResult Result;
+ if (S.LangOpts.GNUMode && ArraySize->Evaluate(Result, S.Context)) {
+ if (!Result.hasSideEffects() && Result.Val.isInt()) {
+ SizeVal = Result.Val.getInt();
+ S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
/// \brief Build an array type.
///
/// \param T The type of each element in the array.
@@ -1200,11 +1272,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getIncompleteArrayType(T, ASM, Quals);
} else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) {
T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
- } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
- (!T->isDependentType() && !T->isIncompleteType() &&
- !T->isConstantSizeType())) {
- // Per C99, a variable array is an array with either a non-constant
- // size or an element type that has a non-constant-size
+ } else if (!T->isDependentType() && !T->isIncompleteType() &&
+ !T->isConstantSizeType()) {
+ // C99: an array with an element type that has a non-constant-size is a VLA.
+ T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
+ } else if (isArraySizeVLA(ArraySize, ConstVal, *this)) {
+ // C99: an array with a non-ICE size is a VLA. We accept any expression
+ // that we can fold to a non-zero positive value as an extension.
T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
} else {
// C99 6.7.5.2p1: If the expression is a constant expression, it shall
@@ -1242,10 +1316,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (!getLangOptions().C99) {
if (T->isVariableArrayType()) {
// Prohibit the use of non-POD types in VLAs.
+ QualType BaseT = Context.getBaseElementType(T);
if (!T->isDependentType() &&
- !Context.getBaseElementType(T)->isPODType()) {
+ !BaseT.isPODType(Context) &&
+ !BaseT->isObjCLifetimeType()) {
Diag(Loc, diag::err_vla_non_pod)
- << Context.getBaseElementType(T);
+ << BaseT;
return QualType();
}
// Prohibit the use of VLAs during template argument deduction.
@@ -1296,8 +1372,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return QualType();
}
- if (!T->isDependentType())
- return Context.getExtVectorType(T, vectorSize);
+ return Context.getExtVectorType(T, vectorSize);
}
return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
@@ -1347,7 +1422,7 @@ QualType Sema::BuildFunctionType(QualType T,
bool Invalid = false;
for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
- QualType ParamType = adjustParameterType(ParamTypes[Idx]);
+ QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
if (ParamType->isVoidType()) {
Diag(Loc, diag::err_param_with_void_type);
Invalid = true;
@@ -1467,6 +1542,109 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) {
return QT;
}
+static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
+ Qualifiers::ObjCLifetime ownership,
+ unsigned chunkIndex);
+
+/// Given that this is the declaration of a parameter under ARC,
+/// attempt to infer attributes and such for pointer-to-whatever
+/// types.
+static void inferARCWriteback(TypeProcessingState &state,
+ QualType &declSpecType) {
+ Sema &S = state.getSema();
+ Declarator &declarator = state.getDeclarator();
+
+ // TODO: should we care about decl qualifiers?
+
+ // Check whether the declarator has the expected form. We walk
+ // from the inside out in order to make the block logic work.
+ unsigned outermostPointerIndex = 0;
+ bool isBlockPointer = false;
+ unsigned numPointers = 0;
+ for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) {
+ unsigned chunkIndex = i;
+ DeclaratorChunk &chunk = declarator.getTypeObject(chunkIndex);
+ switch (chunk.Kind) {
+ case DeclaratorChunk::Paren:
+ // Ignore parens.
+ break;
+
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pointer:
+ // Count the number of pointers. Treat references
+ // interchangeably as pointers; if they're mis-ordered, normal
+ // type building will discover that.
+ outermostPointerIndex = chunkIndex;
+ numPointers++;
+ break;
+
+ case DeclaratorChunk::BlockPointer:
+ // If we have a pointer to block pointer, that's an acceptable
+ // indirect reference; anything else is not an application of
+ // the rules.
+ if (numPointers != 1) return;
+ numPointers++;
+ outermostPointerIndex = chunkIndex;
+ isBlockPointer = true;
+
+ // We don't care about pointer structure in return values here.
+ goto done;
+
+ case DeclaratorChunk::Array: // suppress if written (id[])?
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::MemberPointer:
+ return;
+ }
+ }
+ done:
+
+ // If we have *one* pointer, then we want to throw the qualifier on
+ // the declaration-specifiers, which means that it needs to be a
+ // retainable object type.
+ if (numPointers == 1) {
+ // If it's not a retainable object type, the rule doesn't apply.
+ if (!declSpecType->isObjCRetainableType()) return;
+
+ // If it already has lifetime, don't do anything.
+ if (declSpecType.getObjCLifetime()) return;
+
+ // Otherwise, modify the type in-place.
+ Qualifiers qs;
+
+ if (declSpecType->isObjCARCImplicitlyUnretainedType())
+ qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
+ else
+ qs.addObjCLifetime(Qualifiers::OCL_Autoreleasing);
+ declSpecType = S.Context.getQualifiedType(declSpecType, qs);
+
+ // If we have *two* pointers, then we want to throw the qualifier on
+ // the outermost pointer.
+ } else if (numPointers == 2) {
+ // If we don't have a block pointer, we need to check whether the
+ // declaration-specifiers gave us something that will turn into a
+ // retainable object pointer after we slap the first pointer on it.
+ if (!isBlockPointer && !declSpecType->isObjCObjectType())
+ return;
+
+ // Look for an explicit lifetime attribute there.
+ DeclaratorChunk &chunk = declarator.getTypeObject(outermostPointerIndex);
+ if (chunk.Kind != DeclaratorChunk::Pointer &&
+ chunk.Kind != DeclaratorChunk::BlockPointer)
+ return;
+ for (const AttributeList *attr = chunk.getAttrs(); attr;
+ attr = attr->getNext())
+ if (attr->getKind() == AttributeList::AT_objc_ownership)
+ return;
+
+ transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing,
+ outermostPointerIndex);
+
+ // Any other number of pointers/references does not trigger the rule.
+ } else return;
+
+ // TODO: mark whether we did this inference?
+}
+
static void DiagnoseIgnoredQualifiers(unsigned Quals,
SourceLocation ConstQualLoc,
SourceLocation VolatileQualLoc,
@@ -1513,47 +1691,28 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals,
<< QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt;
}
-/// GetTypeForDeclarator - Convert the type for the specified
-/// declarator to Type instances.
-///
-/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq
-/// owns the declaration of a type (e.g., the definition of a struct
-/// type), then *OwnedDecl will receive the owned declaration.
-///
-/// The result of this call will never be null, but the associated
-/// type may be a null type if there's an unrecoverable error.
-TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
- TagDecl **OwnedDecl,
- bool AutoAllowedInTypeName) {
- // Determine the type of the declarator. Not all forms of declarator
- // have a type.
+static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
+ TypeSourceInfo *&ReturnTypeInfo) {
+ Sema &SemaRef = state.getSema();
+ Declarator &D = state.getDeclarator();
QualType T;
- TypeSourceInfo *ReturnTypeInfo = 0;
-
- TypeProcessingState state(*this, D);
+ ReturnTypeInfo = 0;
- // In C++0x, deallocation functions (normal and array operator delete)
- // are implicitly noexcept.
- bool ImplicitlyNoexcept = false;
+ // The TagDecl owned by the DeclSpec.
+ TagDecl *OwnedTagDecl = 0;
switch (D.getName().getKind()) {
+ case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_OperatorFunctionId:
- if (getLangOptions().CPlusPlus0x) {
- OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
- if (OO == OO_Delete || OO == OO_Array_Delete)
- ImplicitlyNoexcept = true;
- }
- // Intentional fall-through.
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
- T = ConvertDeclSpecToType(*this, state);
+ T = ConvertDeclSpecToType(state);
if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
- TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
+ OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
// Owned declaration is embedded in declarator.
- Owned->setEmbeddedInDeclarator(true);
- if (OwnedDecl) *OwnedDecl = Owned;
+ OwnedTagDecl->setEmbeddedInDeclarator(true);
}
break;
@@ -1562,14 +1721,14 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case UnqualifiedId::IK_DestructorName:
// Constructors and destructors don't have return types. Use
// "void" instead.
- T = Context.VoidTy;
+ T = SemaRef.Context.VoidTy;
break;
case UnqualifiedId::IK_ConversionFunctionId:
// The result type of a conversion function is the type that it
// converts to.
- T = GetTypeFromParser(D.getName().ConversionFunctionId,
- &ReturnTypeInfo);
+ T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
+ &ReturnTypeInfo);
break;
}
@@ -1581,7 +1740,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- (!getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) {
+ (!SemaRef.getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) {
int Error = -1;
switch (D.getContext()) {
@@ -1595,7 +1754,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::MemberContext:
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
break;
- switch (cast<TagDecl>(CurContext)->getTagKind()) {
+ switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) {
case TTK_Enum: assert(0 && "unhandled tag kind"); break;
case TTK_Struct: Error = 1; /* Struct member */ break;
case TTK_Union: Error = 2; /* Union member */ break;
@@ -1603,6 +1762,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
break;
case Declarator::CXXCatchContext:
+ case Declarator::ObjCCatchContext:
Error = 4; // Exception declaration
break;
case Declarator::TemplateParamContext:
@@ -1619,13 +1779,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
Error = 9; // Type alias
break;
case Declarator::TypeNameContext:
- if (!AutoAllowedInTypeName)
- Error = 11; // Generic
+ Error = 11; // Generic
break;
case Declarator::FileContext:
case Declarator::BlockContext:
case Declarator::ForContext:
case Declarator::ConditionContext:
+ case Declarator::CXXNewContext:
break;
}
@@ -1640,7 +1800,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// contains a trailing return type. That is only legal at the outermost
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
- if (getLangOptions().CPlusPlus0x && Error != -1) {
+ if (SemaRef.getLangOptions().CPlusPlus0x && Error != -1) {
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
@@ -1656,15 +1816,86 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
if (Error != -1) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed)
+ SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ diag::err_auto_not_allowed)
<< Error;
- T = Context.IntTy;
+ T = SemaRef.Context.IntTy;
D.setInvalidType(true);
}
}
-
- if (T.isNull())
- return Context.getNullTypeSourceInfo();
+
+ if (SemaRef.getLangOptions().CPlusPlus &&
+ OwnedTagDecl && OwnedTagDecl->isDefinition()) {
+ // Check the contexts where C++ forbids the declaration of a new class
+ // or enumeration in a type-specifier-seq.
+ switch (D.getContext()) {
+ case Declarator::FileContext:
+ case Declarator::MemberContext:
+ case Declarator::BlockContext:
+ case Declarator::ForContext:
+ case Declarator::BlockLiteralContext:
+ // C++0x [dcl.type]p3:
+ // A type-specifier-seq shall not define a class or enumeration unless
+ // it appears in the type-id of an alias-declaration (7.1.3) that is not
+ // the declaration of a template-declaration.
+ case Declarator::AliasDeclContext:
+ break;
+ case Declarator::AliasTemplateContext:
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_alias_template)
+ << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ break;
+ case Declarator::TypeNameContext:
+ case Declarator::TemplateParamContext:
+ case Declarator::CXXNewContext:
+ case Declarator::CXXCatchContext:
+ case Declarator::ObjCCatchContext:
+ case Declarator::TemplateTypeArgContext:
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_type_specifier)
+ << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ break;
+ case Declarator::PrototypeContext:
+ case Declarator::ObjCPrototypeContext:
+ case Declarator::KNRTypeListContext:
+ // C++ [dcl.fct]p6:
+ // Types shall not be defined in return or parameter types.
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_param_type)
+ << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ break;
+ case Declarator::ConditionContext:
+ // C++ 6.4p2:
+ // The type-specifier-seq shall not contain typedef and shall not declare
+ // a new class or enumeration.
+ SemaRef.Diag(OwnedTagDecl->getLocation(),
+ diag::err_type_defined_in_condition);
+ break;
+ }
+ }
+
+ return T;
+}
+
+static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
+ QualType declSpecType,
+ TypeSourceInfo *TInfo) {
+
+ QualType T = declSpecType;
+ Declarator &D = state.getDeclarator();
+ Sema &S = state.getSema();
+ ASTContext &Context = S.Context;
+ const LangOptions &LangOpts = S.getLangOptions();
+
+ bool ImplicitlyNoexcept = false;
+ if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId &&
+ LangOpts.CPlusPlus0x) {
+ OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
+ /// In C++0x, deallocation functions (normal and array operator delete)
+ /// are implicitly noexcept.
+ if (OO == OO_Delete || OO == OO_Array_Delete)
+ ImplicitlyNoexcept = true;
+ }
// The name we're declaring, if any.
DeclarationName Name;
@@ -1687,56 +1918,56 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
switch (DeclType.Kind) {
default: assert(0 && "Unknown decltype!");
case DeclaratorChunk::Paren:
- T = BuildParenType(T);
+ T = S.BuildParenType(T);
break;
case DeclaratorChunk::BlockPointer:
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
- Diag(DeclType.Loc, diag::err_blocks_disable);
+ S.Diag(DeclType.Loc, diag::err_blocks_disable);
- T = BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
+ T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
if (DeclType.Cls.TypeQuals)
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals);
break;
case DeclaratorChunk::Pointer:
// Verify that we're not building a pointer to pointer to function with
// exception specification.
- if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
- Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
}
- if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) {
+ if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) {
T = Context.getObjCObjectPointerType(T);
if (DeclType.Ptr.TypeQuals)
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
break;
}
- T = BuildPointerType(T, DeclType.Loc, Name);
+ T = S.BuildPointerType(T, DeclType.Loc, Name);
if (DeclType.Ptr.TypeQuals)
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
break;
case DeclaratorChunk::Reference: {
// Verify that we're not building a reference to pointer to function with
// exception specification.
- if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
- Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
}
- T = BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name);
+ T = S.BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name);
Qualifiers Quals;
if (DeclType.Ref.HasRestrict)
- T = BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict);
+ T = S.BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict);
break;
}
case DeclaratorChunk::Array: {
// Verify that we're not building an array of pointers to function with
// exception specification.
- if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
- Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
}
@@ -1753,13 +1984,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// FIXME: This check isn't quite right: it allows star in prototypes
// for function definitions, and disallows some edge cases detailed
// in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html
- Diag(DeclType.Loc, diag::err_array_star_outside_prototype);
+ S.Diag(DeclType.Loc, diag::err_array_star_outside_prototype);
ASM = ArrayType::Normal;
D.setInvalidType(true);
}
- T = BuildArrayType(T, ASM, ArraySize,
- Qualifiers::fromCVRMask(ATI.TypeQuals),
- SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
+ T = S.BuildArrayType(T, ASM, ArraySize,
+ Qualifiers::fromCVRMask(ATI.TypeQuals),
+ SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
break;
}
case DeclaratorChunk::Function: {
@@ -1775,27 +2006,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// and not, for instance, a pointer to a function.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
!FTI.TrailingReturnType && chunkIndex == 0) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_auto_missing_trailing_return);
T = Context.IntTy;
D.setInvalidType(true);
} else if (FTI.TrailingReturnType) {
// T must be exactly 'auto' at this point. See CWG issue 681.
if (isa<ParenType>(T)) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_in_parens)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
} else if (T.hasQualifiers() || !isa<AutoType>(T)) {
- Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
}
- T = GetTypeFromParser(
+ T = S.GetTypeFromParser(
ParsedType::getFromOpaquePtr(FTI.TrailingReturnType),
- &ReturnTypeInfo);
+ &TInfo);
}
}
@@ -1809,7 +2040,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (chunkIndex == 0 &&
D.getContext() == Declarator::BlockLiteralContext)
diagID = diag::err_block_returning_array_function;
- Diag(DeclType.Loc, diagID) << T->isFunctionType() << T;
+ S.Diag(DeclType.Loc, diagID) << T->isFunctionType() << T;
T = Context.IntTy;
D.setInvalidType(true);
}
@@ -1818,7 +2049,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// class type in C++.
if (isa<PointerType>(T) && T.getLocalCVRQualifiers() &&
(D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) &&
- (!getLangOptions().CPlusPlus || !T->isDependentType())) {
+ (!LangOpts.CPlusPlus || !T->isDependentType())) {
assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?");
DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer);
@@ -1829,43 +2060,43 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
- *this);
+ S);
} else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
- (!getLangOptions().CPlusPlus ||
+ (!LangOpts.CPlusPlus ||
(!T->isDependentType() && !T->isRecordType()))) {
DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(),
D.getDeclSpec().getConstSpecLoc(),
D.getDeclSpec().getVolatileSpecLoc(),
D.getDeclSpec().getRestrictSpecLoc(),
- *this);
+ S);
}
- if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
+ if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
if (Tag->isDefinition())
- Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
+ S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
<< Context.getTypeDeclType(Tag);
}
// Exception specs are not allowed in typedefs. Complain, but add it
// anyway.
if (IsTypedefName && FTI.getExceptionSpecType())
- Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
+ S.Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
<< (D.getContext() == Declarator::AliasDeclContext ||
D.getContext() == Declarator::AliasTemplateContext);
- if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) {
+ if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T);
} else {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable" attribute. Scan
// for this attribute now.
- if (!FTI.NumArgs && FTI.isVariadic && !getLangOptions().CPlusPlus) {
+ if (!FTI.NumArgs && FTI.isVariadic && !LangOpts.CPlusPlus) {
bool Overloadable = false;
for (const AttributeList *Attrs = D.getAttributes();
Attrs; Attrs = Attrs->getNext()) {
@@ -1876,13 +2107,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
if (!Overloadable)
- Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
+ S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
}
if (FTI.NumArgs && FTI.ArgInfo[0].Param == 0) {
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function
// definition.
- Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
+ S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
D.setInvalidType(true);
break;
}
@@ -1899,13 +2130,18 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
llvm::SmallVector<QualType, 16> ArgTys;
ArgTys.reserve(FTI.NumArgs);
+ llvm::SmallVector<bool, 16> ConsumedArguments;
+ ConsumedArguments.reserve(FTI.NumArgs);
+ bool HasAnyConsumedArguments = false;
+
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
QualType ArgTy = Param->getType();
assert(!ArgTy.isNull() && "Couldn't parse type?");
// Adjust the parameter type.
- assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?");
+ assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) &&
+ "Unadjusted type?");
// Look for 'void'. void is allowed only as a single argument to a
// function with no other parameters (C99 6.7.5.3p10). We record
@@ -1915,19 +2151,19 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// is an incomplete type (C99 6.2.5p19) and function decls cannot
// have arguments of incomplete type.
if (FTI.NumArgs != 1 || FTI.isVariadic) {
- Diag(DeclType.Loc, diag::err_void_only_param);
+ S.Diag(DeclType.Loc, diag::err_void_only_param);
ArgTy = Context.IntTy;
Param->setType(ArgTy);
} else if (FTI.ArgInfo[i].Ident) {
// Reject, but continue to parse 'int(void abc)'.
- Diag(FTI.ArgInfo[i].IdentLoc,
+ S.Diag(FTI.ArgInfo[i].IdentLoc,
diag::err_param_with_void_type);
ArgTy = Context.IntTy;
Param->setType(ArgTy);
} else {
// Reject, but continue to parse 'float(const void)'.
if (ArgTy.hasQualifiers())
- Diag(DeclType.Loc, diag::err_void_param_qualified);
+ S.Diag(DeclType.Loc, diag::err_void_param_qualified);
// Do not add 'void' to the ArgTys list.
break;
@@ -1944,19 +2180,28 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
+ if (LangOpts.ObjCAutoRefCount) {
+ bool Consumed = Param->hasAttr<NSConsumedAttr>();
+ ConsumedArguments.push_back(Consumed);
+ HasAnyConsumedArguments |= Consumed;
+ }
+
ArgTys.push_back(ArgTy);
}
+ if (HasAnyConsumedArguments)
+ EPI.ConsumedArguments = ConsumedArguments.data();
+
llvm::SmallVector<QualType, 4> Exceptions;
EPI.ExceptionSpecType = FTI.getExceptionSpecType();
if (FTI.getExceptionSpecType() == EST_Dynamic) {
Exceptions.reserve(FTI.NumExceptions);
for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
// FIXME: Preserve type source info.
- QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty);
+ QualType ET = S.GetTypeFromParser(FTI.Exceptions[ei].Ty);
// Check that the type is valid for an exception spec, and
// drop it if not.
- if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+ if (!S.CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
Exceptions.push_back(ET);
}
EPI.NumExceptions = Exceptions.size();
@@ -1973,7 +2218,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (!NoexceptExpr->isValueDependent() &&
!NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc,
/*evaluated*/false))
- Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
+ S.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
<< NoexceptExpr->getSourceRange();
else
EPI.NoexceptExpr = NoexceptExpr;
@@ -1996,8 +2241,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (SS.isInvalid()) {
// Avoid emitting extra errors if we already errored on the scope.
D.setInvalidType(true);
- } else if (isDependentScopeSpecifier(SS) ||
- dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS))) {
+ } else if (S.isDependentScopeSpecifier(SS) ||
+ dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS))) {
NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier*>(SS.getScopeRep());
NestedNameSpecifier *NNSPrefix = NNS->getPrefix();
@@ -2026,7 +2271,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
} else {
- Diag(DeclType.Mem.Scope().getBeginLoc(),
+ S.Diag(DeclType.Mem.Scope().getBeginLoc(),
diag::err_illegal_decl_mempointer_in_nonclass)
<< (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
<< DeclType.Mem.Scope().getRange();
@@ -2034,12 +2279,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
if (!ClsType.isNull())
- T = BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier());
+ T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier());
if (T.isNull()) {
T = Context.IntTy;
D.setInvalidType(true);
} else if (DeclType.Mem.TypeQuals) {
- T = BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals);
+ T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals);
}
break;
}
@@ -2054,7 +2299,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
processTypeAttrs(state, T, false, attrs);
}
- if (getLangOptions().CPlusPlus && T->isFunctionType()) {
+ if (LangOpts.CPlusPlus && T->isFunctionType()) {
const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>();
assert(FnTy && "Why oh why is there not a FunctionProtoType here?");
@@ -2071,7 +2316,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FreeFunction = (D.getContext() != Declarator::MemberContext ||
D.getDeclSpec().isFriendSpecified());
} else {
- DeclContext *DC = computeDeclContext(D.getCXXScopeSpec());
+ DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec());
FreeFunction = (DC && !DC->isRecord());
}
@@ -2109,16 +2354,16 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::ext_qualified_function_type_template_arg)
<< Quals;
} else {
if (FnTy->getTypeQuals() != 0) {
if (D.isFunctionDeclarator())
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::err_invalid_qualified_function_type);
else
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::err_invalid_qualified_typedef_function_type_use)
<< FreeFunction;
}
@@ -2135,11 +2380,11 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
- Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
+ S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
<< (FnTy->getRefQualifier() == RQ_LValue)
<< FixItHint::CreateRemoval(Loc);
} else {
- Diag(D.getIdentifierLoc(),
+ S.Diag(D.getIdentifierLoc(),
diag::err_invalid_ref_qualifier_typedef_function_type_use)
<< FreeFunction
<< (FnTy->getRefQualifier() == RQ_LValue);
@@ -2192,7 +2437,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// We represent function parameter packs as function parameters whose
// type is a pack expansion.
if (!T->containsUnexpandedParameterPack()) {
- Diag(D.getEllipsisLoc(),
+ S.Diag(D.getEllipsisLoc(),
diag::err_function_parameter_pack_without_parameter_packs)
<< T << D.getSourceRange();
D.setEllipsisLoc(SourceLocation());
@@ -2212,14 +2457,15 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
- else if (!getLangOptions().CPlusPlus0x)
- Diag(D.getEllipsisLoc(), diag::ext_variadic_templates);
+ else if (!LangOpts.CPlusPlus0x)
+ S.Diag(D.getEllipsisLoc(), diag::ext_variadic_templates);
break;
case Declarator::FileContext:
case Declarator::KNRTypeListContext:
case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
+ case Declarator::CXXNewContext:
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
case Declarator::MemberContext:
@@ -2227,11 +2473,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::ForContext:
case Declarator::ConditionContext:
case Declarator::CXXCatchContext:
+ case Declarator::ObjCCatchContext:
case Declarator::BlockLiteralContext:
case Declarator::TemplateTypeArgContext:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
- Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter);
+ S.Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter);
D.setEllipsisLoc(SourceLocation());
break;
}
@@ -2241,7 +2488,138 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
return Context.getNullTypeSourceInfo();
else if (D.isInvalidType())
return Context.getTrivialTypeSourceInfo(T);
- return GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo);
+
+ return S.GetTypeSourceInfoForDeclarator(D, T, TInfo);
+}
+
+/// GetTypeForDeclarator - Convert the type for the specified
+/// declarator to Type instances.
+///
+/// The result of this call will never be null, but the associated
+/// type may be a null type if there's an unrecoverable error.
+TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
+ // Determine the type of the declarator. Not all forms of declarator
+ // have a type.
+
+ TypeProcessingState state(*this, D);
+
+ TypeSourceInfo *ReturnTypeInfo = 0;
+ QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
+ if (T.isNull())
+ return Context.getNullTypeSourceInfo();
+
+ if (D.isPrototypeContext() && getLangOptions().ObjCAutoRefCount)
+ inferARCWriteback(state, T);
+
+ return GetFullTypeForDeclarator(state, T, ReturnTypeInfo);
+}
+
+static void transferARCOwnershipToDeclSpec(Sema &S,
+ QualType &declSpecTy,
+ Qualifiers::ObjCLifetime ownership) {
+ if (declSpecTy->isObjCRetainableType() &&
+ declSpecTy.getObjCLifetime() == Qualifiers::OCL_None) {
+ Qualifiers qs;
+ qs.addObjCLifetime(ownership);
+ declSpecTy = S.Context.getQualifiedType(declSpecTy, qs);
+ }
+}
+
+static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
+ Qualifiers::ObjCLifetime ownership,
+ unsigned chunkIndex) {
+ Sema &S = state.getSema();
+ Declarator &D = state.getDeclarator();
+
+ // Look for an explicit lifetime attribute.
+ DeclaratorChunk &chunk = D.getTypeObject(chunkIndex);
+ for (const AttributeList *attr = chunk.getAttrs(); attr;
+ attr = attr->getNext())
+ if (attr->getKind() == AttributeList::AT_objc_ownership)
+ return;
+
+ const char *attrStr = 0;
+ switch (ownership) {
+ case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break;
+ case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break;
+ case Qualifiers::OCL_Strong: attrStr = "strong"; break;
+ case Qualifiers::OCL_Weak: attrStr = "weak"; break;
+ case Qualifiers::OCL_Autoreleasing: attrStr = "autoreleasing"; break;
+ }
+
+ // If there wasn't one, add one (with an invalid source location
+ // so that we don't make an AttributedType for it).
+ AttributeList *attr = D.getAttributePool()
+ .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(),
+ /*scope*/ 0, SourceLocation(),
+ &S.Context.Idents.get(attrStr), SourceLocation(),
+ /*args*/ 0, 0,
+ /*declspec*/ false, /*C++0x*/ false);
+ spliceAttrIntoList(*attr, chunk.getAttrListRef());
+
+ // TODO: mark whether we did this inference?
+}
+
+static void transferARCOwnership(TypeProcessingState &state,
+ QualType &declSpecTy,
+ Qualifiers::ObjCLifetime ownership) {
+ Sema &S = state.getSema();
+ Declarator &D = state.getDeclarator();
+
+ int inner = -1;
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+ DeclaratorChunk &chunk = D.getTypeObject(i);
+ switch (chunk.Kind) {
+ case DeclaratorChunk::Paren:
+ // Ignore parens.
+ break;
+
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pointer:
+ inner = i;
+ break;
+
+ case DeclaratorChunk::BlockPointer:
+ return transferARCOwnershipToDeclaratorChunk(state, ownership, i);
+
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::MemberPointer:
+ return;
+ }
+ }
+
+ if (inner == -1)
+ return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
+
+ DeclaratorChunk &chunk = D.getTypeObject(inner);
+ if (chunk.Kind == DeclaratorChunk::Pointer) {
+ if (declSpecTy->isObjCRetainableType())
+ return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
+ if (declSpecTy->isObjCObjectType())
+ return transferARCOwnershipToDeclaratorChunk(state, ownership, inner);
+ } else {
+ assert(chunk.Kind == DeclaratorChunk::Array ||
+ chunk.Kind == DeclaratorChunk::Reference);
+ return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
+ }
+}
+
+TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
+ TypeProcessingState state(*this, D);
+
+ TypeSourceInfo *ReturnTypeInfo = 0;
+ QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
+ if (declSpecTy.isNull())
+ return Context.getNullTypeSourceInfo();
+
+ if (getLangOptions().ObjCAutoRefCount) {
+ Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy);
+ if (ownership != Qualifiers::OCL_None)
+ transferARCOwnership(state, declSpecTy, ownership);
+ }
+
+ return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo);
}
/// Map an AttributedType::Kind to an AttributeList::Kind.
@@ -2259,6 +2637,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_neon_polyvector_type;
case AttributedType::attr_objc_gc:
return AttributeList::AT_objc_gc;
+ case AttributedType::attr_objc_ownership:
+ return AttributeList::AT_objc_ownership;
case AttributedType::attr_noreturn:
return AttributeList::AT_noreturn;
case AttributedType::attr_cdecl:
@@ -2489,6 +2869,9 @@ namespace {
llvm_unreachable("qualified type locs not expected here!");
}
+ void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ fillAttributedTypeLoc(TL, Chunk.getAttrs());
+ }
void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::BlockPointer);
TL.setCaretLoc(Chunk.Loc);
@@ -2657,8 +3040,7 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// the parser.
assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
- TagDecl *OwnedTag = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedTag);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType T = TInfo->getType();
if (D.isInvalidType())
return true;
@@ -2666,26 +3048,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
if (getLangOptions().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
-
- // C++0x [dcl.type]p3:
- // A type-specifier-seq shall not define a class or enumeration unless
- // it appears in the type-id of an alias-declaration (7.1.3) that is not
- // the declaration of a template-declaration.
- if (OwnedTag && OwnedTag->isDefinition()) {
- if (D.getContext() == Declarator::AliasTemplateContext)
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template)
- << Context.getTypeDeclType(OwnedTag);
- else if (D.getContext() != Declarator::AliasDeclContext)
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
- << Context.getTypeDeclType(OwnedTag);
- }
}
return CreateParsedType(T, TInfo);
}
-
-
//===----------------------------------------------------------------------===//
// Type Attribute Processing
//===----------------------------------------------------------------------===//
@@ -2744,6 +3111,99 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
+/// handleObjCOwnershipTypeAttr - Process an objc_ownership
+/// attribute on the specified type.
+///
+/// Returns 'true' if the attribute was handled.
+static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
+ AttributeList &attr,
+ QualType &type) {
+ if (!type->isObjCRetainableType() && !type->isDependentType())
+ return false;
+
+ Sema &S = state.getSema();
+
+ if (type.getQualifiers().getObjCLifetime()) {
+ S.Diag(attr.getLoc(), diag::err_attr_objc_ownership_redundant)
+ << type;
+ return true;
+ }
+
+ if (!attr.getParameterName()) {
+ S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "objc_ownership" << 1;
+ attr.setInvalid();
+ return true;
+ }
+
+ Qualifiers::ObjCLifetime lifetime;
+ if (attr.getParameterName()->isStr("none"))
+ lifetime = Qualifiers::OCL_ExplicitNone;
+ else if (attr.getParameterName()->isStr("strong"))
+ lifetime = Qualifiers::OCL_Strong;
+ else if (attr.getParameterName()->isStr("weak"))
+ lifetime = Qualifiers::OCL_Weak;
+ else if (attr.getParameterName()->isStr("autoreleasing"))
+ lifetime = Qualifiers::OCL_Autoreleasing;
+ else {
+ S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << "objc_ownership" << attr.getParameterName();
+ attr.setInvalid();
+ return true;
+ }
+
+ // Consume lifetime attributes without further comment outside of
+ // ARC mode.
+ if (!S.getLangOptions().ObjCAutoRefCount)
+ return true;
+
+ Qualifiers qs;
+ qs.setObjCLifetime(lifetime);
+ QualType origType = type;
+ type = S.Context.getQualifiedType(type, qs);
+
+ // If we have a valid source location for the attribute, use an
+ // AttributedType instead.
+ if (attr.getLoc().isValid())
+ type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
+ origType, type);
+
+ // Forbid __weak if the runtime doesn't support it.
+ if (lifetime == Qualifiers::OCL_Weak &&
+ !S.getLangOptions().ObjCRuntimeHasWeak) {
+
+ // Actually, delay this until we know what we're parsing.
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(),
+ diag::err_arc_weak_no_runtime, type, /*ignored*/ 0));
+ } else {
+ S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime);
+ }
+
+ attr.setInvalid();
+ return true;
+ }
+
+ // Forbid __weak for class objects marked as
+ // objc_arc_weak_reference_unavailable
+ if (lifetime == Qualifiers::OCL_Weak) {
+ QualType T = type;
+ while (const PointerType *ptr = T->getAs<PointerType>())
+ T = ptr->getPointeeType();
+ if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
+ ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
+ if (Class->isArcWeakrefUnavailable()) {
+ S.Diag(attr.getLoc(), diag::err_arc_unsupported_weak_class);
+ S.Diag(ObjT->getInterfaceDecl()->getLocation(),
+ diag::note_class_declared);
+ }
+ }
+ }
+
+ return true;
+}
+
/// handleObjCGCTypeAttr - Process the __attribute__((objc_gc)) type
/// attribute on the specified type. Returns true to indicate that
/// the attribute was handled, false to indicate that the type does
@@ -2954,6 +3414,23 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
+ // ns_returns_retained is not always a type attribute, but if we got
+ // here, we're treating it as one right now.
+ if (attr.getKind() == AttributeList::AT_ns_returns_retained) {
+ assert(S.getLangOptions().ObjCAutoRefCount &&
+ "ns_returns_retained treated as type attribute in non-ARC");
+ if (attr.getNumArgs()) return true;
+
+ // Delay if this is not a function type.
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ FunctionType::ExtInfo EI
+ = unwrapped.get()->getExtInfo().withProducesResult(true);
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ return true;
+ }
+
if (attr.getKind() == AttributeList::AT_regparm) {
unsigned value;
if (S.CheckRegparmAttr(attr, value))
@@ -3127,6 +3604,40 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr,
VectorType::GenericVector);
}
+/// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on
+/// a type.
+static void HandleExtVectorTypeAttr(QualType &CurType,
+ const AttributeList &Attr,
+ Sema &S) {
+ Expr *sizeExpr;
+
+ // Special case where the argument is a template id.
+ if (Attr.getParameterName()) {
+ CXXScopeSpec SS;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
+
+ ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, id, false,
+ false);
+ if (Size.isInvalid())
+ return;
+
+ sizeExpr = Size.get();
+ } else {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ sizeExpr = Attr.getArg(0);
+ }
+
+ // Create the vector type.
+ QualType T = S.BuildExtVectorType(CurType, sizeExpr, Attr.getLoc());
+ if (!T.isNull())
+ CurType = T;
+}
+
/// HandleNeonVectorTypeAttr - The "neon_vector_type" and
/// "neon_polyvector_type" attributes are used to create vector types that
/// are mangled according to ARM's ABI. Otherwise, these types are identical
@@ -3217,6 +3728,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_vector_size:
HandleVectorSizeAttr(type, attr, state.getSema());
break;
+ case AttributeList::AT_ext_vector_type:
+ if (state.getDeclarator().getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_typedef)
+ HandleExtVectorTypeAttr(type, attr, state.getSema());
+ break;
case AttributeList::AT_neon_vector_type:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
VectorType::NeonVector, "neon_vector_type");
@@ -3226,11 +3742,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
VectorType::NeonPolyVector,
"neon_polyvector_type");
break;
-
case AttributeList::AT_opencl_image_access:
HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
break;
+ case AttributeList::AT_ns_returns_retained:
+ if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+ break;
+ // fallthrough into the function attrs
+
FUNCTION_TYPE_ATTRS_CASELIST:
// Never process function type attributes as part of the
// declaration-specifiers.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ff2e46a..fa87217 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1192,6 +1192,16 @@ public:
Body);
}
+ /// \brief Build a new Objective-C @autoreleasepool statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildObjCAutoreleasePoolStmt(SourceLocation AtLoc,
+ Stmt *Body) {
+ return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body);
+ }
+
+
/// \brief Build a new Objective-C fast enumeration statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1537,9 +1547,9 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildInitList(SourceLocation LBraceLoc,
- MultiExprArg Inits,
- SourceLocation RBraceLoc,
- QualType ResultTy) {
+ MultiExprArg Inits,
+ SourceLocation RBraceLoc,
+ QualType ResultTy) {
ExprResult Result
= SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
if (Result.isInvalid() || ResultTy->isDependentType())
@@ -1856,8 +1866,9 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, Expr *Sub) {
- return getSema().ActOnCXXThrow(ThrowLoc, Sub);
+ ExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, Expr *Sub,
+ bool IsThrownVariableInScope) {
+ return getSema().BuildCXXThrow(ThrowLoc, Sub, IsThrownVariableInScope);
}
/// \brief Build a new C++ default-argument expression.
@@ -2466,6 +2477,10 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
Outputs.push_back(Out.get());
continue;
}
+
+ // Record right away that the argument was changed. This needs
+ // to happen even if the array expands to nothing.
+ if (ArgChanged) *ArgChanged = true;
// The transform has determined that we should perform an elementwise
// expansion of the pattern. Do so.
@@ -2482,8 +2497,6 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
return true;
}
- if (ArgChanged)
- *ArgChanged = true;
Outputs.push_back(Out.get());
}
@@ -3162,6 +3175,38 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
if (Result->isFunctionType() || Result->isReferenceType())
return Result;
+ // Suppress Objective-C lifetime qualifiers if they don't make sense for the
+ // resulting type.
+ if (Quals.hasObjCLifetime()) {
+ if (!Result->isObjCLifetimeType() && !Result->isDependentType())
+ Quals.removeObjCLifetime();
+ else if (Result.getObjCLifetime()) {
+ // Objective-C ARC:
+ // A lifetime qualifier applied to a substituted template parameter
+ // overrides the lifetime qualifier from the template argument.
+ if (const SubstTemplateTypeParmType *SubstTypeParam
+ = dyn_cast<SubstTemplateTypeParmType>(Result)) {
+ QualType Replacement = SubstTypeParam->getReplacementType();
+ Qualifiers Qs = Replacement.getQualifiers();
+ Qs.removeObjCLifetime();
+ Replacement
+ = SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(),
+ Qs);
+ Result = SemaRef.Context.getSubstTemplateTypeParmType(
+ SubstTypeParam->getReplacedParameter(),
+ Replacement);
+ TLB.TypeWasModifiedSafely(Result);
+ } else {
+ // Otherwise, complain about the addition of a qualifier to an
+ // already-qualified type.
+ SourceRange R = TLB.getTemporaryTypeLoc(Result).getSourceRange();
+ SemaRef.Diag(R.getBegin(), diag::err_attr_objc_ownership_redundant)
+ << Result << R;
+
+ Quals.removeObjCLifetime();
+ }
+ }
+ }
if (!Quals.empty()) {
Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals);
TLB.push<QualifiedTypeLoc>(Result);
@@ -3333,7 +3378,11 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
-
+
+ // Objective-C ARC can add lifetime qualifiers to the type that we're
+ // pointing to.
+ TLB.TypeWasModifiedSafely(Result->getPointeeType());
+
PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result);
NewT.setSigilLoc(TL.getSigilLoc());
return Result;
@@ -3387,6 +3436,11 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
return QualType();
}
+ // Objective-C ARC can add lifetime qualifiers to the type that we're
+ // referring to.
+ TLB.TypeWasModifiedSafely(
+ Result->getAs<ReferenceType>()->getPointeeTypeAsWritten());
+
// r-value references can be rebuilt as l-value references.
ReferenceTypeLoc NewTL;
if (isa<LValueReferenceType>(Result))
@@ -5435,6 +5489,25 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
template<typename Derived>
StmtResult
+TreeTransform<Derived>::TransformObjCAutoreleasePoolStmt(
+ ObjCAutoreleasePoolStmt *S) {
+ // Transform the body.
+ StmtResult Body = getDerived().TransformStmt(S->getSubStmt());
+ if (Body.isInvalid())
+ return StmtError();
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Body.get() == S->getSubStmt())
+ return SemaRef.Owned(S);
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAutoreleasePoolStmt(
+ S->getAtLoc(), Body.get());
+}
+
+template<typename Derived>
+StmtResult
TreeTransform<Derived>::TransformObjCForCollectionStmt(
ObjCForCollectionStmt *S) {
// Transform the element statement.
@@ -6721,7 +6794,8 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E);
- return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get());
+ return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get(),
+ E->isThrownVariableInScope());
}
template<typename Derived>
@@ -6867,9 +6941,13 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
AllocType,
AllocTypeInfo,
ArraySize.get(),
- /*FIXME:*/E->getLocStart(),
+ /*FIXME:*/E->hasInitializer()
+ ? E->getLocStart()
+ : SourceLocation(),
move_arg(ConstructorArgs),
- E->getLocEnd());
+ /*FIXME:*/E->hasInitializer()
+ ? E->getLocEnd()
+ : SourceLocation());
}
template<typename Derived>
@@ -7587,6 +7665,21 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ // Default behavior is to do nothing with this transformation.
+ return SemaRef.Owned(E);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
+ MaterializeTemporaryExpr *E) {
+ return getDerived().TransformExpr(E->GetTemporaryExpr());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
return SemaRef.Owned(E);
}
@@ -7609,6 +7702,43 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
}
template<typename Derived>
+ExprResult TreeTransform<Derived>::
+TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+ ExprResult result = getDerived().TransformExpr(E->getSubExpr());
+ if (result.isInvalid()) return ExprError();
+ Expr *subExpr = result.take();
+
+ if (!getDerived().AlwaysRebuild() &&
+ subExpr == E->getSubExpr())
+ return SemaRef.Owned(E);
+
+ return SemaRef.Owned(new(SemaRef.Context)
+ ObjCIndirectCopyRestoreExpr(subExpr, E->getType(), E->shouldCopy()));
+}
+
+template<typename Derived>
+ExprResult TreeTransform<Derived>::
+TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+ TypeSourceInfo *TSInfo
+ = getDerived().TransformType(E->getTypeInfoAsWritten());
+ if (!TSInfo)
+ return ExprError();
+
+ ExprResult Result = getDerived().TransformExpr(E->getSubExpr());
+ if (Result.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ TSInfo == E->getTypeInfoAsWritten() &&
+ Result.get() == E->getSubExpr())
+ return SemaRef.Owned(E);
+
+ return SemaRef.BuildObjCBridgedCast(E->getLParenLoc(), E->getBridgeKind(),
+ E->getBridgeKeywordLoc(), TSInfo,
+ Result.get());
+}
+
+template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
// Transform arguments.
@@ -8227,11 +8357,24 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First);
}
- if (Op == OO_Subscript)
- return SemaRef.CreateOverloadedArraySubscriptExpr(Callee->getLocStart(),
- OpLoc,
- First,
- Second);
+ if (Op == OO_Subscript) {
+ SourceLocation LBrace;
+ SourceLocation RBrace;
+
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) {
+ DeclarationNameLoc &NameLoc = DRE->getNameInfo().getInfo();
+ LBrace = SourceLocation::getFromRawEncoding(
+ NameLoc.CXXOperatorName.BeginOpNameLoc);
+ RBrace = SourceLocation::getFromRawEncoding(
+ NameLoc.CXXOperatorName.EndOpNameLoc);
+ } else {
+ LBrace = Callee->getLocStart();
+ RBrace = OpLoc;
+ }
+
+ return SemaRef.CreateOverloadedArraySubscriptExpr(LBrace, RBrace,
+ First, Second);
+ }
// Create the overloaded operator invocation for binary operators.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 3570737..7a5e43e 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -16,7 +16,6 @@
#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
#include "clang/AST/TypeLoc.h"
-#include "llvm/ADT/SmallVector.h"
#include "clang/AST/ASTContext.h"
namespace clang {
@@ -87,6 +86,14 @@ class TypeLocBuilder {
Index = Capacity;
}
+ /// \brief Tell the TypeLocBuilder that the type it is storing has been
+ /// modified in some safe way that doesn't affect type-location information.
+ void TypeWasModifiedSafely(QualType T) {
+#ifndef NDEBUG
+ LastTy = T;
+#endif
+ }
+
/// Pushes space for a new TypeLoc of the given type. Invalidates
/// any TypeLocs previously retrieved from this builder.
template <class TyLocType> TyLocType push(QualType T) {
@@ -139,7 +146,7 @@ private:
Index -= LocalSize;
- return getTypeLoc(T);
+ return getTemporaryTypeLoc(T);
}
/// Grow to the given capacity.
@@ -171,15 +178,17 @@ private:
reserve(Size);
Index -= Size;
- return getTypeLoc(T);
+ return getTemporaryTypeLoc(T);
}
-
- // This is private because, when we kill off TypeSourceInfo in favor
- // of TypeLoc, we'll want an interface that creates a TypeLoc given
- // an ASTContext, and we don't want people to think they can just
- // use this as an equivalent.
- TypeLoc getTypeLoc(QualType T) {
+public:
+ /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
+ /// object.
+ ///
+ /// The resulting \c TypeLoc should only be used so long as the
+ /// \c TypeLocBuilder is active and has not had more type information
+ /// pushed into it.
+ TypeLoc getTemporaryTypeLoc(QualType T) {
#ifndef NDEBUG
assert(LastTy == T && "type doesn't match last type pushed!");
#endif
OpenPOWER on IntegriCloud