diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 115 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 34 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 21 |
3 files changed, 120 insertions, 50 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 7b16d63a48..bb732e2c9f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7945,52 +7945,85 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { } } -void Sema::CheckDelegatingCtorCycles() { - llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; +static +void DelegatingCycleHelper(CXXConstructorDecl* Ctor, + llvm::SmallSet<CXXConstructorDecl*, 4> &Valid, + llvm::SmallSet<CXXConstructorDecl*, 4> &Invalid, + llvm::SmallSet<CXXConstructorDecl*, 4> &Current, + Sema &S) { + llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), + CE = Current.end(); + if (Ctor->isInvalidDecl()) + return; - llvm::SmallSet<CXXConstructorDecl*, 4>::iterator ci = Current.begin(), - ce = Current.end(); + const FunctionDecl *FNTarget = 0; + CXXConstructorDecl *Target; + + // We ignore the result here since if we don't have a body, Target will be + // null below. + (void)Ctor->getTargetConstructor()->hasBody(FNTarget); + Target += const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget)); - for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator - i = DelegatingCtorDecls.begin(), - e = DelegatingCtorDecls.end(); - i != e; ++i) { - const FunctionDecl *FNTarget; - CXXConstructorDecl *Target; - (*i)->getTargetConstructor()->hasBody(FNTarget); - Target - = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget)); - - if (!Target || !Target->isDelegatingConstructor() || Valid.count(Target)) { - Valid.insert(*i); - for (ci = Current.begin(), ce = Current.end(); ci != ce; ++ci) - Valid.insert(*ci); - Current.clear(); - } else if (Target == *i || Invalid.count(Target) || Current.count(Target)) { - if (!Invalid.count(Target)) { - Diag((*(*i)->init_begin())->getSourceLocation(), + CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(), + // Avoid dereferencing a null pointer here. + *TCanonical = Target ? Target->getCanonicalDecl() : 0; + + if (!Current.insert(Canonical)) + return; + + // We know that beyond here, we aren't chaining into a cycle. + if (!Target || !Target->isDelegatingConstructor() || + Target->isInvalidDecl() || Valid.count(TCanonical)) { + for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) + Valid.insert(*CI); + Current.clear(); + // We've hit a cycle. + } else if (TCanonical == Canonical || Invalid.count(TCanonical) || + Current.count(TCanonical)) { + // If we haven't diagnosed this cycle yet, do so now. + if (!Invalid.count(TCanonical)) { + S.Diag((*Ctor->init_begin())->getSourceLocation(), diag::err_delegating_ctor_cycle) - << *i; - if (Target != *i) - Diag(Target->getLocation(), diag::note_it_delegates_to); - CXXConstructorDecl *Current = Target; - while (Current != *i) { - Current->getTargetConstructor()->hasBody(FNTarget); - Current - = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget)); - Diag(Current->getLocation(), diag::note_which_delegates_to); - } - } + << Ctor; + + // Don't add a note for a function delegating directo to itself. + if (TCanonical != Canonical) + S.Diag(Target->getLocation(), diag::note_it_delegates_to); + + CXXConstructorDecl *C = Target; + while (C->getCanonicalDecl() != Canonical) { + (void)C->getTargetConstructor()->hasBody(FNTarget); + assert(FNTarget && "Ctor cycle through bodiless function"); - (*i)->setInvalidDecl(); - Invalid.insert(*i); - for (ci = Current.begin(), ce = Current.end(); ci != ce; ++ci) { - (*ci)->setInvalidDecl(); - Invalid.insert(*i); + C + = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget)); + S.Diag(C->getLocation(), diag::note_which_delegates_to); } - Current.clear(); - } else { - Current.insert(*i); } + + for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) + Invalid.insert(*CI); + Current.clear(); + } else { + DelegatingCycleHelper(Target, Valid, Invalid, Current, S); + } +} + + +void Sema::CheckDelegatingCtorCycles() { + llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; + + llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), + CE = Current.end(); + + for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator + I = DelegatingCtorDecls.begin(), + E = DelegatingCtorDecls.end(); + I != E; ++I) { + DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); } + + for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) + (*CI)->setInvalidDecl(); } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 3227cfc457..45a771a472 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2114,15 +2114,6 @@ ASTReader::ReadASTBlock(PerFileData &F) { TotalVisibleDeclContexts += Record[3]; break; - case TENTATIVE_DEFINITIONS: - // Optimization for the first block. - if (TentativeDefinitions.empty()) - TentativeDefinitions.swap(Record); - else - TentativeDefinitions.insert(TentativeDefinitions.end(), - Record.begin(), Record.end()); - break; - case UNUSED_FILESCOPED_DECLS: // Optimization for the first block. if (UnusedFileScopedDecls.empty()) @@ -2132,6 +2123,15 @@ ASTReader::ReadASTBlock(PerFileData &F) { Record.begin(), Record.end()); break; + case DELEGATING_CTORS: + // Optimization for the first block. + if (DelegatingCtorDecls.empty()) + DelegatingCtorDecls.swap(Record); + else + DelegatingCtorDecls.insert(DelegatingCtorDecls.end(), + Record.begin(), Record.end()); + break; + case WEAK_UNDECLARED_IDENTIFIERS: // Later blocks overwrite earlier ones. WeakUndeclaredIdentifiers.swap(Record); @@ -2331,6 +2331,15 @@ ASTReader::ReadASTBlock(PerFileData &F) { // Later tables overwrite earlier ones. OpenCLExtensions.swap(Record); break; + + case TENTATIVE_DEFINITIONS: + // Optimization for the first block. + if (TentativeDefinitions.empty()) + TentativeDefinitions.swap(Record); + else + TentativeDefinitions.insert(TentativeDefinitions.end(), + Record.begin(), Record.end()); + break; } First = false; } @@ -4100,6 +4109,13 @@ void ASTReader::InitializeSema(Sema &S) { SemaObj->UnusedFileScopedDecls.push_back(D); } + // If there were any delegating constructors, add them to Sema's list + for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { + CXXConstructorDecl *D + = cast<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I])); + SemaObj->DelegatingCtorDecls.push_back(D); + } + // If there were any locally-scoped external declarations, // deserialize them and add them to Sema's table of locally-scoped // external declarations. diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 30b55c2591..be415015ee 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -764,6 +764,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(HEADER_SEARCH_TABLE); RECORD(FP_PRAGMA_OPTIONS); RECORD(OPENCL_EXTENSIONS); + RECORD(DELEGATING_CTORS); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -2723,6 +2724,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i) AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls); + RecordData DelegatingCtorDecls; + for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) + AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls); + RecordData WeakUndeclaredIdentifiers; if (!SemaRef.WeakUndeclaredIdentifiers.empty()) { WeakUndeclaredIdentifiers.push_back( @@ -2897,6 +2902,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the record containing CUDA-specific declaration references. if (!CUDASpecialDeclRefs.empty()) Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs); + + // Write the delegating constructors. + if (!DelegatingCtorDecls.empty()) + Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); // Some simple statistics Record.clear(); @@ -2971,6 +2980,14 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls); } + // Build a record containing all of the delegating constructor decls in this + // file. + RecordData DelegatingCtorDecls; + for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) { + if (SemaRef.DelegatingCtorDecls[i]->getPCHLevel() == 0) + AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls); + } + // We write the entire table, overwriting the tables from the chain. RecordData WeakUndeclaredIdentifiers; if (!SemaRef.WeakUndeclaredIdentifiers.empty()) { @@ -3128,6 +3145,10 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the record containing declaration references of Sema. if (!SemaDeclRefs.empty()) Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs); + + // Write the delegating constructors. + if (!DelegatingCtorDecls.empty()) + Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); // Write the updates to DeclContexts. for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator |