diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
commit | 53992adde3eda3ccf9da63bc7e45673f043de18f (patch) | |
tree | 3558f327a6f9ab59c5d7a06528d84e1560445247 /lib/Sema | |
parent | 7e411337c0ed226dace6e07f1420486768161308 (diff) | |
download | FreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.zip FreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.tar.gz |
Update clang to r104832.
Diffstat (limited to 'lib/Sema')
31 files changed, 3866 insertions, 1846 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 6ded0a3..448d161 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -54,8 +54,13 @@ static void CheckUnreachable(Sema &S, AnalysisContext &AC) { // Check for missing return value. //===----------------------------------------------------------------------===// -enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, - AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; +enum ControlFlowKind { + UnknownFallThrough, + NeverFallThrough, + MaybeFallThrough, + AlwaysFallThrough, + NeverFallThroughOrReturn +}; /// CheckFallThrough - Check that we don't fall off the end of a /// Statement that should return a value. @@ -68,9 +73,7 @@ enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, /// will return. static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { CFG *cfg = AC.getCFG(); - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; + if (cfg == 0) return UnknownFallThrough; // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. @@ -164,6 +167,19 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { } } } + // FIXME: Remove this hack once temporaries and their destructors are + // modeled correctly by the CFG. + if (CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(S)) { + for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) { + const FunctionDecl *FD = E->getTemporary(I)->getDestructor(); + if (FD->hasAttr<NoReturnAttr>() || + FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + break; + } + } + } // FIXME: Add noreturn message sends. if (NoReturnEdge == false) HasPlainEdge = true; @@ -290,6 +306,9 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // FIXME: Function try block if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { switch (CheckFallThrough(AC)) { + case UnknownFallThrough: + break; + case MaybeFallThrough: if (HasNoReturn) S.Diag(Compound->getRBracLoc(), diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index ac0dfd6..b54e8eb 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -34,4 +34,4 @@ add_clang_library(clangSema TargetAttributesSema.cpp ) -add_dependencies(clangSema ClangDiagnosticSema) +add_dependencies(clangSema ClangDiagnosticSema ClangStmtNodes) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 0ef9a15..6cefc61 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -210,9 +210,10 @@ CodeCompletionString::Chunk::Destroy() { } } -CodeCompletionString::~CodeCompletionString() { +void CodeCompletionString::clear() { std::for_each(Chunks.begin(), Chunks.end(), std::mem_fun_ref(&Chunk::Destroy)); + Chunks.clear(); } std::string CodeCompletionString::getAsString() const { @@ -310,15 +311,13 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { } } -CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, - const char *StrEnd) { +bool CodeCompletionString::Deserialize(const char *&Str, const char *StrEnd) { if (Str == StrEnd || *Str == 0) - return 0; + return false; - CodeCompletionString *Result = new CodeCompletionString; unsigned NumBlocks; if (ReadUnsigned(Str, StrEnd, NumBlocks)) - return Result; + return false; for (unsigned I = 0; I != NumBlocks; ++I) { if (Str + 1 >= StrEnd) @@ -327,7 +326,7 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, // Parse the next kind. unsigned KindValue; if (ReadUnsigned(Str, StrEnd, KindValue)) - return Result; + return false; switch (ChunkKind Kind = (ChunkKind)KindValue) { case CK_TypedText: @@ -338,16 +337,17 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_CurrentParameter: { unsigned StrLen; if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd)) - return Result; + return false; - Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen))); + AddChunk(Chunk(Kind, StringRef(Str, StrLen))); Str += StrLen; break; } case CK_Optional: { - std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd)); - Result->AddOptionalChunk(Optional); + std::auto_ptr<CodeCompletionString> Optional(new CodeCompletionString()); + if (Optional->Deserialize(Str, StrEnd)) + AddOptionalChunk(Optional); break; } @@ -365,12 +365,12 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_Equal: case CK_HorizontalSpace: case CK_VerticalSpace: - Result->AddChunk(Chunk(Kind)); + AddChunk(Chunk(Kind)); break; } }; - return Result; + return true; } void CodeCompleteConsumer::Result::Destroy() { @@ -380,6 +380,25 @@ void CodeCompleteConsumer::Result::Destroy() { } } +unsigned CodeCompleteConsumer::Result::getPriorityFromDecl(NamedDecl *ND) { + if (!ND) + return CCP_Unlikely; + + // Context-based decisions. + DeclContext *DC = ND->getDeclContext()->getLookupContext(); + if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) + return CCP_LocalDeclaration; + if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) + return CCP_MemberDeclaration; + + // Content-based decisions. + if (isa<EnumConstantDecl>(ND)) + return CCP_Constant; + if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) + return CCP_Type; + return CCP_Declaration; +} + //===----------------------------------------------------------------------===// // Code completion overload candidate implementation //===----------------------------------------------------------------------===// @@ -459,11 +478,6 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, } } } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } void @@ -478,11 +492,6 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, delete CCS; } } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } void @@ -594,16 +603,12 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, } WriteUnsigned(OS, Kind); + WriteUnsigned(OS, Results[I].Priority); CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); assert(CCS && "No code-completion string?"); CCS->Serialize(OS); delete CCS; } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } void @@ -613,15 +618,11 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { WriteUnsigned(OS, CXCursor_NotImplemented); + WriteUnsigned(OS, /*Priority=*/0); CodeCompletionString *CCS = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); assert(CCS && "No code-completion string?"); CCS->Serialize(OS); delete CCS; } - - // Once we've printed the code-completion results, suppress remaining - // diagnostics. - // FIXME: Move this somewhere else! - SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 0694294..543c1b6 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/BitVector.h" #include "Sema.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtObjC.h" @@ -39,33 +40,47 @@ class JumpScopeChecker { /// the parent scope is the function body. unsigned ParentScope; - /// Diag - The diagnostic to emit if there is a jump into this scope. - unsigned Diag; + /// InDiag - The diagnostic to emit if there is a jump into this scope. + unsigned InDiag; + + /// OutDiag - The diagnostic to emit if there is an indirect jump out + /// of this scope. Direct jumps always clean up their current scope + /// in an orderly way. + unsigned OutDiag; /// Loc - Location to emit the diagnostic. SourceLocation Loc; - GotoScope(unsigned parentScope, unsigned diag, SourceLocation L) - : ParentScope(parentScope), Diag(diag), Loc(L) {} + GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag, + SourceLocation L) + : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} }; llvm::SmallVector<GotoScope, 48> Scopes; llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; llvm::SmallVector<Stmt*, 16> Jumps; + + llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps; + llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets; public: JumpScopeChecker(Stmt *Body, Sema &S); private: void BuildScopeInformation(Stmt *S, unsigned ParentScope); void VerifyJumps(); + void VerifyIndirectJumps(); + void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, + LabelStmt *Target, unsigned TargetScope); void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, unsigned JumpDiag); + + unsigned GetDeepestCommonScope(unsigned A, unsigned B); }; } // end anonymous namespace JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { // Add a scope entry for function scope. - Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation())); + Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation())); // Build information for the top level compound statement, so that we have a // defined scope record for every "goto" and label. @@ -73,29 +88,64 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { // Check that all jumps we saw are kosher. VerifyJumps(); + VerifyIndirectJumps(); +} + +/// GetDeepestCommonScope - Finds the innermost scope enclosing the +/// two scopes. +unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { + while (A != B) { + // Inner scopes are created after outer scopes and therefore have + // higher indices. + if (A < B) { + assert(Scopes[B].ParentScope < B); + B = Scopes[B].ParentScope; + } else { + assert(Scopes[A].ParentScope < A); + A = Scopes[A].ParentScope; + } + } + return A; } /// 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 unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { +static std::pair<unsigned,unsigned> + GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + unsigned InDiag = 0, OutDiag = 0; if (VD->getType()->isVariablyModifiedType()) - return diag::note_protected_by_vla; - if (VD->hasAttr<CleanupAttr>()) - return diag::note_protected_by_cleanup; - if (VD->hasAttr<BlocksAttr>()) - return diag::note_protected_by___block; - // FIXME: In C++0x, we have to check more conditions than "did we - // just give it an initializer?". See 6.7p3. - if (isCPlusPlus && VD->hasLocalStorage() && VD->hasInit()) - return diag::note_protected_by_variable_init; + 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) { + // FIXME: In C++0x, we have to check more conditions than "did we + // just give it an initializer?". See 6.7p3. + if (VD->hasLocalStorage() && VD->hasInit()) + InDiag = diag::note_protected_by_variable_init; + + CanQualType T = VD->getType()->getCanonicalTypeUnqualified(); + while (CanQual<ArrayType> AT = T->getAs<ArrayType>()) + T = AT->getElementType(); + if (CanQual<RecordType> RT = T->getAs<RecordType>()) + if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor()) + OutDiag = diag::note_exits_dtor; + } - } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + return std::make_pair(InDiag, OutDiag); + } + + if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) - return diag::note_protected_by_vla_typedef; + return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0); } - return 0; + return std::make_pair(0U, 0U); } @@ -106,14 +156,32 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // If we found a label, remember that it is in ParentScope scope. - if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) { + switch (S->getStmtClass()) { + case Stmt::LabelStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::CaseStmtClass: + LabelAndGotoScopes[S] = ParentScope; + break; + + case Stmt::AddrLabelExprClass: + IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel()); + break; + + case Stmt::IndirectGotoStmtClass: LabelAndGotoScopes[S] = ParentScope; - } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) || - isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) { + IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); + break; + + case Stmt::GotoStmtClass: + case Stmt::SwitchStmtClass: // Remember both what scope a goto is in as well as the fact that we have // it. This makes the second scan not have to walk the AST again. LabelAndGotoScopes[S] = ParentScope; Jumps.push_back(S); + break; + + default: + break; } for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; @@ -131,8 +199,11 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { // If this decl causes a new scope, push and switch to it. - if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) { - Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation())); + std::pair<unsigned,unsigned> Diags + = GetDiagForGotoScopeDecl(*I, isCPlusPlus); + if (Diags.first || Diags.second) { + Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, + (*I)->getLocation())); ParentScope = Scopes.size()-1; } @@ -149,7 +220,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // walking all sub-stmts in that scope. if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { // Recursively walk the AST for the @try part. - Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try, + 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); @@ -159,6 +232,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { ObjCAtCatchStmt *AC = AT->getCatchStmt(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_catch, + diag::note_exits_objc_catch, AC->getAtCatchLoc())); // @catches are nested and it isn't BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); @@ -168,6 +242,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_finally, + diag::note_exits_objc_finally, AF->getAtFinallyLoc())); BuildScopeInformation(AF, Scopes.size()-1); } @@ -186,6 +261,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // scope. Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_synchronized, + diag::note_exits_objc_synchronized, AS->getAtSynchronizedLoc())); BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); continue; @@ -194,7 +270,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // Disallow jumps into any part of a C++ try statement. This is pretty // much the same as for Obj-C. if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { - Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try, + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_cxx_try, + diag::note_exits_cxx_try, TS->getSourceRange().getBegin())); if (Stmt *TryBlock = TS->getTryBlock()) BuildScopeInformation(TryBlock, Scopes.size()-1); @@ -204,6 +282,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { CXXCatchStmt *CS = TS->getHandler(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_catch, + diag::note_exits_cxx_catch, CS->getSourceRange().getBegin())); BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1); } @@ -229,54 +308,178 @@ void JumpScopeChecker::VerifyJumps() { continue; } - if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) { - for (SwitchCase *SC = SS->getSwitchCaseList(); SC; - SC = SC->getNextSwitchCase()) { - assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); - CheckJump(SS, SC, SC->getLocStart(), - diag::err_switch_into_protected_scope); - } - continue; + SwitchStmt *SS = cast<SwitchStmt>(Jump); + for (SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); + CheckJump(SS, SC, SC->getLocStart(), + diag::err_switch_into_protected_scope); } + } +} - unsigned DiagnosticScope; - - // We don't know where an indirect goto goes, require that it be at the - // top level of scoping. - if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) { - assert(LabelAndGotoScopes.count(Jump) && - "Jump didn't get added to scopes?"); - unsigned GotoScope = LabelAndGotoScopes[IG]; - if (GotoScope == 0) continue; // indirect jump is ok. - S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); - DiagnosticScope = GotoScope; - } else { - // We model &&Label as a jump for purposes of scope tracking. We actually - // don't care *where* the address of label is, but we require the *label - // itself* to be in scope 0. If it is nested inside of a VLA scope, then - // it is possible for an indirect goto to illegally enter the VLA scope by - // indirectly jumping to the label. - assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type"); - LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel(); - - assert(LabelAndGotoScopes.count(TheLabel) && - "Referenced label didn't get added to scopes?"); - unsigned LabelScope = LabelAndGotoScopes[TheLabel]; - if (LabelScope == 0) continue; // Addr of label is ok. - - S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope); - DiagnosticScope = LabelScope; +/// VerifyIndirectJumps - Verify whether any possible indirect jump +/// might cross a protection boundary. Unlike direct jumps, indirect +/// jumps count cleanups as protection boundaries: since there's no +/// way to know where the jump is going, we can't implicitly run the +/// right cleanups the way we can with direct jumps. +/// +/// Thus, an indirect jump is "trivial" if it bypasses no +/// initializations and no teardowns. More formally, an indirect jump +/// from A to B is trivial if the path out from A to DCA(A,B) is +/// trivial and the path in from DCA(A,B) to B is trivial, where +/// DCA(A,B) is the deepest common ancestor of A and B. +/// Jump-triviality is transitive but asymmetric. +/// +/// A path in is trivial if none of the entered scopes have an InDiag. +/// A path out is trivial is none of the exited scopes have an OutDiag. +/// +/// Under these definitions, this function checks that the indirect +/// jump between A and B is trivial for every indirect goto statement A +/// and every label B whose address was taken in the function. +void JumpScopeChecker::VerifyIndirectJumps() { + if (IndirectJumps.empty()) return; + + // If there aren't any address-of-label expressions in this function, + // complain about the first indirect goto. + if (IndirectJumpTargets.empty()) { + S.Diag(IndirectJumps[0]->getGotoLoc(), + diag::err_indirect_goto_without_addrlabel); + return; + } + + // Collect a single representative of every scope containing an + // indirect goto. For most code bases, this substantially cuts + // down on the number of jump sites we'll have to consider later. + typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; + llvm::SmallVector<JumpScope, 32> JumpScopes; + { + llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; + for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator + I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { + IndirectGotoStmt *IG = *I; + assert(LabelAndGotoScopes.count(IG) && + "indirect jump didn't get added to scopes?"); + unsigned IGScope = LabelAndGotoScopes[IG]; + IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; + if (!Entry) Entry = IG; + } + JumpScopes.reserve(JumpScopesMap.size()); + for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator + I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I) + JumpScopes.push_back(*I); + } + + // Collect a single representative of every scope containing a + // label whose address was taken somewhere in the function. + // For most code bases, there will be only one such scope. + llvm::DenseMap<unsigned, LabelStmt*> TargetScopes; + for (llvm::SmallVectorImpl<LabelStmt*>::iterator + I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); + I != E; ++I) { + LabelStmt *TheLabel = *I; + assert(LabelAndGotoScopes.count(TheLabel) && + "Referenced label didn't get added to scopes?"); + unsigned LabelScope = LabelAndGotoScopes[TheLabel]; + LabelStmt *&Target = TargetScopes[LabelScope]; + if (!Target) Target = TheLabel; + } + + // For each target scope, make sure it's trivially reachable from + // every scope containing a jump site. + // + // A path between scopes always consists of exitting zero or more + // scopes, then entering zero or more scopes. We build a set of + // of scopes S from which the target scope can be trivially + // entered, then verify that every jump scope can be trivially + // exitted to reach a scope in S. + llvm::BitVector Reachable(Scopes.size(), false); + for (llvm::DenseMap<unsigned,LabelStmt*>::iterator + TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { + unsigned TargetScope = TI->first; + LabelStmt *TargetLabel = TI->second; + + Reachable.reset(); + + // Mark all the enclosing scopes from which you can safely jump + // into the target scope. 'Min' will end up being the index of + // the shallowest such scope. + unsigned Min = TargetScope; + while (true) { + Reachable.set(Min); + + // Don't go beyond the outermost scope. + if (Min == 0) break; + + // Stop if we can't trivially enter the current scope. + if (Scopes[Min].InDiag) break; + + Min = Scopes[Min].ParentScope; } - // Report all the things that would be skipped over by this &&label or - // indirect goto. - while (DiagnosticScope != 0) { - S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag); - DiagnosticScope = Scopes[DiagnosticScope].ParentScope; + // Walk through all the jump sites, checking that they can trivially + // reach this label scope. + for (llvm::SmallVectorImpl<JumpScope>::iterator + I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { + unsigned Scope = I->first; + + // Walk out the "scope chain" for this scope, looking for a scope + // we've marked reachable. For well-formed code this amortizes + // to O(JumpScopes.size() / Scopes.size()): we only iterate + // when we see something unmarked, and in well-formed code we + // mark everything we iterate past. + bool IsReachable = false; + while (true) { + if (Reachable.test(Scope)) { + // If we find something reachable, mark all the scopes we just + // walked through as reachable. + for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) + Reachable.set(S); + IsReachable = true; + break; + } + + // Don't walk out if we've reached the top-level scope or we've + // gotten shallower than the shallowest reachable scope. + if (Scope == 0 || Scope < Min) break; + + // Don't walk out through an out-diagnostic. + if (Scopes[Scope].OutDiag) break; + + Scope = Scopes[Scope].ParentScope; + } + + // Only diagnose if we didn't find something. + if (IsReachable) continue; + + DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope); } } } +/// Diagnose an indirect jump which is known to cross scopes. +void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, + unsigned JumpScope, + LabelStmt *Target, + unsigned TargetScope) { + assert(JumpScope != TargetScope); + + S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope); + S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target); + + unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); + + // Walk out the scope chain until we reach the common ancestor. + for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope) + if (Scopes[I].OutDiag) + S.Diag(Scopes[I].Loc, Scopes[I].OutDiag); + + // Now walk into the scopes containing the label whose address was taken. + for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope) + if (Scopes[I].InDiag) + S.Diag(Scopes[I].Loc, Scopes[I].InDiag); +} + /// CheckJump - Validate that the specified jump statement is valid: that it is /// jumping within or out of its current scope, not into a deeper one. void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, @@ -290,42 +493,25 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, // Common case: exactly the same scope, which is fine. if (FromScope == ToScope) return; - // The only valid mismatch jump case happens when the jump is more deeply - // nested inside the jump target. Do a quick scan to see if the jump is valid - // because valid code is more common than invalid code. - unsigned TestScope = Scopes[FromScope].ParentScope; - while (TestScope != ~0U) { - // If we found the jump target, then we're jumping out of our current scope, - // which is perfectly fine. - if (TestScope == ToScope) return; - - // Otherwise, scan up the hierarchy. - TestScope = Scopes[TestScope].ParentScope; - } + unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope); - // If we get here, then we know we have invalid code. Diagnose the bad jump, - // and then emit a note at each VLA being jumped out of. - S.Diag(DiagLoc, JumpDiag); + // It's okay to jump out from a nested scope. + if (CommonScope == ToScope) return; - // Eliminate the common prefix of the jump and the target. Start by - // linearizing both scopes, reversing them as we go. - std::vector<unsigned> FromScopes, ToScopes; - for (TestScope = FromScope; TestScope != ~0U; - TestScope = Scopes[TestScope].ParentScope) - FromScopes.push_back(TestScope); - for (TestScope = ToScope; TestScope != ~0U; - TestScope = Scopes[TestScope].ParentScope) - ToScopes.push_back(TestScope); - - // Remove any common entries (such as the top-level function scope). - while (!FromScopes.empty() && FromScopes.back() == ToScopes.back()) { - FromScopes.pop_back(); - ToScopes.pop_back(); - } + // Pull out (and reverse) any scopes we might need to diagnose skipping. + llvm::SmallVector<unsigned, 10> ToScopes; + for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) + if (Scopes[I].InDiag) + ToScopes.push_back(I); + + // If the only scopes present are cleanup scopes, we're okay. + if (ToScopes.empty()) return; + + S.Diag(DiagLoc, JumpDiag); // Emit diagnostics for whatever is left in ToScopes. for (unsigned i = 0, e = ToScopes.size(); i != e; ++i) - S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].Diag); + S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag); } void Sema::DiagnoseInvalidJumps(Stmt *Body) { diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 755af84..523b196 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -33,22 +33,12 @@ void FunctionScopeInfo::Clear(unsigned NumErrors) { NeedsScopeChecking = false; LabelMap.clear(); SwitchStack.clear(); + Returns.clear(); NumErrorsAtStartOfFunction = NumErrors; } BlockScopeInfo::~BlockScopeInfo() { } -static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { - if (C.getLangOptions().CPlusPlus) - return CXXRecordDecl::Create(C, TagDecl::TK_struct, - C.getTranslationUnitDecl(), - SourceLocation(), &C.Idents.get(Name)); - - return RecordDecl::Create(C, TagDecl::TK_struct, - C.getTranslationUnitDecl(), - SourceLocation(), &C.Idents.get(Name)); -} - void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); @@ -97,8 +87,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { - QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy); - TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(IdT); + QualType T = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, 0, 0); + T = Context.getObjCObjectPointerType(T); + TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T); TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("id"), IdInfo); @@ -108,9 +99,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } // Create the built-in typedef for 'Class'. if (Context.getObjCClassType().isNull()) { - QualType ClassType - = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy); - TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(ClassType); + QualType T = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, 0, 0); + T = Context.getObjCObjectPointerType(T); + TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T); TypedefDecl *ClassTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("Class"), ClassInfo); @@ -175,7 +166,17 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, } } - CheckImplicitConversion(Expr, Ty); + // If this is a derived-to-base cast to a through a virtual base, we + // need a vtable. + if (Kind == CastExpr::CK_DerivedToBase && + BasePathInvolvesVirtualBase(BasePath)) { + QualType T = Expr->getType(); + if (const PointerType *Pointer = T->getAs<PointerType>()) + T = Pointer->getPointeeType(); + if (const RecordType *RecordTy = T->getAs<RecordType>()) + MarkVTableUsed(Expr->getLocStart(), + cast<CXXRecordDecl>(RecordTy->getDecl())); + } if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind && BasePath.empty()) { @@ -212,10 +213,10 @@ void Sema::ActOnEndOfTranslationUnit() { // template instantiations earlier. PerformPendingImplicitInstantiations(); - /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking - /// any virtual member functions it might lead to more pending template + /// If DefinedUsedVTables ends up marking any virtual member + /// functions it might lead to more pending template /// instantiations, which is why we need to loop here. - if (!ProcessPendingClassesWithUnmarkedVirtualMembers()) + if (!DefineUsedVTables()) break; } @@ -304,7 +305,7 @@ void Sema::ActOnEndOfTranslationUnit() { DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) + while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) DC = DC->getParent(); return DC; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f146c85..dfc45ac 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -134,6 +134,11 @@ struct FunctionScopeInfo { /// block. llvm::SmallVector<SwitchStmt*, 8> SwitchStack; + /// \brief The list of return statements that occur within the function or + /// block, if there is any chance of applying the named return value + /// optimization. + llvm::SmallVector<ReturnStmt *, 4> Returns; + FunctionScopeInfo(unsigned NumErrors) : IsBlockInfo(false), NeedsScopeChecking(false), NumErrorsAtStartOfFunction(NumErrors) { } @@ -768,7 +773,8 @@ public: bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); - QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E); QualType BuildDecltypeType(Expr *E); @@ -901,11 +907,11 @@ public: /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS); + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS); - bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, - RecordDecl *AnonRecord); virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, RecordDecl *Record); bool isAcceptableTagRedeclaration(const TagDecl *Previous, @@ -1161,6 +1167,9 @@ public: ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); bool PerformContextuallyConvertToBool(Expr *&From); + ImplicitConversionSequence TryContextuallyConvertToObjCId(Expr *From); + bool PerformContextuallyConvertToObjCId(Expr *&From); + bool PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, @@ -1528,16 +1537,21 @@ public: /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category @implementation. - void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. - void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap); + /// DefaultSynthesizeProperties - This routine default synthesizes all + /// properties which must be synthesized in class's @implementation. + void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl); + /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those it its super class. void CollectImmediateProperties(ObjCContainerDecl *CDecl, @@ -1583,7 +1597,8 @@ public: const bool isAssign, const bool isReadWrite, const unsigned Attributes, QualType T, - tok::ObjCKeywordKind MethodImplKind); + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = 0); /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared @@ -1661,10 +1676,9 @@ public: FullExprArg CondVal, DeclPtrTy CondVar, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal); - virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + ExprArg Cond, DeclPtrTy CondVar); - virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, - StmtArg Body); virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body); virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, @@ -1762,7 +1776,8 @@ public: /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); - + void DiagnoseUnusedDecl(const NamedDecl *ND); + ParsingDeclStackState PushParsingDeclaration(); void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); @@ -1785,6 +1800,7 @@ public: virtual void PopExpressionEvaluationContext(); void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); + void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); // Primary Expressions. @@ -1796,7 +1812,8 @@ public: bool HasTrailingLParen, bool IsAddressOfOperand); - bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R); + bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, + CorrectTypoContext CTC = CTC_Unknown); OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, @@ -2321,7 +2338,9 @@ public: virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); - OwningExprResult CheckConditionVariable(VarDecl *ConditionVar); + OwningExprResult CheckConditionVariable(VarDecl *ConditionVar, + SourceLocation StmtLoc, + bool ConvertToBoolean); /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support /// pseudo-functions. @@ -2553,27 +2572,38 @@ public: void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, CXXRecordDecl *Record); - /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual - /// members need to be marked as referenced at the end of the translation - /// unit. It will contain polymorphic classes that do not have a key - /// function or have a key function that has been defined. - llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4> - ClassesWithUnmarkedVirtualMembers; + /// \brief The list of classes whose vtables have been used within + /// this translation unit, and the source locations at which the + /// first use occurred. + llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 16> + VTableUses; - /// MaybeMarkVirtualMembersReferenced - If the passed in method is the - /// key function of the record decl, will mark virtual member functions as - /// referenced. - void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD); + /// \brief The set of classes whose vtables have been used within + /// this translation unit, and a bit that will be true if the vtable is + /// required to be emitted (otherwise, it should be emitted only if needed + /// by code generation). + llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed; + + /// \brief A list of all of the dynamic classes in this translation + /// unit. + llvm::SmallVector<CXXRecordDecl *, 16> DynamicClasses; + + /// \brief Note that the vtable for the given class was used at the + /// given location. + void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, + bool DefinitionRequired = false); /// MarkVirtualMembersReferenced - Will mark all virtual members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD); - /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes - /// that might need to have their virtual members marked as referenced. - /// Returns false if no work was done. - bool ProcessPendingClassesWithUnmarkedVirtualMembers(); + /// \brief Define all of the vtables that have been used in this + /// translation unit and reference any virtual members used by those + /// vtables. + /// + /// \returns true if any work was done, false otherwise. + bool DefineUsedVTables(); void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl); @@ -2657,6 +2687,8 @@ public: void BuildBasePathArray(const CXXBasePaths &Paths, CXXBaseSpecifierArray &BasePath); + bool BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXBaseSpecifierArray *BasePath = 0, @@ -2768,14 +2800,16 @@ public: // C++ Templates [C++ 14] // void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, - QualType ObjectType, bool EnteringContext); + QualType ObjectType, bool EnteringContext, + bool &MemberOfUnknownSpecialization); virtual TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, - TemplateTy &Template); + TemplateTy &Template, + bool &MemberOfUnknownSpecialization); virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, @@ -3085,7 +3119,9 @@ public: QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo &II, - SourceRange Range); + SourceLocation KeywordLoc, + SourceRange NNSRange, + SourceLocation IILoc); TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, @@ -3568,6 +3604,24 @@ public: } }; + /// \brief RAII class that determines when any errors have occurred + /// between the time the instance was created and the time it was + /// queried. + class ErrorTrap { + Sema &SemaRef; + unsigned PrevErrors; + + public: + explicit ErrorTrap(Sema &SemaRef) + : SemaRef(SemaRef), PrevErrors(SemaRef.getDiagnostics().getNumErrors()) {} + + /// \brief Determine whether any errors have occurred since this + /// object instance was created. + bool hasErrorOccurred() const { + return SemaRef.getDiagnostics().getNumErrors() > PrevErrors; + } + }; + /// \brief A stack-allocated class that identifies which local /// variable declaration instantiations are present in this scope. /// @@ -3858,7 +3912,7 @@ public: void MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl); - virtual void ActOnAtEnd(SourceRange AtEnd, + virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods = 0, unsigned allNum = 0, DeclPtrTy *allProperties = 0, unsigned pNum = 0, @@ -3871,7 +3925,8 @@ public: bool *OverridingProperty, tok::ObjCKeywordKind MethodImplKind); - virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc, + virtual DeclPtrTy ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind,DeclPtrTy ClassImplDecl, IdentifierInfo *PropertyId, @@ -3960,6 +4015,11 @@ public: MultiExprArg Args); + /// ActOnPragmaOptionsAlign - Called on well formed #pragma options align. + virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc, + SourceLocation KindLoc); + /// ActOnPragmaPack - Called on well formed #pragma pack(...). virtual void ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, @@ -3990,9 +4050,9 @@ public: SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); - /// getPragmaPackAlignment() - Return the current alignment as specified by - /// the current #pragma pack directive, or 0 if none is currently active. - unsigned getPragmaPackAlignment() const; + /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to + /// a the record decl, to handle '#pragma pack' and '#pragma options align'. + void AddAlignmentAttributesForRecord(RecordDecl *RD); /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); @@ -4044,7 +4104,8 @@ public: // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will warn if the resulting type is not a POD type. - bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT); + bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, + FunctionDecl *FDecl); // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary @@ -4215,9 +4276,9 @@ public: SourceLocation questionLoc); /// type checking for vector binary operators. - inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); - inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, - SourceLocation l, bool isRel); + QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); + QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, + SourceLocation l, bool isRel); /// type checking unary operators (subroutines of ActOnUnaryOp). /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 @@ -4311,6 +4372,9 @@ public: /// \return true iff there were any errors bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc); + virtual OwningExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc, + ExprArg SubExpr); + /// DiagnoseAssignmentAsCondition - Given that an expression is /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); @@ -4455,9 +4519,7 @@ private: void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); - void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, - const BinaryOperator::Opcode* BinOpc = 0); - void CheckImplicitConversion(Expr *E, QualType Target); + void CheckImplicitConversions(Expr *E); }; //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 095f537..82978c9 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -15,17 +15,28 @@ #include "Sema.h" #include "Lookup.h" #include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" using namespace clang; //===----------------------------------------------------------------------===// -// Pragma Packed +// Pragma 'pack' and 'options align' //===----------------------------------------------------------------------===// namespace { + struct PackStackEntry { + // We just use a sentinel to represent when the stack is set to mac68k + // alignment. + static const unsigned kMac68kAlignmentSentinel = ~0U; + + unsigned Alignment; + IdentifierInfo *Name; + }; + /// PragmaPackStack - Simple class to wrap the stack used by #pragma /// pack. class PragmaPackStack { - typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty; + typedef std::vector<PackStackEntry> stack_ty; /// Alignment - The current user specified alignment. unsigned Alignment; @@ -43,7 +54,8 @@ namespace { /// push - Push the current alignment onto the stack, optionally /// using the given \arg Name for the record, if non-zero. void push(IdentifierInfo *Name) { - Stack.push_back(std::make_pair(Alignment, Name)); + PackStackEntry PSE = { Alignment, Name }; + Stack.push_back(PSE); } /// pop - Pop a record from the stack and restore the current @@ -60,7 +72,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) { // If name is empty just pop top. if (!Name) { - Alignment = Stack.back().first; + Alignment = Stack.back().Alignment; Stack.pop_back(); return true; } @@ -68,9 +80,9 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) { // Otherwise, find the named record. for (unsigned i = Stack.size(); i != 0; ) { --i; - if (Stack[i].second == Name) { + if (Stack[i].Name == Name) { // Found it, pop up to and including this record. - Alignment = Stack[i].first; + Alignment = Stack[i].Alignment; Stack.erase(Stack.begin() + i, Stack.end()); return true; } @@ -86,12 +98,65 @@ void Sema::FreePackedContext() { PackContext = 0; } -/// getPragmaPackAlignment() - Return the current alignment as specified by -/// the current #pragma pack directive, or 0 if none is currently active. -unsigned Sema::getPragmaPackAlignment() const { - if (PackContext) - return static_cast<PragmaPackStack*>(PackContext)->getAlignment(); - return 0; +void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { + // If there is no pack context, we don't need any attributes. + if (!PackContext) + return; + + PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext); + + // Otherwise, check to see if we need a max field alignment attribute. + if (unsigned Alignment = Stack->getAlignment()) { + if (Alignment == PackStackEntry::kMac68kAlignmentSentinel) + RD->addAttr(::new (Context) AlignMac68kAttr()); + else + RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8)); + } +} + +void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc, + SourceLocation KindLoc) { + if (PackContext == 0) + PackContext = new PragmaPackStack(); + + PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); + + // Reset just pops the top of the stack. + if (Kind == Action::POAK_Reset) { + // Do the pop. + if (!Context->pop(0)) { + // If a name was specified then failure indicates the name + // wasn't found. Otherwise failure indicates the stack was + // empty. + Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) + << "stack empty"; + } + return; + } + + // We don't support #pragma options align=power. + switch (Kind) { + case POAK_Natural: + Context->push(0); + Context->setAlignment(0); + break; + + case POAK_Mac68k: + // Check if the target supports this. + if (!PP.getTargetInfo().hasAlignMac68kSupport()) { + Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported); + return; + } + Context->push(0); + Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel); + break; + + default: + Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option) + << KindLoc; + break; + } } void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, @@ -106,7 +171,9 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, // pack(0) is like pack(), which just works out since that is what // we use 0 for in PackAttr. - if (!Alignment->isIntegerConstantExpr(Val, Context) || + if (Alignment->isTypeDependent() || + Alignment->isValueDependent() || + !Alignment->isIntegerConstantExpr(Val, Context) || !(Val == 0 || Val.isPowerOf2()) || Val.getZExtValue() > 16) { Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment); @@ -134,7 +201,10 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, // FIXME: This should come from the target. if (AlignmentVal == 0) AlignmentVal = 8; - Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; + if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel) + Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k"; + else + Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; break; case Action::PPK_Push: // pack(push [, id] [, [n]) diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index ba7e1ff..9b95552 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -388,6 +388,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return; Kind = CastExpr::CK_DerivedToBase; + + // If we are casting to or through a virtual base class, we need a + // vtable. + if (Self.BasePathInvolvesVirtualBase(BasePath)) + Self.MarkVTableUsed(OpRange.getBegin(), + cast<CXXRecordDecl>(SrcRecord->getDecl())); return; } @@ -398,6 +404,8 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); } + Self.MarkVTableUsed(OpRange.getBegin(), + cast<CXXRecordDecl>(SrcRecord->getDecl())); // Done. Everything else is run-time checks. Kind = CastExpr::CK_Dynamic; @@ -578,8 +586,9 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, return TC_Success; } } - else if (CStyle && DestType->isObjCObjectPointerType()) { - // allow c-style cast of objective-c pointers as they are pervasive. + else if (DestType->isObjCObjectPointerType()) { + // allow both c-style cast and static_cast of objective-c pointers as + // they are pervasive. Kind = CastExpr::CK_AnyPointerToObjCPointerCast; return TC_Success; } @@ -590,7 +599,11 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, } } } - + // Allow arbitray objective-c pointer conversion with static casts. + if (SrcType->isObjCObjectPointerType() && + DestType->isObjCObjectPointerType()) + return TC_Success; + // We tried everything. Everything! Nothing works! :-( return TC_NotApplicable; } @@ -846,7 +859,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } // B is a base of D. But is it an allowed base? If not, it's a hard error. - if (Paths.isAmbiguous(DestClass)) { + if (Paths.isAmbiguous(Self.Context.getCanonicalType(DestClass))) { Paths.clear(); Paths.setRecordingPaths(true); bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); @@ -970,7 +983,9 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, // C++ 5.2.11p5: For a const_cast involving pointers to data members [...] // the rules for const_cast are the same as those used for pointers. - if (!DestType->isPointerType() && !DestType->isMemberPointerType()) { + if (!DestType->isPointerType() && + !DestType->isMemberPointerType() && + !DestType->isObjCObjectPointerType()) { // Cannot cast to non-pointer, non-reference type. Note that, if DestType // was a reference type, we converted it to a pointer above. // The status of rvalue references isn't entirely clear, but it looks like diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 7029711..4f3f41b 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -75,14 +75,15 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, TheLexer.LexFromRawLexer(TheTok); // Use the StringLiteralParser to compute the length of the string in bytes. - StringLiteralParser SLP(&TheTok, 1, PP); + StringLiteralParser SLP(&TheTok, 1, PP, /*Complain=*/false); unsigned TokNumBytes = SLP.GetStringLength(); // If the byte is in this token, return the location of the byte. if (ByteNo < TokNumBytes || (ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) { unsigned Offset = - StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP); + StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP, + /*Complain=*/false); // Now that we know the offset of the token in the spelling, use the // preprocessor to get the offset in the original source. @@ -607,12 +608,25 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { if (OrigArg->isTypeDependent()) return false; - // This operation requires a floating-point number + // This operation requires a non-_Complex floating-point number. if (!OrigArg->getType()->isRealFloatingType()) return Diag(OrigArg->getLocStart(), diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); + // If this is an implicit conversion from float -> double, remove it. + if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { + Expr *CastArg = Cast->getSubExpr(); + if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { + assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) && + "promotion from float to double is the only expected cast here"); + Cast->setSubExpr(0); + Cast->Destroy(Context); + TheCall->setArg(NumArgs-1, CastArg); + OrigArg = CastArg; + } + } + return false; } @@ -1718,8 +1732,14 @@ struct IntRange { T = VT->getElementType().getTypePtr(); if (const ComplexType *CT = dyn_cast<ComplexType>(T)) T = CT->getElementType().getTypePtr(); - if (const EnumType *ET = dyn_cast<EnumType>(T)) - T = ET->getDecl()->getIntegerType().getTypePtr(); + + if (const EnumType *ET = dyn_cast<EnumType>(T)) { + EnumDecl *Enum = ET->getDecl(); + unsigned NumPositive = Enum->getNumPositiveBits(); + unsigned NumNegative = Enum->getNumNegativeBits(); + + return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0); + } const BuiltinType *BT = cast<BuiltinType>(T); assert(BT->isInteger()); @@ -1961,6 +1981,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return IntRange::forType(C, E->getType()); } +IntRange GetExprRange(ASTContext &C, Expr *E) { + return GetExprRange(C, E, C.getIntWidth(E->getType())); +} + /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. @@ -1999,7 +2023,40 @@ bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -} // end anonymous namespace +void AnalyzeImplicitConversions(Sema &S, Expr *E); + +bool IsZero(Sema &S, Expr *E) { + llvm::APSInt Value; + return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; +} + +void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { + BinaryOperator::Opcode op = E->getOpcode(); + if (op == BinaryOperator::LT && IsZero(S, E->getRHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) + << "< 0" << "false" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } else if (op == BinaryOperator::GE && IsZero(S, E->getRHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) + << ">= 0" << "true" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } else if (op == BinaryOperator::GT && IsZero(S, E->getLHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) + << "0 >" << "false" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } else if (op == BinaryOperator::LE && IsZero(S, E->getLHS())) { + S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) + << "0 <=" << "true" + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } +} + +/// Analyze the operands of the given comparison. Implements the +/// fallback case from AnalyzeComparison. +void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { + AnalyzeImplicitConversions(S, E->getLHS()); + AnalyzeImplicitConversions(S, E->getRHS()); +} /// \brief Implements -Wsign-compare. /// @@ -2007,138 +2064,85 @@ bool IsSameFloatAfterCast(const APValue &value, /// \param rex the right-hand expression /// \param OpLoc the location of the joining operator /// \param BinOpc binary opcode or 0 -void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const BinaryOperator::Opcode* BinOpc) { - // Don't warn if we're in an unevaluated context. - if (ExprEvalContexts.back().Context == Unevaluated) - return; - - // If either expression is value-dependent, don't warn. We'll get another - // chance at instantiation time. - if (lex->isValueDependent() || rex->isValueDependent()) - return; - - QualType lt = lex->getType(), rt = rex->getType(); - - // Only warn if both operands are integral. - if (!lt->isIntegerType() || !rt->isIntegerType()) - return; - - // In C, the width of a bitfield determines its type, and the - // declared type only contributes the signedness. This duplicates - // the work that will later be done by UsualUnaryConversions. - // Eventually, this check will be reorganized in a way that avoids - // this duplication. - if (!getLangOptions().CPlusPlus) { - QualType tmp; - tmp = Context.isPromotableBitField(lex); - if (!tmp.isNull()) lt = tmp; - tmp = Context.isPromotableBitField(rex); - if (!tmp.isNull()) rt = tmp; - } - - if (const EnumType *E = lt->getAs<EnumType>()) - lt = E->getDecl()->getPromotionType(); - if (const EnumType *E = rt->getAs<EnumType>()) - rt = E->getDecl()->getPromotionType(); - - // The rule is that the signed operand becomes unsigned, so isolate the - // signed operand. - Expr *signedOperand = lex, *unsignedOperand = rex; - QualType signedType = lt, unsignedType = rt; - if (lt->isSignedIntegerType()) { - if (rt->isSignedIntegerType()) return; +void AnalyzeComparison(Sema &S, BinaryOperator *E) { + // The type the comparison is being performed in. + QualType T = E->getLHS()->getType(); + assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()) + && "comparison with mismatched types"); + + // We don't do anything special if this isn't an unsigned integral + // comparison: we're only interested in integral comparisons, and + // signed comparisons only happen in cases we don't care to warn about. + if (!T->isUnsignedIntegerType()) + return AnalyzeImpConvsInComparison(S, E); + + Expr *lex = E->getLHS()->IgnoreParenImpCasts(); + Expr *rex = E->getRHS()->IgnoreParenImpCasts(); + + // Check to see if one of the (unmodified) operands is of different + // signedness. + Expr *signedOperand, *unsignedOperand; + if (lex->getType()->isSignedIntegerType()) { + assert(!rex->getType()->isSignedIntegerType() && + "unsigned comparison between two signed integer expressions?"); + signedOperand = lex; + unsignedOperand = rex; + } else if (rex->getType()->isSignedIntegerType()) { + signedOperand = rex; + unsignedOperand = lex; } else { - if (!rt->isSignedIntegerType()) return; - std::swap(signedOperand, unsignedOperand); - std::swap(signedType, unsignedType); + CheckTrivialUnsignedComparison(S, E); + return AnalyzeImpConvsInComparison(S, E); } - unsigned unsignedWidth = Context.getIntWidth(unsignedType); - unsigned signedWidth = Context.getIntWidth(signedType); + // Otherwise, calculate the effective range of the signed operand. + IntRange signedRange = GetExprRange(S.Context, signedOperand); - // If the unsigned type is strictly smaller than the signed type, - // then (1) the result type will be signed and (2) the unsigned - // value will fit fully within the signed type, and thus the result - // of the comparison will be exact. - if (signedWidth > unsignedWidth) - return; + // Go ahead and analyze implicit conversions in the operands. Note + // that we skip the implicit conversions on both sides. + AnalyzeImplicitConversions(S, lex); + AnalyzeImplicitConversions(S, rex); - // Otherwise, calculate the effective ranges. - IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth); - IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth); - - // We should never be unable to prove that the unsigned operand is - // non-negative. - assert(unsignedRange.NonNegative && "unsigned range includes negative?"); - - // If the signed operand is non-negative, then the signed->unsigned - // conversion won't change it. - if (signedRange.NonNegative) { - // Emit warnings for comparisons of unsigned to integer constant 0. - // always false: x < 0 (or 0 > x) - // always true: x >= 0 (or 0 <= x) - llvm::APSInt X; - if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) { - if (signedOperand != lex) { - if (*BinOpc == BinaryOperator::LT) { - Diag(OpLoc, diag::warn_lunsigned_always_true_comparison) - << "< 0" << "false" - << lex->getSourceRange() << rex->getSourceRange(); - } - else if (*BinOpc == BinaryOperator::GE) { - Diag(OpLoc, diag::warn_lunsigned_always_true_comparison) - << ">= 0" << "true" - << lex->getSourceRange() << rex->getSourceRange(); - } - } - else { - if (*BinOpc == BinaryOperator::GT) { - Diag(OpLoc, diag::warn_runsigned_always_true_comparison) - << "0 >" << "false" - << lex->getSourceRange() << rex->getSourceRange(); - } - else if (*BinOpc == BinaryOperator::LE) { - Diag(OpLoc, diag::warn_runsigned_always_true_comparison) - << "0 <=" << "true" - << lex->getSourceRange() << rex->getSourceRange(); - } - } - } - return; - } + // If the signed range is non-negative, -Wsign-compare won't fire, + // but we should still check for comparisons which are always true + // or false. + if (signedRange.NonNegative) + return CheckTrivialUnsignedComparison(S, E); // For (in)equality comparisons, if the unsigned operand is a // constant which cannot collide with a overflowed signed operand, // then reinterpreting the signed operand as unsigned will not // change the result of the comparison. - if (BinOpc && - (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) && - unsignedRange.Width < unsignedWidth) - return; + if (E->isEqualityOp()) { + unsigned comparisonWidth = S.Context.getIntWidth(T); + IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand); + + // We should never be unable to prove that the unsigned operand is + // non-negative. + assert(unsignedRange.NonNegative && "unsigned range includes negative?"); + + if (unsignedRange.Width < comparisonWidth) + return; + } - Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison - : diag::warn_mixed_sign_conditional) - << lt << rt << lex->getSourceRange() << rex->getSourceRange(); + S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { +void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); } -/// Implements -Wconversion. -void Sema::CheckImplicitConversion(Expr *E, QualType T) { - // Don't diagnose in unevaluated contexts. - if (ExprEvalContexts.back().Context == Sema::Unevaluated) - return; +void CheckImplicitConversion(Sema &S, Expr *E, QualType T, + bool *ICContext = 0) { + if (E->isTypeDependent() || E->isValueDependent()) return; - // Don't diagnose for value-dependent expressions. - if (E->isValueDependent()) - return; - - const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr(); - const Type *Target = Context.getCanonicalType(T).getTypePtr(); + const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); + const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); + if (Source == Target) return; + if (Target->isDependentType()) return; // Never diagnose implicit casts to bool. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) @@ -2147,7 +2151,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // Strip vector types. if (isa<VectorType>(Source)) { if (!isa<VectorType>(Target)) - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar); Source = cast<VectorType>(Source)->getElementType().getTypePtr(); Target = cast<VectorType>(Target)->getElementType().getTypePtr(); @@ -2156,7 +2160,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // Strip complex types. if (isa<ComplexType>(Source)) { if (!isa<ComplexType>(Target)) - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar); Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); @@ -2176,15 +2180,15 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // Don't warn about float constants that are precisely // representable in the target type. Expr::EvalResult result; - if (E->Evaluate(result, Context)) { + if (E->Evaluate(result, S.Context)) { // Value might be a float, a float vector, or a float complex. if (IsSameFloatAfterCast(result.Val, - Context.getFloatTypeSemantics(QualType(TargetBT, 0)), - Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), + S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) return; } - DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision); + DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision); } return; } @@ -2192,7 +2196,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { // If the target is integral, always warn. if ((TargetBT && TargetBT->isInteger())) // TODO: don't warn for integer values? - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer); + DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); return; } @@ -2200,22 +2204,158 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { if (!Source->isIntegerType() || !Target->isIntegerType()) return; - IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType())); - IntRange TargetRange = IntRange::forCanonicalType(Context, Target); - - // FIXME: also signed<->unsigned? + IntRange SourceRange = GetExprRange(S.Context, E); + IntRange TargetRange = IntRange::forCanonicalType(S.Context, Target); if (SourceRange.Width > TargetRange.Width) { // People want to build with -Wshorten-64-to-32 and not -Wconversion // and by god we'll let them. if (SourceRange.Width == 64 && TargetRange.Width == 32) - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32); - return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision); + } + + if ((TargetRange.NonNegative && !SourceRange.NonNegative) || + (!TargetRange.NonNegative && SourceRange.NonNegative && + SourceRange.Width == TargetRange.Width)) { + unsigned DiagID = diag::warn_impcast_integer_sign; + + // Traditionally, gcc has warned about this under -Wsign-compare. + // We also want to warn about it in -Wconversion. + // So if -Wconversion is off, use a completely identical diagnostic + // in the sign-compare group. + // The conditional-checking code will + if (ICContext) { + DiagID = diag::warn_impcast_integer_sign_conditional; + *ICContext = true; + } + + return DiagnoseImpCast(S, E, T, DiagID); } return; } +void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T); + +void CheckConditionalOperand(Sema &S, Expr *E, QualType T, + bool &ICContext) { + E = E->IgnoreParenImpCasts(); + + if (isa<ConditionalOperator>(E)) + return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T); + + AnalyzeImplicitConversions(S, E); + if (E->getType() != T) + return CheckImplicitConversion(S, E, T, &ICContext); + return; +} + +void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { + AnalyzeImplicitConversions(S, E->getCond()); + + bool Suspicious = false; + CheckConditionalOperand(S, E->getTrueExpr(), T, Suspicious); + CheckConditionalOperand(S, E->getFalseExpr(), T, Suspicious); + + // If -Wconversion would have warned about either of the candidates + // for a signedness conversion to the context type... + if (!Suspicious) return; + + // ...but it's currently ignored... + if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional)) + return; + + // ...and -Wsign-compare isn't... + if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional)) + return; + + // ...then check whether it would have warned about either of the + // candidates for a signedness conversion to the condition type. + if (E->getType() != T) { + Suspicious = false; + CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + E->getType(), &Suspicious); + if (!Suspicious) + CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), + E->getType(), &Suspicious); + if (!Suspicious) + return; + } + + // If so, emit a diagnostic under -Wsign-compare. + Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts(); + Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts(); + S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); +} + +/// AnalyzeImplicitConversions - Find and report any interesting +/// implicit conversions in the given expression. There are a couple +/// of competing diagnostics here, -Wconversion and -Wsign-compare. +void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) { + QualType T = OrigE->getType(); + Expr *E = OrigE->IgnoreParenImpCasts(); + + // For conditional operators, we analyze the arguments as if they + // were being fed directly into the output. + if (isa<ConditionalOperator>(E)) { + ConditionalOperator *CO = cast<ConditionalOperator>(E); + CheckConditionalOperator(S, CO, T); + return; + } + + // Go ahead and check any implicit conversions we might have skipped. + // The non-canonical typecheck is just an optimization; + // CheckImplicitConversion will filter out dead implicit conversions. + if (E->getType() != T) + CheckImplicitConversion(S, E, T); + + // Now continue drilling into this expression. + + // Skip past explicit casts. + if (isa<ExplicitCastExpr>(E)) { + E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts(); + return AnalyzeImplicitConversions(S, E); + } + + // Do a somewhat different check with comparison operators. + if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isComparisonOp()) + return AnalyzeComparison(S, cast<BinaryOperator>(E)); + + // These break the otherwise-useful invariant below. Fortunately, + // we don't really need to recurse into them, because any internal + // expressions should have been analyzed already when they were + // built into statements. + if (isa<StmtExpr>(E)) return; + + // Don't descend into unevaluated contexts. + if (isa<SizeOfAlignOfExpr>(E)) return; + + // Now just recurse over the expression's children. + for (Stmt::child_iterator I = E->child_begin(), IE = E->child_end(); + I != IE; ++I) + AnalyzeImplicitConversions(S, cast<Expr>(*I)); +} + +} // end anonymous namespace + +/// Diagnoses "dangerous" implicit conversions within the given +/// expression (which is a full expression). Implements -Wconversion +/// and -Wsign-compare. +void Sema::CheckImplicitConversions(Expr *E) { + // Don't diagnose in unevaluated contexts. + if (ExprEvalContexts.back().Context == Sema::Unevaluated) + return; + + // Don't diagnose for value- or type-dependent expressions. + if (E->isTypeDependent() || E->isValueDependent()) + return; + + AnalyzeImplicitConversions(*this, E); +} + /// CheckParmsForFunctionDef - Check that the parameters of the given /// function are appropriate for the definition of a function. This /// takes care of any checks that cannot be performed on the diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index c075d16..d8c1a5c 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -127,6 +127,13 @@ namespace { explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { } + /// \brief Whether we should include code patterns in the completion + /// results. + bool includeCodePatterns() const { + return SemaRef.CodeCompleter && + SemaRef.CodeCompleter->includeCodePatterns(); + } + /// \brief Set the filter used for code-completion results. void setFilter(LookupFilter Filter) { this->Filter = Filter; @@ -532,8 +539,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. - if (AsNestedNameSpecifier) + if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; + R.Priority = CCP_NestedNameSpecifier; + } // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && @@ -581,8 +590,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. - if (AsNestedNameSpecifier) + if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; + R.Priority = CCP_NestedNameSpecifier; + } else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass && isa<CXXRecordDecl>(R.Declaration->getDeclContext() ->getLookupContext())) @@ -601,6 +612,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, R.QualifierIsInformative = false; } + // Adjust the priority if this result comes from a base class. + if (InBaseClass) + R.Priority += CCD_InBaseClass; + // Insert this result into the set of results. Results.push_back(R); } @@ -672,8 +687,8 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const { ND = ClassTemplate->getTemplatedDecl(); if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TagDecl::TK_class || - RD->getTagKind() == TagDecl::TK_struct; + return RD->getTagKind() == TTK_Class || + RD->getTagKind() == TTK_Struct; return false; } @@ -685,7 +700,7 @@ bool ResultBuilder::IsUnion(NamedDecl *ND) const { ND = ClassTemplate->getTemplatedDecl(); if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TagDecl::TK_union; + return RD->getTagKind() == TTK_Union; return false; } @@ -744,47 +759,56 @@ namespace { static void AddTypeSpecifierResults(const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; - Results.AddResult(Result("short")); - Results.AddResult(Result("long")); - Results.AddResult(Result("signed")); - Results.AddResult(Result("unsigned")); - Results.AddResult(Result("void")); - Results.AddResult(Result("char")); - Results.AddResult(Result("int")); - Results.AddResult(Result("float")); - Results.AddResult(Result("double")); - Results.AddResult(Result("enum")); - Results.AddResult(Result("struct")); - Results.AddResult(Result("union")); - Results.AddResult(Result("const")); - Results.AddResult(Result("volatile")); + Results.AddResult(Result("short", CCP_Type)); + Results.AddResult(Result("long", CCP_Type)); + Results.AddResult(Result("signed", CCP_Type)); + Results.AddResult(Result("unsigned", CCP_Type)); + Results.AddResult(Result("void", CCP_Type)); + Results.AddResult(Result("char", CCP_Type)); + Results.AddResult(Result("int", CCP_Type)); + Results.AddResult(Result("float", CCP_Type)); + Results.AddResult(Result("double", CCP_Type)); + Results.AddResult(Result("enum", CCP_Type)); + Results.AddResult(Result("struct", CCP_Type)); + Results.AddResult(Result("union", CCP_Type)); + Results.AddResult(Result("const", CCP_Type)); + Results.AddResult(Result("volatile", CCP_Type)); if (LangOpts.C99) { // C99-specific - Results.AddResult(Result("_Complex")); - Results.AddResult(Result("_Imaginary")); - Results.AddResult(Result("_Bool")); - Results.AddResult(Result("restrict")); + Results.AddResult(Result("_Complex", CCP_Type)); + Results.AddResult(Result("_Imaginary", CCP_Type)); + Results.AddResult(Result("_Bool", CCP_Type)); + Results.AddResult(Result("restrict", CCP_Type)); } if (LangOpts.CPlusPlus) { // C++-specific - Results.AddResult(Result("bool")); - Results.AddResult(Result("class")); - Results.AddResult(Result("wchar_t")); + Results.AddResult(Result("bool", CCP_Type)); + Results.AddResult(Result("class", CCP_Type)); + Results.AddResult(Result("wchar_t", CCP_Type)); + + if (Results.includeCodePatterns()) { + // typename qualified-id + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Results.AddResult(Result(Pattern)); + } - // typename qualified-id - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typename"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("qualified-id"); - Results.AddResult(Result(Pattern)); - if (LangOpts.CPlusPlus0x) { - Results.AddResult(Result("auto")); - Results.AddResult(Result("char16_t")); - Results.AddResult(Result("char32_t")); - Results.AddResult(Result("decltype")); + Results.AddResult(Result("auto", CCP_Type)); + Results.AddResult(Result("char16_t", CCP_Type)); + Results.AddResult(Result("char32_t", CCP_Type)); + if (Results.includeCodePatterns()) { + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("decltype"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + } } } @@ -795,12 +819,14 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, // Results.AddResult(Result("_Decimal64")); // Results.AddResult(Result("_Decimal128")); - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeof"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + } } } @@ -843,6 +869,7 @@ static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC, case Action::CCC_Statement: case Action::CCC_ForInit: case Action::CCC_Condition: + case Action::CCC_RecoveryInFunction: break; } } @@ -868,7 +895,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, typedef CodeCompleteConsumer::Result Result; switch (CCC) { case Action::CCC_Namespace: - if (SemaRef.getLangOptions().CPlusPlus) { + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // namespace <identifier> { } CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("namespace"); @@ -920,8 +947,10 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, // Fall through case Action::CCC_Class: - Results.AddResult(Result("typedef")); - if (SemaRef.getLangOptions().CPlusPlus) { + if (Results.includeCodePatterns()) + Results.AddResult(Result("typedef")); + + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // Using declaration CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("using"); @@ -964,7 +993,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, case Action::CCC_Template: case Action::CCC_MemberTemplate: - if (SemaRef.getLangOptions().CPlusPlus) { + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // template < parameters > CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("template"); @@ -994,11 +1023,13 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true); break; + case Action::CCC_RecoveryInFunction: case Action::CCC_Statement: { - Results.AddResult(Result("typedef")); + if (Results.includeCodePatterns()) + Results.AddResult(Result("typedef")); CodeCompletionString *Pattern = 0; - if (SemaRef.getLangOptions().CPlusPlus) { + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("try"); Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); @@ -1018,37 +1049,39 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, if (SemaRef.getLangOptions().ObjC1) AddObjCStatementResults(Results, true); - // if (condition) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("if"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); - else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); - - // switch (condition) { } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("switch"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); - else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // if (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("if"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + // switch (condition) { } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("switch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + } + // Switch-specific statements. - if (!SemaRef.getSwitchStack().empty()) { + if (!SemaRef.getSwitchStack().empty() && Results.includeCodePatterns()) { // case expression: Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("case"); @@ -1063,52 +1096,54 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Results.AddResult(Result(Pattern)); } - /// while (condition) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("while"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); - else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + /// while (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); - // do { statements } while ( expression ); - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("do"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Pattern->AddTextChunk("while"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // do { statements } while ( expression ); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("do"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // for ( for-init-statement ; condition ; expression ) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("for"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) - Pattern->AddPlaceholderChunk("init-statement"); - else - Pattern->AddPlaceholderChunk("init-expression"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); - Pattern->AddPlaceholderChunk("condition"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); - Pattern->AddPlaceholderChunk("inc-expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + // for ( for-init-statement ; condition ; expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("for"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) + Pattern->AddPlaceholderChunk("init-statement"); + else + Pattern->AddPlaceholderChunk("init-expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("condition"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("inc-expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + } if (S->getContinueParent()) { // continue ; @@ -1143,21 +1178,23 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, } Results.AddResult(Result(Pattern)); - // goto identifier ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("goto"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // goto identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("goto"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Results.AddResult(Result(Pattern)); - // Using directives - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Results.AddResult(Result(Pattern)); + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Results.AddResult(Result(Pattern)); + } } // Fall through (for statement expressions). @@ -1178,103 +1215,107 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Results.AddResult(Result("true")); Results.AddResult(Result("false")); - // dynamic_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("dynamic_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); - - // static_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("static_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); - - // reinterpret_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("reinterpret_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // dynamic_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("dynamic_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // static_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("static_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // const_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("const_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // reinterpret_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("reinterpret_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // typeid ( expression-or-type ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeid"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // const_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("const_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // new T ( ... ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("new"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expressions"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // typeid ( expression-or-type ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeid"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // new T [ ] ( ... ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("new"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type-id"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); - Pattern->AddPlaceholderChunk("size"); - Pattern->AddChunk(CodeCompletionString::CK_RightBracket); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expressions"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + // new T ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); - // delete expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("delete"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + // new T [ ] ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddPlaceholderChunk("size"); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // delete expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); - // delete [] expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("delete"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); - Pattern->AddChunk(CodeCompletionString::CK_RightBracket); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + // delete [] expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); - // throw expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("throw"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + // throw expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + } + + // FIXME: Rethrow? } if (SemaRef.getLangOptions().ObjC1) { @@ -1286,13 +1327,15 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, AddObjCExpressionResults(Results, true); } - // sizeof expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("sizeof"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + if (Results.includeCodePatterns()) { + // sizeof expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("sizeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + } break; } } @@ -1543,7 +1586,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { return Result; } - assert(Kind == RK_Declaration && "Missed a macro kind?"); + assert(Kind == RK_Declaration && "Missed a result kind?"); NamedDecl *ND = Declaration; if (StartsNestedNameSpecifier) { @@ -1925,6 +1968,10 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, case CCC_Condition: Results.setFilter(&ResultBuilder::IsOrdinaryName); break; + + case CCC_RecoveryInFunction: + // Unfiltered + break; } CodeCompletionDeclConsumer Consumer(Results, CurContext); @@ -2047,14 +2094,14 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, I != E; ++I) AddObjCProperties(*I, true, CurContext, Results); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || - (!IsArrow && BaseType->isObjCInterfaceType())) { + (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. ObjCInterfaceDecl *Class = 0; if (const ObjCObjectPointerType *ObjCPtr = BaseType->getAs<ObjCObjectPointerType>()) Class = ObjCPtr->getInterfaceDecl(); else - Class = BaseType->getAs<ObjCInterfaceType>()->getDecl(); + Class = BaseType->getAs<ObjCObjectType>()->getInterface(); // Add all ivars from this class and its superclasses. if (Class) { @@ -2413,6 +2460,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) { static void AddObjCImplementationResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; // Since we have an implementation, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); @@ -2438,6 +2488,9 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts, static void AddObjCInterfaceResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; // Since we have an interface or protocol, we can end it. @@ -2456,6 +2509,9 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts, } static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; @@ -2515,6 +2571,9 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, } static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; @@ -2544,6 +2603,9 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { } static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; @@ -2590,6 +2652,9 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { static void AddObjCVisibilityResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { + if (!Results.includeCodePatterns()) + return; + typedef CodeCompleteConsumer::Result Result; Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private))); Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected))); @@ -2911,9 +2976,9 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { ObjCInterfaceDecl *IFace = 0; switch (Msg->getReceiverKind()) { case ObjCMessageExpr::Class: - if (const ObjCInterfaceType *IFaceType - = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()) - IFace = IFaceType->getDecl(); + if (const ObjCObjectType *ObjType + = Msg->getClassReceiver()->getAs<ObjCObjectType>()) + IFace = ObjType->getInterface(); break; case ObjCMessageExpr::Instance: { @@ -2994,9 +3059,9 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) { // "super" names an interface. Use it. } else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) { - if (const ObjCInterfaceType *Iface - = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>()) - CDecl = Iface->getDecl(); + if (const ObjCObjectType *Iface + = Context.getTypeDeclType(TD)->getAs<ObjCObjectType>()) + CDecl = Iface->getInterface(); } else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) { // "super" names an unresolved type; we can't be more specific. } else { @@ -3030,8 +3095,8 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, if (Receiver) { QualType T = GetTypeFromParser(Receiver, 0); if (!T.isNull()) - if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>()) - CDecl = Interface->getDecl(); + if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>()) + CDecl = Interface->getInterface(); } // Add all of the factory methods in this Objective-C class, its protocols, @@ -3079,8 +3144,6 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, } Results.ExitScope(); - - // This also suppresses remaining diagnostics. HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a802679..af02099 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -90,8 +90,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // We know from the grammar that this name refers to a type, so build a // DependentNameType node to describe the type. return CheckTypenameType(ETK_None, - (NestedNameSpecifier *)SS->getScopeRep(), - II, SS->getRange()).getAsOpaquePtr(); + (NestedNameSpecifier *)SS->getScopeRep(), II, + SourceLocation(), SS->getRange(), NameLoc + ).getAsOpaquePtr(); } return 0; @@ -191,7 +192,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, T = Context.getTypeDeclType(TD); if (SS) - T = getQualifiedNameType(*SS, T); + T = getElaboratedType(ETK_None, *SS, T); } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { T = Context.getObjCInterfaceType(IDecl); @@ -223,10 +224,11 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { if (R.getResultKind() == LookupResult::Found) if (const TagDecl *TD = R.getAsSingle<TagDecl>()) { switch (TD->getTagKind()) { - case TagDecl::TK_struct: return DeclSpec::TST_struct; - case TagDecl::TK_union: return DeclSpec::TST_union; - case TagDecl::TK_class: return DeclSpec::TST_class; - case TagDecl::TK_enum: return DeclSpec::TST_enum; + default: return DeclSpec::TST_unspecified; + case TTK_Struct: return DeclSpec::TST_struct; + case TTK_Union: return DeclSpec::TST_union; + case TTK_Class: return DeclSpec::TST_class; + case TTK_Enum: return DeclSpec::TST_enum; } } @@ -285,8 +287,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, Name.setIdentifier(&II, IILoc); CXXScopeSpec EmptySS; TemplateTy TemplateResult; - if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult) - == TNK_Type_template) { + bool MemberOfUnknownSpecialization; + if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult, + MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.getAsVal<TemplateName>(); Diag(IILoc, diag::err_template_missing_args) << TplName; if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { @@ -544,9 +547,9 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; } - // If we failed to complete the type for some reason, don't - // diagnose the variable. - if (Ty->isIncompleteType()) + // If we failed to complete the type for some reason, or if the type is + // dependent, don't diagnose the variable. + if (Ty->isIncompleteType() || Ty->isDependentType()) return false; if (const TagType *TT = Ty->getAs<TagType>()) { @@ -555,9 +558,10 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) { - if (!RD->hasTrivialConstructor()) - return false; - if (!RD->hasTrivialDestructor()) + // FIXME: Checking for the presence of a user-declared constructor + // isn't completely accurate; we'd prefer to check that the initializer + // has no side effects. + if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor()) return false; } } @@ -568,6 +572,18 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return true; } +void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { + if (!ShouldDiagnoseUnusedDecl(D)) + return; + + if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) + Diag(D->getLocation(), diag::warn_unused_exception_param) + << D->getDeclName(); + else + Diag(D->getLocation(), diag::warn_unused_variable) + << D->getDeclName(); +} + void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && @@ -584,15 +600,9 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (ShouldDiagnoseUnusedDecl(D) && - S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) { - if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) - Diag(D->getLocation(), diag::warn_unused_exception_param) - << D->getDeclName(); - else - Diag(D->getLocation(), diag::warn_unused_variable) - << D->getDeclName(); - } + if (S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) + DiagnoseUnusedDecl(D); + // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } @@ -1069,10 +1079,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { = cast<FunctionType>(OldQType.getTypePtr())->getResultType(); QualType NewReturnType = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); + QualType ResQT; if (OldReturnType != NewReturnType) { - Diag(New->getLocation(), diag::err_ovl_diff_return_type); - Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - return true; + if (NewReturnType->isObjCObjectPointerType() + && OldReturnType->isObjCObjectPointerType()) + ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); + if (ResQT.isNull()) { + Diag(New->getLocation(), diag::err_ovl_diff_return_type); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; + } + else + NewQType = ResQT; } const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); @@ -1356,6 +1374,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { = Context.getCanonicalType(New->getType())->getAs<ArrayType>(); if (OldArray->getElementType() == NewArray->getElementType()) MergedT = Old->getType(); + } else if (New->getType()->isObjCObjectPointerType() + && Old->getType()->isObjCObjectPointerType()) { + MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); @@ -1435,7 +1456,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. -Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { +Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS) { // FIXME: Error on auto/register at file scope // FIXME: Error on inline/virtual/explicit // FIXME: Warn on useless __thread @@ -1485,7 +1507,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOptions().CPlusPlus || Record->getDeclContext()->isRecord()) - return BuildAnonymousStructOrUnion(S, DS, Record); + return BuildAnonymousStructOrUnion(S, DS, AS, Record); Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); @@ -1563,8 +1585,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, /// /// This routine is recursive, injecting the names of nested anonymous /// structs/unions into the owning context and scope as well. -bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, - RecordDecl *AnonRecord) { +static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, + DeclContext *Owner, + RecordDecl *AnonRecord, + AccessSpecifier AS) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; @@ -1574,7 +1598,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(), + if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(), (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be @@ -1588,15 +1612,19 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, // considered to have been defined in the scope in which the // anonymous union is declared. Owner->makeDeclVisibleInContext(*F); - S->AddDecl(DeclPtrTy::make(*F)); - IdResolver.AddDecl(*F); + S->AddDecl(Sema::DeclPtrTy::make(*F)); + SemaRef.IdResolver.AddDecl(*F); + + // That includes picking up the appropriate access specifier. + if (AS != AS_none) (*F)->setAccess(AS); } } else if (const RecordType *InnerRecordType = (*F)->getType()->getAs<RecordType>()) { RecordDecl *InnerRecord = InnerRecordType->getDecl(); if (InnerRecord->isAnonymousStructOrUnion()) Invalid = Invalid || - InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord); + InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner, + InnerRecord, AS); } } @@ -1666,6 +1694,7 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec, /// (C++ [class.union]) and a GNU C extension; anonymous structures /// are a GNU C and GNU C++ extension. Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, RecordDecl *Record) { DeclContext *Owner = Record->getDeclContext(); @@ -1720,7 +1749,8 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // C++ [class.union]p3: // An anonymous union shall not have private or protected // members (clause 11). - if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) { + assert(FD->getAccess() != AS_none); + if (FD->getAccess() != AS_public) { Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member) << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected); Invalid = true; @@ -1777,7 +1807,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false); - Anon->setAccess(AS_public); + Anon->setAccess(AS); if (getLangOptions().CPlusPlus) { FieldCollector->Add(cast<FieldDecl>(Anon)); if (!cast<CXXRecordDecl>(Record)->isEmpty()) @@ -1814,7 +1844,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - if (InjectAnonymousStructOrUnionMembers(S, Owner, Record)) + if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS)) Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not @@ -2711,7 +2741,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, QualType T = NewVD->getType(); - if (T->isObjCInterfaceType()) { + if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object); return NewVD->setInvalidDecl(); } @@ -2929,7 +2959,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.setInvalidType(); // Do not allow returning a objc interface by-value. - if (R->getAs<FunctionType>()->getResultType()->isObjCInterfaceType()) { + if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << R->getAs<FunctionType>()->getResultType(); @@ -4322,7 +4352,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, // Parameter declarators cannot be interface types. All ObjC objects are // passed by reference. - if (T->isObjCInterfaceType()) { + if (T->isObjCObjectType()) { Diag(NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; New->setInvalidDecl(); @@ -4540,6 +4570,38 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { return DeclPtrTy::make(FD); } +/// \brief Given the set of return statements within a function body, +/// compute the variables that are subject to the named return value +/// optimization. +/// +/// Each of the variables that is subject to the named return value +/// optimization will be marked as NRVO variables in the AST, and any +/// return statement that has a marked NRVO variable as its NRVO candidate can +/// use the named return value optimization. +/// +/// This function applies a very simplistic algorithm for NRVO: if every return +/// statement in the function has the same NRVO candidate, that candidate is +/// the NRVO variable. +/// +/// FIXME: Employ a smarter algorithm that accounts for multiple return +/// statements and the lifetimes of the NRVO candidates. We should be able to +/// find a maximal set of NRVO variables. +static void ComputeNRVO(Stmt *Body, ReturnStmt **Returns, unsigned NumReturns) { + const VarDecl *NRVOCandidate = 0; + for (unsigned I = 0; I != NumReturns; ++I) { + if (!Returns[I]->getNRVOCandidate()) + return; + + if (!NRVOCandidate) + NRVOCandidate = Returns[I]->getNRVOCandidate(); + else if (NRVOCandidate != Returns[I]->getNRVOCandidate()) + return; + } + + if (NRVOCandidate) + const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true); +} + Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) { return ActOnFinishFunctionBody(D, move(BodyArg), false); } @@ -4567,12 +4629,17 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, WP.disableCheckFallThrough(); } - if (!FD->isInvalidDecl()) + if (!FD->isInvalidDecl()) { DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); - - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) - MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method); - + + // If this is a constructor, we need a vtable. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) + MarkVTableUsed(FD->getLocation(), Constructor->getParent()); + + ComputeNRVO(Body, FunctionScopes.back()->Returns.data(), + FunctionScopes.back()->Returns.size()); + } + assert(FD == getCurFunctionDecl() && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); @@ -4636,7 +4703,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Verify that that gotos and switch cases don't jump into scopes illegally. // Verify that that gotos and switch cases don't jump into scopes illegally. - if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction()) + if (FunctionNeedsScopeChecking() && + !dcl->isInvalidDecl() && + !hasAnyErrorsInThisFunction()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) @@ -4838,38 +4907,38 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// /// \returns true if the new tag kind is acceptable, false otherwise. bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, - TagDecl::TagKind NewTag, + TagTypeKind NewTag, SourceLocation NewTagLoc, const IdentifierInfo &Name) { // C++ [dcl.type.elab]p3: // The class-key or enum keyword present in the // elaborated-type-specifier shall agree in kind with the - // declaration to which the name in theelaborated-type-specifier + // declaration to which the name in the elaborated-type-specifier // refers. This rule also applies to the form of // elaborated-type-specifier that declares a class-name or // friend class since it can be construed as referring to the // definition of the class. Thus, in any // elaborated-type-specifier, the enum keyword shall be used to - // refer to an enumeration (7.2), the union class-keyshall be + // refer to an enumeration (7.2), the union class-key shall be // used to refer to a union (clause 9), and either the class or // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. - TagDecl::TagKind OldTag = Previous->getTagKind(); + TagTypeKind OldTag = Previous->getTagKind(); if (OldTag == NewTag) return true; - if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) && - (NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) { + if ((OldTag == TTK_Struct || OldTag == TTK_Class) && + (NewTag == TTK_Struct || NewTag == TTK_Class)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) isTemplate = Record->getDescribedClassTemplate(); Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TagDecl::TK_class) + << (NewTag == TTK_Class) << isTemplate << &Name << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - OldTag == TagDecl::TK_class? "class" : "struct"); + OldTag == TTK_Class? "class" : "struct"); Diag(Previous->getLocation(), diag::note_previous_use); return true; } @@ -4891,7 +4960,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, "Nameless record must be a definition!"); OwnedDecl = false; - TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec); + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); // FIXME: Check explicit specializations more carefully. bool isExplicitSpecialization = false; @@ -4915,7 +4984,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) - << ElaboratedType::getNameForTagKind(Kind) << Name; + << TypeWithKeyword::getTagTypeKindName(Kind) << Name; isExplicitSpecialization = true; } } @@ -5134,8 +5203,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { bool SafeToContinue - = (PrevTagDecl->getTagKind() != TagDecl::TK_enum && - Kind != TagDecl::TK_enum); + = (PrevTagDecl->getTagKind() != TTK_Enum && + Kind != TTK_Enum); if (SafeToContinue) Diag(KWLoc, diag::err_use_with_wrong_tag) << Name @@ -5289,7 +5358,7 @@ CreateNewDecl: // PrevDecl. TagDecl *New; - if (Kind == TagDecl::TK_enum) { + if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc, @@ -5319,16 +5388,18 @@ CreateNewDecl: // Maybe add qualifier info. if (SS.isNotEmpty()) { - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - New->setQualifierInfo(NNS, SS.getRange()); + if (SS.isSet()) { + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + New->setQualifierInfo(NNS, SS.getRange()); + } + else + Invalid = true; } - if (Kind != TagDecl::TK_enum) { - // Handle #pragma pack: if the #pragma pack stack has non-default - // alignment, make up a packed attribute for this decl. These - // attributes are checked when the ASTContext lays out the - // structure. + if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) { + // Add alignment attributes if necessary; these attributes are checked when + // the ASTContext lays out the structure. // // It is important for implementing the correct semantics that this // happen here (in act on tag decl). The #pragma pack stack is @@ -5336,15 +5407,14 @@ CreateNewDecl: // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the // parsing of the struct). - if (unsigned Alignment = getPragmaPackAlignment()) - New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8)); + AddAlignmentAttributesForRecord(RD); } // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) Invalid = true; - + if (Invalid) New->setInvalidDecl(); @@ -5439,37 +5509,6 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD, "Broken injected-class-name"); } -// Traverses the class and any nested classes, making a note of any -// dynamic classes that have no key function so that we can mark all of -// their virtual member functions as "used" at the end of the translation -// unit. This ensures that all functions needed by the vtable will get -// instantiated/synthesized. -static void -RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record, - SourceLocation Loc) { - // We don't look at dependent or undefined classes. - if (Record->isDependentContext() || !Record->isDefinition()) - return; - - if (Record->isDynamicClass()) { - const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record); - - if (!KeyFunction) - S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, - Loc)); - - if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined())) - && Record->getLinkage() == ExternalLinkage) - S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record; - } - for (DeclContext::decl_iterator D = Record->decls_begin(), - DEnd = Record->decls_end(); - D != DEnd; ++D) { - if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D)) - RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc); - } -} - void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); @@ -5481,10 +5520,6 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, // Exit this scope of this tag's definition. PopDeclContext(); - - if (isa<CXXRecordDecl>(Tag) && !Tag->getLexicalDeclContext()->isRecord()) - RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag), - RBraceLoc); // Notify the consumer that we've defined a tag. Consumer.HandleTagDeclDefinition(Tag); @@ -6098,6 +6133,15 @@ void Sema::ActOnFields(Scope* S, EnclosingDecl->setInvalidDecl(); continue; } + if (!FD->getType()->isDependentType() && + !Context.getBaseElementType(FD->getType())->isPODType()) { + Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type) + << FD->getDeclName() << FD->getType(); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Okay, we have a legal flexible array member at the end of the struct. if (Record) Record->setHasFlexibleArrayMember(true); @@ -6132,7 +6176,7 @@ void Sema::ActOnFields(Scope* S, } if (Record && FDTTy->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); - } else if (FDTy->isObjCInterfaceType()) { + } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object); FD->setInvalidDecl(); @@ -6435,7 +6479,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(EnumType); } - Enum->completeDefinition(Context.DependentTy, Context.DependentTy); + Enum->completeDefinition(Context.DependentTy, Context.DependentTy, 0, 0); return; } @@ -6616,7 +6660,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(NewTy); } - Enum->completeDefinition(BestType, BestPromotionType); + Enum->completeDefinition(BestType, BestPromotionType, + NumPositiveBits, NumNegativeBits); } Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 90aa9c1..c6dcc3b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -129,11 +129,11 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) { if (!PT) return false; - const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>(); - if (!ClsT) + ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); + if (!Cls) return false; - IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier(); + IdentifierInfo* ClsName = Cls->getIdentifier(); // FIXME: Should we walk the chain of classes? return ClsName == &Ctx.Idents.get("NSString") || @@ -150,7 +150,7 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return false; const RecordDecl *RD = RT->getDecl(); - if (RD->getTagKind() != TagDecl::TK_struct) + if (RD->getTagKind() != TTK_Struct) return false; return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); @@ -259,6 +259,26 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); } +static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, + Sema &S) { + + // The iboutletcollection attribute can have zero or one arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // The IBOutletCollection attributes only apply to instance variables of + // Objective-C classes. + if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) { + S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); + return; + } + + // FIXME: Eventually accept the type argument. + d->addAttr(::new (S.Context) IBOutletCollectionAttr()); +} + static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // GCC ignores the nonnull attribute on K&R style function prototypes, so we // ignore it as well @@ -280,7 +300,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // The argument must be an integer constant expression. Expr *Ex = static_cast<Expr *>(*I); llvm::APSInt ArgNum(32); - if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) { + if (Ex->isTypeDependent() || Ex->isValueDependent() || + !Ex->isIntegerConstantExpr(ArgNum, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "nonnull" << Ex->getSourceRange(); return; @@ -560,7 +581,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 0) { Expr *E = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "constructor" << 1 << E->getSourceRange(); return; @@ -589,7 +611,8 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 0) { Expr *E = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "destructor" << 1 << E->getSourceRange(); return; @@ -745,7 +768,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 0) { Expr *E = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "sentinel" << 1 << E->getSourceRange(); return; @@ -763,7 +787,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() > 1) { Expr *E = static_cast<Expr *>(Attr.getArg(1)); llvm::APSInt Idx(32); - if (!E->isIntegerConstantExpr(Idx, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "sentinel" << 2 << E->getSourceRange(); return; @@ -924,7 +949,8 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, for (unsigned i = 0; i < 3; ++i) { Expr *E = static_cast<Expr *>(Attr.getArg(i)); llvm::APSInt ArgNum(32); - if (!E->isIntegerConstantExpr(ArgNum, S.Context)) { + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(ArgNum, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "reqd_work_group_size" << E->getSourceRange(); return; @@ -1076,7 +1102,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { // checks for the 2nd argument Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { + if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || + !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "format" << 2 << IdxExpr->getSourceRange(); return; @@ -1198,7 +1225,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // checks for the 2nd argument Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Idx(32); - if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { + if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || + !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "format" << 2 << IdxExpr->getSourceRange(); return; @@ -1261,7 +1289,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the 3rd argument Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1)); llvm::APSInt FirstArg(32); - if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) { + if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() || + !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) << "format" << 3 << FirstArgExpr->getSourceRange(); return; @@ -1403,7 +1432,8 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Alignment(32); - if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) { + if (alignmentExpr->isTypeDependent() || alignmentExpr->isValueDependent() || + !alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "aligned" << alignmentExpr->getSourceRange(); return; @@ -1654,6 +1684,8 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { case AttributeList::AT_stdcall: d->addAttr(::new (S.Context) StdCallAttr()); return; + case AttributeList::AT_thiscall: + d->addAttr(::new (S.Context) ThisCallAttr()); case AttributeList::AT_cdecl: d->addAttr(::new (S.Context) CDeclAttr()); return; @@ -1678,7 +1710,8 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt NumParams(32); - if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || + !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "regparm" << NumParamsExpr->getSourceRange(); return; @@ -1871,7 +1904,9 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, return; switch (Attr.getKind()) { case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break; - case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; + case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; + case AttributeList::AT_IBOutletCollection: + HandleIBOutletCollection(D, Attr, S); break; case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: case AttributeList::AT_vector_size: @@ -1950,6 +1985,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_stdcall: case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: + case AttributeList::AT_thiscall: HandleCallConvAttr(D, Attr, S); break; default: diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b9c7d79..148d146 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -461,7 +461,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, if (BaseType->isDependentType()) return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == RecordDecl::TK_class, + Class->getTagKind() == TTK_Class, Access, BaseType); // Base specifiers must be record types. @@ -504,9 +504,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual); // Create the base specifier. - // FIXME: Allocate via ASTContext? return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == RecordDecl::TK_class, + Class->getTagKind() == TTK_Class, Access, BaseType); } @@ -623,7 +622,13 @@ 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 @@ -736,6 +741,18 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths, BasePathArray.push_back(Path[I].Base); } +/// \brief Determine whether the given base path includes a virtual +/// base class. +bool Sema::BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath) { + for (CXXBaseSpecifierArray::iterator B = BasePath.begin(), + BEnd = BasePath.end(); + B != BEnd; ++B) + if ((*B)->isVirtual()) + return true; + + return false; +} + /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and @@ -1125,7 +1142,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // specialization, we take it as a type name. BaseType = CheckTypenameType(ETK_None, (NestedNameSpecifier *)SS.getScopeRep(), - *MemberOrBase, SS.getRange()); + *MemberOrBase, SourceLocation(), + SS.getRange(), IdLoc); if (BaseType.isNull()) return true; @@ -1192,7 +1210,7 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, static_cast<NestedNameSpecifier*>(SS.getScopeRep()); // FIXME: preserve source range information - BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + BaseType = Context.getElaboratedType(ETK_None, Qualifier, BaseType); } } } @@ -1357,7 +1375,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); - SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin(); + SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (BaseType->isDependentType() || HasDependentArg) { // Can't check initialization for a base of dependent type or when // any of the arguments are type-dependent expressions. @@ -1381,7 +1399,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (!BaseType->isRecordType()) return Diag(BaseLoc, diag::err_base_init_does_not_name_class) - << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); + << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data @@ -1402,7 +1420,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // class, the mem-initializer is ill-formed. if (DirectBaseSpec && VirtualBaseSpec) return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) - << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); + << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); // C++ [base.class.init]p2: // Unless the mem-initializer-id names a nonstatic data membeer of the // constructor's class ot a direst or virtual base of that class, the @@ -1410,7 +1428,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (!DirectBaseSpec && !VirtualBaseSpec) return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) << BaseType << Context.getTypeDeclType(ClassDecl) - << BaseTInfo->getTypeLoc().getSourceRange(); + << BaseTInfo->getTypeLoc().getLocalSourceRange(); CXXBaseSpecifier *BaseSpec = const_cast<CXXBaseSpecifier *>(DirectBaseSpec); @@ -1550,42 +1568,107 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, FieldDecl *Field, CXXBaseOrMemberInitializer *&CXXMemberInit) { + if (Field->isInvalidDecl()) + return true; + if (ImplicitInitKind == IIK_Copy) { - // FIXME: We should not return early here, but will do so until - // we know how to handle copy initialization of arrays. - CXXMemberInit = 0; - return false; - + SourceLocation Loc = Constructor->getLocation(); ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, - SourceLocation(), ParamType, 0); + Loc, ParamType, 0); + + // Build a reference to this field within the parameter. + CXXScopeSpec SS; + LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc, + Sema::LookupMemberName); + MemberLookup.addDecl(Field, AS_public); + MemberLookup.resolveKind(); + Sema::OwningExprResult CopyCtorArg + = SemaRef.BuildMemberReferenceExpr(SemaRef.Owned(MemberExprBase), + ParamType, Loc, + /*IsArrow=*/false, + SS, + /*FirstQualifierInScope=*/0, + MemberLookup, + /*TemplateArgs=*/0); + if (CopyCtorArg.isInvalid()) + return true; + // When the field we are copying is an array, create index variables for + // each dimension of the array. We use these index variables to subscript + // the source array, and other clients (e.g., CodeGen) will perform the + // necessary iteration with these index variables. + llvm::SmallVector<VarDecl *, 4> IndexVariables; + QualType BaseType = Field->getType(); + QualType SizeType = SemaRef.Context.getSizeType(); + while (const ConstantArrayType *Array + = SemaRef.Context.getAsConstantArrayType(BaseType)) { + // Create the iteration variable for this array index. + IdentifierInfo *IterationVarName = 0; + { + llvm::SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "__i" << IndexVariables.size(); + IterationVarName = &SemaRef.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar + = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, + IterationVarName, SizeType, + SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc), + VarDecl::None, VarDecl::None); + IndexVariables.push_back(IterationVar); + + // Create a reference to the iteration variable. + Sema::OwningExprResult IterationVarRef + = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, Loc); + assert(!IterationVarRef.isInvalid() && + "Reference to invented variable cannot fail!"); + + // Subscript the array with this iteration variable. + CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(move(CopyCtorArg), + Loc, + move(IterationVarRef), + Loc); + if (CopyCtorArg.isInvalid()) + return true; + + BaseType = Array->getElementType(); + } - Expr *CopyCtorArg = - MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false, - 0, SourceRange(), Field, - DeclAccessPair::make(Field, Field->getAccess()), - SourceLocation(), 0, - Field->getType().getNonReferenceType()); + // Construct the entity that we will be initializing. For an array, this + // will be first element in the array, which may require several levels + // of array-subscript entities. + llvm::SmallVector<InitializedEntity, 4> Entities; + Entities.reserve(1 + IndexVariables.size()); + Entities.push_back(InitializedEntity::InitializeMember(Field)); + for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) + Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context, + 0, + Entities.back())); - InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + // Direct-initialize to use the copy constructor. InitializationKind InitKind = - InitializationKind::CreateDirect(Constructor->getLocation(), - SourceLocation(), SourceLocation()); + InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, - &CopyCtorArg, 1); + Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>(); + InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, + &CopyCtorArgE, 1); - Sema::OwningExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, - Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0); + Sema::OwningExprResult MemberInit + = InitSeq.Perform(SemaRef, Entities.back(), InitKind, + Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArgE, 1)); + MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit)); if (MemberInit.isInvalid()) return true; - - CXXMemberInit = 0; + + CXXMemberInit + = CXXBaseOrMemberInitializer::Create(SemaRef.Context, Field, Loc, Loc, + MemberInit.takeAs<Expr>(), Loc, + IndexVariables.data(), + IndexVariables.size()); return false; } @@ -1640,6 +1723,81 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, CXXMemberInit = 0; return false; } + +namespace { +struct BaseAndFieldInfo { + Sema &S; + CXXConstructorDecl *Ctor; + bool AnyErrorsInInits; + ImplicitInitializerKind IIK; + llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; + llvm::SmallVector<CXXBaseOrMemberInitializer*, 8> AllToInit; + + BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits) + : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) { + // FIXME: Handle implicit move constructors. + if (Ctor->isImplicit() && Ctor->isCopyConstructor()) + IIK = IIK_Copy; + else + IIK = IIK_Default; + } +}; +} + +static bool CollectFieldInitializer(BaseAndFieldInfo &Info, + FieldDecl *Top, FieldDecl *Field) { + + // Overwhelmingly common case: we have a direct initializer for this field. + if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(Field)) { + Info.AllToInit.push_back(Init); + + if (Field != Top) { + Init->setMember(Top); + Init->setAnonUnionMember(Field); + } + return false; + } + + if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) { + const RecordType *FieldClassType = Field->getType()->getAs<RecordType>(); + assert(FieldClassType && "anonymous struct/union without record type"); + + // Walk through the members, tying in any initializers for fields + // we find. The earlier semantic checks should prevent redundant + // initialization of union members, given the requirement that + // union members never have non-trivial default constructors. + + // TODO: in C++0x, it might be legal to have union members with + // non-trivial default constructors in unions. Revise this + // implementation then with the appropriate semantics. + CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), + EA = FieldClassDecl->field_end(); FA != EA; FA++) + if (CollectFieldInitializer(Info, Top, *FA)) + return true; + } + + // Don't try to build an implicit initializer if there were semantic + // errors in any of the initializers (and therefore we might be + // missing some that the user actually wrote). + if (Info.AnyErrorsInInits) + return false; + + CXXBaseOrMemberInitializer *Init = 0; + if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init)) + return true; + + // If the member doesn't need to be initialized, Init will still be null. + if (!Init) return false; + + Info.AllToInit.push_back(Init); + if (Top != Field) { + Init->setMember(Top); + Init->setAnonUnionMember(Field); + } + return false; +} bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, @@ -1661,11 +1819,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, return false; } - ImplicitInitializerKind ImplicitInitKind = IIK_Default; - - // FIXME: Handle implicit move constructors. - if (Constructor->isImplicit() && Constructor->isCopyConstructor()) - ImplicitInitKind = IIK_Copy; + BaseAndFieldInfo Info(*this, Constructor, AnyErrors); // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. @@ -1673,17 +1827,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, if (!ClassDecl) return true; - llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; - llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { CXXBaseOrMemberInitializer *Member = Initializers[i]; if (Member->isBaseInitializer()) - AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; + Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; else - AllBaseFields[Member->getMember()] = Member; + Info.AllBaseFields[Member->getMember()] = Member; } // Keep track of the direct virtual bases. @@ -1699,22 +1851,23 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, E = ClassDecl->vbases_end(); VBase != E; ++VBase) { if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { - AllToInit.push_back(Value); + = Info.AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { + Info.AllToInit.push_back(Value); } else if (!AnyErrors) { bool IsInheritedVirtualBase = !DirectVBases.count(VBase); CXXBaseOrMemberInitializer *CXXBaseInit; - if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, VBase, IsInheritedVirtualBase, CXXBaseInit)) { HadError = true; continue; } - AllToInit.push_back(CXXBaseInit); + Info.AllToInit.push_back(CXXBaseInit); } } + // Non-virtual bases. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Virtuals are in the virtual base list and already constructed. @@ -1722,70 +1875,39 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { - AllToInit.push_back(Value); + = Info.AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { + Info.AllToInit.push_back(Value); } else if (!AnyErrors) { CXXBaseOrMemberInitializer *CXXBaseInit; - if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, Base, /*IsInheritedVirtualBase=*/false, CXXBaseInit)) { HadError = true; continue; } - AllToInit.push_back(CXXBaseInit); + Info.AllToInit.push_back(CXXBaseInit); } } - // non-static data members. + // Fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { - if ((*Field)->isAnonymousStructOrUnion()) { - if (const RecordType *FieldClassType = - Field->getType()->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), - EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) { - // 'Member' is the anonymous union field and 'AnonUnionMember' is - // set to the anonymous union data member used in the initializer - // list. - Value->setMember(*Field); - Value->setAnonUnionMember(*FA); - AllToInit.push_back(Value); - break; - } - } - } - continue; - } - if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) { - AllToInit.push_back(Value); + if ((*Field)->getType()->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); continue; } - - if (AnyErrors) - continue; - - CXXBaseOrMemberInitializer *Member; - if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind, - *Field, Member)) { + if (CollectFieldInitializer(Info, *Field, *Field)) HadError = true; - continue; - } - - // If the member doesn't need to be initialized, it will be null. - if (Member) - AllToInit.push_back(Member); } - NumInitializers = AllToInit.size(); + NumInitializers = Info.AllToInit.size(); if (NumInitializers > 0) { Constructor->setNumBaseOrMemberInitializers(NumInitializers); CXXBaseOrMemberInitializer **baseOrMemberInitializers = new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; - memcpy(baseOrMemberInitializers, AllToInit.data(), + memcpy(baseOrMemberInitializers, Info.AllToInit.data(), NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); @@ -1900,9 +2022,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, // If we didn't find this initializer, it must be because we // scanned past it on a previous iteration. That can only // happen if we're out of order; emit a warning. - if (IdealIndex == NumIdealInits) { - assert(PrevInit && "initializer not found in initializer list"); - + if (IdealIndex == NumIdealInits && PrevInit) { Sema::SemaDiagnosticBuilder D = SemaRef.Diag(PrevInit->getSourceLocation(), diag::warn_initializer_out_of_order); @@ -2028,6 +2148,9 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, for (unsigned i = 0; i < NumMemInits; i++) { CXXBaseOrMemberInitializer *Init = MemInits[i]; + // Set the source order index. + Init->setSourceOrder(i); + if (Init->isMemberInitializer()) { FieldDecl *Field = Init->getMember(); if (CheckRedundantInit(*this, Init, Members[Field]) || @@ -2064,7 +2187,8 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { FieldDecl *Field = *I; - + if (Field->isInvalidDecl()) + continue; QualType FieldType = Context.getBaseElementType(Field->getType()); const RecordType* RT = FieldType->getAs<RecordType>(); @@ -2403,6 +2527,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { } } } + + if (Record->isDynamicClass()) + DynamicClasses.push_back(Record); } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2530,7 +2657,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, Context.getFunctionType(Context.VoidTy, &ArgType, 1, false, 0, - /*FIXME:*/false, + /*FIXME: hasExceptionSpec*/false, false, 0, 0, FunctionType::ExtInfo()), /*TInfo=*/0, @@ -2623,7 +2750,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(RetType, &ArgType, 1, false, 0, - /*FIXME:*/false, + /*FIXME: hasExceptionSpec*/false, false, 0, 0, FunctionType::ExtInfo()), /*TInfo=*/0, /*isStatic=*/false, @@ -2659,7 +2786,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, // inline public member of its class. QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, - /*FIXME:*/false, + /*FIXME: hasExceptionSpec*/false, false, 0, 0, FunctionType::ExtInfo()); DeclarationName Name @@ -3817,8 +3944,9 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // A using-declaration is a declaration and can therefore be used // repeatedly where (and only where) multiple declarations are // allowed. - // That's only in file contexts. - if (CurContext->getLookupContext()->isFileContext()) + // + // That's in non-member contexts. + if (!CurContext->getLookupContext()->isRecord()) return false; NestedNameSpecifier *Qual @@ -4082,12 +4210,15 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, Constructor); - if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) { + ErrorTrap Trap(*this); + if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || + Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); } else { Constructor->setUsed(); + MarkVTableUsed(CurrentLocation, ClassDecl); } } @@ -4098,14 +4229,16 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); + if (Destructor->isInvalidDecl()) + return; + ImplicitlyDefinedFunctionScope Scope(*this, Destructor); + ErrorTrap Trap(*this); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); - // FIXME: If CheckDestructor fails, we should emit a note about where the - // implicit destructor was needed. - if (CheckDestructor(Destructor)) { + if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXDestructor << Context.getTagDeclType(ClassDecl); @@ -4114,6 +4247,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } Destructor->setUsed(); + MarkVTableUsed(CurrentLocation, ClassDecl); } /// \brief Builds a statement that copies the given entity from \p From to @@ -4332,6 +4466,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CopyAssignOperator->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); + ErrorTrap Trap(*this); // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator @@ -4407,8 +4542,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, move(To), Owned(From), /*CopyingBaseSubobject=*/true); if (Copy.isInvalid()) { - Invalid = true; - continue; + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); + CopyAssignOperator->setInvalidDecl(); + return; } // Success! Record the copy. @@ -4427,7 +4564,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(Loc, diag::note_first_required_here); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } @@ -4438,12 +4576,18 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(Loc, diag::note_first_required_here); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } QualType FieldType = Field->getType().getNonReferenceType(); + if (FieldType->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } // Build references to the field in the object we're copying from and to. CXXScopeSpec SS; // Intentionally empty @@ -4528,8 +4672,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, move(To), move(From), /*CopyingBaseSubobject=*/false); if (Copy.isInvalid()) { - Invalid = true; - continue; + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); + CopyAssignOperator->setInvalidDecl(); + return; } // Success! Record the copy. @@ -4546,6 +4692,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Invalid = true; else { Statements.push_back(Return.takeAs<Stmt>()); + + if (Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + } } } @@ -4572,37 +4724,22 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); + ErrorTrap Trap(*this); - if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) { + if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) || + Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); CopyConstructor->setInvalidDecl(); - } else { - CopyConstructor->setUsed(); - } - - // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of - // fields, this code below should be removed. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (CXXConstructorDecl *FieldCopyCtor = - FieldClassDecl->getCopyConstructor(Context, TypeQuals)) { - CheckDirectMemberAccess(Field->getLocation(), - FieldCopyCtor, - PDiag(diag::err_access_copy_field) - << Field->getDeclName() << Field->getType()); - - MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor); - } - } + } else { + CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(), + CopyConstructor->getLocation(), + MultiStmtArg(*this, 0, 0), + /*isStmtExpr=*/false) + .takeAs<Stmt>()); } + + CopyConstructor->setUsed(); } Sema::OwningExprResult @@ -4672,7 +4809,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD, void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl()); if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() && - !ClassDecl->hasTrivialDestructor()) { + !ClassDecl->hasTrivialDestructor() && !ClassDecl->isDependentContext()) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Destructor, @@ -5419,7 +5556,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); QualType T = TSInfo->getType(); - SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); + SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange(); if (!getLangOptions().CPlusPlus0x) { // C++03 [class.friend]p2: @@ -5948,90 +6085,125 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } -static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) { - // Ignore dependent types. - if (MD->isDependentContext()) - return false; - - // Ignore declarations that are not definitions. - if (!MD->isThisDeclarationADefinition()) - return false; - - CXXRecordDecl *RD = MD->getParent(); - - // Ignore classes without a vtable. - if (!RD->isDynamicClass()) - return false; - - switch (MD->getParent()->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - // Classes that aren't instantiations of templates don't need their - // virtual methods marked until we see the definition of the key - // function. - break; +void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, + bool DefinitionRequired) { + // Ignore any vtable uses in unevaluated operands or for classes that do + // not have a vtable. + if (!Class->isDynamicClass() || Class->isDependentContext() || + CurContext->isDependentContext() || + ExprEvalContexts.back().Context == Unevaluated) + return; - case TSK_ImplicitInstantiation: - // This is a constructor of a class template; mark all of the virtual - // members as referenced to ensure that they get instantiatied. - if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) - return true; - break; + // Try to insert this class into the map. + Class = cast<CXXRecordDecl>(Class->getCanonicalDecl()); + std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool> + Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); + if (!Pos.second) { + // If we already had an entry, check to see if we are promoting this vtable + // to required a definition. If so, we need to reappend to the VTableUses + // list, since we may have already processed the first entry. + if (DefinitionRequired && !Pos.first->second) { + Pos.first->second = true; + } else { + // Otherwise, we can early exit. + return; + } + } - case TSK_ExplicitInstantiationDeclaration: - return false; + // Local classes need to have their virtual members marked + // immediately. For all other classes, we mark their virtual members + // at the end of the translation unit. + if (Class->isLocalClass()) + MarkVirtualMembersReferenced(Loc, Class); + else + VTableUses.push_back(std::make_pair(Class, Loc)); +} - case TSK_ExplicitInstantiationDefinition: - // This is method of a explicit instantiation; mark all of the virtual - // members as referenced to ensure that they get instantiatied. - return true; +bool Sema::DefineUsedVTables() { + // If any dynamic classes have their key function defined within + // this translation unit, then those vtables are considered "used" and must + // be emitted. + for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { + if (const CXXMethodDecl *KeyFunction + = Context.getKeyFunction(DynamicClasses[I])) { + const FunctionDecl *Definition = 0; + if (KeyFunction->getBody(Definition)) + MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true); + } } - // Consider only out-of-line definitions of member functions. When we see - // an inline definition, it's too early to compute the key function. - if (!MD->isOutOfLine()) + if (VTableUses.empty()) return false; + + // Note: The VTableUses vector could grow as a result of marking + // the members of a class as "used", so we check the size each + // time through the loop and prefer indices (with are stable) to + // iterators (which are not). + for (unsigned I = 0; I != VTableUses.size(); ++I) { + CXXRecordDecl *Class = VTableUses[I].first->getDefinition(); + if (!Class) + continue; - const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); - - // If there is no key function, we will need a copy of the vtable. - if (!KeyFunction) - return true; - - // If this is the key function, we need to mark virtual members. - if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl()) - return true; - - return false; -} - -void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, - CXXMethodDecl *MD) { - CXXRecordDecl *RD = MD->getParent(); + SourceLocation Loc = VTableUses[I].second; + + // If this class has a key function, but that key function is + // defined in another translation unit, we don't need to emit the + // vtable even though we're using it. + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class); + if (KeyFunction && !KeyFunction->getBody()) { + switch (KeyFunction->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDeclaration: + // The key function is in another translation unit. + continue; - // We will need to mark all of the virtual members as referenced to build the - // vtable. - if (!needsVTable(MD, Context)) - return; + case TSK_ExplicitInstantiationDefinition: + case TSK_ImplicitInstantiation: + // We will be instantiating the key function. + break; + } + } else if (!KeyFunction) { + // If we have a class with no key function that is the subject + // of an explicit instantiation declaration, suppress the + // vtable; it will live with the explicit instantiation + // definition. + bool IsExplicitInstantiationDeclaration + = Class->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration; + for (TagDecl::redecl_iterator R = Class->redecls_begin(), + REnd = Class->redecls_end(); + R != REnd; ++R) { + TemplateSpecializationKind TSK + = cast<CXXRecordDecl>(*R)->getTemplateSpecializationKind(); + if (TSK == TSK_ExplicitInstantiationDeclaration) + IsExplicitInstantiationDeclaration = true; + else if (TSK == TSK_ExplicitInstantiationDefinition) { + IsExplicitInstantiationDeclaration = false; + break; + } + } - TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); - if (kind == TSK_ImplicitInstantiation) - ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc)); - else - MarkVirtualMembersReferenced(Loc, RD); -} + if (IsExplicitInstantiationDeclaration) + continue; + } -bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { - if (ClassesWithUnmarkedVirtualMembers.empty()) - return false; - - while (!ClassesWithUnmarkedVirtualMembers.empty()) { - CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first; - SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second; - ClassesWithUnmarkedVirtualMembers.pop_back(); - MarkVirtualMembersReferenced(Loc, RD); + // Mark all of the virtual members of this class as referenced, so + // that we can build a vtable. Then, tell the AST consumer that a + // vtable for this class is required. + MarkVirtualMembersReferenced(Loc, Class); + CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl()); + Consumer.HandleVTable(Class, VTablesUsed[Canonical]); + + // Optionally warn if we're emitting a weak vtable. + if (Class->getLinkage() == ExternalLinkage && + Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { + if (!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined())) + Diag(Class->getLocation(), diag::warn_weak_vtable) << Class; + } } - + VTableUses.clear(); + return true; } @@ -6076,6 +6248,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; for (unsigned i = 0; i < ivars.size(); i++) { FieldDecl *Field = ivars[i]; + if (Field->isInvalidDecl()) + continue; + CXXBaseOrMemberInitializer *Member; InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); InitializationKind InitKind = @@ -6098,6 +6273,20 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { MemberInit.takeAs<Expr>(), SourceLocation()); AllToInit.push_back(Member); + + // Be sure that the destructor is accessible and is marked as referenced. + if (const RecordType *RecordTy + = Context.getBaseElementType(Field->getType()) + ->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (CXXDestructorDecl *Destructor + = const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) { + MarkDeclarationReferenced(Field->getLocation(), Destructor); + CheckDestructorAccess(Field->getLocation(), Destructor, + PDiag(diag::err_access_dtor_ivar) + << Context.getBaseElementType(Field->getType())); + } + } } ObjCImplementation->setIvarInitializers(Context, AllToInit.data(), AllToInit.size()); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index d446cc1..3b05f5a 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -142,8 +142,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // typedef. If we do, get the underlying class type. if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) { QualType T = TDecl->getUnderlyingType(); - if (T->isObjCInterfaceType()) { - if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); } } @@ -210,8 +210,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, LookupOrdinaryName, ForRedeclaration); if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); - if (T->isObjCInterfaceType()) { - if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) { + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { ClassName = IDecl->getIdentifier(); CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName, ForRedeclaration); @@ -763,6 +763,10 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, << (*IM)->getType(); Diag((*IF)->getLocation(), diag::note_previous_definition); } + if (ImpMethodDecl->isVariadic() != IntfMethodDecl->isVariadic()) { + Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic); + Diag(IntfMethodDecl->getLocation(), diag::note_previous_declaration); + } } /// FIXME: Type hierarchies in Objective-C can be deep. We could most likely @@ -925,7 +929,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } } -void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, +void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { llvm::DenseSet<Selector> InsMap; @@ -938,8 +942,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // Check and see if properties declared in the interface have either 1) // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. - if (isa<ObjCInterfaceDecl>(CDecl)) - DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + if (isa<ObjCInterfaceDecl>(CDecl) && !LangOpts.ObjCNonFragileABI2) + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); llvm::DenseSet<Selector> ClsMap; for (ObjCImplementationDecl::classmeth_iterator @@ -968,7 +972,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, for (ObjCCategoryDecl *Categories = I->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { if (Categories->IsClassExtension()) { - ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); + ImplMethodsVsClassMethods(S, IMPDecl, Categories, IncompleteImpl); break; } } @@ -990,7 +994,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) InsMap.insert((*I)->getSelector()); } - DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); } } else assert(false && "invalid ObjCContainerDecl type."); @@ -1024,15 +1028,15 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, // // FIXME: Make an extension? TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl); - if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) { + if (!TDD || !TDD->getUnderlyingType()->isObjCObjectType()) { Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i]; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } else if (TDD) { + } else { // a forward class declaration matching a typedef name of a class refers // to the underlying class. - if (ObjCInterfaceType * OI = - dyn_cast<ObjCInterfaceType>(TDD->getUnderlyingType())) - PrevDecl = OI->getDecl(); + if (const ObjCObjectType *OI = + TDD->getUnderlyingType()->getAs<ObjCObjectType>()) + PrevDecl = OI->getInterface(); } } ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); @@ -1326,7 +1330,7 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, // Note: For class/category implemenations, allMethods/allProperties is // always null. -void Sema::ActOnAtEnd(SourceRange AtEnd, +void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods, unsigned allNum, DeclPtrTy *allProperties, unsigned pNum, @@ -1433,7 +1437,9 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { IC->setAtEndRange(AtEnd); if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { - ImplMethodsVsClassMethods(IC, IDecl); + if (LangOpts.ObjCNonFragileABI2) + DefaultSynthesizeProperties(S, IC, IDecl); + ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); if (LangOpts.ObjCNonFragileABI2) while (IDecl->getSuperClass()) { @@ -1452,7 +1458,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, for (ObjCCategoryDecl *Categories = IDecl->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { - ImplMethodsVsClassMethods(CatImplClass, Categories); + ImplMethodsVsClassMethods(S, CatImplClass, Categories); break; } } @@ -1530,7 +1536,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( // Methods cannot return interface types. All ObjC objects are // passed by reference. - if (resultDeclType->isObjCInterfaceType()) { + if (resultDeclType->isObjCObjectType()) { Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << resultDeclType; return DeclPtrTy(); @@ -1568,7 +1574,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( ArgInfo[i].Name, ArgType, DI, VarDecl::None, VarDecl::None, 0); - if (ArgType->isObjCInterfaceType()) { + if (ArgType->isObjCObjectType()) { Diag(ArgInfo[i].NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << ArgType; @@ -1592,7 +1598,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( else // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). ArgType = adjustParameterType(ArgType); - if (ArgType->isObjCInterfaceType()) { + if (ArgType->isObjCObjectType()) { Diag(Param->getLocation(), diag::err_object_cannot_be_passed_returned_by_value) << 1 << ArgType; @@ -1810,7 +1816,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, E = OI->ivar_end(); I != E; ++I) { ObjCIvarDecl *Iv = (*I); QualType QT = Context.getBaseElementType(Iv->getType()); - if (isa<RecordType>(QT)) + if (QT->isRecordType()) Ivars.push_back(*I); } @@ -1820,7 +1826,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, E = CDecl->ivar_end(); I != E; ++I) { ObjCIvarDecl *Iv = (*I); QualType QT = Context.getBaseElementType(Iv->getType()); - if (isa<RecordType>(QT)) + if (QT->isRecordType()) Ivars.push_back(*I); } } @@ -1832,7 +1838,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, E = ImplDecl->ivar_end(); I != E; ++I) { ObjCIvarDecl *Iv = (*I); QualType QT = Context.getBaseElementType(Iv->getType()); - if (isa<RecordType>(QT)) + if (QT->isRecordType()) Ivars.push_back(*I); } } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 53e9385..7d73fe4 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -389,7 +389,7 @@ bool Sema::CheckExceptionSpecSubset( if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) continue; - if (Paths.isAmbiguous(CanonicalSuperT)) + if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT))) continue; // Do this check from a context without privileges. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 869d6df..f745352 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -22,6 +22,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -160,16 +161,19 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ++sentinel; } Expr *sentinelExpr = Args[sentinel]; - if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) && - !sentinelExpr->isTypeDependent() && - !sentinelExpr->isValueDependent() && - (!sentinelExpr->getType()->isPointerType() || - !sentinelExpr->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)))) { - Diag(Loc, diag::warn_missing_sentinel) << isMethod; - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; - } - return; + if (!sentinelExpr) return; + if (sentinelExpr->isTypeDependent()) return; + if (sentinelExpr->isValueDependent()) return; + if (sentinelExpr->getType()->isPointerType() && + sentinelExpr->IgnoreParenCasts()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) + return; + + // Unfortunately, __null has type 'int'. + if (isa<GNUNullExpr>(sentinelExpr)) return; + + Diag(Loc, diag::warn_missing_sentinel) << isMethod; + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; } SourceRange Sema::getExprRange(ExprTy *E) const { @@ -275,10 +279,9 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); // If this is a 'float' (CVR qualified or typedef) promote to double. - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) - if (BT->getKind() == BuiltinType::Float) - return ImpCastExprToType(Expr, Context.DoubleTy, - CastExpr::CK_FloatingCast); + if (Ty->isSpecificBuiltinType(BuiltinType::Float)) + return ImpCastExprToType(Expr, Context.DoubleTy, + CastExpr::CK_FloatingCast); UsualUnaryConversions(Expr); } @@ -287,10 +290,17 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { /// will warn if the resulting type is not a POD type, and rejects ObjC /// interfaces passed by value. This returns true if the argument type is /// completely illegal. -bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { +bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, + FunctionDecl *FDecl) { DefaultArgumentPromotion(Expr); - if (Expr->getType()->isObjCInterfaceType() && + // __builtin_va_start takes the second argument as a "varargs" argument, but + // it doesn't actually do anything with it. It doesn't need to be non-pod + // etc. + if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start) + return false; + + if (Expr->getType()->isObjCObjectType() && DiagRuntimeBehavior(Expr->getLocStart(), PDiag(diag::err_cannot_pass_objc_interface_to_vararg) << Expr->getType() << CT)) @@ -486,35 +496,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, D, Loc, Ty)); } -/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or -/// variable corresponding to the anonymous union or struct whose type -/// is Record. -static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context, - RecordDecl *Record) { - assert(Record->isAnonymousStructOrUnion() && - "Record must be an anonymous struct or union!"); - - // FIXME: Once Decls are directly linked together, this will be an O(1) - // operation rather than a slow walk through DeclContext's vector (which - // itself will be eliminated). DeclGroups might make this even better. - DeclContext *Ctx = Record->getDeclContext(); - for (DeclContext::decl_iterator D = Ctx->decls_begin(), - DEnd = Ctx->decls_end(); - D != DEnd; ++D) { - if (*D == Record) { - // The object for the anonymous struct/union directly - // follows its type in the list of declarations. - ++D; - assert(D != DEnd && "Missing object for anonymous record"); - assert(!cast<NamedDecl>(*D)->getDeclName() && "Decl should be unnamed"); - return *D; - } - } - - assert(false && "Missing object for anonymous record"); - return 0; -} - /// \brief Given a field that represents a member of an anonymous /// struct/union, build the path from that field's context to the /// actual member. @@ -539,7 +520,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field, DeclContext *Ctx = Field->getDeclContext(); do { RecordDecl *Record = cast<RecordDecl>(Ctx); - Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record); + ValueDecl *AnonObject = Record->getAnonymousStructOrUnionObject(); if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject)) Path.push_back(AnonField); else { @@ -592,7 +573,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, // 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". - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + DeclContext *DC = getFunctionLevelDeclContext(); + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { if (!MD->isStatic()) { QualType AnonFieldType = Context.getTagDeclType( @@ -828,9 +810,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); + DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); bool isStaticContext = - (!isa<CXXMethodDecl>(SemaRef.CurContext) || - cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic()); + (!isa<CXXMethodDecl>(DC) || + cast<CXXMethodDecl>(DC)->isStatic()); if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -870,7 +853,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // 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, - cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(), + cast<CXXMethodDecl>(DC)->getParent(), Classes)) return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); @@ -907,7 +890,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef, /// /// \return false if new lookup candidates were found bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, - LookupResult &R) { + LookupResult &R, CorrectTypoContext CTC) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -958,7 +941,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, // We didn't find anything, so try to correct for a typo. DeclarationName Corrected; - if (S && (Corrected = CorrectTypo(R, S, &SS))) { + if (S && (Corrected = CorrectTypo(R, S, &SS, false, CTC))) { if (!R.empty()) { if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { if (SS.isEmpty()) @@ -1067,17 +1050,14 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Perform the required lookup. LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); if (TemplateArgs) { - // Just re-use the lookup done by isTemplateName. - DecomposeTemplateName(R, Id); - - // Re-derive the naming class. - if (SS.isSet()) { - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - if (const Type *Ty = Qualifier->getAsType()) - if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) - R.setNamingClass(NamingClass); - } + // Lookup the template name again to correctly establish the context in + // which it was found. This is really unfortunate as we already did the + // lookup to determine that it was a template name in the first place. If + // this becomes a performance hit, we can work harder to preserve those + // results until we get here but it's likely not worth it. + bool MemberOfUnknownSpecialization; + LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, + MemberOfUnknownSpecialization); } else { bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); @@ -1112,7 +1092,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { - if (DiagnoseEmptyLookup(S, SS, R)) + if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown)) return ExprError(); assert(!R.empty() && @@ -1166,7 +1146,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, QualType T = Func->getType(); QualType NoProtoType = T; if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>()) - NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType()); + NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType(), + Proto->getExtInfo()); return BuildDeclRefExpr(Func, NoProtoType, NameLoc, &SS); } } @@ -1423,6 +1404,9 @@ Sema::PerformObjectMemberConversion(Expr *&From, SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); + bool isLvalue + = (From->isLvalue(Context) == Expr::LV_Valid) && !PointerConversions; + // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. @@ -1460,7 +1444,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (PointerConversions) QType = Context.getPointerType(QType); ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); FromType = QType; FromRecordType = QRecordType; @@ -1497,7 +1481,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (PointerConversions) UType = Context.getPointerType(UType); ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); FromType = UType; FromRecordType = URecordType; } @@ -1514,7 +1498,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, return true; ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); return false; } @@ -1558,7 +1542,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // If this is known to be an instance access, go ahead and build a // 'this' expression now. - QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + DeclContext *DC = getFunctionLevelDeclContext(); + QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); Expr *This = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); @@ -1682,8 +1667,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, (NestedNameSpecifier*) SS.getScopeRep(), SS.getRange(), R.getLookupName(), R.getNameLoc(), - NeedsADL, R.isOverloadedResult()); - ULE->addDecls(R.begin(), R.end()); + NeedsADL, R.isOverloadedResult(), + R.begin(), R.end()); return Owned(ULE); } @@ -2036,12 +2021,18 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, return true; // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. - if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) { + if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) { Diag(OpLoc, diag::err_sizeof_nonfragile_interface) << exprType << isSizeof << ExprRange; return true; } + if (Context.hasSameUnqualifiedType(exprType, Context.OverloadTy)) { + Diag(OpLoc, diag::err_sizeof_alignof_overloaded_function_type) + << !isSizeof << ExprRange; + return true; + } + return false; } @@ -2312,7 +2303,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, return ExprError(); // Diagnose bad cases where we step over interface counts. - if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(LLoc, diag::err_subscript_nonfragile_interface) << ResultType << BaseExpr->getSourceRange(); return ExprError(); @@ -2665,6 +2656,9 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, if (Result.get()) return move(Result); + + // LookupMemberExpr can modify Base, and thus change BaseType + BaseType = Base->getType(); } return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, @@ -2741,8 +2735,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, IsArrow, OpLoc, Qualifier, SS.getRange(), MemberName, MemberLoc, - TemplateArgs); - MemExpr->addDecls(R.begin(), R.end()); + TemplateArgs, R.begin(), R.end()); return Owned(MemExpr); } @@ -2917,7 +2910,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle the following exceptional case PObj->isa. if (const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>()) { - if (OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && + if (OPT->getObjectType()->isObjCId() && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc, Context.getObjCClassType())); @@ -3041,8 +3034,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, } } - // Handle field access to simple records. This also handles access - // to fields of the ObjC 'id' struct. + // Handle field access to simple records. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), RTy, OpLoc, SS)) @@ -3053,14 +3045,14 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. if ((IsArrow && BaseType->isObjCObjectPointerType()) || - (!IsArrow && BaseType->isObjCInterfaceType())) { + (!IsArrow && BaseType->isObjCObjectType())) { const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>(); - const ObjCInterfaceType *IFaceT = - OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>(); - if (IFaceT) { + ObjCInterfaceDecl *IDecl = + OPT ? OPT->getInterfaceDecl() + : BaseType->getAs<ObjCObjectType>()->getInterface(); + if (IDecl) { IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - ObjCInterfaceDecl *IDecl = IFaceT->getDecl(); ObjCInterfaceDecl *ClassDeclared; ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); @@ -3173,7 +3165,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle the following exceptional case (*Obj).isa. if (!IsArrow && - BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) && + BaseType->isObjCObjectType() && + BaseType->getAs<ObjCObjectType>()->isObjCId() && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, Context.getObjCClassType())); @@ -3471,9 +3464,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // If this is a variadic call, handle args passed through "...". if (CallType != VariadicDoesNotApply) { // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = ArgIx; i < NumArgs; i++) { + for (unsigned i = ArgIx; i != NumArgs; ++i) { Expr *Arg = Args[i]; - Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType); + Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType, FDecl); AllArgs.push_back(Arg); } } @@ -4081,8 +4074,6 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (getLangOptions().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); - CheckSignCompare(LHS, RHS, QuestionLoc); - UsualUnaryConversions(Cond); UsualUnaryConversions(LHS); UsualUnaryConversions(RHS); @@ -4659,7 +4650,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return Incompatible; } - if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) + if (lhsType->isArithmeticType() && rhsType->isArithmeticType() && + !(getLangOptions().CPlusPlus && lhsType->isEnumeralType())) return Compatible; if (isa<PointerType>(lhsType)) { @@ -4917,7 +4909,13 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { if (const VectorType *RV = rhsType->getAs<VectorType>()) if (LV->getElementType() == RV->getElementType() && LV->getNumElements() == RV->getNumElements()) { - return lhsType->isExtVectorType() ? lhsType : rhsType; + if (lhsType->isExtVectorType()) { + ImpCastExprToType(rex, lhsType, CastExpr::CK_BitCast); + return lhsType; + } + + ImpCastExprToType(lex, rhsType, CastExpr::CK_BitCast); + return rhsType; } } } @@ -5059,7 +5057,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 return QualType(); } // Diagnose bad cases where we step over interface counts. - if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) << PointeeTy << PExp->getSourceRange(); return QualType(); @@ -5135,7 +5133,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, return QualType(); // Diagnose bad cases where we step over interface counts. - if (lpointee->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) << lpointee << lex->getSourceRange(); return QualType(); @@ -5274,8 +5272,6 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); - CheckSignCompare(lex, rex, Loc, &Opc); - // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) UsualArithmeticConversions(lex, rex); @@ -5904,7 +5900,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, << ResType)) return QualType(); // Diagnose bad cases where we step over interface counts. - else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + else if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) << PointeeTy << Op->getSourceRange(); return QualType(); @@ -6626,7 +6622,7 @@ Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, SourceLocation RParenLoc) { QualType ArgTy = TInfo->getType(); bool Dependent = ArgTy->isDependentType(); - SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange(); + SourceRange TypeRange = TInfo->getTypeLoc().getLocalSourceRange(); // We must have at least one component that refers to the type, and the first // one is known to be a field designator. Verify that the ArgTy represents @@ -7018,7 +7014,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType(); // Do not allow returning a objc interface by-value. - if (RetTy->isObjCInterfaceType()) { + if (RetTy->isObjCObjectType()) { Diag(ParamInfo.getSourceRange().getBegin(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; return; @@ -7090,7 +7086,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { QualType RetTy = T->getAs<FunctionType>()->getResultType(); // Do not allow returning a objc interface by-value. - if (RetTy->isObjCInterfaceType()) { + if (RetTy->isObjCObjectType()) { Diag(ParamInfo.getSourceRange().getBegin(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; } else if (!RetTy->isDependentType()) @@ -7500,22 +7496,24 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } - MaybeMarkVirtualMembersReferenced(Loc, Constructor); + MarkVTableUsed(Loc, Constructor->getParent()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { if (Destructor->isImplicit() && !Destructor->isUsed()) DefineImplicitDestructor(Loc, Destructor); - + if (Destructor->isVirtual()) + MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { if (!MethodDecl->isUsed()) DefineImplicitCopyAssignment(Loc, MethodDecl); - } + } else if (MethodDecl->isVirtual()) + MarkVTableUsed(Loc, MethodDecl->getParent()); } if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // Implicit instantiation of function templates and member functions of // class templates. - if (!Function->getBody() && Function->isImplicitlyInstantiable()) { + if (Function->isImplicitlyInstantiable()) { bool AlreadyInstantiated = false; if (FunctionTemplateSpecializationInfo *SpecInfo = Function->getTemplateSpecializationInfo()) { @@ -7570,6 +7568,48 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } } +namespace { + // Mark all of the declarations referenced + // FIXME: Not fully implemented yet! We need to have a better understanding + // of when we're entering + class MarkReferencedDecls : public RecursiveASTVisitor<MarkReferencedDecls> { + Sema &S; + SourceLocation Loc; + + public: + typedef RecursiveASTVisitor<MarkReferencedDecls> Inherited; + + MarkReferencedDecls(Sema &S, SourceLocation Loc) : S(S), Loc(Loc) { } + + bool VisitTemplateArgument(const TemplateArgument &Arg); + bool VisitRecordType(RecordType *T); + }; +} + +bool MarkReferencedDecls::VisitTemplateArgument(const TemplateArgument &Arg) { + if (Arg.getKind() == TemplateArgument::Declaration) { + S.MarkDeclarationReferenced(Loc, Arg.getAsDecl()); + } + + return Inherited::VisitTemplateArgument(Arg); +} + +bool MarkReferencedDecls::VisitRecordType(RecordType *T) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) { + const TemplateArgumentList &Args = Spec->getTemplateArgs(); + return VisitTemplateArguments(Args.getFlatArgumentList(), + Args.flat_size()); + } + + return false; +} + +void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { + MarkReferencedDecls Marker(*this, Loc); + Marker.Visit(Context.getCanonicalType(T)); +} + /// \brief Emit a diagnostic that describes an effect on the run-time behavior /// of the program being compiled. /// @@ -7698,3 +7738,17 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { return false; } + +Sema::OwningExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, + ExprArg SubExpr) { + Expr *Sub = SubExpr.takeAs<Expr>(); + if (!Sub) + return ExprError(); + + if (CheckBooleanCondition(Sub, Loc)) { + Sub->Destroy(Context); + return ExprError(); + } + + return Owned(Sub); +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 425fc2d..97de96a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -261,7 +261,8 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, Range = SourceRange(NameLoc); } - return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr(); + return CheckTypenameType(ETK_None, NNS, II, SourceLocation(), + Range, NameLoc).getAsOpaquePtr(); } if (ObjectTypePtr) @@ -314,8 +315,12 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, // When typeid is applied to an expression other than an lvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] - if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) + if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) { isUnevaluatedOperand = false; + + // We require a vtable to query the type at run time. + MarkVTableUsed(TypeidLoc, RecordD); + } } // C++ [expr.typeid]p4: @@ -437,14 +442,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. + // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34. InitializedEntity Entity = - InitializedEntity::InitializeException(ThrowLoc, E->getType()); + InitializedEntity::InitializeException(ThrowLoc, E->getType(), + /*NRVO=*/false); OwningExprResult Res = PerformCopyInitialization(Entity, SourceLocation(), Owned(E)); if (Res.isInvalid()) return true; E = Res.takeAs<Expr>(); + + // If we are throwing a polymorphic class type or pointer thereof, + // exception handling will make use of the vtable. + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) + MarkVTableUsed(ThrowLoc, cast<CXXRecordDecl>(RecordTy->getDecl())); + return false; } @@ -453,10 +466,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - if (!isa<FunctionDecl>(CurContext)) - return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); - - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) + DeclContext *DC = getFunctionLevelDeclContext(); + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) if (MD->isInstance()) return Owned(new (Context) CXXThisExpr(ThisLoc, MD->getThisType(Context), @@ -668,10 +679,19 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (CheckAllocatedType(AllocType, TypeLoc, TypeRange)) return ExprError(); - QualType ResultType = Context.getPointerType(AllocType); + // Per C++0x [expr.new]p5, the type being constructed may be a + // typedef of an array type. + if (!ArraySizeE.get()) { + if (const ConstantArrayType *Array + = Context.getAsConstantArrayType(AllocType)) { + ArraySizeE = Owned(new (Context) IntegerLiteral(Array->getSize(), + Context.getSizeType(), + TypeRange.getEnd())); + AllocType = Array->getElementType(); + } + } - // That every array dimension except the first is constant was already - // checked by the type check above. + 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." @@ -739,7 +759,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); // Array 'new' can't have any initializers. - if (NumConsArgs && ArraySize) { + if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) { SourceRange InitRange(ConsArgs[0]->getLocStart(), ConsArgs[NumConsArgs - 1]->getLocEnd()); @@ -1173,7 +1193,7 @@ void Sema::DeclareGlobalNewDelete() { if (!StdBadAlloc) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. - StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class, + StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, StdNamespace, SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), @@ -1378,7 +1398,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, << Type << Ex->getSourceRange()); QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); - if (Pointee->isFunctionType() || Pointee->isVoidType()) + if (Pointee->isVoidType() && !isSFINAEContext()) { + // The C++ standard bans deleting a pointer to a non-object type, which + // effectively bans deletion of "void*". However, most compilers support + // this, so we treat it as a warning unless we're in a SFINAE context. + Diag(StartLoc, diag::ext_delete_void_ptr_operand) + << Type << Ex->getSourceRange(); + } else if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && @@ -1437,7 +1463,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, /// \brief Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. -Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) { +Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, + SourceLocation StmtLoc, + bool ConvertToBoolean) { QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: @@ -1451,9 +1479,15 @@ Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) { diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); - return Owned(DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, - ConditionVar->getLocation(), - ConditionVar->getType().getNonReferenceType())); + Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, + ConditionVar->getLocation(), + ConditionVar->getType().getNonReferenceType()); + if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) { + Condition->Destroy(Context); + return ExprError(); + } + + return Owned(Condition); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. @@ -1748,10 +1782,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ImpCastExprToType(From, ToType, CastExpr::CK_FloatingToIntegral); break; - case ICK_Complex_Real: - ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); - break; - case ICK_Compatible_Conversion: ImpCastExprToType(From, ToType, CastExpr::CK_NoOp); break; @@ -1794,18 +1824,41 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; } - case ICK_Derived_To_Base: + case ICK_Derived_To_Base: { + CXXBaseSpecifierArray BasePath; if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange(), 0, + From->getSourceRange(), + &BasePath, IgnoreBaseAccess)) return true; + ImpCastExprToType(From, ToType.getNonReferenceType(), - CastExpr::CK_DerivedToBase); + CastExpr::CK_DerivedToBase, + /*isLvalue=*/(From->getType()->isRecordType() && + From->isLvalue(Context) == Expr::LV_Valid), + BasePath); + break; + } + + case ICK_Vector_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_BitCast); + break; + + case ICK_Vector_Splat: + ImpCastExprToType(From, ToType, CastExpr::CK_VectorSplat); break; - default: + case ICK_Complex_Real: + ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + break; + + case ICK_Lvalue_To_Rvalue: + case ICK_Array_To_Pointer: + case ICK_Function_To_Pointer: + case ICK_Qualification: + case ICK_Num_Conversion_Kinds: assert(false && "Improper second standard conversion"); break; } @@ -1828,7 +1881,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; default: - assert(false && "Improper second standard conversion"); + assert(false && "Improper third standard conversion"); break; } @@ -2113,8 +2166,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; - CheckSignCompare(LHS, RHS, QuestionLoc); - // C++0x 5.16p2 // If either the second or the third operand has type (cv) void, ... QualType LTy = LHS->getType(); @@ -2218,9 +2269,36 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // After those conversions, one of the following shall hold: // -- The second and third operands have the same type; the result - // is of that type. - if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) + // is of that type. If the operands have class type, the result + // is a prvalue temporary of the result type, which is + // copy-initialized from either the second operand or the third + // operand depending on the value of the first operand. + if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { + if (LTy->isRecordType()) { + // The operands have class type. Make a temporary copy. + InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); + OwningExprResult LHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(LHS)); + if (LHSCopy.isInvalid()) + return QualType(); + + OwningExprResult RHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(RHS)); + if (RHSCopy.isInvalid()) + return QualType(); + + LHS = LHSCopy.takeAs<Expr>(); + RHS = RHSCopy.takeAs<Expr>(); + } + return LTy; + } + + // Extension: conditional operator involving vector types. + if (LTy->isVectorType() || RTy->isVectorType()) + return CheckVectorOperands(QuestionLoc, LHS, RHS); // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a @@ -2529,6 +2607,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) { assert(SubExpr && "sub expression can't be null!"); + // Check any implicit conversions within the expression. + CheckImplicitConversions(SubExpr); + unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; assert(ExprTemporaries.size() >= FirstTemporary); if (ExprTemporaries.size() == FirstTemporary) @@ -2713,12 +2794,12 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); SourceLocation DestructedTypeStart - = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(); + = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << BaseE->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getSourceRange(); + << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); // Recover by setting the destructed type to the object type. DestructedType = ObjectType; @@ -2740,10 +2821,10 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameType(ScopeType, ObjectType)) { - Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(), + Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << BaseE->getSourceRange() - << ScopeTypeInfo->getTypeLoc().getSourceRange(); + << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); ScopeType = QualType(); ScopeTypeInfo = 0; @@ -2943,6 +3024,8 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr); - + else + return ExprError(); + return Owned(FullExpr); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index db9a2e2..695a1be 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -254,7 +254,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, if (Args[i]->isTypeDependent()) continue; - IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod); + IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0); } } else { // Check for extra arguments to non-variadic methods. @@ -718,14 +718,12 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, } SourceLocation Loc = SuperLoc.isValid()? SuperLoc - : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin(); + : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); // Find the class to which we are sending this message. ObjCInterfaceDecl *Class = 0; - if (const ObjCInterfaceType *ClassType - = ReceiverType->getAs<ObjCInterfaceType>()) - Class = ClassType->getDecl(); - else { + const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>(); + if (!ClassType || !(Class = ClassType->getInterface())) { Diag(Loc, diag::err_invalid_receiver_class_message) << ReceiverType; return ExprError(); @@ -766,15 +764,17 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, } // Construct the appropriate ObjCMessageExpr. + Expr *Result; if (SuperLoc.isValid()) - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, Method, Args, - NumArgs, RBracLoc)); - - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - ReceiverTypeInfo, Sel, Method, Args, - NumArgs, RBracLoc)); + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/false, + ReceiverType, Sel, Method, Args, + NumArgs, RBracLoc); + else + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + ReceiverTypeInfo, Sel, Method, Args, + NumArgs, RBracLoc); + return MaybeBindToTemporary(Result); } // ActOnClassMessage - used for both unary and keyword messages. @@ -976,6 +976,21 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, ImpCastExprToType(Receiver, Context.getObjCIdType(), CastExpr::CK_IntegralToPointer); ReceiverType = Receiver->getType(); + } + else if (getLangOptions().CPlusPlus && + !PerformContextuallyConvertToObjCId(Receiver)) { + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { + Receiver = ICE->getSubExpr(); + ReceiverType = Receiver->getType(); + } + return BuildInstanceMessage(Owned(Receiver), + ReceiverType, + SuperLoc, + Sel, + Method, + LBracLoc, + RBracLoc, + move(ArgsIn)); } else { // Reject other random receiver types (e.g. structs). Diag(Loc, diag::err_bad_receiver_type) @@ -994,14 +1009,16 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, return ExprError(); // Construct the appropriate ObjCMessageExpr instance. + Expr *Result; if (SuperLoc.isValid()) - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, Method, - Args, NumArgs, RBracLoc)); - - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, - Sel, Method, Args, NumArgs, RBracLoc)); + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/true, + ReceiverType, Sel, Method, + Args, NumArgs, RBracLoc); + else + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, + Sel, Method, Args, NumArgs, RBracLoc); + return MaybeBindToTemporary(Result); } // ActOnInstanceMessage - used for both unary and keyword messages. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 0aa3446..20f0c79 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -624,7 +624,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, } else if (DeclType->isReferenceType()) { CheckReferenceType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); - } else if (DeclType->isObjCInterfaceType()) { + } else if (DeclType->isObjCObjectType()) { SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) << DeclType; hadError = true; @@ -1984,6 +1984,26 @@ DeclaratorDecl *InitializedEntity::getDecl() const { return 0; } +bool InitializedEntity::allowsNRVO() const { + switch (getKind()) { + case EK_Result: + case EK_Exception: + return LocAndNRVO.NRVO; + + case EK_Variable: + case EK_Parameter: + case EK_Member: + case EK_New: + case EK_Temporary: + case EK_Base: + case EK_ArrayElement: + case EK_VectorElement: + break; + } + + return false; +} + //===----------------------------------------------------------------------===// // Initialization sequence //===----------------------------------------------------------------------===// @@ -2034,6 +2054,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_ReferenceBindingToInitList: case FK_InitListBadDestinationType: case FK_DefaultInitOfConst: + case FK_Incomplete: return false; case FK_ReferenceInitOverloadFailed: @@ -2245,11 +2266,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; const RecordType *T1RecordType = 0; - if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) { + if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) && + !S.RequireCompleteType(Kind.getLocation(), T1, 0)) { // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl()); - DeclarationName ConstructorName = S.Context.DeclarationNames.getCXXConstructorName( S.Context.getCanonicalType(T1).getUnqualifiedType()); @@ -2281,7 +2302,9 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, } } - if (const RecordType *T2RecordType = T2->getAs<RecordType>()) { + const RecordType *T2RecordType = 0; + if ((T2RecordType = T2->getAs<RecordType>()) && + !S.RequireCompleteType(Kind.getLocation(), T2, 0)) { // The type we're converting from is a class type, enumerate its conversion // functions. CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl()); @@ -2627,7 +2650,7 @@ static void TryConstructorInitialization(Sema &S, // The type we're constructing needs to be complete. if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { - Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + Sequence.SetFailed(InitializationSequence::FK_Incomplete); return; } @@ -2740,8 +2763,8 @@ static void TryValueInitialization(Sema &S, // without a user-provided constructor, then the object is // zero-initialized and, if T’s implicitly-declared default // constructor is non-trivial, that constructor is called. - if ((ClassDecl->getTagKind() == TagDecl::TK_class || - ClassDecl->getTagKind() == TagDecl::TK_struct) && + if ((ClassDecl->getTagKind() == TTK_Class || + ClassDecl->getTagKind() == TTK_Struct) && !ClassDecl->hasTrivialConstructor()) { Sequence.AddZeroInitializationStep(Entity.getType()); return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); @@ -3240,9 +3263,9 @@ static Sema::OwningExprResult CopyObject(Sema &S, // directly into the target of the omitted copy/move // // Note that the other three bullets are handled elsewhere. Copy - // elision for return statements and throw expressions are (FIXME: - // not yet) handled as part of constructor initialization, while - // copy elision for exception handlers is handled by the run-time. + // elision for return statements and throw expressions are handled as part + // of constructor initialization, while copy elision for exception handlers + // is handled by the run-time. bool Elidable = CurInitExpr->isTemporaryObject() && S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType()); SourceLocation Loc; @@ -3517,6 +3540,7 @@ InitializationSequence::Perform(Sema &S, // Overload resolution determined which function invoke; update the // initializer to reflect that choice. S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); + S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function.FoundDecl, Step->Function.Function); @@ -3537,6 +3561,15 @@ InitializationSequence::Perform(Sema &S, &BasePath, IgnoreBaseAccess)) return S.ExprError(); + if (S.BasePathInvolvesVirtualBase(BasePath)) { + QualType T = SourceType; + if (const PointerType *Pointer = T->getAs<PointerType>()) + T = Pointer->getPointeeType(); + if (const RecordType *RecordTy = T->getAs<RecordType>()) + S.MarkVTableUsed(CurInitExpr->getLocStart(), + cast<CXXRecordDecl>(RecordTy->getDecl())); + } + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, CastExpr::CK_DerivedToBase, (Expr*)CurInit.release(), @@ -3619,6 +3652,7 @@ InitializationSequence::Perform(Sema &S, S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); + S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); CastKind = CastExpr::CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); @@ -3633,6 +3667,7 @@ InitializationSequence::Perform(Sema &S, IsLvalue = Conversion->getResultType()->isLValueReferenceType(); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, FoundFn); + S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because @@ -3723,7 +3758,7 @@ InitializationSequence::Perform(Sema &S, unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); - + // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); SourceLocation Loc = Kind.getLocation(); @@ -3760,11 +3795,21 @@ InitializationSequence::Perform(Sema &S, CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; } - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, - move_arg(ConstructorArgs), - ConstructorInitRequiresZeroInit, - ConstructKind); + + // If the entity allows NRVO, mark the construction as elidable + // unconditionally. + if (Entity.allowsNRVO()) + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, /*Elidable=*/true, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit, + ConstructKind); + else + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit, + ConstructKind); } if (CurInit.isInvalid()) return S.ExprError(); @@ -3772,6 +3817,7 @@ InitializationSequence::Perform(Sema &S, // Only check access if all of that succeeded. S.CheckConstructorAccess(Loc, Constructor, Entity, Step->Function.FoundDecl.getAccess()); + S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc); if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); @@ -4092,6 +4138,11 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << (bool)DestType->getAs<RecordType>(); } break; + + case FK_Incomplete: + S.RequireCompleteType(Kind.getLocation(), DestType, + diag::err_init_incomplete_type); + break; } PrintInitLocationNote(S, Entity); @@ -4170,6 +4221,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case FK_DefaultInitOfConst: OS << "default initialization of a const variable"; break; + + case FK_Incomplete: + OS << "initialization of incomplete type"; + break; } OS << '\n'; return; diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 5f2592f..a9064ed 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -85,11 +85,16 @@ private: /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. DeclaratorDecl *VariableOrMember; - /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the - /// location of the 'return', 'throw', or 'new' keyword, - /// respectively. When Kind == EK_Temporary, the location where - /// the temporary is being created. - unsigned Location; + struct { + /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. + unsigned Location; + + /// \brief Whether the + bool NRVO; + } LocAndNRVO; /// \brief When Kind == EK_Base, the base specifier that provides the /// base class. The lower bit specifies whether the base is an inherited @@ -116,8 +121,13 @@ private: /// \brief Create the initialization entity for the result of a /// function, throwing an object, performing an explicit cast, or /// initializing a parameter for which there is no declaration. - InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type) - : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { } + InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, + bool NRVO = false) + : Kind(Kind), Parent(0), Type(Type) + { + LocAndNRVO.Location = Loc.getRawEncoding(); + LocAndNRVO.NRVO = NRVO; + } /// \brief Create the initialization entity for a member subobject. InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) @@ -152,14 +162,14 @@ public: /// \brief Create the initialization entity for the result of a function. static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - QualType Type) { - return InitializedEntity(EK_Result, ReturnLoc, Type); + QualType Type, bool NRVO) { + return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); } /// \brief Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, - QualType Type) { - return InitializedEntity(EK_Exception, ThrowLoc, Type); + QualType Type, bool NRVO) { + return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); } /// \brief Create the initialization entity for an object allocated via new. @@ -208,6 +218,10 @@ public: /// initialized. DeclaratorDecl *getDecl() const; + /// \brief Determine whether this initialization allows the named return + /// value optimization, which also applies to thrown objects. + bool allowsNRVO() const; + /// \brief Retrieve the base specifier. CXXBaseSpecifier *getBaseSpecifier() const { assert(getKind() == EK_Base && "Not a base specifier"); @@ -224,14 +238,14 @@ public: /// the result of a function call. SourceLocation getReturnLoc() const { assert(getKind() == EK_Result && "No 'return' location!"); - return SourceLocation::getFromRawEncoding(Location); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief Determine the location of the 'throw' keyword when initializing /// an exception object. SourceLocation getThrowLoc() const { assert(getKind() == EK_Exception && "No 'throw' location!"); - return SourceLocation::getFromRawEncoding(Location); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief If this is already the initializer for an array or vector @@ -530,7 +544,9 @@ public: /// \brief Overloaded for initialization by constructor failed. FK_ConstructorOverloadFailed, /// \brief Default-initialization of a 'const' object. - FK_DefaultInitOfConst + FK_DefaultInitOfConst, + /// \brief Initialization of an incomplete type. + FK_Incomplete }; private: diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 337a4a3..4555a86 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -665,6 +665,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // DeclContext *OutsideOfTemplateParamDC = 0; for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { + DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); + // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { @@ -675,10 +677,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { } if (Found) { R.resolveKind(); + if (S->isClassScope()) + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx)) + R.setNamingClass(Record); return true; } - DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && S->getParent() && !S->getParent()->isTemplateParamScope()) { // We've just searched the last template parameter scope and @@ -761,10 +765,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // context as well as walking through the scopes. for (; S; S = S->getParent()) { - DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); - if (Ctx && Ctx->isTransparentContext()) - continue; - // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { @@ -778,21 +778,57 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { } } - // If we have a context, and it's not a context stashed in the - // template parameter scope for an out-of-line definition, also - // look into that context. - if (Ctx && !(Found && S && S->isTemplateParamScope())) { - assert(Ctx->isFileContext() && - "We should have been looking only at file context here already."); + if (Found && S->isTemplateParamScope()) { + R.resolveKind(); + return true; + } - // Look into context considering using-directives. - if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) - Found = true; + DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); + if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && + S->getParent() && !S->getParent()->isTemplateParamScope()) { + // We've just searched the last template parameter scope and + // found nothing, so look into the the contexts between the + // lexical and semantic declaration contexts returned by + // findOuterContext(). This implements the name lookup behavior + // of C++ [temp.local]p8. + Ctx = OutsideOfTemplateParamDC; + OutsideOfTemplateParamDC = 0; } + + if (Ctx) { + DeclContext *OuterCtx; + bool SearchAfterTemplateScope; + llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); + if (SearchAfterTemplateScope) + OutsideOfTemplateParamDC = OuterCtx; - if (Found) { - R.resolveKind(); - return true; + for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { + // We do not directly look into transparent contexts, since + // those entities will be found in the nearest enclosing + // non-transparent context. + if (Ctx->isTransparentContext()) + continue; + + // If we have a context, and it's not a context stashed in the + // template parameter scope for an out-of-line definition, also + // look into that context. + if (!(Found && S && S->isTemplateParamScope())) { + assert(Ctx->isFileContext() && + "We should have been looking only at file context here already."); + + // Look into context considering using-directives. + if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) + Found = true; + } + + if (Found) { + R.resolveKind(); + return true; + } + + if (R.isForRedeclaration() && !Ctx->isTransparentContext()) + return false; + } } if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext()) @@ -2580,6 +2616,12 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, WantExpressionKeywords = true; WantCXXNamedCasts = true; WantRemainingKeywords = true; + + if (ObjCMethodDecl *Method = getCurMethodDecl()) + if (Method->getClassInterface() && + Method->getClassInterface()->getSuperClass()) + Consumer.addKeywordResult(Context, "super"); + break; case CTC_NoKeywords: @@ -2646,7 +2688,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, Consumer.addKeywordResult(Context, "typeof"); } - if (WantCXXNamedCasts) { + if (WantCXXNamedCasts && getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "const_cast"); Consumer.addKeywordResult(Context, "dynamic_cast"); Consumer.addKeywordResult(Context, "reinterpret_cast"); @@ -2776,6 +2818,25 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, BestIvarOrPropertyDecl = 0; FoundIvarOrPropertyDecl = false; Consumer.clear_decls(); + } else if (CTC == CTC_ObjCMessageReceiver && + (*Consumer.keyword_begin())->isStr("super")) { + // In an Objective-C message send, give the "super" keyword a slight + // edge over entities not in function or method scope. + for (TypoCorrectionConsumer::iterator I = Consumer.begin(), + IEnd = Consumer.end(); + I != IEnd; ++I) { + if ((*I)->getDeclName() == BestName) { + if ((*I)->getDeclContext()->isFunctionOrMethod()) + return DeclarationName(); + } + } + + // Everything found was outside a function or method; the 'super' + // keyword takes precedence. + BestIvarOrPropertyDecl = 0; + FoundIvarOrPropertyDecl = false; + Consumer.clear_decls(); + BestName = *Consumer.keyword_begin(); } else { // Name collision; we will not correct typos. return DeclarationName(); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index b73739f..4c89a11 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" +#include "clang/AST/ExprObjC.h" using namespace clang; @@ -119,7 +121,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CCPrimary, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, - Attributes, T, MethodImplKind); + Attributes, T, MethodImplKind, DC); // 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. @@ -189,7 +191,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, const bool isReadWrite, const unsigned Attributes, QualType T, - tok::ObjCKeywordKind MethodImplKind){ + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC){ IdentifierInfo *PropertyId = FD.D.getIdentifier(); @@ -197,19 +200,16 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // gc'able conforms to NSCopying protocol if (getLangOptions().getGCMode() != LangOptions::NonGC && isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) - if (T->isObjCObjectPointerType()) { - QualType InterfaceTy = T->getPointeeType(); - if (const ObjCInterfaceType *OIT = - InterfaceTy->getAs<ObjCInterfaceType>()) { - ObjCInterfaceDecl *IDecl = OIT->getDecl(); - if (IDecl) - if (ObjCProtocolDecl* PNSCopying = - LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc)) - if (IDecl->ClassImplementsProtocol(PNSCopying, true)) - Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; - } + if (const ObjCObjectPointerType *ObjPtrTy = + T->getAs<ObjCObjectPointerType>()) { + ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); + if (IDecl) + if (ObjCProtocolDecl* PNSCopying = + LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc)) + if (IDecl->ClassImplementsProtocol(PNSCopying, true)) + Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; } - if (T->isObjCInterfaceType()) + if (T->isObjCObjectType()) Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); DeclContext *DC = cast<DeclContext>(CDecl); @@ -223,8 +223,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, Diag(prevDecl->getLocation(), diag::note_property_declare); PDecl->setInvalidDecl(); } - else + else { DC->addDecl(PDecl); + if (lexicalDC) + PDecl->setLexicalDeclContext(lexicalDC); + } if (T->isArrayType() || T->isFunctionType()) { Diag(AtLoc, diag::err_property_type) << T; @@ -275,7 +278,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, /// builds the AST node for a property implementation declaration; declared /// as @synthesize or @dynamic. /// -Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, +Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, SourceLocation PropertyLoc, bool Synthesize, DeclPtrTy ClassCatImpDecl, @@ -379,7 +383,16 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, // Check that type of property and its ivar are type compatible. if (PropType != IvarType) { - if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { + bool compat = false; + if (isa<ObjCObjectPointerType>(PropType) + && isa<ObjCObjectPointerType>(IvarType)) + compat = + Context.canAssignObjCInterfaces( + PropType->getAs<ObjCObjectPointerType>(), + IvarType->getAs<ObjCObjectPointerType>()); + else + compat = (CheckAssignmentConstraints(PropType, IvarType) == Compatible); + if (!compat) { Diag(PropertyLoc, diag::error_property_ivar_type) << property->getDeclName() << PropType << Ivar->getDeclName() << IvarType; @@ -427,6 +440,55 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, ObjCPropertyImplDecl::Synthesize : ObjCPropertyImplDecl::Dynamic), Ivar); + if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { + getterMethod->createImplicitParams(Context, IDecl); + if (getLangOptions().CPlusPlus && Synthesize) { + // For Objective-C++, need to synthesize the AST for the IVAR object to be + // returned by the getter as it must conform to C++'s copy-return rules. + // FIXME. Eventually we want to do this for Objective-C as well. + ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl(); + DeclRefExpr *SelfExpr = + new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), + SourceLocation()); + Expr *IvarRefExpr = + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + SelfExpr, true, true); + OwningExprResult Res = + PerformCopyInitialization(InitializedEntity::InitializeResult( + SourceLocation(), + getterMethod->getResultType(), + /*NRVO=*/false), + SourceLocation(), + Owned(IvarRefExpr)); + if (!Res.isInvalid()) { + Expr *ResExpr = Res.takeAs<Expr>(); + if (ResExpr) + ResExpr = MaybeCreateCXXExprWithTemporaries(ResExpr); + PIDecl->setGetterCXXConstructor(ResExpr); + } + } + } + if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { + setterMethod->createImplicitParams(Context, IDecl); + if (getLangOptions().CPlusPlus && Synthesize) { + // FIXME. Eventually we want to do this for Objective-C as well. + ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl(); + DeclRefExpr *SelfExpr = + new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), + SourceLocation()); + Expr *lhs = + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + SelfExpr, true, true); + ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); + ParmVarDecl *Param = (*P); + Expr *rhs = new (Context) DeclRefExpr(Param,Param->getType(), + SourceLocation()); + OwningExprResult Res = BuildBinOp(S, SourceLocation(), + BinaryOperator::Assign, lhs, rhs); + PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>()); + } + } + if (IC) { if (Synthesize) if (ObjCPropertyImplDecl *PPIDecl = @@ -751,6 +813,47 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, } } +/// CollectClassPropertyImplementations - This routine collects list of +/// properties to be implemented in the class. This includes, class's +/// and its conforming protocols' properties. +static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) + CollectClassPropertyImplementations((*PI), PropMap); + } + else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + CollectClassPropertyImplementations((*PI), PropMap); + } +} + +/// CollectSuperClassPropertyImplementations - This routine collects list of +/// properties to be implemented in super class(s) and also coming from their +/// conforming protocols. +static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) { + while (SDecl) { + CollectClassPropertyImplementations(SDecl, PropMap); + SDecl = SDecl->getSuperClass(); + } + } +} + /// ProtocolConformsToSuperClass - Returns true if class's given protocol /// conforms to one of its super class's protocols. bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, @@ -817,8 +920,36 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, return 0; } +/// DefaultSynthesizeProperties - This routine default synthesizes all +/// properties which must be synthesized in class's @implementation. +void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl) { + + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; + CollectClassPropertyImplementations(IDecl, PropMap); + if (PropMap.empty()) + return; + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap; + CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); + + for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { + ObjCPropertyDecl *Prop = P->second; + // If property to be implemented in the super class, ignore. + if (SuperPropMap[Prop->getIdentifier()]) + continue; + // Is there a matching propery synthesize/dynamic? + if (Prop->isInvalidDecl() || + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || + IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) + continue; + ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(), + true, DeclPtrTy::make(IMPDecl), + Prop->getIdentifier(), Prop->getIdentifier()); + } +} -void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, +void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap) { llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; @@ -840,14 +971,6 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || PropImplMap.count(Prop)) continue; - if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) { - ActOnPropertyImplDecl(IMPDecl->getLocation(), - IMPDecl->getLocation(), - true, DeclPtrTy::make(IMPDecl), - Prop->getIdentifier(), - Prop->getIdentifier()); - continue; - } if (!InsMap.count(Prop->getGetterName())) { Diag(Prop->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? @@ -954,6 +1077,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCMethodDecl::Optional : ObjCMethodDecl::Required); CD->addDecl(GetterMethod); + // FIXME: Eventually this shouldn't be needed, as the lexical context + // and the real context should be the same. + if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + GetterMethod->setLexicalDeclContext(lexicalDC); + } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -987,6 +1115,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, 0); SetterMethod->setMethodParams(Context, &Argument, 1, 1); CD->addDecl(SetterMethod); + // FIXME: Eventually this shouldn't be needed, as the lexical context + // and the real context should be the same. + if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + SetterMethod->setLexicalDeclContext(lexicalDC); } else // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index b87fa7d..2754d44 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -52,6 +52,8 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Conversion, ICC_Conversion, ICC_Conversion, + ICC_Conversion, + ICC_Conversion, ICC_Conversion }; return Category[(int)Kind]; @@ -80,6 +82,8 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Conversion, ICR_Conversion, ICR_Conversion, + ICR_Conversion, + ICR_Conversion, ICR_Complex_Real_Conversion }; return Rank[(int)Kind]; @@ -102,12 +106,14 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Floating conversion", "Complex conversion", "Floating-integral conversion", - "Complex-real conversion", "Pointer conversion", "Pointer-to-member conversion", "Boolean conversion", "Compatible-types conversion", - "Derived-to-base conversion" + "Derived-to-base conversion", + "Vector conversion", + "Vector splat", + "Complex-real conversion" }; return Name[Kind]; } @@ -275,7 +281,194 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) { new (&conversions()) ConversionSet(O.conversions()); } +namespace { + // Structure used by OverloadCandidate::DeductionFailureInfo to store + // template parameter and template argument information. + struct DFIParamWithArguments { + TemplateParameter Param; + TemplateArgument FirstArg; + TemplateArgument SecondArg; + }; +} + +/// \brief Convert from Sema's representation of template deduction information +/// to the form used in overload-candidate information. +OverloadCandidate::DeductionFailureInfo +static MakeDeductionFailureInfo(ASTContext &Context, + Sema::TemplateDeductionResult TDK, + Sema::TemplateDeductionInfo &Info) { + OverloadCandidate::DeductionFailureInfo Result; + Result.Result = static_cast<unsigned>(TDK); + Result.Data = 0; + switch (TDK) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + break; + + case Sema::TDK_Incomplete: + case Sema::TDK_InvalidExplicitArguments: + Result.Data = Info.Param.getOpaqueValue(); + break; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: { + // FIXME: Should allocate from normal heap so that we can free this later. + DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments; + Saved->Param = Info.Param; + Saved->FirstArg = Info.FirstArg; + Saved->SecondArg = Info.SecondArg; + Result.Data = Saved; + break; + } + + case Sema::TDK_SubstitutionFailure: + Result.Data = Info.take(); + break; + + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return Result; +} + +void OverloadCandidate::DeductionFailureInfo::Destroy() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_Incomplete: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + break; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + // FIXME: Destroy the data? + Data = 0; + break; + case Sema::TDK_SubstitutionFailure: + // FIXME: Destroy the template arugment list? + Data = 0; + break; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } +} + +TemplateParameter +OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_SubstitutionFailure: + return TemplateParameter(); + + case Sema::TDK_Incomplete: + case Sema::TDK_InvalidExplicitArguments: + return TemplateParameter::getFromOpaqueValue(Data); + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return static_cast<DFIParamWithArguments*>(Data)->Param; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return TemplateParameter(); +} + +TemplateArgumentList * +OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_Incomplete: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return 0; + + case Sema::TDK_SubstitutionFailure: + return static_cast<TemplateArgumentList*>(Data); + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return 0; +} + +const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_Incomplete: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_SubstitutionFailure: + return 0; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return &static_cast<DFIParamWithArguments*>(Data)->FirstArg; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return 0; +} + +const TemplateArgument * +OverloadCandidate::DeductionFailureInfo::getSecondArg() { + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_Incomplete: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_SubstitutionFailure: + return 0; + + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return &static_cast<DFIParamWithArguments*>(Data)->SecondArg; + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return 0; +} + +void OverloadCandidateSet::clear() { + inherited::clear(); + Functions.clear(); +} + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -586,6 +779,48 @@ static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, ResultTy = FromType; return true; } + +/// \brief Determine whether the conversion from FromType to ToType is a valid +/// vector conversion. +/// +/// \param ICK Will be set to the vector conversion kind, if this is a vector +/// conversion. +static bool IsVectorConversion(ASTContext &Context, QualType FromType, + QualType ToType, ImplicitConversionKind &ICK) { + // We need at least one of these types to be a vector type to have a vector + // conversion. + if (!ToType->isVectorType() && !FromType->isVectorType()) + return false; + + // Identical types require no conversions. + if (Context.hasSameUnqualifiedType(FromType, ToType)) + return false; + + // There are no conversions between extended vector types, only identity. + if (ToType->isExtVectorType()) { + // There are no conversions between extended vector types other than the + // identity conversion. + if (FromType->isExtVectorType()) + return false; + + // Vector splat from any arithmetic type to a vector. + if (!FromType->isVectorType() && FromType->isArithmeticType()) { + ICK = ICK_Vector_Splat; + return true; + } + } + + // If lax vector conversions are permitted and the vector types are of the + // same size, we can perform the conversion. + if (Context.getLangOptions().LaxVectorConversions && + FromType->isVectorType() && ToType->isVectorType() && + Context.getTypeSize(FromType) == Context.getTypeSize(ToType)) { + ICK = ICK_Vector_Conversion; + return true; + } + + return false; +} /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the @@ -708,6 +943,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // For overloading in C, this can also be a "compatible-type" // conversion. bool IncompatibleObjC = false; + ImplicitConversionKind SecondICK = ICK_Identity; if (Context.hasSameUnqualifiedType(FromType, ToType)) { // The unqualified versions of the types are the same: there's no // conversion to do. @@ -769,10 +1005,14 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // Boolean conversions (C++ 4.12). SCS.Second = ICK_Boolean_Conversion; FromType = Context.BoolTy; + } else if (IsVectorConversion(Context, FromType, ToType, SecondICK)) { + SCS.Second = SecondICK; + FromType = ToType.getUnqualifiedType(); } else if (!getLangOptions().CPlusPlus && Context.typesAreCompatible(ToType, FromType)) { // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; + FromType = ToType.getUnqualifiedType(); } else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) { // Treat a conversion that strips "noreturn" as an identity conversion. SCS.Second = ICK_NoReturn_Adjustment; @@ -802,7 +1042,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, CanonTo = Context.getCanonicalType(ToType); if (CanonFrom.getLocalUnqualifiedType() == CanonTo.getLocalUnqualifiedType() && - CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()) { + (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers() + || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) { FromType = ToType; CanonFrom = CanonTo; } @@ -992,7 +1233,7 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, if (CanonToPointee.getLocalQualifiers() == Quals) { // ToType is exactly what we need. Return it. if (!ToType.isNull()) - return ToType; + return ToType.getUnqualifiedType(); // Build a pointer to ToPointee. It has the right qualifiers // already. @@ -1350,22 +1591,18 @@ bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType, if (ToType != FromType) { if (const PointerType *PTTo = ToType->getAs<PointerType>()) { if (const PointerType *PTFr = FromType->getAs<PointerType>()) - if (PTTo->getPointeeType()->isObjCQualifiedIdType() && - PTFr->getPointeeType()->isObjCQualifiedIdType() || - PTTo->getPointeeType()->isObjCQualifiedClassType() && - PTFr->getPointeeType()->isObjCQualifiedClassType()) + if ((PTTo->getPointeeType()->isObjCQualifiedIdType() && + PTFr->getPointeeType()->isObjCQualifiedIdType()) || + (PTTo->getPointeeType()->isObjCQualifiedClassType() && + PTFr->getPointeeType()->isObjCQualifiedClassType())) continue; } - else if (ToType->isObjCObjectPointerType() && - FromType->isObjCObjectPointerType()) { - QualType ToInterfaceTy = ToType->getPointeeType(); - QualType FromInterfaceTy = FromType->getPointeeType(); - if (const ObjCInterfaceType *OITTo = - ToInterfaceTy->getAs<ObjCInterfaceType>()) - if (const ObjCInterfaceType *OITFr = - FromInterfaceTy->getAs<ObjCInterfaceType>()) - if (OITTo->getDecl() == OITFr->getDecl()) - continue; + else if (const ObjCObjectPointerType *PTTo = + ToType->getAs<ObjCObjectPointerType>()) { + if (const ObjCObjectPointerType *PTFr = + FromType->getAs<ObjCObjectPointerType>()) + if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl()) + continue; } return false; } @@ -1839,6 +2076,15 @@ compareStandardConversionSubsets(ASTContext &Context, ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; + // the identity conversion sequence is considered to be a subsequence of + // any non-identity conversion sequence + if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) { + if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Better; + else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Worse; + } + if (SCS1.Second != SCS2.Second) { if (SCS1.Second == ICK_Identity) Result = ImplicitConversionSequence::Better; @@ -1954,8 +2200,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Objective-C++: If one interface is more specific than the // other, it is the better one. - const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>(); + const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>(); + const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>(); if (FromIface1 && FromIface1) { if (Context.canAssignObjCInterfaces(FromIface2, FromIface1)) return ImplicitConversionSequence::Better; @@ -2161,10 +2407,10 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, QualType ToPointee2 = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* ToIface1 = ToPointee1->getAs<ObjCInterfaceType>(); - const ObjCInterfaceType* ToIface2 = ToPointee2->getAs<ObjCInterfaceType>(); + const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>(); + const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>(); + const ObjCObjectType* ToIface1 = ToPointee1->getAs<ObjCObjectType>(); + const ObjCObjectType* ToIface2 = ToPointee2->getAs<ObjCObjectType>(); // -- conversion of C* to B* is better than conversion of C* to A*, if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { @@ -2289,8 +2535,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // T1 is a base class of T2. if (UnqualT1 == UnqualT2) DerivedToBase = false; - else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && - !RequireCompleteType(Loc, OrigT2, PDiag()) && + else if (!RequireCompleteType(Loc, OrigT2, PDiag()) && IsDerivedFrom(UnqualT2, UnqualT1)) DerivedToBase = true; else @@ -2724,6 +2969,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, /// TryContextuallyConvertToBool - Attempt to contextually convert the /// expression From to bool (C++0x [conv]p3). ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { + // FIXME: This is pretty broken. return TryImplicitConversion(From, Context.BoolTy, // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, @@ -2744,6 +2990,27 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { << From->getType() << From->getSourceRange(); return true; } + +/// TryContextuallyConvertToObjCId - Attempt to contextually convert the +/// expression From to 'id'. +ImplicitConversionSequence Sema::TryContextuallyConvertToObjCId(Expr *From) { + QualType Ty = Context.getObjCIdType(); + return TryImplicitConversion(From, Ty, + // FIXME: Are these flags correct? + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/true, + /*InOverloadResolution=*/false); +} + +/// PerformContextuallyConvertToObjCId - Perform a contextual conversion +/// of the expression From to 'id'. +bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { + QualType Ty = Context.getObjCIdType(); + ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(From); + if (!ICS.isBad()) + return PerformImplicitConversion(From, Ty, ICS, AA_Converting); + return true; +} /// AddOverloadCandidate - Adds the given function to the set of /// candidate functions, using the given function call arguments. If @@ -3029,7 +3296,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, } } } - + /// \brief Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member /// function template specialization. @@ -3059,11 +3326,18 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, if (TemplateDeductionResult Result = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args, NumArgs, Specialization, Info)) { - // FIXME: Record what happened with template argument deduction, so - // that we can give the user a beautiful diagnostic. - (void)Result; - return; - } + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate &Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = MethodTmpl->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_deduction; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Info); + return; + } // Add the function template specialization produced by template argument // deduction as a candidate. @@ -3110,10 +3384,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; - - // TODO: record more information about failed template arguments - Candidate.DeductionFailure.Result = Result; - Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue(); + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Info); return; } @@ -3260,9 +3532,16 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, ToType, Specialization, Info)) { - // FIXME: Record what happened with template argument deduction, so - // that we can give the user a beautiful diagnostic. - (void)Result; + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate &Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = FunctionTemplate->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_deduction; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Info); return; } @@ -3504,6 +3783,10 @@ class BuiltinCandidateTypeSet { /// used in the built-in candidates. TypeSet EnumerationTypes; + /// \brief The set of vector types that will be used in the built-in + /// candidates. + TypeSet VectorTypes; + /// Sema - The semantic analysis instance where we are building the /// candidate type set. Sema &SemaRef; @@ -3545,6 +3828,9 @@ public: /// enumeration_end - Past the last enumeration type found; iterator enumeration_end() { return EnumerationTypes.end(); } + + iterator vector_begin() { return VectorTypes.begin(); } + iterator vector_end() { return VectorTypes.end(); } }; /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to @@ -3677,6 +3963,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, return; } else if (Ty->isEnumeralType()) { EnumerationTypes.insert(Ty); + } else if (Ty->isVectorType()) { + VectorTypes.insert(Ty); } else if (AllowUserConversions) { if (const RecordType *TyRec = Ty->getAs<RecordType>()) { if (SemaRef.RequireCompleteType(Loc, Ty, 0)) { @@ -3841,21 +4129,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); BuiltinCandidateTypeSet CandidateTypes(*this); - if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || - Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || - Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal || - Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript || - Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus || - (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) { - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) - CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), - OpLoc, - true, - (Op == OO_Exclaim || - Op == OO_AmpAmp || - Op == OO_PipePipe), - VisibleTypeConversionsQuals); - } + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), + OpLoc, + true, + (Op == OO_Exclaim || + Op == OO_AmpAmp || + Op == OO_PipePipe), + VisibleTypeConversionsQuals); bool isComparison = false; switch (Op) { @@ -4019,6 +4300,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType ArithTy = ArithmeticTypes[Arith]; AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); } + + // Extension: We also add these operators for vector types. + for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), + VecEnd = CandidateTypes.vector_end(); + Vec != VecEnd; ++Vec) { + QualType VecTy = *Vec; + AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + } break; case OO_Tilde: @@ -4032,6 +4321,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType IntTy = ArithmeticTypes[Int]; AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); } + + // Extension: We also add this operator for vector types. + for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), + VecEnd = CandidateTypes.vector_end(); + Vec != VecEnd; ++Vec) { + QualType VecTy = *Vec; + AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + } break; case OO_New: @@ -4188,6 +4485,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } + + // Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the + // conditional operator for vector types. + for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), + Vec1End = CandidateTypes.vector_end(); + Vec1 != Vec1End; ++Vec1) + for (BuiltinCandidateTypeSet::iterator + Vec2 = CandidateTypes.vector_begin(), + Vec2End = CandidateTypes.vector_end(); + Vec2 != Vec2End; ++Vec2) { + QualType LandR[2] = { *Vec1, *Vec2 }; + QualType Result; + if (isComparison) + Result = Context.BoolTy; + else { + if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType()) + Result = *Vec1; + else + Result = *Vec2; + } + + AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + } + break; case OO_Percent: @@ -4243,7 +4564,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, MemPtr != MemPtrEnd; ++MemPtr) AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2, CandidateSet); - // Fall through. + + // Fall through. case OO_PlusEqual: case OO_MinusEqual: @@ -4318,6 +4640,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } } } + + // Extension: Add the binary operators =, +=, -=, *=, /= for vector types. + for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), + Vec1End = CandidateTypes.vector_end(); + Vec1 != Vec1End; ++Vec1) + for (BuiltinCandidateTypeSet::iterator + Vec2 = CandidateTypes.vector_begin(), + Vec2End = CandidateTypes.vector_end(); + Vec2 != Vec2End; ++Vec2) { + QualType ParamTypes[2]; + ParamTypes[1] = *Vec2; + // Add this built-in operator as a candidate (VQ is empty). + ParamTypes[0] = Context.getLValueReferenceType(*Vec1); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + + // Add this built-in operator as a candidate (VQ is 'volatile'). + if (VisibleTypeConversionsQuals.hasVolatile()) { + ParamTypes[0] = Context.getVolatileType(*Vec1); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + } + } break; case OO_PercentEqual: @@ -4413,7 +4759,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, ParamTypes[0] = ParamTypes[1]; ParamTypes[1] = *Ptr; AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); - } + } break; case OO_ArrowStar: @@ -4901,16 +5247,21 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, unsigned MinParams = Fn->getMinRequiredArguments(); // at least / at most / exactly + // FIXME: variadic templates "at most" should account for parameter packs unsigned mode, modeCount; if (NumFormalArgs < MinParams) { - assert(Cand->FailureKind == ovl_fail_too_few_arguments); + assert((Cand->FailureKind == ovl_fail_too_few_arguments) || + (Cand->FailureKind == ovl_fail_bad_deduction && + Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments)); if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic()) mode = 0; // "at least" else mode = 2; // "exactly" modeCount = MinParams; } else { - assert(Cand->FailureKind == ovl_fail_too_many_arguments); + assert((Cand->FailureKind == ovl_fail_too_many_arguments) || + (Cand->FailureKind == ovl_fail_bad_deduction && + Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments)); if (MinParams != FnTy->getNumArgs()) mode = 1; // "at most" else @@ -4922,7 +5273,8 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) - << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; + << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode + << modeCount << NumFormalArgs; } /// Diagnose a failed template-argument deduction. @@ -4930,34 +5282,86 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, Expr **Args, unsigned NumArgs) { FunctionDecl *Fn = Cand->Function; // pattern - TemplateParameter Param = TemplateParameter::getFromOpaqueValue( - Cand->DeductionFailure.TemplateParameter); - + TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter(); + NamedDecl *ParamD; + (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) || + (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) || + (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>()); switch (Cand->DeductionFailure.Result) { case Sema::TDK_Success: llvm_unreachable("TDK_success while diagnosing bad deduction"); case Sema::TDK_Incomplete: { - NamedDecl *ParamD; - (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) || - (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) || - (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>()); assert(ParamD && "no parameter found for incomplete deduction result"); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction) << ParamD->getDeclName(); return; } - // TODO: diagnose these individually, then kill off - // note_ovl_candidate_bad_deduction, which is uselessly vague. - case Sema::TDK_InstantiationDepth: case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: - case Sema::TDK_SubstitutionFailure: - case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_InconsistentQuals: { + assert(ParamD && "no parameter found for inconsistent deduction result"); + int which = 0; + if (isa<TemplateTypeParmDecl>(ParamD)) + which = 0; + else if (isa<NonTypeTemplateParmDecl>(ParamD)) + which = 1; + else { + which = 2; + } + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction) + << which << ParamD->getDeclName() + << *Cand->DeductionFailure.getFirstArg() + << *Cand->DeductionFailure.getSecondArg(); + return; + } + + case Sema::TDK_InvalidExplicitArguments: + assert(ParamD && "no parameter found for invalid explicit arguments"); + if (ParamD->getDeclName()) + S.Diag(Fn->getLocation(), + diag::note_ovl_candidate_explicit_arg_mismatch_named) + << ParamD->getDeclName(); + else { + int index = 0; + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD)) + index = TTP->getIndex(); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(ParamD)) + index = NTTP->getIndex(); + else + index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex(); + S.Diag(Fn->getLocation(), + diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) + << (index + 1); + } + return; + case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: - case Sema::TDK_InvalidExplicitArguments: + DiagnoseArityMismatch(S, Cand, NumArgs); + return; + + case Sema::TDK_InstantiationDepth: + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth); + return; + + case Sema::TDK_SubstitutionFailure: { + std::string ArgString; + if (TemplateArgumentList *Args + = Cand->DeductionFailure.getTemplateArgumentList()) + ArgString = S.getTemplateArgumentBindingsText( + Fn->getDescribedFunctionTemplate()->getTemplateParameters(), + *Args); + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure) + << ArgString; + return; + } + + // TODO: diagnose these individually, then kill off + // note_ovl_candidate_bad_deduction, which is uselessly vague. + case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction); return; @@ -5500,8 +5904,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, assert(Result != MatchesCopy.end() && "no most-specialized template"); MarkDeclarationReferenced(From->getLocStart(), *Result); FoundResult = Matches[Result - MatchesCopy.begin()].first; - if (Complain) + if (Complain) { CheckUnresolvedAccess(*this, OvlExpr, FoundResult); + DiagnoseUseOfDecl(FoundResult, OvlExpr->getNameLoc()); + } return cast<FunctionDecl>(*Result); } @@ -5521,8 +5927,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Matches.size() == 1) { MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); FoundResult = Matches[0].first; - if (Complain) + if (Complain) { CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); + DiagnoseUseOfDecl(Matches[0].first, OvlExpr->getNameLoc()); + } return cast<FunctionDecl>(Matches[0].second); } @@ -5724,7 +6132,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - if (SemaRef.DiagnoseEmptyLookup(S, SS, R)) + if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)) return Destroy(SemaRef, Fn, Args, NumArgs); assert(!R.empty() && "lookup results empty despite recovery"); @@ -5801,6 +6209,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, ULE->getNameLoc()); Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5885,9 +6294,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, - /*ADL*/ true, IsOverloaded(Fns)); - Fn->addDecls(Fns.begin(), Fns.end()); - + /*ADL*/ true, IsOverloaded(Fns), + Fns.begin(), Fns.end()); input.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, &Args[0], NumArgs, @@ -5945,6 +6353,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, Input = (Expr *)input.get(); } + DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); + // Determine the result type QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); @@ -5958,7 +6368,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, ExprOwningPtr<CallExpr> TheCall(this, new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, Args, NumArgs, ResultTy, OpLoc)); - + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), FnDecl)) return ExprError(); @@ -6056,9 +6466,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, - /*ADL*/ true, IsOverloaded(Fns)); - - Fn->addDecls(Fns.begin(), Fns.end()); + /*ADL*/ true, IsOverloaded(Fns), + Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, 2, Context.DependentTy, @@ -6150,6 +6559,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Args[1] = RHS = Arg1.takeAs<Expr>(); } + DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); + // Determine the result type QualType ResultTy = FnDecl->getType()->getAs<FunctionType>()->getResultType(); @@ -6252,7 +6663,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, LLoc, - /*ADL*/ true, /*Overloaded*/ false); + /*ADL*/ true, /*Overloaded*/ false, + UnresolvedSetIterator(), + UnresolvedSetIterator()); // Can't add any actual overloads yet Base.release(); @@ -6286,6 +6699,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // operator. CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, LLoc); // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); @@ -6452,6 +6866,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Method = cast<CXXMethodDecl>(Best->Function); FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()); break; case OR_No_Viable_Function: @@ -6661,6 +7076,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, Best->Conversions[0].UserDefined.ConversionFunction); CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -6677,6 +7093,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, } CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); // We found an overloaded operator(). Build a CXXOperatorCallExpr // that calls this method, using Object for the implicit object @@ -6767,7 +7184,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Promote the arguments (C99 6.5.2.2p7). for (unsigned i = NumArgsInProto; i != NumArgs; i++) { Expr *Arg = Args[i]; - IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod); + IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod, 0); TheCall->setArg(i + 1, Arg); } } @@ -6847,6 +7264,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { } CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl); + DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 5e61111..eb4fc65 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -16,7 +16,9 @@ #define LLVM_CLANG_SEMA_OVERLOAD_H #include "clang/AST/Decl.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/AST/UnresolvedSet.h" #include "llvm/ADT/SmallPtrSet.h" @@ -60,6 +62,8 @@ namespace clang { ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) ICK_Compatible_Conversion, ///< Conversions between compatible types in C99 ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics]) + ICK_Vector_Conversion, ///< Vector conversions + ICK_Vector_Splat, ///< A vector splat from an arithmetic type ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Num_Conversion_Kinds ///< The number of conversion kinds }; @@ -173,6 +177,12 @@ namespace clang { } void setAsIdentityConversion(); + + bool isIdentityConversion() const { + return First == ICK_Identity && Second == ICK_Identity && + Third == ICK_Identity; + } + ImplicitConversionRank getRank() const; bool isPointerConversionToBool() const; bool isPointerConversionToVoidPointer(ASTContext& Context) const; @@ -529,8 +539,28 @@ namespace clang { // A Sema::TemplateDeductionResult. unsigned Result; - // A TemplateParameter. - void *TemplateParameter; + /// \brief Opaque pointer containing additional data about + /// this deduction failure. + void *Data; + + /// \brief Retrieve the template parameter this deduction failure + /// refers to, if any. + TemplateParameter getTemplateParameter(); + + /// \brief Retrieve the template argument list associated with this + /// deduction failure, if any. + TemplateArgumentList *getTemplateArgumentList(); + + /// \brief Return the first template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getFirstArg(); + + /// \brief Return the second template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getSecondArg(); + + /// \brief Free any memory associated with this deduction failure. + void Destroy(); }; union { @@ -562,6 +592,10 @@ namespace clang { llvm::SmallPtrSet<Decl *, 16> Functions; SourceLocation Loc; + + OverloadCandidateSet(const OverloadCandidateSet &); + OverloadCandidateSet &operator=(const OverloadCandidateSet &); + public: OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {} @@ -574,10 +608,9 @@ namespace clang { } /// \brief Clear out all of the candidates. - void clear() { - inherited::clear(); - Functions.clear(); - } + void clear(); + + ~OverloadCandidateSet() { clear(); } }; } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9d6132d..875b160 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -30,7 +30,7 @@ using namespace clang; Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) { Expr *E = expr->takeAs<Expr>(); assert(E && "ActOnExprStmt(): missing expression"); - if (E->getType()->isObjCInterfaceType()) { + if (E->getType()->isObjCObjectType()) { if (LangOpts.ObjCNonFragileABI) Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object) << E->getType(); @@ -280,7 +280,7 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, VarDecl *ConditionVar = 0; if (CondVar.get()) { ConditionVar = CondVar.getAs<VarDecl>(); - CondResult = CheckConditionVariable(ConditionVar); + CondResult = CheckConditionVariable(ConditionVar, IfLoc, true); if (CondResult.isInvalid()) return StmtError(); } @@ -288,11 +288,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, if (!ConditionExpr) return StmtError(); - if (CheckBooleanCondition(ConditionExpr, IfLoc)) { - CondResult = ConditionExpr; - return StmtError(); - } - Stmt *thenStmt = ThenVal.takeAs<Stmt>(); DiagnoseUnusedExprResult(thenStmt); @@ -313,23 +308,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, thenStmt, ElseLoc, elseStmt)); } -Action::OwningStmtResult -Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) { - OwningExprResult CondResult(cond.release()); - - VarDecl *ConditionVar = 0; - if (CondVar.get()) { - ConditionVar = CondVar.getAs<VarDecl>(); - CondResult = CheckConditionVariable(ConditionVar); - if (CondResult.isInvalid()) - return StmtError(); - } - SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, - CondResult.takeAs<Expr>()); - getSwitchStack().push_back(SS); - return Owned(SS); -} - /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. @@ -540,14 +518,36 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, return false; } -/// ActOnSwitchBodyError - This is called if there is an error parsing the -/// body of the switch stmt instead of ActOnFinishSwitchStmt. -void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, - StmtArg Body) { - // Keep the switch stack balanced. - assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() && - "switch stack missing push/pop!"); - getSwitchStack().pop_back(); +Action::OwningStmtResult +Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond, + DeclPtrTy CondVar) { + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs<VarDecl>(); + OwningExprResult CondE = CheckConditionVariable(ConditionVar, SourceLocation(), false); + if (CondE.isInvalid()) + return StmtError(); + + Cond = move(CondE); + } + + Expr *CondExpr = Cond.takeAs<Expr>(); + if (!CondExpr) + return StmtError(); + + if (getLangOptions().CPlusPlus && + CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr)) + return StmtError(); + + if (!CondVar.get()) { + CondExpr = MaybeCreateCXXExprWithTemporaries(CondExpr); + if (!CondExpr) + return StmtError(); + } + + SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, CondExpr); + getSwitchStack().push_back(SS); + return Owned(SS); } Action::OwningStmtResult @@ -567,13 +567,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } Expr *CondExpr = SS->getCond(); + Expr *CondExprBeforePromotion = CondExpr; QualType CondTypeBeforePromotion = GetTypeBeforeIntegralPromotion(CondExpr); - if (getLangOptions().CPlusPlus && - CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr)) - return StmtError(); - // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. UsualUnaryConversions(CondExpr); QualType CondType = CondExpr->getType(); @@ -679,16 +676,38 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } if (!HasDependentValue) { + // If we don't have a default statement, check whether the + // condition is constant. + llvm::APSInt ConstantCondValue; + bool HasConstantCond = false; + bool ShouldCheckConstantCond = false; + if (!HasDependentValue && !TheDefaultStmt) { + Expr::EvalResult Result; + HasConstantCond = CondExprBeforePromotion->Evaluate(Result, Context); + if (HasConstantCond) { + assert(Result.Val.isInt() && "switch condition evaluated to non-int"); + ConstantCondValue = Result.Val.getInt(); + ShouldCheckConstantCond = true; + + assert(ConstantCondValue.getBitWidth() == CondWidth && + ConstantCondValue.isSigned() == CondIsSigned); + } + } + // Sort all the scalar case values so we can easily detect duplicates. std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); if (!CaseVals.empty()) { - for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) { - if (CaseVals[i].first == CaseVals[i+1].first) { + for (unsigned i = 0, e = CaseVals.size(); i != e; ++i) { + if (ShouldCheckConstantCond && + CaseVals[i].first == ConstantCondValue) + ShouldCheckConstantCond = false; + + if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) { // If we have a duplicate, report it. - Diag(CaseVals[i+1].second->getLHS()->getLocStart(), - diag::err_duplicate_case) << CaseVals[i].first.toString(10); Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::err_duplicate_case) << CaseVals[i].first.toString(10); + Diag(CaseVals[i-1].second->getLHS()->getLocStart(), diag::note_duplicate_case_prev); // FIXME: We really want to remove the bogus case stmt from the // substmt, but we have no way to do this right now. @@ -707,6 +726,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // Scan the ranges, computing the high values and removing empty ranges. std::vector<llvm::APSInt> HiVals; for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + llvm::APSInt &LoVal = CaseRanges[i].first; CaseStmt *CR = CaseRanges[i].second; Expr *Hi = CR->getRHS(); llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); @@ -722,7 +742,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. - if (CaseRanges[i].first > HiVal) { + if (LoVal > HiVal) { Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) << SourceRange(CR->getLHS()->getLocStart(), CR->getRHS()->getLocEnd()); @@ -730,6 +750,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, --i, --e; continue; } + + if (ShouldCheckConstantCond && + LoVal <= ConstantCondValue && + ConstantCondValue <= HiVal) + ShouldCheckConstantCond = false; + HiVals.push_back(HiVal); } @@ -783,18 +809,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } } - // Check to see if switch is over an Enum and handles all of its - // values + // Complain if we have a constant condition and we didn't find a match. + if (!CaseListIsErroneous && ShouldCheckConstantCond) { + // TODO: it would be nice if we printed enums as enums, chars as + // chars, etc. + Diag(CondExpr->getExprLoc(), diag::warn_missing_case_for_condition) + << ConstantCondValue.toString(10) + << CondExpr->getSourceRange(); + } + + // Check to see if switch is over an Enum and handles all of its + // values. We don't need to do this if there's a default + // statement or if we have a constant condition. + // + // TODO: we might want to check whether case values are out of the + // enum even if we don't want to check whether all cases are handled. const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>(); // If switch has default case, then ignore it. - if (!CaseListIsErroneous && !TheDefaultStmt && ET) { + if (!CaseListIsErroneous && !TheDefaultStmt && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; EnumValsTy EnumVals; - // Gather all enum values, set their type and sort them, allowing easier comparison - // with CaseVals. - for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) { + // Gather all enum values, set their type and sort them, + // allowing easier comparison with CaseVals. + for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); + EDI != ED->enumerator_end(); EDI++) { llvm::APSInt Val = (*EDI)->getInitVal(); if(Val.getBitWidth() < CondWidth) Val.extend(CondWidth); @@ -802,30 +842,36 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, EnumVals.push_back(std::make_pair(Val, (*EDI))); } std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); - EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); + EnumValsTy::iterator EIend = + std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); // See which case values aren't in enum EnumValsTy::const_iterator EI = EnumVals.begin(); - for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) { + for (CaseValsTy::const_iterator CI = CaseVals.begin(); + CI != CaseVals.end(); CI++) { while (EI != EIend && EI->first < CI->first) EI++; if (EI == EIend || EI->first > CI->first) - Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); } // See which of case ranges aren't in enum EI = EnumVals.begin(); - for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) { + for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); + RI != CaseRanges.end() && EI != EIend; RI++) { while (EI != EIend && EI->first < RI->first) EI++; if (EI == EIend || EI->first != RI->first) { - Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); } llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); while (EI != EIend && EI->first < Hi) EI++; if (EI == EIend || EI->first != Hi) - Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); } //Check which enum vals aren't in switch CaseValsTy::const_iterator CI = CaseVals.begin(); @@ -848,7 +894,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } if (RI == CaseRanges.end() || EI->first < RI->first) - Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName(); + Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) + << EI->second->getDeclName(); } } } @@ -870,7 +917,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, VarDecl *ConditionVar = 0; if (CondVar.get()) { ConditionVar = CondVar.getAs<VarDecl>(); - CondResult = CheckConditionVariable(ConditionVar); + CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true); if (CondResult.isInvalid()) return StmtError(); } @@ -878,11 +925,6 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, if (!ConditionExpr) return StmtError(); - if (CheckBooleanCondition(ConditionExpr, WhileLoc)) { - CondResult = ConditionExpr; - return StmtError(); - } - Stmt *bodyStmt = Body.takeAs<Stmt>(); DiagnoseUnusedExprResult(bodyStmt); @@ -903,6 +945,10 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, return StmtError(); } + condExpr = MaybeCreateCXXExprWithTemporaries(condExpr); + if (!condExpr) + return StmtError(); + Stmt *bodyStmt = Body.takeAs<Stmt>(); DiagnoseUnusedExprResult(bodyStmt); @@ -939,17 +985,11 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, VarDecl *ConditionVar = 0; if (secondVar.get()) { ConditionVar = secondVar.getAs<VarDecl>(); - SecondResult = CheckConditionVariable(ConditionVar); + SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true); if (SecondResult.isInvalid()) return StmtError(); } - Expr *Second = SecondResult.takeAs<Expr>(); - if (Second && CheckBooleanCondition(Second, ForLoc)) { - SecondResult = Second; - return StmtError(); - } - Expr *Third = third.release().takeAs<Expr>(); Stmt *Body = static_cast<Stmt*>(body.get()); @@ -959,7 +999,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, first.release(); body.release(); - return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body, + return Owned(new (Context) ForStmt(First, SecondResult.takeAs<Expr>(), + ConditionVar, Third, Body, ForLoc, LParenLoc, RParenLoc)); } @@ -1068,6 +1109,45 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { return Owned(new (Context) BreakStmt(BreakLoc)); } +/// \brief Determine whether a return statement is a candidate for the named +/// return value optimization (C++0x 12.8p34, bullet 1). +/// +/// \param Ctx The context in which the return expression and type occur. +/// +/// \param RetType The return type of the function or block. +/// +/// \param RetExpr The expression being returned from the function or block. +/// +/// \returns The NRVO candidate variable, if the return statement may use the +/// NRVO, or NULL if there is no such candidate. +static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType, + Expr *RetExpr) { + QualType ExprType = RetExpr->getType(); + // - in a return statement in a function with ... + // ... a class return type ... + if (!RetType->isRecordType()) + return 0; + // ... the same cv-unqualified type as the function return type ... + if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) + return 0; + // ... the expression is the name of a non-volatile automatic object ... + // We ignore parentheses here. + // FIXME: Is this compliant? (Everyone else does it) + const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens()); + if (!DR) + return 0; + const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); + if (!VD) + return 0; + + if (VD->getKind() == Decl::Var && VD->hasLocalStorage() && + !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() && + !VD->getType().isVolatileQualified()) + return VD; + + return 0; +} + /// ActOnBlockReturnStmt - Utility routine to figure out block's return type. /// Action::OwningStmtResult @@ -1102,68 +1182,58 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Otherwise, verify that this result type matches the previous one. We are // pickier with blocks than for normal functions because we don't have GCC // compatibility to worry about here. + ReturnStmt *Result = 0; if (CurBlock->ReturnType->isVoidType()) { if (RetValExp) { Diag(ReturnLoc, diag::err_return_block_has_expr); RetValExp->Destroy(Context); RetValExp = 0; } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); - } - - if (!RetValExp) + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); + } else if (!RetValExp) { return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + } else { + const VarDecl *NRVOCandidate = 0; + + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void block with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // 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. + // the C version of which boils down to CheckSingleAssignmentConstraints. + NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); + } + + if (RetValExp) + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void block with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // 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. - // the C version of which boils down to CheckSingleAssignmentConstraints. - OwningExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType), - SourceLocation(), - Owned(RetValExp)); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); -} - -/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that -/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15). -static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType, - Expr *RetExpr) { - QualType ExprType = RetExpr->getType(); - // - in a return statement in a function with ... - // ... a class return type ... - if (!RetType->isRecordType()) - return false; - // ... the same cv-unqualified type as the function return type ... - if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) - return false; - // ... the expression is the name of a non-volatile automatic object ... - // We ignore parentheses here. - // FIXME: Is this compliant? - const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens()); - if (!DR) - return false; - const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); - if (!VD) - return false; - return VD->hasLocalStorage() && !VD->getType()->isReferenceType() - && !VD->getType().isVolatileQualified(); + // If we need to check for the named return value optimization, save the + // return statement in our scope for later processing. + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext()) + FunctionScopes.back()->Returns.push_back(Result); + + return Owned(Result); } Action::OwningStmtResult @@ -1184,6 +1254,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { else // If we don't have a function/method context, bail. return StmtError(); + ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { if (RetValExp && !RetValExp->isTypeDependent()) { // C99 6.8.6.4p1 (ext_ since GCC warns) @@ -1202,10 +1273,9 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); - } - - if (!RetValExp && !FnRetType->isDependentType()) { + + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); + } else if (!RetValExp && !FnRetType->isDependentType()) { unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 // C99 6.8.6.4p1 (ext_ since GCC warns) if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr; @@ -1214,54 +1284,47 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/; else Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; - return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0)); - } + Result = new (Context) ReturnStmt(ReturnLoc); + } else { + const VarDecl *NRVOCandidate = 0; + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void function with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // 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. + // the C version of which boils down to CheckSingleAssignmentConstraints. + NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); + } - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void function with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. - - // C++0x 12.8p15: When certain criteria are met, an implementation is - // allowed to omit the copy construction of a class object, [...] - // - in a return statement in a function with a class return type, when - // the expression is the name of a non-volatile automatic object with - // the same cv-unqualified type as the function return type, the copy - // operation can be omitted [...] - // C++0x 12.8p16: When the criteria for elision of a copy operation are met - // and the object to be copied is designated by an lvalue, overload - // resolution to select the constructor for the copy is first performed - // as if the object were designated by an rvalue. - // Note that we only compute Elidable if we're in C++0x, since we don't - // care otherwise. - bool Elidable = getLangOptions().CPlusPlus0x ? - IsReturnCopyElidable(Context, FnRetType, RetValExp) : - false; - // FIXME: Elidable - (void)Elidable; - - // In C++ the return statement is handled via a copy initialization. - // the C version of which boils down to CheckSingleAssignmentConstraints. - OwningExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType), - SourceLocation(), - Owned(RetValExp)); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + + if (RetValExp) + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - - if (RetValExp) - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); + + // If we need to check for the named return value optimization, save the + // return statement in our scope for later processing. + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext()) + FunctionScopes.back()->Returns.push_back(Result); + + return Owned(Result); } /// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 694b21c..307be9d 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -100,10 +100,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S, UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, - TemplateTy &TemplateResult) { + TemplateTy &TemplateResult, + bool &MemberOfUnknownSpecialization) { assert(getLangOptions().CPlusPlus && "No template names in C!"); DeclarationName TName; + MemberOfUnknownSpecialization = false; switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: @@ -128,7 +130,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupResult R(*this, TName, Name.getSourceRange().getBegin(), LookupOrdinaryName); R.suppressDiagnostics(); - LookupTemplateName(R, S, SS, ObjectType, EnteringContext); + LookupTemplateName(R, S, SS, ObjectType, EnteringContext, + MemberOfUnknownSpecialization); if (R.empty() || R.isAmbiguous()) return TNK_Non_template; @@ -172,6 +175,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, TemplateNameKind &SuggestedKind) { // We can't recover unless there's a dependent scope specifier preceding the // template name. + // FIXME: Typo correction? if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || computeDeclContext(*SS)) return false; @@ -191,8 +195,10 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, void Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, - bool EnteringContext) { + bool EnteringContext, + bool &MemberOfUnknownSpecialization) { // Determine where to perform name lookup + MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = 0; bool isDependent = false; if (!ObjectType.isNull()) { @@ -241,6 +247,7 @@ void Sema::LookupTemplateName(LookupResult &Found, } else if (isDependent) { // We cannot look into a dependent object type or nested nme // specifier. + MemberOfUnknownSpecialization = true; return; } else { // Perform unqualified name lookup in the current scope. @@ -330,11 +337,13 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + + DeclContext *DC = getFunctionLevelDeclContext(); if (!isAddressOfOperand && - isa<CXXMethodDecl>(CurContext) && - cast<CXXMethodDecl>(CurContext)->isInstance()) { - QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + isa<CXXMethodDecl>(DC) && + cast<CXXMethodDecl>(DC)->isInstance()) { + QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. @@ -525,6 +534,14 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, /// otherwise, produces a diagnostic and returns a NULL type. QualType Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { + // We don't allow variably-modified types as the type of non-type template + // parameters. + if (T->isVariablyModifiedType()) { + Diag(Loc, diag::err_variably_modified_nontype_template_param) + << T; + return QualType(); + } + // C++ [temp.param]p4: // // A non-type template-parameter shall have one of the following @@ -555,7 +572,7 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { else if (T->isFunctionType()) // FIXME: Keep the type prior to promotion? return Context.getPointerType(T); - + Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; @@ -739,8 +756,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (CheckTemplateDeclScope(S, TemplateParams)) return true; - TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec); - assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type"); + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + assert(Kind != TTK_Enum && "can't build template of enumerated type"); // There is no such thing as an unnamed class template. if (!Name) { @@ -1088,7 +1105,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, DiagnoseDefaultTemplateArgument(*this, TPC, NewTypeParm->getLocation(), NewTypeParm->getDefaultArgumentInfo()->getTypeLoc() - .getFullSourceRange())) + .getSourceRange())) NewTypeParm->removeDefaultArgument(); // Merge default arguments for template type parameters. @@ -1506,10 +1523,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // specialization. Create the canonical declaration and add it to // the set of specializations. Decl = ClassTemplateSpecializationDecl::Create(Context, - ClassTemplate->getDeclContext(), - ClassTemplate->getLocation(), - ClassTemplate, - Converted, 0); + ClassTemplate->getTemplatedDecl()->getTagKind(), + ClassTemplate->getDeclContext(), + ClassTemplate->getLocation(), + ClassTemplate, + Converted, 0); ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); Decl->setLexicalDeclContext(CurContext); } @@ -1567,7 +1585,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, QualType Type = GetTypeFromParser(TypeResult.get(), &DI); // Verify the tag specifier. - TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); + TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); if (const RecordType *RT = Type->getAs<RecordType>()) { RecordDecl *D = RT->getDecl(); @@ -1583,7 +1601,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, } } - QualType ElabType = Context.getElaboratedType(Type, TagKind); + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); + QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type); return ElabType.getAsOpaquePtr(); } @@ -1618,8 +1638,8 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), Qualifier, QualifierRange, R.getLookupName(), R.getNameLoc(), - RequiresADL, TemplateArgs); - ULE->addDecls(R.begin(), R.end()); + RequiresADL, TemplateArgs, + R.begin(), R.end()); return Owned(ULE); } @@ -1636,8 +1656,10 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs); + bool MemberOfUnknownSpecialization; LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); - LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false); + LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false, + MemberOfUnknownSpecialization); if (R.isAmbiguous()) return ExprError(); @@ -1694,8 +1716,10 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // "template" keyword is now permitted). We follow the C++0x // rules, even in C++03 mode, retroactively applying the DR. TemplateTy Template; + bool MemberOfUnknownSpecialization; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && isa<CXXRecordDecl>(LookupCtx) && cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { @@ -1704,7 +1728,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) - << Name.getSourceRange(); + << Name.getSourceRange() + << TemplateKWLoc; return TemplateTy(); } else { // We found something; return it. @@ -1734,7 +1759,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) - << Name.getSourceRange(); + << Name.getSourceRange() + << TemplateKWLoc; return TemplateTy(); } @@ -2336,24 +2362,27 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, // compounded from any of these types shall not be used as a // template-argument for a template type-parameter. // - // FIXME: Perform the recursive and no-linkage type checks. + // FIXME: Perform the unnamed type check. + SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); const TagType *Tag = 0; if (const EnumType *EnumT = Arg->getAs<EnumType>()) Tag = EnumT; else if (const RecordType *RecordT = Arg->getAs<RecordType>()) Tag = RecordT; if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) { - SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); + SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); return Diag(SR.getBegin(), diag::err_template_arg_local_type) << QualType(Tag, 0) << SR; } else if (Tag && !Tag->getDecl()->getDeclName() && !Tag->getDecl()->getTypedefForAnonDecl()) { - SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR; Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here); return true; + } else if (Arg->isVariablyModifiedType()) { + Diag(SR.getBegin(), diag::err_variably_modified_template_arg) + << Arg; + return true; } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { - SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; } @@ -3661,13 +3690,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Check that the specialization uses the same tag kind as the // original template. - TagDecl::TagKind Kind; - switch (TagSpec) { - default: assert(0 && "Unknown tag type!"); - case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; - case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; - case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; - } + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, KWLoc, *ClassTemplate->getIdentifier())) { @@ -3796,7 +3820,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber() : ClassTemplate->getPartialSpecializations().size(); ClassTemplatePartialSpecializationDecl *Partial - = ClassTemplatePartialSpecializationDecl::Create(Context, + = ClassTemplatePartialSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), TemplateNameLoc, TemplateParams, @@ -3857,7 +3881,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. Specialization - = ClassTemplateSpecializationDecl::Create(Context, + = ClassTemplateSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, @@ -4217,10 +4241,10 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, return false; } -/// \brief Perform semantic analysis for the given function template +/// \brief Perform semantic analysis for the given function template /// specialization. /// -/// This routine performs all of the semantic analysis required for an +/// This routine performs all of the semantic analysis required for an /// explicit function template specialization. On successful completion, /// the function declaration \p FD will become a function template /// specialization. @@ -4228,24 +4252,14 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, /// \param FD the function declaration, which will be updated to become a /// function template specialization. /// -/// \param HasExplicitTemplateArgs whether any template arguments were -/// explicitly provided. -/// -/// \param LAngleLoc the location of the left angle bracket ('<'), if -/// template arguments were explicitly provided. -/// -/// \param ExplicitTemplateArgs the explicitly-provided template arguments, -/// if any. -/// -/// \param NumExplicitTemplateArgs the number of explicitly-provided template -/// arguments. This number may be zero even when HasExplicitTemplateArgs is -/// true as in, e.g., \c void sort<>(char*, char*); +/// \param ExplicitTemplateArgs the explicitly-provided template arguments, +/// if any. Note that this may be valid info even when 0 arguments are +/// explicitly provided as in, e.g., \c void sort<>(char*, char*); +/// as it anyway contains info on the angle brackets locations. /// -/// \param RAngleLoc the location of the right angle bracket ('>'), if -/// template arguments were explicitly provided. -/// -/// \param PrevDecl the set of declarations that -bool +/// \param PrevDecl the set of declarations that may be specialized by +/// this function specialization. +bool Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous) { @@ -4347,12 +4361,16 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Turn the given function declaration into a function template // specialization, with the template arguments from the previous // specialization. + // Take copies of (semantic and syntactic) template argument lists. + const TemplateArgumentList* TemplArgs = new (Context) + TemplateArgumentList(Specialization->getTemplateSpecializationArgs()); + const TemplateArgumentListInfo* TemplArgsAsWritten = ExplicitTemplateArgs + ? new (Context) TemplateArgumentListInfo(*ExplicitTemplateArgs) : 0; FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(), - new (Context) TemplateArgumentList( - *Specialization->getTemplateSpecializationArgs()), - /*InsertPos=*/0, - SpecInfo->getTemplateSpecializationKind()); - + TemplArgs, /*InsertPos=*/0, + SpecInfo->getTemplateSpecializationKind(), + TemplArgsAsWritten); + // The "previous declaration" for this function template specialization is // the prior function template specialization. Previous.clear(); @@ -4541,10 +4559,16 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, if (S.getLangOptions().CPlusPlus0x && !CurContext->Encloses(ExpectedContext)) { if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ExpectedContext)) - S.Diag(InstLoc, diag::err_explicit_instantiation_out_of_scope) + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? + diag::err_explicit_instantiation_out_of_scope + : diag::warn_explicit_instantiation_out_of_scope_0x) << D << NS; else - S.Diag(InstLoc, diag::err_explicit_instantiation_must_be_global) + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? + diag::err_explicit_instantiation_must_be_global + : diag::warn_explicit_instantiation_out_of_scope_0x) << D; S.Diag(D->getLocation(), diag::note_explicit_instantiation_here); return; @@ -4561,7 +4585,10 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, if (CurContext->Equals(ExpectedContext)) return; - S.Diag(InstLoc, diag::err_explicit_instantiation_unqualified_wrong_namespace) + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? + diag::err_explicit_instantiation_unqualified_wrong_namespace + : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x) << D << ExpectedContext; S.Diag(D->getLocation(), diag::note_explicit_instantiation_here); } @@ -4588,7 +4615,6 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { } // Explicit instantiation of a class template specialization -// FIXME: Implement extern template semantics Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, @@ -4609,13 +4635,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Check that the specialization uses the same tag kind as the // original template. - TagDecl::TagKind Kind; - switch (TagSpec) { - default: assert(0 && "Unknown tag type!"); - case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; - case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; - case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; - } + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + assert(Kind != TTK_Enum && + "Invalid enum tag in class template explicit instantiation!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, KWLoc, *ClassTemplate->getIdentifier())) { @@ -4703,7 +4725,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Create a new class template specialization declaration node for // this explicit specialization. Specialization - = ClassTemplateSpecializationDecl::Create(Context, + = ClassTemplateSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, @@ -4755,7 +4777,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->getDefinition()); if (!Def) InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); - + else if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(TemplateNameLoc, Specialization, true); + // Instantiate the members of this class template specialization. Def = cast_or_null<ClassTemplateSpecializationDecl>( Specialization->getDefinition()); @@ -4890,6 +4914,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, InstantiateClassMembers(NameLoc, RecordDef, getTemplateInstantiationArgs(Record), TSK); + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(NameLoc, RecordDef, true); + // FIXME: We don't have any representation for explicit instantiations of // member classes. Such a representation is not needed for compilation, but it // should be available for clients that want to see all of the declarations in @@ -5161,37 +5188,33 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!NNS) return true; - ElaboratedTypeKeyword Keyword = ETK_None; - switch (TagDecl::getTagKindForTypeSpec(TagSpec)) { - case TagDecl::TK_struct: Keyword = ETK_Struct; break; - case TagDecl::TK_class: Keyword = ETK_Class; break; - case TagDecl::TK_union: Keyword = ETK_Union; break; - case TagDecl::TK_enum: Keyword = ETK_Enum; break; - } - assert(Keyword != ETK_None && "Invalid tag kind!"); + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); if (TUK == TUK_Declaration || TUK == TUK_Definition) { Diag(NameLoc, diag::err_dependent_tag_decl) - << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec) - << SS.getRange(); + << (TUK == TUK_Definition) << Kind << SS.getRange(); return true; } - - return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr(); + + ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind); + return Context.getDependentNameType(Kwd, NNS, Name).getAsOpaquePtr(); } static void FillTypeLoc(DependentNameTypeLoc TL, SourceLocation TypenameLoc, - SourceRange QualifierRange) { - // FIXME: typename, qualifier range - TL.setNameLoc(TypenameLoc); + SourceRange QualifierRange, + SourceLocation NameLoc) { + TL.setKeywordLoc(TypenameLoc); + TL.setQualifierRange(QualifierRange); + TL.setNameLoc(NameLoc); } -static void FillTypeLoc(QualifiedNameTypeLoc TL, +static void FillTypeLoc(ElaboratedTypeLoc TL, SourceLocation TypenameLoc, SourceRange QualifierRange) { - // FIXME: typename, qualifier range - TL.setNameLoc(TypenameLoc); + // FIXME: inner locations. + TL.setKeywordLoc(TypenameLoc); + TL.setQualifierRange(QualifierRange); } Sema::TypeResult @@ -5203,7 +5226,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, return true; QualType T = CheckTypenameType(ETK_Typename, NNS, II, - SourceRange(TypenameLoc, IdLoc)); + TypenameLoc, SS.getRange(), IdLoc); if (T.isNull()) return true; @@ -5211,9 +5234,9 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, if (isa<DependentNameType>(T)) { DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc - FillTypeLoc(TL, TypenameLoc, SS.getRange()); + FillTypeLoc(TL, TypenameLoc, SS.getRange(), IdLoc); } else { - QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc FillTypeLoc(TL, TypenameLoc, SS.getRange()); } @@ -5233,14 +5256,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, if (computeDeclContext(SS, false)) { // If we can compute a declaration context, then the "typename" - // keyword was superfluous. Just build a QualifiedNameType to keep + // keyword was superfluous. Just build an ElaboratedType to keep // track of the nested-name-specifier. - - // FIXME: Note that the QualifiedNameType had the "typename" keyword! - - T = Context.getQualifiedNameType(NNS, T); + T = Context.getElaboratedType(ETK_Typename, NNS, T); TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); - QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc FillTypeLoc(TL, TypenameLoc, SS.getRange()); return CreateLocInfoType(T, TSI).getAsOpaquePtr(); @@ -5250,7 +5270,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); // FIXME: fill inner type loc - FillTypeLoc(TL, TypenameLoc, SS.getRange()); + FillTypeLoc(TL, TypenameLoc, SS.getRange(), TemplateLoc); return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } @@ -5259,10 +5279,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, QualType Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo &II, - SourceRange Range) { + SourceLocation KeywordLoc, SourceRange NNSRange, + SourceLocation IILoc) { CXXScopeSpec SS; SS.setScopeRep(NNS); - SS.setRange(Range); + SS.setRange(NNSRange); DeclContext *Ctx = computeDeclContext(SS); if (!Ctx) { @@ -5282,7 +5303,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, return QualType(); DeclarationName Name(&II); - LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName); + LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); LookupQualifiedName(Result, Ctx); unsigned DiagID = 0; Decl *Referenced = 0; @@ -5297,10 +5318,10 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { - // We found a type. Build a QualifiedNameType, since the - // typename-specifier was just sugar. FIXME: Tell - // QualifiedNameType that it has a "typename" prefix. - return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type)); + // We found a type. Build an ElaboratedType, since the + // typename-specifier was just sugar. + return Context.getElaboratedType(ETK_Typename, NNS, + Context.getTypeDeclType(Type)); } DiagID = diag::err_typename_nested_not_type; @@ -5322,7 +5343,9 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // If we get here, it's because name lookup did not find a // type. Emit an appropriate diagnostic and return an error. - Diag(Range.getEnd(), DiagID) << Range << Name << Ctx; + SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(), + IILoc); + Diag(IILoc, DiagID) << FullRange << Name << Ctx; if (Referenced) Diag(Referenced->getLocation(), diag::note_typename_refers_here) << Name; @@ -5379,9 +5402,10 @@ namespace { /// \brief Transforms a typename type by determining whether the type now /// refers to a member of the current instantiation, and then - /// type-checking and building a QualifiedNameType (when possible). - QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL, - QualType ObjectType); + /// type-checking and building an ElaboratedType (when possible). + QualType TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, + QualType ObjectType); }; } @@ -5393,7 +5417,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), - /*FIXME:*/SourceRange(getBaseLocation()), + TL.getQualifierRange(), ObjectType); if (!NNS) return QualType(); @@ -5402,7 +5426,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, // context corresponding to the nested-name-specifier, then this // typename type will not change; exit early. CXXScopeSpec SS; - SS.setRange(SourceRange(getBaseLocation())); + SS.setRange(TL.getQualifierRange()); SS.setScopeRep(NNS); QualType Result; @@ -5410,7 +5434,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, Result = QualType(T, 0); // Rebuild the typename type, which will probably turn into a - // QualifiedNameType. + // ElaboratedType. else if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { QualType NewTemplateId = TransformType(QualType(TemplateId, 0)); @@ -5421,18 +5445,38 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) Result = QualType(T, 0); else - Result = getDerived().RebuildDependentNameType(T->getKeyword(), + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, NewTemplateId); } else - Result = getDerived().RebuildDependentNameType(T->getKeyword(), - NNS, T->getIdentifier(), - SourceRange(TL.getNameLoc())); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + T->getIdentifier(), + TL.getKeywordLoc(), + TL.getQualifierRange(), + TL.getNameLoc()); if (Result.isNull()) return QualType(); - DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); + if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) { + QualType NamedT = ElabT->getNamedType(); + if (isa<TemplateSpecializationType>(NamedT)) { + TemplateSpecializationTypeLoc NamedTLoc + = TLB.push<TemplateSpecializationTypeLoc>(NamedT); + // FIXME: fill locations + NamedTLoc.initializeLocal(TL.getNameLoc()); + } else { + TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc()); + } + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + } + else { + DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + NewTL.setNameLoc(TL.getNameLoc()); + } return Result; } @@ -5459,7 +5503,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, /// Here, the type "typename X<T>::pointer" will be created as a DependentNameType, /// since we do not know that we can look into X<T> when we parsed the type. /// This function will rebuild the type, performing the lookup of "pointer" -/// in X<T> and returning a QualifiedNameType whose canonical type is the same +/// in X<T> and returning an ElaboratedType whose canonical type is the same /// as the canonical type of T*, allowing the return types of the out-of-line /// definition and the declaration to match. TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 2bb97eb..88ceeca 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -482,14 +482,20 @@ DeduceTemplateArguments(Sema &S, // T * case Type::Pointer: { - const PointerType *PointerArg = Arg->getAs<PointerType>(); - if (!PointerArg) + QualType PointeeType; + if (const PointerType *PointerArg = Arg->getAs<PointerType>()) { + PointeeType = PointerArg->getPointeeType(); + } else if (const ObjCObjectPointerType *PointerArg + = Arg->getAs<ObjCObjectPointerType>()) { + PointeeType = PointerArg->getPointeeType(); + } else { return Sema::TDK_NonDeducedMismatch; + } unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); return DeduceTemplateArguments(S, TemplateParams, cast<PointerType>(Param)->getPointeeType(), - PointerArg->getPointeeType(), + PointeeType, Info, Deduced, SubTDF); } @@ -1030,10 +1036,8 @@ FinishTemplateArgumentDeduction(Sema &S, ClassTemplate->getTemplateParameters(), N); if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), - InstArgs, false, ConvertedInstArgs)) { - // FIXME: fail with more useful information? + InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; - } for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I]; @@ -1190,8 +1194,13 @@ Sema::SubstituteExplicitTemplateArguments( SourceLocation(), ExplicitTemplateArgs, true, - Builder) || Trap.hasErrorOccurred()) + Builder) || Trap.hasErrorOccurred()) { + unsigned Index = Builder.structuredSize(); + if (Index >= TemplateParams->size()) + Index = TemplateParams->size() - 1; + Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); return TDK_InvalidExplicitArguments; + } // Form the template argument list from the explicitly-specified // template arguments. @@ -1374,6 +1383,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, NTTP->getDeclName()); if (NTTPType.isNull()) { Info.Param = makeTemplateParameter(Param); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } } @@ -1399,6 +1410,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, : CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } @@ -1429,6 +1442,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } @@ -1456,7 +1471,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // If the template argument list is owned by the function template // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList) + if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && + !Trap.hasErrorOccurred()) Info.take(); // There may have been an error that did not prevent us from constructing a @@ -2636,6 +2652,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, case Type::Record: case Type::Enum: case Type::ObjCInterface: + case Type::ObjCObject: case Type::ObjCObjectPointer: case Type::UnresolvedUsing: #define TYPE(Class, Base) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 14bd243..1adf594 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -560,9 +560,7 @@ namespace { /// /// For the purposes of template instantiation, a type has already been /// transformed if it is NULL or if it is not dependent. - bool AlreadyTransformed(QualType T) { - return T.isNull() || !T->isDependentType(); - } + bool AlreadyTransformed(QualType T); /// \brief Returns the location of the entity being instantiated, if known. SourceLocation getBaseLocation() { return Loc; } @@ -603,7 +601,8 @@ namespace { /// \brief Check for tag mismatches when instantiating an /// elaborated type. - QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); + QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType T); Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); @@ -624,6 +623,17 @@ namespace { }; } +bool TemplateInstantiator::AlreadyTransformed(QualType T) { + if (T.isNull()) + return true; + + if (T->isDependentType() || T->isVariablyModifiedType()) + return false; + + getSema().MarkDeclarationsReferencedInType(Loc, T); + return true; +} + Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { if (!D) return 0; @@ -710,8 +720,9 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, } QualType -TemplateInstantiator::RebuildElaboratedType(QualType T, - ElaboratedType::TagKind Tag) { +TemplateInstantiator::RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType T) { if (const TagType *TT = T->getAs<TagType>()) { TagDecl* TD = TT->getDecl(); @@ -723,16 +734,20 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, // TODO: should we even warn on struct/class mismatches for this? Seems // like it's likely to produce a lot of spurious errors. - if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) { - SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) - << Id - << FixItHint::CreateReplacement(SourceRange(TagLocation), - TD->getKindName()); - SemaRef.Diag(TD->getLocation(), diag::note_previous_use); + if (Keyword != ETK_None && Keyword != ETK_Typename) { + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); + if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) { + SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) + << Id + << FixItHint::CreateReplacement(SourceRange(TagLocation), + TD->getKindName()); + SemaRef.Diag(TD->getLocation(), diag::note_previous_use); + } } } - return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag); + return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(Keyword, + NNS, T); } Sema::OwningExprResult @@ -927,7 +942,8 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, "Cannot perform an instantiation without some context on the " "instantiation stack"); - if (!T->getType()->isDependentType()) + if (!T->getType()->isDependentType() && + !T->getType()->isVariablyModifiedType()) return T; TemplateInstantiator Instantiator(*this, Args, Loc, Entity); @@ -942,8 +958,9 @@ QualType Sema::SubstType(QualType T, "Cannot perform an instantiation without some context on the " "instantiation stack"); - // If T is not a dependent type, there is nothing to do. - if (!T->isDependentType()) + // If T is not a dependent type or a variably-modified type, there + // is nothing to do. + if (!T->isDependentType() && !T->isVariablyModifiedType()) return T; TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); @@ -951,7 +968,7 @@ QualType Sema::SubstType(QualType T, } static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { - if (T->getType()->isDependentType()) + if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType()) return true; TypeLoc TL = T->getTypeLoc(); @@ -1160,6 +1177,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. ContextRAII SavedContext(*this, Instantiation); + EnterExpressionEvaluationContext EvalContext(*this, + Action::PotentiallyEvaluated); // If this is an instantiation of a local class, merge this local // instantiation scope with the enclosing scope. Otherwise, every @@ -1169,6 +1188,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Start the definition of this instantiation. Instantiation->startDefinition(); + + Instantiation->setTagKind(Pattern->getTagKind()); // Do substitution on the base class specifiers. if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) @@ -1202,25 +1223,15 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Exit the scope of this instantiation. SavedContext.pop(); - // If this is a polymorphic C++ class without a key function, we'll - // have to mark all of the virtual members to allow emission of a vtable - // in this translation unit. - if (Instantiation->isDynamicClass() && - !Context.getKeyFunction(Instantiation)) { - // Local classes need to have their methods instantiated immediately in - // order to have the correct instantiation scope. - if (Instantiation->isLocalClass()) { - MarkVirtualMembersReferenced(PointOfInstantiation, - Instantiation); - } else { - ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation, - PointOfInstantiation)); - } - } - - if (!Invalid) + if (!Invalid) { Consumer.HandleTagDeclDefinition(Instantiation); + // Always emit the vtable for an explicit instantiation definition + // of a polymorphic class template specialization. + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(PointOfInstantiation, Instantiation, true); + } + return Invalid; } @@ -1244,6 +1255,12 @@ Sema::InstantiateClassTemplateSpecialization( // declaration (C++0x [temp.explicit]p10); go ahead and perform the // explicit instantiation. ClassTemplateSpec->setSpecializationKind(TSK); + + // If this is an explicit instantiation definition, mark the + // vtable as used. + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(PointOfInstantiation, ClassTemplateSpec, true); + return false; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index da84806..834b86d 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -184,13 +184,16 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI->getType()->isDependentType()) { + if (DI->getType()->isDependentType() || + DI->getType()->isVariablyModifiedType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { Invalid = true; DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy); } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); } // Create the new typedef @@ -215,6 +218,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } + InstantiateAttrs(D, Typedef); Typedef->setAccess(D->getAccess()); Owner->addDecl(Typedef); @@ -320,6 +324,13 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, } Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { + // If this is the variable for an anonymous struct or union, + // instantiate the anonymous struct/union type first. + if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) + if (RecordTy->getDecl()->isAnonymousStructOrUnion()) + if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) + return 0; + // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, @@ -349,7 +360,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setLexicalDeclContext(D->getLexicalDeclContext()); Var->setAccess(D->getAccess()); - + Var->setUsed(D->isUsed()); + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; @@ -417,13 +429,18 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { } else if (!Var->isStaticDataMember() || Var->isOutOfLine()) SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); + // Diagnose unused local variables. + if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed()) + SemaRef.DiagnoseUnusedDecl(Var); + return Var; } Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI->getType()->isDependentType()) { + if (DI->getType()->isDependentType() || + DI->getType()->isVariablyModifiedType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { @@ -440,6 +457,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { << DI->getType(); Invalid = true; } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); } Expr *BitWidth = D->getBitWidth(); @@ -480,6 +499,11 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { if (!Field->getDeclName()) { // Keep track of where this decl came from. SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D); + } + if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) { + if (Parent->isAnonymousStructOrUnion() && + Parent->getLookupContext()->isFunctionOrMethod()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Field); } Field->setImplicit(D->isImplicit()); @@ -903,7 +927,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { if (Decl::FriendObjectKind FOK = D->getFriendObjectKind()) Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared); - Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion()); + // Make sure that anonymous structs and unions are recorded. + if (D->isAnonymousStructOrUnion()) { + Record->setAnonymousStructOrUnion(true); + if (Record->getDeclContext()->getLookupContext()->isFunctionOrMethod()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record); + } Owner->addDecl(Record); return Record; @@ -943,6 +972,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, isFriend = (D->getFriendObjectKind() != Decl::FOK_None); bool MergeWithParentScope = (TemplateParams != 0) || + Owner->isFunctionOrMethod() || !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); @@ -1000,6 +1030,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Params[P]->setOwningFunction(Function); Function->setParams(Params.data(), Params.size()); + SourceLocation InstantiateAtPOI; if (TemplateParams) { // Our resulting instantiation is actually a function template, since we // are substituting only the outer template parameters. For example, given @@ -1118,6 +1149,38 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0); DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false); + + if (!SemaRef.getLangOptions().CPlusPlus0x && + D->isThisDeclarationADefinition()) { + // Check for a function body. + const FunctionDecl *Definition = 0; + if (Function->getBody(Definition) && + Definition->getTemplateSpecializationKind() == TSK_Undeclared) { + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + << Function->getDeclName(); + SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); + Function->setInvalidDecl(); + } + // Check for redefinitions due to other instantiations of this or + // a similar friend function. + else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(), + REnd = Function->redecls_end(); + R != REnd; ++R) { + if (*R != Function && + ((*R)->getFriendObjectKind() != Decl::FOK_None)) { + if (const FunctionDecl *RPattern + = (*R)->getTemplateInstantiationPattern()) + if (RPattern->getBody(RPattern)) { + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + << Function->getDeclName(); + SemaRef.Diag((*R)->getLocation(), diag::note_previous_definition); + Function->setInvalidDecl(); + break; + } + } + } + } + } if (Function->isOverloadedOperator() && !DC->isRecord() && @@ -1761,7 +1824,9 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec - = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner, + = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, + PartialSpec->getTagKind(), + Owner, PartialSpec->getLocation(), InstParams, ClassTemplate, @@ -1946,15 +2011,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive, bool DefinitionRequired) { - if (Function->isInvalidDecl()) + if (Function->isInvalidDecl() || Function->getBody()) return; - assert(!Function->getBody() && "Already instantiated!"); - // Never instantiate an explicit specialization. if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) return; - + // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); Stmt *Pattern = 0; @@ -1975,6 +2038,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl) Diag(PatternDecl->getLocation(), diag::note_explicit_instantiation_here); + Function->setInvalidDecl(); } return; @@ -2000,6 +2064,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Recursive) PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + EnterExpressionEvaluationContext EvalContext(*this, + Action::PotentiallyEvaluated); ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be @@ -2644,8 +2710,7 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { Context.getSourceManager(), "instantiating function definition"); - if (!Function->getBody()) - InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); + InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); continue; } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index d1a74be..35efa61 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -25,6 +25,8 @@ #include "llvm/Support/ErrorHandling.h" using namespace clang; +#include <iostream> + /// \brief Perform adjustment on the parameter type of a function. /// /// This routine adjusts the given parameter type @p T to the actual @@ -162,9 +164,10 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, + (ObjCProtocolDecl**)PQ, + DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectPointerType(Result); break; } @@ -283,12 +286,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // In C++, make an ElaboratedType. if (TheSema.getLangOptions().CPlusPlus) { - TagDecl::TagKind Tag - = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType()); - Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result); - Result = Context.getElaboratedType(Result, Tag); + ElaboratedTypeKeyword Keyword + = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); + Result = TheSema.getElaboratedType(Keyword, DS.getTypeSpecScope(), + Result); } - if (D->isInvalidDecl()) TheDeclarator.setInvalidType(true); break; @@ -300,28 +302,28 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = TheSema.GetTypeFromParser(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - if (const ObjCInterfaceType * - Interface = Result->getAs<ObjCInterfaceType>()) { - // It would be nice if protocol qualifiers were only stored with the - // ObjCObjectPointerType. Unfortunately, this isn't possible due - // to the following typedef idiom (which is uncommon, but allowed): - // - // typedef Foo<P> T; - // static void func() { - // Foo<P> *yy; - // T *zz; - // } - Result = Context.getObjCInterfaceType(Interface->getDecl(), - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); - } else if (Result->isObjCIdType()) + if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { + // Silently drop any existing protocol qualifiers. + // TODO: determine whether that's the right thing to do. + if (ObjT->getNumProtocols()) + Result = ObjT->getBaseType(); + + if (DS.getNumProtocolQualifiers()) + Result = Context.getObjCObjectType(Result, + (ObjCProtocolDecl**) PQ, + DS.getNumProtocolQualifiers()); + } else if (Result->isObjCIdType()) { // id<protocol-list> - Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); - else if (Result->isObjCClassType()) { + Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, + (ObjCProtocolDecl**) PQ, + DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectPointerType(Result); + } else if (Result->isObjCClassType()) { // Class<protocol-list> - Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy, - (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, + (ObjCProtocolDecl**) PQ, + DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectPointerType(Result); } else { TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); @@ -504,7 +506,7 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, Qs.removeRestrict(); } - assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType"); + assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); // Build the pointer type. return Context.getQualifiedType(Context.getPointerType(T), Qs); @@ -659,7 +661,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, // array, accept it as a GNU extension: C99 6.7.2.1p2. if (EltTy->getDecl()->hasFlexibleArrayMember()) Diag(Loc, diag::ext_flexible_array_in_array) << T; - } else if (T->isObjCInterfaceType()) { + } else if (T->isObjCObjectType()) { Diag(Loc, diag::err_objc_array_of_interfaces) << T; return QualType(); } @@ -678,7 +680,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets); else T = Context.getIncompleteArrayType(T, ASM, Quals); - } else if (ArraySize->isValueDependent()) { + } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || (!T->isDependentType() && !T->isIncompleteType() && @@ -707,11 +709,23 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOptions().C99) { - if (ArraySize && !ArraySize->isTypeDependent() && - !ArraySize->isValueDependent() && - !ArraySize->isIntegerConstantExpr(Context)) - Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla); - else if (ASM != ArrayType::Normal || Quals != 0) + if (T->isVariableArrayType()) { + // Prohibit the use of non-POD types in VLAs. + if (!T->isDependentType() && + !Context.getBaseElementType(T)->isPODType()) { + Diag(Loc, diag::err_vla_non_pod) + << Context.getBaseElementType(T); + return QualType(); + } + // Prohibit the use of VLAs during template argument deduction. + else if (isSFINAEContext()) { + Diag(Loc, diag::err_vla_in_sfinae); + return QualType(); + } + // Just extwarn about VLAs. + else + Diag(Loc, diag::ext_vla); + } else if (ASM != ArrayType::Normal || Quals != 0) Diag(Loc, getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx : diag::ext_c99_array_usage); @@ -995,10 +1009,10 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; case Declarator::MemberContext: switch (cast<TagDecl>(CurContext)->getTagKind()) { - case TagDecl::TK_enum: assert(0 && "unhandled tag kind"); break; - case TagDecl::TK_struct: Error = 1; /* Struct member */ break; - case TagDecl::TK_union: Error = 2; /* Union member */ break; - case TagDecl::TK_class: Error = 3; /* Class member */ break; + 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; + case TTK_Class: Error = 3; /* Class member */ break; } break; case Declarator::CXXCatchContext: @@ -1056,13 +1070,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, D.setInvalidType(true); // Build the type anyway. } - if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) { - const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>(); - T = Context.getObjCObjectPointerType(T, - const_cast<ObjCProtocolDecl **>( - OIT->qual_begin()), - OIT->getNumProtocols(), - DeclType.Ptr.TypeQuals); + if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) { + T = Context.getObjCObjectPointerType(T); + T = Context.getCVRQualifiedType(T, DeclType.Ptr.TypeQuals); break; } T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); @@ -1301,7 +1311,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case NestedNameSpecifier::TypeSpecWithTemplate: ClsType = QualType(NNS->getAsType(), 0); if (NNSPrefix) - ClsType = Context.getQualifiedNameType(NNSPrefix, ClsType); + ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType); break; } } else { @@ -1401,7 +1411,18 @@ namespace { } void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + // Handle the base type, which might not have been written explicitly. + if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { + TL.setHasBaseTypeAsWritten(false); + TL.getBaseLoc().initialize(SourceLocation()); + } else { + TL.setHasBaseTypeAsWritten(true); + Visit(TL.getBaseLoc()); + } + // Protocol qualifiers. if (DS.getProtocolQualifiers()) { assert(TL.getNumProtocols() > 0); assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); @@ -1416,34 +1437,8 @@ namespace { } } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - TL.setStarLoc(SourceLocation()); - - if (DS.getProtocolQualifiers()) { - assert(TL.getNumProtocols() > 0); - assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - TL.setHasProtocolsAsWritten(true); - TL.setLAngleLoc(DS.getProtocolLAngleLoc()); - TL.setRAngleLoc(DS.getSourceRange().getEnd()); - for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) - TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); - - } else { - assert(TL.getNumProtocols() == 0); - TL.setHasProtocolsAsWritten(false); - TL.setLAngleLoc(SourceLocation()); - TL.setRAngleLoc(SourceLocation()); - } - - // This might not have been written with an inner type. - if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { - TL.setHasBaseTypeAsWritten(false); - TL.getBaseTypeLoc().initialize(SourceLocation()); - } else { - TL.setHasBaseTypeAsWritten(true); - Visit(TL.getBaseTypeLoc()); - } + Visit(TL.getPointeeLoc()); } void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { TypeSourceInfo *TInfo = 0; @@ -1456,9 +1451,15 @@ namespace { return; } - TemplateSpecializationTypeLoc OldTL = - cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc()); - TL.copy(OldTL); + TypeLoc OldTL = TInfo->getTypeLoc(); + if (TInfo->getType()->getAs<ElaboratedType>()) { + ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(OldTL); + TemplateSpecializationTypeLoc NamedTL = + cast<TemplateSpecializationTypeLoc>(ElabTL.getNamedTypeLoc()); + TL.copy(NamedTL); + } + else + TL.copy(cast<TemplateSpecializationTypeLoc>(OldTL)); } void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr); @@ -1489,6 +1490,44 @@ namespace { TL.setBuiltinLoc(DS.getTypeSpecWidthLoc()); } } + void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); + if (Keyword == ETK_Typename) { + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); + if (TInfo) { + TL.copy(cast<ElaboratedTypeLoc>(TInfo->getTypeLoc())); + return; + } + } + TL.setKeywordLoc(Keyword != ETK_None + ? DS.getTypeSpecTypeLoc() + : SourceLocation()); + const CXXScopeSpec& SS = DS.getTypeSpecScope(); + TL.setQualifierRange(SS.isEmpty() ? SourceRange(): SS.getRange()); + Visit(TL.getNextTypeLoc().getUnqualifiedLoc()); + } + void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); + if (Keyword == ETK_Typename) { + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); + if (TInfo) { + TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc())); + return; + } + } + TL.setKeywordLoc(Keyword != ETK_None + ? DS.getTypeSpecTypeLoc() + : SourceLocation()); + const CXXScopeSpec& SS = DS.getTypeSpecScope(); + TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange()); + // FIXME: load appropriate source location. + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); @@ -1516,10 +1555,6 @@ namespace { void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Pointer); TL.setStarLoc(Chunk.Loc); - TL.setHasBaseTypeAsWritten(true); - TL.setHasProtocolsAsWritten(false); - TL.setLAngleLoc(SourceLocation()); - TL.setRAngleLoc(SourceLocation()); } void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::MemberPointer); @@ -1642,6 +1677,16 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) { T2 = T2MPType->getPointeeType(); return true; } + + if (getLangOptions().ObjC1) { + const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(), + *T2OPType = T2->getAs<ObjCObjectPointerType>(); + if (T1OPType && T2OPType) { + T1 = T1OPType->getPointeeType(); + T2 = T2OPType->getPointeeType(); + return true; + } + } return false; } @@ -1704,7 +1749,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, } Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt addrSpace(32); - if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { + if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() || + !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) << ASArgExpr->getSourceRange(); Attr.setInvalid(); @@ -1810,7 +1856,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { llvm::APSInt NumParams(32); // The warning is emitted elsewhere - if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) + if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || + !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) return false; Type = S.Context.getRegParmType(Type, NumParams.getZExtValue()); @@ -1838,6 +1885,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { case AttributeList::AT_cdecl: CC = CC_C; break; case AttributeList::AT_fastcall: CC = CC_X86FastCall; break; case AttributeList::AT_stdcall: CC = CC_X86StdCall; break; + case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break; default: llvm_unreachable("unexpected attribute kind"); return false; } @@ -1895,7 +1943,8 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S } Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { + if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() || + !sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "vector_size" << sizeExpr->getSourceRange(); Attr.setInvalid(); @@ -1962,6 +2011,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: case AttributeList::AT_stdcall: + case AttributeList::AT_thiscall: case AttributeList::AT_regparm: // Don't process these on the DeclSpec. if (IsDeclSpec || @@ -2082,15 +2132,21 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, std::make_pair(SourceLocation(), PDiag(0))); } -/// \brief Retrieve a version of the type 'T' that is qualified by the -/// nested-name-specifier contained in SS. -QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { - if (!SS.isSet() || SS.isInvalid() || T.isNull()) +/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword +/// and qualified by the nested-name-specifier contained in SS. +QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, + const CXXScopeSpec &SS, QualType T) { + if (T.isNull()) return T; - - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - return Context.getQualifiedNameType(NNS, T); + NestedNameSpecifier *NNS; + if (SS.isValid()) + NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + else { + if (Keyword == ETK_None) + return T; + NNS = 0; + } + return Context.getElaboratedType(Keyword, NNS, T); } QualType Sema::BuildTypeofExprType(Expr *E) { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 5ce268b..a18701e 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -344,8 +344,8 @@ public: OwningStmtResult Transform##Node(Node *S); #define EXPR(Node, Parent) \ OwningExprResult Transform##Node(Node *E); -#define ABSTRACT_EXPR(Node, Parent) -#include "clang/AST/StmtNodes.def" +#define ABSTRACT_STMT(Stmt) +#include "clang/AST/StmtNodes.inc" /// \brief Build a new pointer type given its pointee type. /// @@ -492,11 +492,6 @@ public: return SemaRef.Context.getTypeDeclType(Enum); } - /// \brief Build a new elaborated type. - QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag) { - return SemaRef.Context.getElaboratedType(T, Tag); - } - /// \brief Build a new typeof(expr) type. /// /// By default, performs semantic analysis when building the typeof type. @@ -525,19 +520,19 @@ public: /// \brief Build a new qualified name type. /// - /// By default, builds a new QualifiedNameType type from the - /// nested-name-specifier and the named type. Subclasses may override - /// this routine to provide different behavior. - QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) { - return SemaRef.Context.getQualifiedNameType(NNS, Named); + /// By default, builds a new ElaboratedType type from the keyword, + /// the nested-name-specifier and the named type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType Named) { + return SemaRef.Context.getElaboratedType(Keyword, NNS, Named); } /// \brief Build a new typename type that refers to a template-id. /// - /// By default, builds a new DependentNameType type from the - /// nested-name-specifier - /// and the given type. Subclasses may override this routine to provide - /// different behavior. + /// By default, builds a new DependentNameType type from the + /// nested-name-specifier and the given type. Subclasses may override + /// this routine to provide different behavior. QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType T) { if (NNS->isDependent()) { @@ -548,50 +543,48 @@ public: return SemaRef.Context.getDependentNameType(Keyword, NNS, cast<TemplateSpecializationType>(T)); } - - // FIXME: Handle elaborated-type-specifiers separately. - return SemaRef.Context.getQualifiedNameType(NNS, T); + + return SemaRef.Context.getElaboratedType(Keyword, NNS, T); } /// \brief Build a new typename type that refers to an identifier. /// /// By default, performs semantic analysis when building the typename type - /// (or qualified name type). Subclasses may override this routine to provide + /// (or elaborated type). Subclasses may override this routine to provide /// different behavior. - QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, + QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Id, - SourceRange SR) { + SourceLocation KeywordLoc, + SourceRange NNSRange, + SourceLocation IdLoc) { CXXScopeSpec SS; SS.setScopeRep(NNS); - + SS.setRange(NNSRange); + if (NNS->isDependent()) { // If the name is still dependent, just build a new dependent name type. if (!SemaRef.computeDeclContext(SS)) return SemaRef.Context.getDependentNameType(Keyword, NNS, Id); } - TagDecl::TagKind Kind = TagDecl::TK_enum; - switch (Keyword) { - case ETK_None: - // Fall through. - case ETK_Typename: - return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR); - - case ETK_Class: Kind = TagDecl::TK_class; break; - case ETK_Struct: Kind = TagDecl::TK_struct; break; - case ETK_Union: Kind = TagDecl::TK_union; break; - case ETK_Enum: Kind = TagDecl::TK_enum; break; - } - - // We had a dependent elaborated-type-specifier that as been transformed + if (Keyword == ETK_None || Keyword == ETK_Typename) + return SemaRef.CheckTypenameType(Keyword, NNS, *Id, + KeywordLoc, NNSRange, IdLoc); + + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); + + // We had a dependent elaborated-type-specifier that has been transformed // into a non-dependent elaborated-type-specifier. Find the tag we're // referring to. - LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName); + LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName); DeclContext *DC = SemaRef.computeDeclContext(SS, false); if (!DC) return QualType(); + if (SemaRef.RequireCompleteDeclContext(SS, DC)) + return QualType(); + TagDecl *Tag = 0; SemaRef.LookupQualifiedName(Result, DC); switch (Result.getResultKind()) { @@ -615,22 +608,20 @@ public: if (!Tag) { // FIXME: Would be nice to highlight just the source range. - SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope) + SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) << Kind << Id << DC; return QualType(); } - - // FIXME: Terrible location information - if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) { - SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id; + + if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) { + SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); } // Build the elaborated-type-specifier type. QualType T = SemaRef.Context.getTypeDeclType(Tag); - T = SemaRef.Context.getQualifiedNameType(NNS, T); - return SemaRef.Context.getElaboratedType(T, Kind); + return SemaRef.Context.getElaboratedType(Keyword, NNS, T); } /// \brief Build a new nested-name-specifier given the prefix and an @@ -769,9 +760,11 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OwningStmtResult RebuildSwitchStmtStart(Sema::FullExprArg Cond, + OwningStmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, + Sema::ExprArg Cond, VarDecl *CondVar) { - return getSema().ActOnStartOfSwitchStmt(Cond, DeclPtrTy::make(CondVar)); + return getSema().ActOnStartOfSwitchStmt(SwitchLoc, move(Cond), + DeclPtrTy::make(CondVar)); } /// \brief Attach the body to the switch statement. @@ -792,8 +785,8 @@ public: Sema::FullExprArg Cond, VarDecl *CondVar, StmtArg Body) { - return getSema().ActOnWhileStmt(WhileLoc, Cond, DeclPtrTy::make(CondVar), - move(Body)); + return getSema().ActOnWhileStmt(WhileLoc, Cond, + DeclPtrTy::make(CondVar), move(Body)); } /// \brief Build a new do-while statement. @@ -1966,13 +1959,13 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { #define STMT(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S)); #define EXPR(Node, Parent) -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" // Transform expressions by calling TransformExpr. #define STMT(Node, Parent) -#define ABSTRACT_EXPR(Node, Parent) +#define ABSTRACT_STMT(Stmt) #define EXPR(Node, Parent) case Stmt::Node##Class: -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" { Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S)); if (E.isInvalid()) @@ -1994,10 +1987,10 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) { switch (E->getStmtClass()) { case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; -#define ABSTRACT_EXPR(Node, Parent) +#define ABSTRACT_STMT(Stmt) #define EXPR(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E)); -#include "clang/AST/StmtNodes.def" +#include "clang/AST/StmtNodes.inc" } return SemaRef.Owned(E->Retain()); @@ -2457,23 +2450,15 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, return QualType(); QualType Result = TL.getType(); - if (PointeeType->isObjCInterfaceType()) { + if (PointeeType->getAs<ObjCObjectType>()) { // A dependent pointer type 'T *' has is being transformed such // that an Objective-C class type is being replaced for 'T'. The // resulting pointer type is an ObjCObjectPointerType, not a // PointerType. - const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>(); - Result = SemaRef.Context.getObjCObjectPointerType(PointeeType, - const_cast<ObjCProtocolDecl **>( - IFace->qual_begin()), - IFace->getNumProtocols()); + Result = SemaRef.Context.getObjCObjectPointerType(PointeeType); - ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); - NewT.setStarLoc(TL.getSigilLoc()); - NewT.setHasProtocolsAsWritten(false); - NewT.setLAngleLoc(SourceLocation()); - NewT.setRAngleLoc(SourceLocation()); - NewT.setHasBaseTypeAsWritten(true); + ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); + NewT.setStarLoc(TL.getStarLoc()); return Result; } @@ -3144,31 +3129,6 @@ QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, return Result; } -template <typename Derived> -QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, - ElaboratedTypeLoc TL, - QualType ObjectType) { - ElaboratedType *T = TL.getTypePtr(); - - // FIXME: this should be a nested type. - QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); - if (Underlying.isNull()) - return QualType(); - - QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Underlying != T->getUnderlyingType()) { - Result = getDerived().RebuildElaboratedType(Underlying, T->getTagKind()); - if (Result.isNull()) - return QualType(); - } - - ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - - return Result; -} - template<typename Derived> QualType TreeTransform<Derived>::TransformInjectedClassNameType( TypeLocBuilder &TLB, @@ -3273,32 +3233,54 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( template<typename Derived> QualType -TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB, - QualifiedNameTypeLoc TL, - QualType ObjectType) { - QualifiedNameType *T = TL.getTypePtr(); - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - SourceRange(), - ObjectType); - if (!NNS) - return QualType(); +TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, + ElaboratedTypeLoc TL, + QualType ObjectType) { + ElaboratedType *T = TL.getTypePtr(); - QualType Named = getDerived().TransformType(T->getNamedType()); - if (Named.isNull()) - return QualType(); + NestedNameSpecifier *NNS = 0; + // NOTE: the qualifier in an ElaboratedType is optional. + if (T->getQualifier() != 0) { + NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + TL.getQualifierRange(), + ObjectType); + if (!NNS) + return QualType(); + } + + QualType NamedT; + // FIXME: this test is meant to workaround a problem (failing assertion) + // occurring if directly executing the code in the else branch. + if (isa<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc())) { + TemplateSpecializationTypeLoc OldNamedTL + = cast<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc()); + const TemplateSpecializationType* OldTST + = OldNamedTL.getType()->template getAs<TemplateSpecializationType>(); + NamedT = TransformTemplateSpecializationType(OldTST, ObjectType); + if (NamedT.isNull()) + return QualType(); + TemplateSpecializationTypeLoc NewNamedTL + = TLB.push<TemplateSpecializationTypeLoc>(NamedT); + NewNamedTL.copy(OldNamedTL); + } + else { + NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); + if (NamedT.isNull()) + return QualType(); + } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NNS != T->getQualifier() || - Named != T->getNamedType()) { - Result = getDerived().RebuildQualifiedNameType(NNS, Named); + NamedT != T->getNamedType()) { + Result = getDerived().RebuildElaboratedType(T->getKeyword(), NNS, NamedT); if (Result.isNull()) return QualType(); } - QualifiedNameTypeLoc NewTL = TLB.push<QualifiedNameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); return Result; } @@ -3309,11 +3291,9 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, QualType ObjectType) { DependentNameType *T = TL.getTypePtr(); - /* FIXME: preserve source information better than this */ - SourceRange SR(TL.getNameLoc()); - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR, + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + TL.getQualifierRange(), ObjectType); if (!NNS) return QualType(); @@ -3331,18 +3311,38 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) return QualType(T, 0); - Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, NewTemplateId); } else { - Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, - T->getIdentifier(), SR); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + T->getIdentifier(), + TL.getKeywordLoc(), + TL.getQualifierRange(), + TL.getNameLoc()); } if (Result.isNull()) return QualType(); - DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - + if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) { + QualType NamedT = ElabT->getNamedType(); + if (isa<TemplateSpecializationType>(NamedT)) { + TemplateSpecializationTypeLoc NamedTLoc + = TLB.push<TemplateSpecializationTypeLoc>(NamedT); + // FIXME: fill locations + NamedTLoc.initializeLocal(TL.getNameLoc()); + } else { + TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc()); + } + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + } + else { + DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + NewTL.setQualifierRange(TL.getQualifierRange()); + NewTL.setNameLoc(TL.getNameLoc()); + } return Result; } @@ -3352,6 +3352,17 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, ObjCInterfaceTypeLoc TL, QualType ObjectType) { // ObjCInterfaceType is never dependent. + TLB.pushFullCopy(TL); + return TL.getType(); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, + ObjCObjectTypeLoc TL, + QualType ObjectType) { + // ObjCObjectType is never dependent. + TLB.pushFullCopy(TL); return TL.getType(); } @@ -3361,6 +3372,7 @@ TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, ObjCObjectPointerTypeLoc TL, QualType ObjectType) { // ObjCObjectPointerType is never dependent. + TLB.pushFullCopy(TL); return TL.getType(); } @@ -3489,10 +3501,23 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + + // Convert the condition to a boolean value. + if (S->getCond()) { + OwningExprResult CondE = getSema().ActOnBooleanCondition(0, + S->getIfLoc(), + move(Cond)); + if (CondE.isInvalid()) + return getSema().StmtError(); + + Cond = move(CondE); + } } Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); - + if (!S->getConditionVariable() && S->getCond() && !FullCond->get()) + return SemaRef.StmtError(); + // Transform the "then" branch. OwningStmtResult Then = getDerived().TransformStmt(S->getThen()); if (Then.isInvalid()) @@ -3536,11 +3561,10 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { return SemaRef.StmtError(); } - Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); - // Rebuild the switch statement. - OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond, - ConditionVar); + OwningStmtResult Switch + = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), move(Cond), + ConditionVar); if (Switch.isInvalid()) return SemaRef.StmtError(); @@ -3573,9 +3597,21 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + + if (S->getCond()) { + // Convert the condition to a boolean value. + OwningExprResult CondE = getSema().ActOnBooleanCondition(0, + S->getWhileLoc(), + move(Cond)); + if (CondE.isInvalid()) + return getSema().StmtError(); + Cond = move(CondE); + } } Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); + if (!S->getConditionVariable() && S->getCond() && !FullCond->get()) + return SemaRef.StmtError(); // Transform the body OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); @@ -3588,23 +3624,23 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { Body.get() == S->getBody()) return SemaRef.Owned(S->Retain()); - return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, ConditionVar, - move(Body)); + return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, + ConditionVar, move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformDoStmt(DoStmt *S) { - // Transform the condition - OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); - if (Cond.isInvalid()) - return SemaRef.StmtError(); - // Transform the body OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return SemaRef.StmtError(); + // Transform the condition + OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + if (!getDerived().AlwaysRebuild() && Cond.get() == S->getCond() && Body.get() == S->getBody()) @@ -3639,13 +3675,32 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + + if (S->getCond()) { + // Convert the condition to a boolean value. + OwningExprResult CondE = getSema().ActOnBooleanCondition(0, + S->getForLoc(), + move(Cond)); + if (CondE.isInvalid()) + return getSema().StmtError(); + + Cond = move(CondE); + } } + Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond)); + if (!S->getConditionVariable() && S->getCond() && !FullCond->get()) + return SemaRef.StmtError(); + // Transform the increment OwningExprResult Inc = getDerived().TransformExpr(S->getInc()); if (Inc.isInvalid()) return SemaRef.StmtError(); + Sema::FullExprArg FullInc(getSema().MakeFullExpr(Inc)); + if (S->getInc() && !FullInc->get()) + return SemaRef.StmtError(); + // Transform the body OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) @@ -3653,16 +3708,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (!getDerived().AlwaysRebuild() && Init.get() == S->getInit() && - Cond.get() == S->getCond() && + FullCond->get() == S->getCond() && Inc.get() == S->getInc() && Body.get() == S->getBody()) return SemaRef.Owned(S->Retain()); return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(), - move(Init), getSema().MakeFullExpr(Cond), - ConditionVar, - getSema().MakeFullExpr(Inc), - S->getRParenLoc(), move(Body)); + move(Init), FullCond, ConditionVar, + FullInc, S->getRParenLoc(), move(Body)); } template<typename Derived> @@ -5160,6 +5213,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { // transform the constructor arguments (if any). ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef); for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) { + if (getDerived().DropCallArgument(E->getConstructorArg(I))) + break; + OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I)); if (Arg.isInvalid()) return SemaRef.ExprError(); @@ -5855,7 +5911,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) R.resolveKind(); // Determine the naming class. - if (!Old->getNamingClass()) { + if (Old->getNamingClass()) { CXXRecordDecl *NamingClass = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( Old->getMemberLoc(), |