diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
commit | 4c8b24812ddcd1dedaca343a6d4e76f91f398981 (patch) | |
tree | 137ebebcae16fb0ce7ab4af456992bbd8d22fced /lib/Sema | |
parent | 5362a71c02e7d448a8ce98cf00c47e353fba5d04 (diff) |
Notes
Diffstat (limited to 'lib/Sema')
34 files changed, 25627 insertions, 9219 deletions
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 85c67df8f1de5..fd3265d874ce5 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -1,33 +1,33 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangSema + CodeCompleteConsumer.cpp IdentifierResolver.cpp JumpDiagnostics.cpp ParseAST.cpp Sema.cpp SemaAccess.cpp SemaAttr.cpp - SemaChecking.cpp + SemaCXXCast.cpp SemaCXXScopeSpec.cpp - SemaDeclAttr.cpp + SemaChecking.cpp + SemaCodeComplete.cpp SemaDecl.cpp + SemaDeclAttr.cpp SemaDeclCXX.cpp SemaDeclObjC.cpp + SemaExceptionSpec.cpp SemaExpr.cpp SemaExprCXX.cpp SemaExprObjC.cpp - SemaInherit.cpp SemaInit.cpp SemaLookup.cpp - SemaNamedCast.cpp SemaOverload.cpp SemaStmt.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp - SemaTemplateInstantiateExpr.cpp - SemaTemplateInstantiateStmt.cpp SemaType.cpp ) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp new file mode 100644 index 0000000000000..c78ab5b3e959e --- /dev/null +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -0,0 +1,184 @@ +//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the CodeCompleteConsumer class. +// +//===----------------------------------------------------------------------===// +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Parse/Scope.h" +#include "clang/Lex/Preprocessor.h" +#include "Sema.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstring> +#include <functional> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Code completion string implementation +//===----------------------------------------------------------------------===// +CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) + : Kind(Kind), Text(0) +{ + assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative) + && "Invalid text chunk kind"); + char *New = new char [std::strlen(Text) + 1]; + std::strcpy(New, Text); + this->Text = New; +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateText(const char *Text) { + return Chunk(CK_Text, Text); +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateOptional( + std::auto_ptr<CodeCompletionString> Optional) { + Chunk Result; + Result.Kind = CK_Optional; + Result.Optional = Optional.release(); + return Result; +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) { + return Chunk(CK_Placeholder, Placeholder); +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateInformative(const char *Informative) { + return Chunk(CK_Informative, Informative); +} + +void +CodeCompletionString::Chunk::Destroy() { + switch (Kind) { + case CK_Optional: + delete Optional; + break; + + case CK_Text: + case CK_Placeholder: + case CK_Informative: + delete [] Text; + break; + } +} + +CodeCompletionString::~CodeCompletionString() { + std::for_each(Chunks.begin(), Chunks.end(), + std::mem_fun_ref(&Chunk::Destroy)); +} + +std::string CodeCompletionString::getAsString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { + switch (C->Kind) { + case CK_Text: OS << C->Text; break; + case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; + case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; + case CK_Informative: OS << "[#" << C->Text << "#]"; break; + } + } + OS.flush(); + return Result; +} + +//===----------------------------------------------------------------------===// +// Code completion overload candidate implementation +//===----------------------------------------------------------------------===// +FunctionDecl * +CodeCompleteConsumer::OverloadCandidate::getFunction() const { + if (getKind() == CK_Function) + return Function; + else if (getKind() == CK_FunctionTemplate) + return FunctionTemplate->getTemplatedDecl(); + else + return 0; +} + +const FunctionType * +CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { + switch (Kind) { + case CK_Function: + return Function->getType()->getAs<FunctionType>(); + + case CK_FunctionTemplate: + return FunctionTemplate->getTemplatedDecl()->getType() + ->getAs<FunctionType>(); + + case CK_FunctionType: + return Type; + } + + return 0; +} + +//===----------------------------------------------------------------------===// +// Code completion consumer implementation +//===----------------------------------------------------------------------===// + +CodeCompleteConsumer::~CodeCompleteConsumer() { } + +void +PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, + unsigned NumResults) { + // Print the results. + for (unsigned I = 0; I != NumResults; ++I) { + OS << "COMPLETION: "; + switch (Results[I].Kind) { + case Result::RK_Declaration: + OS << Results[I].Declaration->getNameAsString() << " : " + << Results[I].Rank; + if (Results[I].Hidden) + OS << " (Hidden)"; + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + OS << " : " << CCS->getAsString(); + delete CCS; + } + + OS << '\n'; + break; + + case Result::RK_Keyword: + OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; + break; + } + } + + // Once we've printed the code-completion results, suppress remaining + // diagnostics. + // FIXME: Move this somewhere else! + SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); +} + +void +PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + for (unsigned I = 0; I != NumCandidates; ++I) { + if (CodeCompletionString *CCS + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { + OS << "OVERLOAD: " << CCS->getAsString() << "\n"; + 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/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index ceab859c90aa0..0dbf21961fe9f 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -32,7 +32,7 @@ class IdentifierResolver::IdDeclInfoMap { // New vectors are added when the current one is full. std::list< std::vector<IdDeclInfo> > IDIVecs; unsigned int CurIndex; - + public: IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {} @@ -75,7 +75,7 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) { assert(0 && "Didn't find this decl on its identifier's chain!"); } -bool +bool IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) { for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { if (Old == *(I-1)) { @@ -108,7 +108,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, if (Ctx->isFunctionOrMethod()) { // Ignore the scopes associated within transparent declaration contexts. - while (S->getEntity() && + while (S->getEntity() && ((DeclContext *)S->getEntity())->isTransparentContext()) S = S->getParent(); @@ -134,7 +134,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, return false; } - return D->getDeclContext()->getLookupContext() == Ctx->getPrimaryContext(); + return D->getDeclContext()->getLookupContext()->Equals(Ctx); } /// AddDecl - Link the decl to its shadowed decl chain. @@ -200,14 +200,14 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) { Name.setFETokenInfo(NULL); return; } - + return toIdDeclInfo(Ptr)->RemoveDecl(D); } bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) { - assert(Old->getDeclName() == New->getDeclName() && + assert(Old->getDeclName() == New->getDeclName() && "Cannot replace a decl with another decl of a different name"); - + DeclarationName Name = Old->getDeclName(); void *Ptr = Name.getFETokenInfo<void>(); @@ -222,7 +222,7 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) { return false; } - return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New); + return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New); } /// begin - Returns an iterator for decls with name 'Name'. @@ -243,7 +243,7 @@ IdentifierResolver::begin(DeclarationName Name) { return end(); } -void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II, +void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II, NamedDecl *D) { void *Ptr = II->getFETokenInfo<void>(); diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h index 0b0e6b388dde7..65f3256c2138f 100644 --- a/lib/Sema/IdentifierResolver.h +++ b/lib/Sema/IdentifierResolver.h @@ -99,7 +99,7 @@ public: assert(isIterator() && "Ptr not an iterator!"); return reinterpret_cast<BaseIter>(Ptr & ~0x3); } - + friend class IdentifierResolver; public: iterator() : Ptr(0) {} @@ -110,14 +110,14 @@ public: else return reinterpret_cast<NamedDecl*>(Ptr); } - + bool operator==(const iterator &RHS) const { return Ptr == RHS.Ptr; } bool operator!=(const iterator &RHS) const { return Ptr != RHS.Ptr; } - + // Preincrement. iterator& operator++() { if (!isIterator()) // common case. @@ -127,7 +127,7 @@ public: void *InfoPtr = D->getDeclName().getFETokenInfo<void>(); assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?"); IdDeclInfo *Info = toIdDeclInfo(InfoPtr); - + BaseIter I = getIterator(); if (I != Info->decls_begin()) *this = iterator(I-1); @@ -138,7 +138,7 @@ public: } uintptr_t getAsOpaqueValue() const { return Ptr; } - + static iterator getFromOpaqueValue(uintptr_t P) { iterator Result; Result.Ptr = P; diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index ae863f2df1ee1..a8e31d2cfa2b8 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -28,7 +28,7 @@ namespace { /// class JumpScopeChecker { Sema &S; - + /// GotoScope - This is a record that we use to keep track of all of the /// scopes that are introduced by VLAs and other things that scope jumps like /// gotos. This scope tree has nothing to do with the source scope tree, @@ -38,17 +38,17 @@ class JumpScopeChecker { /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for /// the parent scope is the function body. unsigned ParentScope; - + /// Diag - The diagnostic to emit if there is a jump into this scope. unsigned Diag; - + /// Loc - Location to emit the diagnostic. SourceLocation Loc; - + GotoScope(unsigned parentScope, unsigned diag, SourceLocation L) : ParentScope(parentScope), Diag(diag), Loc(L) {} }; - + llvm::SmallVector<GotoScope, 48> Scopes; llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; llvm::SmallVector<Stmt*, 16> Jumps; @@ -66,15 +66,15 @@ private: JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { // Add a scope entry for function scope. Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation())); - + // Build information for the top level compound statement, so that we have a // defined scope record for every "goto" and label. BuildScopeInformation(Body, 0); - + // Check that all jumps we saw are kosher. VerifyJumps(); } - + /// 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) { @@ -83,11 +83,13 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) { 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; } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) return diag::note_protected_by_vla_typedef; } - + return 0; } @@ -97,7 +99,7 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) { /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively /// walking the AST as needed. 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)) { LabelAndGotoScopes[S] = ParentScope; @@ -108,12 +110,12 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { LabelAndGotoScopes[S] = ParentScope; Jumps.push_back(S); } - + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) { Stmt *SubStmt = *CI; if (SubStmt == 0) continue; - + // FIXME: diagnose jumps past initialization: required in C++, warning in C. // goto L; int X = 4; L: ; @@ -129,7 +131,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation())); ParentScope = Scopes.size()-1; } - + // If the decl has an initializer, walk it with the potentially new // scope we just installed. if (VarDecl *VD = dyn_cast<VarDecl>(*I)) @@ -154,10 +156,10 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_catch, AC->getAtCatchLoc())); - // @catches are nested and it isn't + // @catches are nested and it isn't BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); } - + // Jump from the finally to the try or catch is not valid. if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { Scopes.push_back(GotoScope(ParentScope, @@ -165,17 +167,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { AF->getAtFinallyLoc())); BuildScopeInformation(AF, Scopes.size()-1); } - + continue; } - + // Disallow jumps into the protected statement of an @synchronized, but // allow jumps into the object expression it protects. if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ // Recursively walk the AST for the @synchronized object expr, it is // evaluated in the normal scope. BuildScopeInformation(AS->getSynchExpr(), ParentScope); - + // Recursively walk the AST for the @synchronized part, protected by a new // scope. Scopes.push_back(GotoScope(ParentScope, @@ -194,7 +196,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { BuildScopeInformation(TryBlock, Scopes.size()-1); // Jump from the catch into the try is not allowed either. - for(unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { + for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { CXXCatchStmt *CS = TS->getHandler(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_catch, @@ -215,14 +217,14 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { void JumpScopeChecker::VerifyJumps() { while (!Jumps.empty()) { Stmt *Jump = Jumps.pop_back_val(); - - // With a goto, + + // With a goto, if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { CheckJump(GS, GS->getLabel(), GS->getGotoLoc(), diag::err_goto_into_protected_scope); continue; } - + if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) { for (SwitchCase *SC = SS->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { @@ -234,7 +236,7 @@ void JumpScopeChecker::VerifyJumps() { } 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)) { @@ -252,12 +254,12 @@ void JumpScopeChecker::VerifyJumps() { // 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; } @@ -280,10 +282,10 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?"); unsigned ToScope = LabelAndGotoScopes[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. @@ -292,11 +294,11 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, // 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; } - + // 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); @@ -316,7 +318,7 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, FromScopes.pop_back(); ToScopes.pop_back(); } - + // 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); diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index e2ee88ac86bcb..d3f26d875cc4f 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -13,13 +13,15 @@ #include "clang/Sema/ParseAST.h" #include "Sema.h" +#include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Stmt.h" #include "clang/Parse/Parser.h" -#include "llvm/ADT/OwningPtr.h" +#include <cstdio> + using namespace clang; //===----------------------------------------------------------------------===// @@ -32,7 +34,9 @@ using namespace clang; /// void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, - bool CompleteTranslationUnit) { + bool CompleteTranslationUnit, + CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data), + void *CreateCodeCompleterData) { // Collect global stats on Decls/Stmts (until we have a module streamer). if (PrintStats) { Decl::CollectingStats(true); @@ -42,25 +46,31 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit); Parser P(PP, S); PP.EnterMainSourceFile(); - + // Initialize the parser. P.Initialize(); - + Consumer->Initialize(Ctx); - + if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer)) SC->InitializeSema(S); if (ExternalASTSource *External = Ctx.getExternalSource()) { - if (ExternalSemaSource *ExternalSema = + if (ExternalSemaSource *ExternalSema = dyn_cast<ExternalSemaSource>(External)) ExternalSema->InitializeSema(S); External->StartTranslationUnit(Consumer); } - Parser::DeclGroupPtrTy ADecl; + CodeCompleteConsumer *CodeCompleter = 0; + if (CreateCodeCompleter) { + CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData); + S.setCodeCompleteConsumer(CodeCompleter); + } + Parser::DeclGroupPtrTy ADecl; + while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. // If we got a null return and something *was* parsed, ignore it. This // is due to a top-level semicolon, an action override, or a parse error @@ -68,9 +78,18 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, if (ADecl) Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>()); }; - + + // process any TopLevelDecls generated by #pragma weak + for (llvm::SmallVector<Decl*,2>::iterator + I = S.WeakTopLevelDecls().begin(), + E = S.WeakTopLevelDecls().end(); I != E; ++I) + Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); + Consumer->HandleTranslationUnit(Ctx); + if (CreateCodeCompleter) + delete CodeCompleter; + if (PrintStats) { fprintf(stderr, "\nSTATISTICS:\n"); P.getActions().PrintStats(); @@ -78,7 +97,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Decl::PrintStats(); Stmt::PrintStats(); Consumer->PrintStats(); - + Decl::CollectingStats(false); Stmt::CollectingStats(false); } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index d1e8e2104d50f..ba05a07f26540 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -13,15 +13,65 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "llvm/ADT/DenseMap.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" using namespace clang; -/// ConvertQualTypeToStringFn - This function is used to pretty print the +/// \brief Convert the given type to a string suitable for printing as part of +/// a diagnostic. +/// +/// \param Context the context in which the type was allocated +/// \param Ty the type to print +static std::string ConvertTypeToDiagnosticString(ASTContext &Context, + QualType Ty) { + // FIXME: Playing with std::string is really slow. + std::string S = Ty.getAsString(Context.PrintingPolicy); + + // If this is a sugared type (like a typedef, typeof, etc), then unwrap one + // level of the sugar so that the type is more obvious to the user. + QualType DesugaredTy = Ty.getDesugaredType(); + + if (Ty != DesugaredTy && + // If the desugared type is a vector type, we don't want to expand it, + // it will turn into an attribute mess. People want their "vec4". + !isa<VectorType>(DesugaredTy) && + + // Don't aka just because we saw an elaborated type... + (!isa<ElaboratedType>(Ty) || + cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) && + + // ...or a qualified name type... + (!isa<QualifiedNameType>(Ty) || + cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) && + + // ...or a non-dependent template specialization. + (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) && + + // Don't desugar magic Objective-C types. + Ty.getUnqualifiedType() != Context.getObjCIdType() && + Ty.getUnqualifiedType() != Context.getObjCClassType() && + Ty.getUnqualifiedType() != Context.getObjCSelType() && + Ty.getUnqualifiedType() != Context.getObjCProtoType() && + + // Not va_list. + Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { + S = "'"+S+"' (aka '"; + S += DesugaredTy.getAsString(Context.PrintingPolicy); + S += "')"; + return S; + } + + S = "'" + S + "'"; + return S; +} + +/// ConvertQualTypeToStringFn - This function is used to pretty print the /// specified QualType as a string in diagnostics. static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModLen, @@ -29,48 +79,21 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, llvm::SmallVectorImpl<char> &Output, void *Cookie) { ASTContext &Context = *static_cast<ASTContext*>(Cookie); - + std::string S; + bool NeedQuotes = true; if (Kind == Diagnostic::ak_qualtype) { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for QualType argument"); QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); - - // FIXME: Playing with std::string is really slow. - S = Ty.getAsString(Context.PrintingPolicy); - - // If this is a sugared type (like a typedef, typeof, etc), then unwrap one - // level of the sugar so that the type is more obvious to the user. - QualType DesugaredTy = Ty->getDesugaredType(true); - DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() | - Ty.getCVRQualifiers()); - - if (Ty != DesugaredTy && - // If the desugared type is a vector type, we don't want to expand it, - // it will turn into an attribute mess. People want their "vec4". - !isa<VectorType>(DesugaredTy) && - - // Don't desugar magic Objective-C types. - Ty.getUnqualifiedType() != Context.getObjCIdType() && - Ty.getUnqualifiedType() != Context.getObjCSelType() && - Ty.getUnqualifiedType() != Context.getObjCProtoType() && - Ty.getUnqualifiedType() != Context.getObjCClassType() && - - // Not va_list. - Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { - S = "'"+S+"' (aka '"; - S += DesugaredTy.getAsString(Context.PrintingPolicy); - S += "')"; - Output.append(S.begin(), S.end()); - return; - } - + S = ConvertTypeToDiagnosticString(Context, Ty); + NeedQuotes = false; } else if (Kind == Diagnostic::ak_declarationname) { - + DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); S = N.getAsString(); - + if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) S = '+' + S; else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0) @@ -78,30 +101,73 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, else assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - } else { - assert(Kind == Diagnostic::ak_nameddecl); + } else if (Kind == Diagnostic::ak_nameddecl) { + bool Qualified; if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) - S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString(); - else { + Qualified = true; + else { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for NamedDecl* argument"); - S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString(); + Qualified = false; + } + reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S, + Context.PrintingPolicy, + Qualified); + } else if (Kind == Diagnostic::ak_nestednamespec) { + llvm::raw_string_ostream OS(S); + reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS, + Context.PrintingPolicy); + NeedQuotes = false; + } else { + assert(Kind == Diagnostic::ak_declcontext); + DeclContext *DC = reinterpret_cast<DeclContext *> (Val); + NeedQuotes = false; + if (!DC) { + assert(false && "Should never have a null declaration context"); + S = "unknown context"; + } else if (DC->isTranslationUnit()) { + // FIXME: Get these strings from some localized place + if (Context.getLangOptions().CPlusPlus) + S = "the global namespace"; + else + S = "the global scope"; + } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { + S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type)); + NeedQuotes = false; + } else { + // FIXME: Get these strings from some localized place + NamedDecl *ND = cast<NamedDecl>(DC); + if (isa<NamespaceDecl>(ND)) + S += "namespace "; + else if (isa<ObjCMethodDecl>(ND)) + S += "method "; + else if (isa<FunctionDecl>(ND)) + S += "function "; + + S += "'"; + ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); + S += "'"; + NeedQuotes = false; } } + + if (NeedQuotes) + Output.push_back('\''); - Output.push_back('\''); Output.append(S.begin(), S.end()); - Output.push_back('\''); + + if (NeedQuotes) + Output.push_back('\''); } static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { if (C.getLangOptions().CPlusPlus) - return CXXRecordDecl::Create(C, TagDecl::TK_struct, + return CXXRecordDecl::Create(C, TagDecl::TK_struct, C.getTranslationUnitDecl(), SourceLocation(), &C.Idents.get(Name)); - return RecordDecl::Create(C, TagDecl::TK_struct, + return RecordDecl::Create(C, TagDecl::TK_struct, C.getTranslationUnitDecl(), SourceLocation(), &C.Idents.get(Name)); } @@ -109,7 +175,7 @@ static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); - + if (PP.getTargetInfo().getPointerWidth(0) >= 64) { // Install [u]int128_t for 64-bit targets. PushOnScopeChains(TypedefDecl::Create(Context, CurContext, @@ -121,16 +187,16 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { &Context.Idents.get("__uint128_t"), Context.UnsignedInt128Ty), TUScope); } - - + + if (!PP.getLangOptions().ObjC1) return; - + // Built-in ObjC types may already be set by PCHReader (hence isNull checks). if (Context.getObjCSelType().isNull()) { // Synthesize "typedef struct objc_selector *SEL;" RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector"); PushOnScopeChains(SelTag, TUScope); - + QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), @@ -140,74 +206,72 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); } - if (Context.getObjCClassType().isNull()) { - RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class"); - QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); - TypedefDecl *ClassTypedef = - TypedefDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Class"), ClassT); - PushOnScopeChains(ClassTag, TUScope); - PushOnScopeChains(ClassTypedef, TUScope); - Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); - } - // Synthesize "@class Protocol; if (Context.getObjCProtoType().isNull()) { ObjCInterfaceDecl *ProtocolDecl = ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Protocol"), + &Context.Idents.get("Protocol"), SourceLocation(), true); Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); PushOnScopeChains(ProtocolDecl, TUScope); } - - // Synthesize "typedef struct objc_object { Class isa; } *id;" + // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { - RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object"); - - QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); - PushOnScopeChains(ObjectTag, TUScope); - TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, - SourceLocation(), - &Context.Idents.get("id"), - ObjT); + TypedefDecl *IdTypedef = + TypedefDecl::Create( + Context, CurContext, SourceLocation(), &Context.Idents.get("id"), + Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy) + ); PushOnScopeChains(IdTypedef, TUScope); Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); + Context.ObjCIdRedefinitionType = Context.getObjCIdType(); + } + // Create the built-in typedef for 'Class'. + if (Context.getObjCClassType().isNull()) { + TypedefDecl *ClassTypedef = + TypedefDecl::Create( + Context, CurContext, SourceLocation(), &Context.Idents.get("Class"), + Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy) + ); + PushOnScopeChains(ClassTypedef, TUScope); + Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); + Context.ObjCClassRedefinitionType = Context.getObjCClassType(); } } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit) : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), - Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - ExternalSource(0), CurContext(0), PreDeclaratorDC(0), - CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()), + Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), + ExternalSource(0), CodeCompleter(0), CurContext(0), + PreDeclaratorDC(0), CurBlock(0), PackContext(0), + IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), CurrentInstantiationScope(0) { - - StdNamespace = 0; + TUScope = 0; if (getLangOptions().CPlusPlus) FieldCollector.reset(new CXXFieldCollector()); - + // Tell diagnostics how to render things from the AST library. PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context); } -/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. +/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. -void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) { +void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, + CastExpr::CastKind Kind, bool isLvalue) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); - + if (ExprTy == TypeTy) return; - + if (Expr->getType().getTypePtr()->isPointerType() && Ty.getTypePtr()->isPointerType()) { - QualType ExprBaseType = + QualType ExprBaseType = cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType(); QualType BaseType = cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType(); @@ -216,12 +280,16 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) { << Expr->getSourceRange(); } } - + if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { - ImpCast->setType(Ty); - ImpCast->setLvalueCast(isLvalue); - } else - Expr = new (Context) ImplicitCastExpr(Ty, Expr, isLvalue); + if (ImpCast->getCastKind() == Kind) { + ImpCast->setType(Ty); + ImpCast->setLvalueCast(isLvalue); + return; + } + } + + Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue); } void Sema::DeleteExpr(ExprTy *E) { @@ -241,12 +309,24 @@ void Sema::ActOnEndOfTranslationUnit() { // keep track of the point of instantiation (C++ [temp.point]). This means // that name lookup that occurs within the template instantiation will // always happen at the end of the translation unit, so it will find - // some names that should not be found. Although this is common behavior + // some names that should not be found. Although this is common behavior // for C++ compilers, it is technically wrong. In the future, we either need // to be able to filter the results of name lookup or we need to perform // template instantiations earlier. PerformPendingImplicitInstantiations(); - + + // Check for #pragma weak identifiers that were never declared + // FIXME: This will cause diagnostics to be emitted in a non-determinstic + // order! Iterating over a densemap like this is bad. + for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator + I = WeakUndeclaredIdentifiers.begin(), + E = WeakUndeclaredIdentifiers.end(); I != E; ++I) { + if (I->second.getUsed()) continue; + + Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared) + << I->first; + } + if (!CompleteTranslationUnit) return; @@ -261,32 +341,31 @@ void Sema::ActOnEndOfTranslationUnit() { // translation unit contains a file scope declaration of that // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. - for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator - D = TentativeDefinitions.begin(), - DEnd = TentativeDefinitions.end(); - D != DEnd; ++D) { - VarDecl *VD = D->second; + for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) { + VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]); - if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context)) + // If the tentative definition was completed, it will be in the list, but + // not the map. + if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context)) continue; - if (const IncompleteArrayType *ArrayT + if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(VD->getType())) { - if (RequireCompleteType(VD->getLocation(), + if (RequireCompleteType(VD->getLocation(), ArrayT->getElementType(), - diag::err_tentative_def_incomplete_type_arr)) + diag::err_tentative_def_incomplete_type_arr)) { VD->setInvalidDecl(); - else { - // Set the length of the array to 1 (C99 6.9.2p5). - Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); - llvm::APInt One(Context.getTypeSize(Context.getSizeType()), - true); - QualType T - = Context.getConstantArrayType(ArrayT->getElementType(), - One, ArrayType::Normal, 0); - VD->setType(T); + continue; } - } else if (RequireCompleteType(VD->getLocation(), VD->getType(), + + // Set the length of the array to 1 (C99 6.9.2p5). + Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); + llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); + QualType T + = Context.getConstantArrayWithoutExprType(ArrayT->getElementType(), + One, ArrayType::Normal, 0); + VD->setType(T); + } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); @@ -302,27 +381,30 @@ void Sema::ActOnEndOfTranslationUnit() { // Helper functions. //===----------------------------------------------------------------------===// +DeclContext *Sema::getFunctionLevelDeclContext() { + DeclContext *DC = PreDeclaratorDC ? PreDeclaratorDC : CurContext; + + while (isa<BlockDecl>(DC)) + DC = DC->getParent(); + + return DC; +} + /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. FunctionDecl *Sema::getCurFunctionDecl() { - DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) - DC = DC->getParent(); + DeclContext *DC = getFunctionLevelDeclContext(); return dyn_cast<FunctionDecl>(DC); } ObjCMethodDecl *Sema::getCurMethodDecl() { - DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) - DC = DC->getParent(); + DeclContext *DC = getFunctionLevelDeclContext(); return dyn_cast<ObjCMethodDecl>(DC); } NamedDecl *Sema::getCurFunctionOrMethodDecl() { - DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) - DC = DC->getParent(); + DeclContext *DC = getFunctionLevelDeclContext(); if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC)) return cast<NamedDecl>(DC); return 0; @@ -331,21 +413,30 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { if (!this->Emit()) return; - + // If this is not a note, and we're in a template instantiation // that is different from the last template instantiation where // we emitted an error, print a template instantiation // backtrace. if (!SemaRef.Diags.isBuiltinNote(DiagID) && !SemaRef.ActiveTemplateInstantiations.empty() && - SemaRef.ActiveTemplateInstantiations.back() + SemaRef.ActiveTemplateInstantiations.back() != SemaRef.LastTemplateInstantiationErrorContext) { SemaRef.PrintInstantiationStack(); - SemaRef.LastTemplateInstantiationErrorContext + SemaRef.LastTemplateInstantiationErrorContext = SemaRef.ActiveTemplateInstantiations.back(); } } +Sema::SemaDiagnosticBuilder +Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { + SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID())); + PD.Emit(Builder); + + return Builder; +} + void Sema::ActOnComment(SourceRange Comment) { Context.Comments.push_back(Comment); } + diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 7af80c0261e4d..80f366302171b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -18,6 +18,7 @@ #include "IdentifierResolver.h" #include "CXXFieldCollector.h" #include "SemaOverload.h" +#include "SemaTemplate.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclBase.h" #include "clang/AST/Decl.h" @@ -41,6 +42,7 @@ namespace llvm { namespace clang { class ASTContext; class ASTConsumer; + class CodeCompleteConsumer; class Preprocessor; class Decl; class DeclContext; @@ -50,6 +52,7 @@ namespace clang { class Stmt; class Expr; class InitListExpr; + class ParenListExpr; class DesignatedInitExpr; class CallExpr; class DeclRefExpr; @@ -87,8 +90,7 @@ namespace clang { class ObjCPropertyDecl; class ObjCContainerDecl; class FunctionProtoType; - class BasePaths; - struct MemberLookupCriteria; + class CXXBasePaths; class CXXTemporary; /// BlockSemaInfo - When a block is being parsed, this contains information @@ -98,35 +100,69 @@ struct BlockSemaInfo { bool hasPrototype; bool isVariadic; bool hasBlockDeclRefExprs; - + BlockDecl *TheDecl; - + /// TheScope - This is the scope for the block itself, which contains /// arguments etc. Scope *TheScope; - + /// ReturnType - This will get set to block result type, by looking at /// return types, if any, in the block body. QualType ReturnType; - + /// LabelMap - This is a mapping from label identifiers to the LabelStmt for /// it (which acts like the label decl in some ways). Forward referenced /// labels have a LabelStmt created for them with a null location & SubStmt. llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap; - + /// SwitchStack - This is the current set of active switch statements in the /// block. llvm::SmallVector<SwitchStmt*, 8> SwitchStack; - + /// SavedFunctionNeedsScopeChecking - This is the value of /// CurFunctionNeedsScopeChecking at the point when the block started. bool SavedFunctionNeedsScopeChecking; - + /// PrevBlockInfo - If this is nested inside another block, this points /// to the outer block. BlockSemaInfo *PrevBlockInfo; }; +/// \brief Holds a QualType and a DeclaratorInfo* that came out of a declarator +/// parsing. +/// +/// LocInfoType is a "transient" type, only needed for passing to/from Parser +/// and Sema, when we want to preserve type source info for a parsed type. +/// It will not participate in the type system semantics in any way. +class LocInfoType : public Type { + enum { + // The last number that can fit in Type's TC. + // Avoids conflict with an existing Type class. + LocInfo = (1 << TypeClassBitSize) - 1 + }; + + DeclaratorInfo *DeclInfo; + + LocInfoType(QualType ty, DeclaratorInfo *DInfo) + : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(DInfo) { + assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); + } + friend class Sema; + +public: + QualType getType() const { return getCanonicalTypeInternal(); } + DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; } + + virtual void getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == (TypeClass)LocInfo; + } + static bool classof(const LocInfoType *) { return true; } +}; + /// Sema - This implements semantic analysis and AST building for C. class Sema : public Action { Sema(const Sema&); // DO NOT IMPLEMENT @@ -142,6 +178,9 @@ public: /// \brief Source of additional semantic information. ExternalSemaSource *ExternalSource; + /// \brief Code-completion consumer. + CodeCompleteConsumer *CodeCompleter; + /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; @@ -165,13 +204,13 @@ public: /// Note that this should always be accessed through getLabelMap() in order /// to handle blocks properly. llvm::DenseMap<IdentifierInfo*, LabelStmt*> FunctionLabelMap; - + /// FunctionSwitchStack - This is the current set of active switch statements /// in the top level function. Clients should always use getSwitchStack() to /// handle the case when they are in a block. llvm::SmallVector<SwitchStmt*, 8> FunctionSwitchStack; - /// ExprTemporaries - This is the stack of temporaries that are created by + /// ExprTemporaries - This is the stack of temporaries that are created by /// the current full expression. llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries; @@ -180,26 +219,22 @@ public: /// scopes that need to be checked for goto conditions. If a function does /// not contain this, then it need not have the jump checker run on it. bool CurFunctionNeedsScopeChecking; - + /// ExtVectorDecls - This is a list all the extended vector types. This allows /// us to associate a raw vector type with one of the ext_vector type names. /// This is only necessary for issuing pretty diagnostics. llvm::SmallVector<TypedefDecl*, 24> ExtVectorDecls; - /// ObjCCategoryImpls - Maintain a list of category implementations so - /// we can check for duplicates and find local method declarations. - llvm::SmallVector<ObjCCategoryImplDecl*, 8> ObjCCategoryImpls; - /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. llvm::OwningPtr<CXXFieldCollector> FieldCollector; typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy; - - /// PureVirtualClassDiagSet - a set of class declarations which we have + + /// PureVirtualClassDiagSet - a set of class declarations which we have /// emitted a list of pure virtual functions. Used to prevent emitting the /// same list more than once. llvm::OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet; - + /// \brief A mapping from external names to the most recent /// locally-scoped external declaration with that name. /// @@ -234,6 +269,37 @@ public: /// declaration, and only the most recent tentative declaration for /// a given variable will be recorded here. llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions; + std::vector<DeclarationName> TentativeDefinitionList; + + /// WeakUndeclaredIdentifiers - Identifiers contained in + /// #pragma weak before declared. rare. may alias another + /// identifier, declared or undeclared + class WeakInfo { + IdentifierInfo *alias; // alias (optional) + SourceLocation loc; // for diagnostics + bool used; // identifier later declared? + public: + WeakInfo() + : alias(0), loc(SourceLocation()), used(false) {} + WeakInfo(IdentifierInfo *Alias, SourceLocation Loc) + : alias(Alias), loc(Loc), used(false) {} + inline IdentifierInfo * getAlias() const { return alias; } + inline SourceLocation getLocation() const { return loc; } + void setUsed(bool Used=true) { used = Used; } + inline bool getUsed() { return used; } + bool operator==(WeakInfo RHS) const { + return alias == RHS.getAlias() && loc == RHS.getLocation(); + } + bool operator!=(WeakInfo RHS) const { return !(*this == RHS); } + }; + llvm::DenseMap<IdentifierInfo*,WeakInfo> WeakUndeclaredIdentifiers; + + /// WeakTopLevelDecl - Translation-unit scoped declarations generated by + /// #pragma weak during processing of other Decls. + /// I couldn't figure out a clean way to generate these in-line, so + /// we store them here and handle separately -- which is a hack. + /// It would be best to refactor this. + llvm::SmallVector<Decl*,2> WeakTopLevelDecl; IdentifierResolver IdResolver; @@ -242,27 +308,30 @@ public: /// For example, user-defined classes, built-in "id" type, etc. Scope *TUScope; - /// The C++ "std" namespace, where the standard library resides. Cached here - /// by GetStdNamespace + /// \brief The C++ "std" namespace, where the standard library resides. NamespaceDecl *StdNamespace; + /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ + /// standard library. + CXXRecordDecl *StdBadAlloc; + /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// The current expression evaluation context. ExpressionEvaluationContext ExprEvalContext; - - typedef std::vector<std::pair<SourceLocation, Decl *> > + + typedef std::vector<std::pair<SourceLocation, Decl *> > PotentiallyReferencedDecls; - + /// A stack of declarations, each element of which is a set of declarations /// that will be marked as referenced if the corresponding potentially /// potentially evaluated expression is potentially evaluated. Each element /// in the stack corresponds to a PotentiallyPotentiallyEvaluated expression /// evaluation context. std::list<PotentiallyReferencedDecls> PotentiallyReferencedDeclStack; - + /// \brief Whether the code handled by Sema should be considered a /// complete translation unit or not. /// @@ -274,6 +343,8 @@ public: /// unit. bool CompleteTranslationUnit; + llvm::BumpPtrAllocator BumpAlloc; + /// \brief The number of SFINAE diagnostics that have been trapped. unsigned NumSFINAEErrors; @@ -281,11 +352,11 @@ public: /// Instance/Factory Method Pools - allows efficient lookup when typechecking /// messages to "id". We need to maintain a list, since selectors can have - /// differing signatures across classes. In Cocoa, this happens to be + /// differing signatures across classes. In Cocoa, this happens to be /// extremely uncommon (only 1% of selectors are "overloaded"). MethodPool InstanceMethodPool; MethodPool FactoryMethodPool; - + MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance); /// Private Helper predicate to check for 'self'. @@ -296,7 +367,7 @@ public: ~Sema() { if (PackContext) FreePackedContext(); } - + const LangOptions &getLangOptions() const { return LangOpts; } Diagnostic &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } @@ -318,7 +389,7 @@ public: SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } - explicit SemaDiagnosticBuilder(Sema &SemaRef) + explicit SemaDiagnosticBuilder(Sema &SemaRef) : DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { } ~SemaDiagnosticBuilder(); @@ -331,6 +402,7 @@ public: // deduction, and that error is one of the SFINAE errors, // suppress the diagnostic. ++NumSFINAEErrors; + Diags.setLastDiagnosticIgnored(); return SemaDiagnosticBuilder(*this); } @@ -338,6 +410,9 @@ public: return SemaDiagnosticBuilder(DB, *this, DiagID); } + /// \brief Emit a partial diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); + virtual void DeleteExpr(ExprTy *E); virtual void DeleteStmt(StmtTy *S); @@ -356,13 +431,16 @@ public: llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() { return CurBlock ? CurBlock->LabelMap : FunctionLabelMap; } - + /// getSwitchStack - This is returns the switch stack for the current block or /// function. llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() { return CurBlock ? CurBlock->SwitchStack : FunctionSwitchStack; } - + + /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls + llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } + virtual void ActOnComment(SourceRange Comment); //===--------------------------------------------------------------------===// @@ -370,34 +448,51 @@ public: // QualType adjustParameterType(QualType T); QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &IsInvalid); + bool &IsInvalid, QualType &SourceTy); void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); - QualType BuildPointerType(QualType T, unsigned Quals, + QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, SourceLocation Loc, DeclarationName Entity); QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, - SourceLocation Loc, DeclarationName Entity); - QualType BuildExtVectorType(QualType T, ExprArg ArraySize, + SourceRange Brackets, DeclarationName Entity); + QualType BuildExtVectorType(QualType T, ExprArg ArraySize, SourceLocation AttrLoc); QualType BuildFunctionType(QualType T, QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, SourceLocation Loc, DeclarationName Entity); - QualType BuildMemberPointerType(QualType T, QualType Class, - unsigned Quals, SourceLocation Loc, + QualType BuildMemberPointerType(QualType T, QualType Class, + unsigned Quals, SourceLocation Loc, DeclarationName Entity); QualType BuildBlockPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); - QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0, - TagDecl **OwnedDecl = 0); + QualType GetTypeForDeclarator(Declarator &D, Scope *S, + DeclaratorInfo **DInfo = 0, + unsigned Skip = 0, TagDecl **OwnedDecl = 0); + DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, + unsigned Skip); + /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. + QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo); DeclarationName GetNameForDeclarator(Declarator &D); + static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); + bool CheckEquivalentExceptionSpec( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc); + bool CheckExceptionSpecSubset( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Superset, SourceLocation SuperLoc, + const FunctionProtoType *Subset, SourceLocation SubLoc); + bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID, + const FunctionProtoType *Target, SourceLocation TargetLoc, + const FunctionProtoType *Source, SourceLocation SourceLoc); QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D); @@ -405,72 +500,87 @@ public: virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); - bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, - SourceRange Range1 = SourceRange(), - SourceRange Range2 = SourceRange(), - QualType PrintType = QualType()); + bool RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD, + std::pair<SourceLocation, + PartialDiagnostic> Note = + std::make_pair(SourceLocation(), PDiag())); QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E); QualType BuildDecltypeType(Expr *E); - + //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // /// getDeclName - Return a pretty name for the specified decl if possible, or - /// an empty string if not. This is used for pretty crash reporting. + /// an empty string if not. This is used for pretty crash reporting. virtual std::string getDeclName(DeclPtrTy D); - + DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr); - virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS); + virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec *SS, + bool isClassName = false); virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); + virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TypeTy *&SuggestedType); virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); } - - DeclPtrTy HandleDeclarator(Scope *S, Declarator &D, + + DeclPtrTy HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, bool IsFunctionDefinition); void RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl, Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, Decl* PrevDecl, - bool &Redeclaration); + QualType R, DeclaratorInfo *DInfo, + NamedDecl* PrevDecl, bool &Redeclaration); NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, NamedDecl* PrevDecl, + QualType R, DeclaratorInfo *DInfo, + NamedDecl* PrevDecl, + MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration); void CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, bool &Redeclaration); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, NamedDecl* PrevDecl, + QualType R, DeclaratorInfo *DInfo, + NamedDecl* PrevDecl, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration); void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, - bool &Redeclaration, + bool IsExplicitSpecialization, + bool &Redeclaration, bool &OverloadableAttrRequired); + void CheckMain(FunctionDecl *FD); virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); virtual void ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, ExprArg defarg); - virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, + virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, SourceLocation ArgLoc); virtual void ActOnParamDefaultArgumentError(DeclPtrTy param); - + bool SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, + SourceLocation EqualLoc); + + // Contains the locations of the beginning of unparsed default // argument locations. llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs; - virtual void AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init); + virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init); void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit); - void ActOnUninitializedDecl(DeclPtrTy dcl); + void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto); virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc); virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, DeclPtrTy *Group, @@ -484,19 +594,19 @@ public: virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body); DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body, bool IsInstantiation); - + /// \brief Diagnose any unused parameters in the given sequence of /// ParmVarDecl pointers. template<typename InputIterator> void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) { for (; Param != ParamEnd; ++Param) { - if (!(*Param)->isUsed() && (*Param)->getDeclName() && + if (!(*Param)->isUsed() && (*Param)->getDeclName() && !(*Param)->template hasAttr<UnusedAttr>()) Diag((*Param)->getLocation(), diag::warn_unused_parameter) << (*Param)->getDeclName(); } } - + void DiagnoseInvalidJumps(Stmt *Body); virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr); @@ -507,23 +617,32 @@ 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); - + bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, RecordDecl *AnonRecord); - virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, RecordDecl *Record); - bool isAcceptableTagRedeclaration(const TagDecl *Previous, + bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagDecl::TagKind NewTag, SourceLocation NewTagLoc, const IdentifierInfo &Name); - virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, + virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, - bool &OwnedDecl); - + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent); + + virtual TypeResult ActOnDependentTag(Scope *S, + unsigned TagSpec, + TagUseKind TUK, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation TagLoc, + SourceLocation NameLoc); + virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl<DeclPtrTy> &Decls); @@ -535,12 +654,22 @@ public: Declarator &D, Expr *BitfieldWidth, AccessSpecifier AS); - FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, + FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, + DeclaratorInfo *DInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, + SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D = 0); - + + enum CXXSpecialMember { + CXXDefaultConstructor = 0, + CXXCopyConstructor = 1, + CXXCopyAssignment = 2, + CXXDestructor = 3 + }; + void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem); + virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, DeclPtrTy IntfDecl, Declarator &D, ExprTy *BitfieldWidth, @@ -560,7 +689,8 @@ public: /// ActOnTagFinishDefinition - Invoked once we have finished parsing /// the definition of a tag (enumeration, class, struct, or union). - virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl); + virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl, + SourceLocation RBraceLoc); EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, @@ -574,25 +704,27 @@ public: SourceLocation EqualLoc, ExprTy *Val); virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, DeclPtrTy EnumDecl, - DeclPtrTy *Elements, unsigned NumElements); + DeclPtrTy *Elements, unsigned NumElements, + Scope *S, AttributeList *Attr); DeclContext *getContainingDC(DeclContext *DC); /// Set the current declaration context until it gets popped. void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); - + /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. void EnterDeclaratorContext(Scope *S, DeclContext *DC); void ExitDeclaratorContext(Scope *S); - - + + DeclContext *getFunctionLevelDeclContext(); + /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. FunctionDecl *getCurFunctionDecl(); - + /// getCurMethodDecl - If inside of a method body, this returns a pointer to /// the method decl for the method being parsed. If we're currently /// in a 'block', this returns the containing context. @@ -604,15 +736,35 @@ public: NamedDecl *getCurFunctionOrMethodDecl(); /// Add this decl to the scope shadowed decl chains. - void PushOnScopeChains(NamedDecl *D, Scope *S); + void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. - bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) { - return IdResolver.isDeclInScope(D, Ctx, Context, S); + bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0); + + /// Finds the scope corresponding to the given decl context, if it + /// happens to be an enclosing scope. Otherwise return NULL. + Scope *getScopeForDeclContext(Scope *S, DeclContext *DC) { + DeclContext *TargetDC = DC->getPrimaryContext(); + do { + if (DeclContext *ScopeDC = (DeclContext*) S->getEntity()) + if (ScopeDC->getPrimaryContext() == TargetDC) + return S; + } while ((S = S->getParent())); + + return NULL; } + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + OR_Success, ///< Overload resolution succeeded. + OR_No_Viable_Function, ///< No viable function found. + OR_Ambiguous, ///< Ambiguous candidates found. + OR_Deleted ///< Overload resoltuion refers to a deleted function. + }; + /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T); @@ -623,41 +775,52 @@ public: bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); /// C++ Overloading. - bool IsOverload(FunctionDecl *New, Decl* OldD, + bool IsOverload(FunctionDecl *New, Decl* OldD, OverloadedFunctionDecl::function_iterator &MatchedDecl); - ImplicitConversionSequence + ImplicitConversionSequence TryImplicitConversion(Expr* From, QualType ToType, - bool SuppressUserConversions = false, - bool AllowExplicit = false, - bool ForceRValue = false); - bool IsStandardConversion(Expr *From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, + bool ForceRValue, + bool InOverloadResolution, + bool UserCast = false); + bool IsStandardConversion(Expr *From, QualType ToType, + bool InOverloadResolution, StandardConversionSequence& SCS); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); bool IsComplexPromotion(QualType FromType, QualType ToType); bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); - bool CheckPointerConversion(Expr *From, QualType ToType); + bool CheckPointerConversion(Expr *From, QualType ToType, + CastExpr::CastKind &Kind); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, QualType &ConvertedType); - bool CheckMemberPointerConversion(Expr *From, QualType ToType); + bool CheckMemberPointerConversion(Expr *From, QualType ToType, + CastExpr::CastKind &Kind); bool IsQualificationConversion(QualType FromType, QualType ToType); - bool IsUserDefinedConversion(Expr *From, QualType ToType, + OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType, UserDefinedConversionSequence& User, + OverloadCandidateSet& Conversions, bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue); + bool AllowExplicit, bool ForceRValue, + bool UserCast = false); + bool DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType); + - ImplicitConversionSequence::CompareKind + ImplicitConversionSequence::CompareKind CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, const ImplicitConversionSequence& ICS2); - ImplicitConversionSequence::CompareKind + ImplicitConversionSequence::CompareKind CompareStandardConversionSequences(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2); - ImplicitConversionSequence::CompareKind + ImplicitConversionSequence::CompareKind CompareQualificationConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2); @@ -665,11 +828,11 @@ public: CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2); - ImplicitConversionSequence + ImplicitConversionSequence TryCopyInitialization(Expr* From, QualType ToType, - bool SuppressUserConversions = false, - bool ForceRValue = false); - bool PerformCopyInitialization(Expr *&From, QualType ToType, + bool SuppressUserConversions, bool ForceRValue, + bool InOverloadResolution); + bool PerformCopyInitialization(Expr *&From, QualType ToType, const char *Flavor, bool Elidable = false); ImplicitConversionSequence @@ -679,24 +842,21 @@ public: ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); bool PerformContextuallyConvertToBool(Expr *&From); - /// OverloadingResult - Capture the result of performing overload - /// resolution. - enum OverloadingResult { - OR_Success, ///< Overload resolution succeeded. - OR_No_Viable_Function, ///< No viable function found. - OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Overload resoltuion refers to a deleted function. - }; + bool PerformObjectMemberConversion(Expr *&From, NamedDecl *Member); + + // Members have to be NamespaceDecl* or TranslationUnitDecl*. + // TODO: make this is a typesafe union. + typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet; typedef llvm::SmallPtrSet<AnyFunctionDecl, 16> FunctionSet; - typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet; typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet; - void AddOverloadCandidate(FunctionDecl *Function, + void AddOverloadCandidate(FunctionDecl *Function, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, - bool ForceRValue = false); + bool ForceRValue = false, + bool PartialOverloading = false); void AddFunctionCandidates(const FunctionSet &Functions, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -706,6 +866,14 @@ public: OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); + void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + Expr *Object, Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool ForceRValue = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, const TemplateArgument *ExplicitTemplateArgs, @@ -717,6 +885,9 @@ public: void AddConversionCandidate(CXXConversionDecl *Conversion, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); + void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet); void AddSurrogateCandidate(CXXConversionDecl *Conversion, const FunctionProtoType *Proto, Expr *Object, Expr **Args, unsigned NumArgs, @@ -731,29 +902,45 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, SourceRange OpRange = SourceRange()); - void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, + void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); - void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, - Expr **Args, unsigned NumArgs, + void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet); + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + OverloadCandidateSet& CandidateSet, + bool PartialOverloading = false); bool isBetterOverloadCandidate(const OverloadCandidate& Cand1, const OverloadCandidate& Cand2); OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet, SourceLocation Loc, OverloadCandidateSet::iterator& Best); void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - bool OnlyViable); - + bool OnlyViable, + const char *Opc=0, + SourceLocation Loc=SourceLocation()); + FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + void AddOverloadedCallCandidates(NamedDecl *Callee, + DeclarationName &UnqualifiedName, + bool &ArgumentDependentLookup, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading = false); + FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, DeclarationName UnqualifiedName, bool HasExplicitTemplateArgs, @@ -761,7 +948,7 @@ public: unsigned NumExplicitTemplateArgs, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, + SourceLocation *CommaLocs, SourceLocation RParenLoc, bool &ArgumentDependentLookup); @@ -777,23 +964,33 @@ public: ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, - SourceLocation LParenLoc, Expr **Args, + SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, SourceLocation RParenLoc); - ExprResult + ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, + SourceLocation *CommaLocs, SourceLocation RParenLoc); - ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, - SourceLocation MemberLoc, - IdentifierInfo &Member); - - /// Helpers for dealing with function parameters. + OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc); + + /// CheckCallReturnType - Checks that a call expression's return type is + /// complete. Returns true on failure. The location passed in is the location + /// that best represents the call. + bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, + CallExpr *CE, FunctionDecl *FD); + + /// Helpers for dealing with blocks and functions. + void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body); + void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body); bool CheckParmsForFunctionDef(FunctionDecl *FD); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); + enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, + AlwaysFallThrough = 2 }; + ControlFlowKind CheckFallThrough(Stmt *); Scope *getNonFieldDeclScope(Scope *S); @@ -804,7 +1001,7 @@ public: /// overloaded operator names, constructor names, etc.) into zero or /// more declarations within a particular scope. The major entry /// points are LookupName, which performs unqualified name lookup, - /// and LookupQualifiedName, which performs qualified name lookup. + /// and LookupQualifiedName, which performs qualified name lookup. /// /// All name lookup is performed based on some specific criteria, /// which specify what names will be visible to name lookup and how @@ -851,7 +1048,7 @@ public: LookupNamespaceName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that - /// are outside of the current scope unless they have linkage. See + /// are outside of the current scope unless they have linkage. See /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up the name of an Objective-C protocol. @@ -868,66 +1065,16 @@ public: /// single name lookup, which can return no result (nothing found), /// a single declaration, a set of overloaded functions, or an /// ambiguity. Use the getKind() method to determine which of these - /// results occurred for a given lookup. + /// results occurred for a given lookup. /// /// Any non-ambiguous lookup can be converted into a single - /// (possibly NULL) @c NamedDecl* via a conversion function or the - /// getAsDecl() method. This conversion permits the common-case - /// usage in C and Objective-C where name lookup will always return - /// a single declaration. - struct LookupResult { - /// The kind of entity that is actually stored within the - /// LookupResult object. - enum { - /// First is a single declaration (a NamedDecl*), which may be NULL. - SingleDecl, - - /// First is a single declaration (an OverloadedFunctionDecl*). - OverloadedDeclSingleDecl, - - /// [First, Last) is an iterator range represented as opaque - /// pointers used to reconstruct IdentifierResolver::iterators. - OverloadedDeclFromIdResolver, - - /// [First, Last) is an iterator range represented as opaque - /// pointers used to reconstruct DeclContext::lookup_iterators. - OverloadedDeclFromDeclContext, - - /// First is a pointer to a BasePaths structure, which is owned - /// by the LookupResult. Last is non-zero to indicate that the - /// ambiguity is caused by two names found in base class - /// subobjects of different types. - AmbiguousLookupStoresBasePaths, - - /// [First, Last) is an iterator range represented as opaque - /// pointers used to reconstruct new'ed Decl*[] array containing - /// found ambiguous decls. LookupResult is owner of this array. - AmbiguousLookupStoresDecls - } StoredKind; - - /// The first lookup result, whose contents depend on the kind of - /// lookup result. This may be a NamedDecl* (if StoredKind == - /// SingleDecl), OverloadedFunctionDecl* (if StoredKind == - /// OverloadedDeclSingleDecl), the opaque pointer from an - /// IdentifierResolver::iterator (if StoredKind == - /// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator - /// (if StoredKind == OverloadedDeclFromDeclContext), or a - /// BasePaths pointer (if StoredKind == AmbiguousLookupStoresBasePaths). - mutable uintptr_t First; - - /// The last lookup result, whose contents depend on the kind of - /// lookup result. This may be unused (if StoredKind == - /// SingleDecl), it may have the same type as First (for - /// overloaded function declarations), or is may be used as a - /// Boolean value (if StoredKind == AmbiguousLookupStoresBasePaths). - mutable uintptr_t Last; - - /// Context - The context in which we will build any - /// OverloadedFunctionDecl nodes needed by the conversion to - /// Decl*. - ASTContext *Context; - - /// @brief The kind of entity found by name lookup. + /// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method. + /// This permits the common-case usage in C and Objective-C where + /// name lookup will always return a single declaration. Use of + /// this is largely deprecated; callers should handle the possibility + /// of multiple declarations. + class LookupResult { + public: enum LookupKind { /// @brief No entity found met the criteria. NotFound = 0, @@ -941,6 +1088,13 @@ public: /// functions into an OverloadedFunctionDecl. FoundOverloaded, + /// @brief Name lookup results in an ambiguity; use + /// getAmbiguityKind to figure out what kind of ambiguity + /// we have. + Ambiguous + }; + + enum AmbiguityKind { /// Name lookup results in an ambiguity because multiple /// entities that meet the lookup criteria were found in /// subobjects of different types. For example: @@ -948,7 +1102,7 @@ public: /// struct A { void f(int); } /// struct B { void f(double); } /// struct C : A, B { }; - /// void test(C c) { + /// void test(C c) { /// c.f(0); // error: A::f and B::f come from subobjects of different /// // types. overload resolution is not performed. /// } @@ -982,125 +1136,178 @@ public: /// } /// } /// @endcode - AmbiguousReference + AmbiguousReference, + + /// Name lookup results in an ambiguity because an entity with a + /// tag name was hidden by an entity with an ordinary name from + /// a different context. + /// @code + /// namespace A { struct Foo {}; } + /// namespace B { void Foo(); } + /// namespace C { + /// using namespace A; + /// using namespace B; + /// } + /// void test() { + /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a + /// // different namespace + /// } + /// @endcode + AmbiguousTagHiding }; - static LookupResult CreateLookupResult(ASTContext &Context, NamedDecl *D); + typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; + typedef DeclsTy::const_iterator iterator; - static LookupResult CreateLookupResult(ASTContext &Context, - IdentifierResolver::iterator F, - IdentifierResolver::iterator L); + LookupResult() + : Kind(NotFound), + Paths(0) + {} + ~LookupResult() { + if (Paths) deletePaths(Paths); + } - static LookupResult CreateLookupResult(ASTContext &Context, - DeclContext::lookup_iterator F, - DeclContext::lookup_iterator L); + bool isAmbiguous() const { + return getKind() == Ambiguous; + } - static LookupResult CreateLookupResult(ASTContext &Context, BasePaths *Paths, - bool DifferentSubobjectTypes) { - LookupResult Result; - Result.StoredKind = AmbiguousLookupStoresBasePaths; - Result.First = reinterpret_cast<uintptr_t>(Paths); - Result.Last = DifferentSubobjectTypes? 1 : 0; - Result.Context = &Context; - return Result; + LookupKind getKind() const { + sanity(); + return Kind; } - template <typename Iterator> - static LookupResult CreateLookupResult(ASTContext &Context, - Iterator B, std::size_t Len) { - NamedDecl ** Array = new NamedDecl*[Len]; - for (std::size_t Idx = 0; Idx < Len; ++Idx, ++B) - Array[Idx] = *B; - LookupResult Result; - Result.StoredKind = AmbiguousLookupStoresDecls; - Result.First = reinterpret_cast<uintptr_t>(Array); - Result.Last = reinterpret_cast<uintptr_t>(Array + Len); - Result.Context = &Context; - return Result; + AmbiguityKind getAmbiguityKind() const { + assert(isAmbiguous()); + return Ambiguity; } - LookupKind getKind() const; + iterator begin() const { return Decls.begin(); } + iterator end() const { return Decls.end(); } - /// @brief Determine whether name look found something. - operator bool() const { return getKind() != NotFound; } + /// \brief Return true if no decls were found + bool empty() const { return Decls.empty(); } - /// @brief Determines whether the lookup resulted in an ambiguity. - bool isAmbiguous() const { - return StoredKind == AmbiguousLookupStoresBasePaths || - StoredKind == AmbiguousLookupStoresDecls; + /// \brief Return the base paths structure that's associated with + /// these results, or null if none is. + CXXBasePaths *getBasePaths() const { + return Paths; } - /// @brief Allows conversion of a lookup result into a - /// declaration, with the same behavior as getAsDecl. - operator NamedDecl*() const { return getAsDecl(); } + /// \brief Add a declaration to these results. + void addDecl(NamedDecl *D) { + Decls.push_back(D->getUnderlyingDecl()); + Kind = Found; + } - NamedDecl* getAsDecl() const; + /// \brief Add all the declarations from another set of lookup + /// results. + void addAllDecls(const LookupResult &Other) { + Decls.append(Other.begin(), Other.end()); + Kind = Found; + } - BasePaths *getBasePaths() const; + /// \brief Hides a set of declarations. + template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) { + unsigned I = 0, N = Decls.size(); + while (I < N) { + if (Set.count(Decls[I])) + Decls[I] = Decls[--N]; + else + I++; + } + Decls.set_size(N); + } - /// \brief Iterate over the results of name lookup. + /// \brief Resolves the kind of the lookup, possibly hiding decls. /// - /// The @c iterator class provides iteration over the results of a - /// non-ambiguous name lookup. - class iterator { - /// The LookupResult structure we're iterating through. - LookupResult *Result; + /// This should be called in any environment where lookup might + /// generate multiple lookup results. + void resolveKind(); - /// The current position of this iterator within the sequence of - /// results. This value will have the same representation as the - /// @c First field in the LookupResult structure. - mutable uintptr_t Current; - - public: - typedef NamedDecl * value_type; - typedef NamedDecl * reference; - typedef NamedDecl * pointer; - typedef std::ptrdiff_t difference_type; - typedef std::forward_iterator_tag iterator_category; + /// \brief Fetch this as an unambiguous single declaration + /// (possibly an overloaded one). + /// + /// This is deprecated; users should be written to handle + /// ambiguous and overloaded lookups. + NamedDecl *getAsSingleDecl(ASTContext &Context) const; - iterator() : Result(0), Current(0) { } + /// \brief Fetch the unique decl found by this lookup. Asserts + /// that one was found. + /// + /// This is intended for users who have examined the result kind + /// and are certain that there is only one result. + NamedDecl *getFoundDecl() const { + assert(getKind() == Found && "getFoundDecl called on non-unique result"); + return *Decls.begin(); + } - iterator(LookupResult *Res, uintptr_t Cur) : Result(Res), Current(Cur) { } + /// \brief Asks if the result is a single tag decl. + bool isSingleTagDecl() const { + return getKind() == Found && isa<TagDecl>(getFoundDecl()); + } - reference operator*() const; + /// \brief Make these results show that the name was found in + /// base classes of different types. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); - pointer operator->() const { return **this; } + /// \brief Make these results show that the name was found in + /// distinct base classes of the same type. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjects(CXXBasePaths &P); + + /// \brief Make these results show that the name was found in + /// different contexts and a tag decl was hidden by an ordinary + /// decl in a different context. + void setAmbiguousQualifiedTagHiding() { + setAmbiguous(AmbiguousTagHiding); + } - iterator &operator++(); + /// \brief Clears out any current state. + void clear() { + Kind = NotFound; + Decls.clear(); + if (Paths) deletePaths(Paths); + Paths = NULL; + } - iterator operator++(int) { - iterator tmp(*this); - ++(*this); - return tmp; - } + void print(llvm::raw_ostream &); - friend inline bool operator==(iterator const& x, iterator const& y) { - return x.Current == y.Current; - } + private: + void setAmbiguous(AmbiguityKind AK) { + Kind = Ambiguous; + Ambiguity = AK; + } - friend inline bool operator!=(iterator const& x, iterator const& y) { - return x.Current != y.Current; - } - }; - friend class iterator; + void addDeclsFromBasePaths(const CXXBasePaths &P); + + // Sanity checks. + void sanity() const { + assert(Kind != NotFound || Decls.size() == 0); + assert(Kind != Found || Decls.size() == 1); + assert(Kind == NotFound || Kind == Found || + (Kind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects) + || Decls.size() > 1); + assert((Paths != NULL) == (Kind == Ambiguous && + (Ambiguity == AmbiguousBaseSubobjectTypes || + Ambiguity == AmbiguousBaseSubobjects))); + } - iterator begin(); - iterator end(); + static void deletePaths(CXXBasePaths *); - /// \brief Free the memory associated with this lookup. - void Destroy(); + LookupKind Kind; + AmbiguityKind Ambiguity; // ill-defined unless ambiguous + DeclsTy Decls; + CXXBasePaths *Paths; }; private: typedef llvm::SmallVector<LookupResult, 3> LookupResultsVecTy; - std::pair<bool, LookupResult> CppLookupName(Scope *S, DeclarationName Name, - LookupNameKind NameKind, - bool RedeclarationOnly); - ObjCMethodDecl *FindMethodInNestedImplementations( - const ObjCInterfaceDecl *IFace, - const Selector &Sel); - + bool CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, + LookupNameKind NameKind, bool RedeclarationOnly); public: /// Determines whether D is a suitable lookup result according to the /// lookup criteria. @@ -1115,62 +1322,75 @@ public: case Sema::LookupObjCImplementationName: case Sema::LookupObjCCategoryImplName: return D->isInIdentifierNamespace(IDNS); - + case Sema::LookupOperatorName: - return D->isInIdentifierNamespace(IDNS) && + return D->isInIdentifierNamespace(IDNS) && !D->getDeclContext()->isRecord(); case Sema::LookupNestedNameSpecifierName: return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag); - + case Sema::LookupNamespaceName: return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D); } - - assert(false && + + assert(false && "isAcceptableLookupResult always returns before this point"); return false; } - LookupResult LookupName(Scope *S, DeclarationName Name, - LookupNameKind NameKind, - bool RedeclarationOnly = false, - bool AllowBuiltinCreation = false, - SourceLocation Loc = SourceLocation()); - LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, - LookupNameKind NameKind, - bool RedeclarationOnly = false); - LookupResult LookupParsedName(Scope *S, const CXXScopeSpec *SS, - DeclarationName Name, - LookupNameKind NameKind, - bool RedeclarationOnly = false, - bool AllowBuiltinCreation = false, - SourceLocation Loc = SourceLocation()); + /// \brief Look up a name, looking for a single declaration. Return + /// null if no unambiguous results were found. + /// + /// It is preferable to use the elaborated form and explicitly handle + /// ambiguity and overloaded. + NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly = false) { + LookupResult R; + LookupName(R, S, Name, NameKind, RedeclarationOnly); + return R.getAsSingleDecl(Context); + } + bool LookupName(LookupResult &R, Scope *S, + DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly = false, + bool AllowBuiltinCreation = false, + SourceLocation Loc = SourceLocation()); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly = false); + bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, + DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly = false, + bool AllowBuiltinCreation = false, + SourceLocation Loc = SourceLocation(), + bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); - ObjCImplementationDecl *LookupObjCImplementation(IdentifierInfo *II); ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, - QualType T1, QualType T2, + QualType T1, QualType T2, FunctionSet &Functions); - + void ArgumentDependentLookup(DeclarationName Name, Expr **Args, unsigned NumArgs, FunctionSet &Functions); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, - AssociatedClassSet &AssociatedClasses, - bool &GlobalScope); + AssociatedClassSet &AssociatedClasses); bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, - SourceLocation NameLoc, + SourceLocation NameLoc, SourceRange LookupRange = SourceRange()); //@} - + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); - NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, + NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, @@ -1179,7 +1399,7 @@ public: // More parsing and symbol table subroutines. - // Decl attributes - this routine is the top level dispatcher. + // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList); @@ -1187,13 +1407,10 @@ public: bool &IncompleteImpl); void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod, ObjCMethodDecl *IntfMethod); - bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS); - NamespaceDecl *GetStdNamespace(); - bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl, ObjCInterfaceDecl *IDecl); - + /// CheckProtocolMethodDefs - This routine checks unimplemented /// methods declared in protocol, and those referenced by it. /// \param IDecl - Used for checking for methods which may have been @@ -1204,24 +1421,24 @@ public: const llvm::DenseSet<Selector> &InsMap, const llvm::DenseSet<Selector> &ClsMap, ObjCInterfaceDecl *IDecl); - + /// CheckImplementationIvars - This routine checks if the instance variables - /// listed in the implelementation match those listed in the interface. + /// listed in the implelementation match those listed in the interface. void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, ObjCIvarDecl **Fields, unsigned nIvars, SourceLocation Loc); - + /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category @implementation. - void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, - ObjCContainerDecl* IDecl, + void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, bool IncompleteImpl = false); - + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. - bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, - bool matchBasedOnSizeAndAlignment = false); + bool matchBasedOnSizeAndAlignment = false); /// MatchAllMethodDeclarations - Check methods declaraed in interface or /// or protocol against those declared in their implementations. @@ -1239,15 +1456,16 @@ public: /// a selector with a method declaraation for purposes of typechecking /// messages sent to "id" (where the class of the object is unknown). void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method); - + /// LookupInstanceMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. - ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R); + ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, + bool warn=true); /// LookupFactoryMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R); - + /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); //===--------------------------------------------------------------------===// @@ -1266,7 +1484,7 @@ public: SourceLocation DotDotDotLoc, ExprArg RHSVal, SourceLocation ColonLoc); virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt); - + virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, StmtArg SubStmt, Scope *CurScope); @@ -1274,13 +1492,13 @@ public: IdentifierInfo *II, SourceLocation ColonLoc, StmtArg SubStmt); - virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, StmtArg ThenVal, + virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, + FullExprArg CondVal, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal); virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond); virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body); - virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, + virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body); virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, SourceLocation WhileLoc, @@ -1309,7 +1527,7 @@ public: Scope *CurScope); virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc, - FullExprArg RetValExp); + ExprArg RetValExp); OwningStmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); @@ -1338,13 +1556,14 @@ public: StmtArg Catch, StmtArg Finally); virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, - ExprArg Throw, + ExprArg Throw, Scope *CurScope); virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, StmtArg SynchBody); VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType, + DeclaratorInfo *DInfo, IdentifierInfo *Name, SourceLocation Loc, SourceRange Range); @@ -1358,25 +1577,29 @@ public: MultiStmtArg Handlers); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); + /// DiagnoseUnusedExprResult - If the statement passed in is an expression + /// whose result is unused, warn. + void DiagnoseUnusedExprResult(const Stmt *S); + //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc); - bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, + bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, Expr **Args, unsigned NumArgs); - virtual ExpressionEvaluationContext + virtual ExpressionEvaluationContext PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); - - virtual void + + virtual void PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, ExpressionEvaluationContext NewContext); - + void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); - + // Primary Expressions. virtual SourceRange getExprRange(ExprTy *E) const; @@ -1397,8 +1620,8 @@ public: bool HasTrailingLParen, const CXXScopeSpec &SS, bool isAddressOfOperand); - OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty, - SourceLocation Loc, bool TypeDependent, + OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty, + SourceLocation Loc, bool TypeDependent, bool ValueDependent, const CXXScopeSpec *SS = 0); VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, @@ -1415,15 +1638,18 @@ public: bool isAddressOfOperand = false); OwningExprResult BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, bool HasTrailingLParen, - const CXXScopeSpec *SS, + const CXXScopeSpec *SS, bool isAddressOfOperand); - + virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); virtual OwningExprResult ActOnNumericConstant(const Token &); virtual OwningExprResult ActOnCharacterConstant(const Token &); virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, ExprArg Val); + virtual OwningExprResult ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). @@ -1432,19 +1658,19 @@ public: // Binary/Unary Operators. 'Tok' is the token for the operator. OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, - unsigned OpcIn, + unsigned OpcIn, ExprArg InputArg); virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); - OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, + OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, bool isSizeOf, SourceRange R); - OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, + OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, bool isSizeOf, SourceRange R); virtual OwningExprResult ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, void *TyOrEx, const SourceRange &ArgRange); - + bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R); bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, const SourceRange &R, bool isSizeof); @@ -1457,18 +1683,67 @@ public: SourceLocation LLoc, ExprArg Idx, SourceLocation RLoc); + + OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation MemberLoc, + DeclarationName MemberName, + DeclPtrTy ImplDecl, + const CXXScopeSpec *SS = 0, + NamedDecl *FirstQualifierInScope = 0) { + // FIXME: Temporary helper while we migrate existing calls to + // BuildMemberReferenceExpr to support explicitly-specified template + // arguments. + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc, + MemberName, false, SourceLocation(), 0, 0, + SourceLocation(), ImplDecl, SS, + FirstQualifierInScope); + } + + OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation MemberLoc, + DeclarationName MemberName, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + DeclPtrTy ImplDecl, + const CXXScopeSpec *SS, + NamedDecl *FirstQualifierInScope = 0); + virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation MemberLoc, IdentifierInfo &Member, - DeclPtrTy ImplDecl); + DeclPtrTy ImplDecl, + const CXXScopeSpec *SS = 0); + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc); - + void BuildBaseOrMemberInitializers(ASTContext &C, + CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers + ); + + void DeconstructCallFunction(Expr *FnExpr, + NamedDecl *&Function, + DeclarationName &Name, + NestedNameSpecifier *&Qualifier, + SourceRange &QualifierRange, + bool &ArgumentDependentLookup, + bool &HasExplicitTemplateArguments, + const TemplateArgument *&ExplicitTemplateArgs, + unsigned &NumExplicitTemplateArgs); + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -1478,8 +1753,14 @@ public: SourceLocation *CommaLocs, SourceLocation RParenLoc); - virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprArg Op); + virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + TypeTy *Ty, SourceLocation RParenLoc, + ExprArg Op); + + OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME); + OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, + SourceLocation RParenLoc, ExprArg E, + QualType Ty); virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, @@ -1577,7 +1858,7 @@ public: SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList); - + void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope, @@ -1588,16 +1869,24 @@ public: SourceLocation IdentLoc, IdentifierInfo *Ident); + NamedDecl *BuildUsingDeclaration(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + DeclarationName Name, + AttributeList *AttrList, + bool IsTypeName); + virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, - SourceLocation UsingLoc, - const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, - AttributeList *AttrList, - bool IsTypeName); - - /// AddCXXDirectInitializerToDecl - This action is called immediately after + AccessSpecifier AS, + SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *TargetName, + OverloadedOperatorKind Op, + AttributeList *AttrList, + bool IsTypeName); + + /// AddCXXDirectInitializerToDecl - This action is called immediately after /// ActOnDeclarator, when a C++ direct initializer is present. /// e.g: "int x(1);" virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, @@ -1608,57 +1897,79 @@ public: /// InitializeVarWithConstructor - Creates an CXXConstructExpr /// and sets it as the initializer for the the passed in VarDecl. - void InitializeVarWithConstructor(VarDecl *VD, + bool InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - QualType DeclInitType, - Expr **Exprs, unsigned NumExprs); - - /// MarkDestructorReferenced - Prepare for calling destructor on the - /// constructed decl. - void MarkDestructorReferenced(SourceLocation Loc, QualType DeclInitType); - - /// DefineImplicitDefaultConstructor - Checks for feasibility of + QualType DeclInitType, + MultiExprArg Exprs); + + /// BuildCXXConstructExpr - Creates a complete call to a constructor, + /// including handling of its default argument expressions. + OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, + QualType DeclInitType, + CXXConstructorDecl *Constructor, + MultiExprArg Exprs); + + // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if + // the constructor can be elidable? + OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, + QualType DeclInitType, + CXXConstructorDecl *Constructor, + bool Elidable, + MultiExprArg Exprs); + + OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons, + QualType writtenTy, + SourceLocation tyBeginLoc, + MultiExprArg Args, + SourceLocation rParenLoc); + + OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc, + QualType Ty, + CastExpr::CastKind Kind, + CXXMethodDecl *Method, + ExprArg Arg); + + /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating + /// the default expr if needed. + OwningExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, + FunctionDecl *FD, + ParmVarDecl *Param); + + /// FinalizeVarWithDestructor - Prepare for calling destructor on the + /// constructed variable. + void FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType); + + /// DefineImplicitDefaultConstructor - Checks for feasibility of /// defining this constructor as the default constructor. void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); - - /// DefineImplicitDestructor - Checks for feasibility of + + /// DefineImplicitDestructor - Checks for feasibility of /// defining this destructor as the default destructor. void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); - - /// DefineImplicitCopyConstructor - Checks for feasibility of + + /// DefineImplicitCopyConstructor - Checks for feasibility of /// defining this constructor as the copy constructor. void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor, unsigned TypeQuals); - + /// DefineImplicitOverloadedAssign - Checks for feasibility of /// defining implicit this overloaded assignment operator. - void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, + void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); - + /// getAssignOperatorMethod - Returns the default copy assignmment operator /// for the class. CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl, - CXXRecordDecl *ClassDecl); + CXXRecordDecl *ClassDecl); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. OwningExprResult MaybeBindToTemporary(Expr *E); - /// RemoveOutermostTemporaryBinding - Remove and destroy the outermost - /// CXXBindToTemporaryExpr if necessary. This is used when we want to not - /// destroy a temporary when a full expression has been evaluated. - /// For example: - /// - /// const T& t = T(10, T()); - /// - /// Here the outermost T needs to be destroyed when t goes out of scope, but - /// the innermost T needs to be destroyed when the expr has been evaluated. - Expr *RemoveOutermostTemporaryBinding(Expr *E); - /// InitializationKind - Represents which kind of C++ initialization /// [dcl.init] a routine is to perform. enum InitializationKind { @@ -1669,11 +1980,17 @@ public: CXXConstructorDecl * PerformInitializationByConstructor(QualType ClassType, - Expr **Args, unsigned NumArgs, + MultiExprArg ArgsPtr, SourceLocation Loc, SourceRange Range, DeclarationName InitEntity, - InitializationKind Kind); + InitializationKind Kind, + ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); + bool CompleteConstructorCall(CXXConstructorDecl *Constructor, + MultiExprArg ArgsPtr, + SourceLocation Loc, + ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, @@ -1729,7 +2046,7 @@ public: SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, - bool ParenTypeId, + bool ParenTypeId, QualType AllocType, SourceLocation TypeLoc, SourceRange TypeRange, @@ -1737,7 +2054,7 @@ public: SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen); - + bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, @@ -1775,17 +2092,62 @@ public: TypeTy *Ty, SourceLocation RParen); - /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is + virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S, + ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + TypeTy *&ObjectType); + + virtual OwningExprResult + ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + IdentifierInfo *ClassName, + const CXXScopeSpec &SS, + bool HasTrailingLParen); + + virtual OwningExprResult + ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + OverloadedOperatorKind OverOpKind, + const CXXScopeSpec *SS = 0); + virtual OwningExprResult + ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + TypeTy *Ty, + const CXXScopeSpec *SS = 0); + + virtual OwningExprResult + ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + // FIXME: "template" keyword? + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc); + + /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, bool ShouldDestroyTemporaries); - + virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); bool RequireCompleteDeclContext(const CXXScopeSpec &SS); - - DeclContext *computeDeclContext(const CXXScopeSpec &SS); + + DeclContext *computeDeclContext(QualType T); + DeclContext *computeDeclContext(const CXXScopeSpec &SS, + bool EnteringContext = false); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); bool isUnknownSpecialization(const CXXScopeSpec &SS); @@ -1795,17 +2157,26 @@ public: virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc); - /// ActOnCXXNestedNameSpecifier - Called during parsing of a - /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now - /// we want to resolve "bar::". 'SS' is empty or the previously parsed - /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', - /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. - /// Returns a CXXScopeTy* object representing the C++ scope. + bool isAcceptableNestedNameSpecifier(NamedDecl *SD); + NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); + + + CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + SourceLocation IdLoc, + SourceLocation CCLoc, + IdentifierInfo &II, + QualType ObjectType, + NamedDecl *ScopeLookupResult, + bool EnteringContext); + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, - IdentifierInfo &II); + IdentifierInfo &II, + TypeTy *ObjectType, + bool EnteringContext); /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier that involves a template-id, e.g., @@ -1827,7 +2198,7 @@ public: /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. - virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same @@ -1848,26 +2219,28 @@ public: virtual void ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl); // ParseObjCStringLiteral - Parse Objective-C string literals. - virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ExprTy **Strings, unsigned NumStrings); - - Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, + + Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, QualType EncodedType, - SourceLocation RParenLoc); + SourceLocation RParenLoc); + CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method); + virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc); - + // ParseObjCSelectorExpression - Build selector expression for @selector virtual ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, SourceLocation LParenLoc, SourceLocation RParenLoc); - + // ParseObjCProtocolExpression - Build protocol expression for @protocol virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, SourceLocation AtLoc, @@ -1897,6 +2270,7 @@ public: virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, ExprTy *BitfieldWidth, ExprTy *Init, bool Deleted = false); @@ -1912,12 +2286,33 @@ public: SourceLocation *CommaLocs, SourceLocation RParenLoc); + MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc); + + MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc, + CXXRecordDecl *ClassDecl); + + void setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers, + llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, + llvm::SmallVectorImpl<FieldDecl *>&Members); + + /// computeBaseOrMembersToDestroy - Compute information in current + /// destructor decl's AST of bases and non-static data members which will be + /// implicitly destroyed. We are storing the destruction in the order that + /// they should occur (which is the reverse of construction order). + void computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor); + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); - virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, + virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits); - + virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, @@ -1930,12 +2325,14 @@ public: virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy Method); - virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, + virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, ExprArg AssertExpr, ExprArg AssertMessageExpr); - - virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, - DeclPtrTy Dcl); + + DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, + MultiTemplateParamsArg TemplateParams); + DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, + MultiTemplateParamsArg TemplateParams); QualType CheckConstructorDeclarator(Declarator &D, QualType R, FunctionDecl::StorageClass& SC); @@ -1954,23 +2351,22 @@ public: CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - QualType BaseType, + QualType BaseType, SourceLocation BaseLoc); - virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - TypeTy *basetype, SourceLocation + TypeTy *basetype, SourceLocation BaseLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, unsigned NumBases); - virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, + virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, unsigned NumBases); bool IsDerivedFrom(QualType Derived, QualType Base); - bool IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths); - bool LookupInBases(CXXRecordDecl *Class, const MemberLookupCriteria& Criteria, - BasePaths &Paths); + bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, @@ -1978,29 +2374,37 @@ public: unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name); - - std::string getAmbiguousPathsDisplayString(BasePaths &Paths); - - /// CheckReturnTypeCovariance - Checks whether two types are covariant, - /// according to C++ [class.virtual]p5. - bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, + + std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); + + /// CheckOverridingFunctionReturnType - Checks whether the return types are + /// covariant, according to C++ [class.virtual]p5. + bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old); - + + /// CheckOverridingFunctionExceptionSpec - Checks whether the exception + /// spec is a subset of base spec. + bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, + const CXXMethodDecl *Old); //===--------------------------------------------------------------------===// // C++ Access Control // - - bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, + + bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS); - - bool CheckBaseClassAccess(QualType Derived, QualType Base, + + const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base, + CXXBasePaths &Paths, + bool NoPrivileges = false); + + bool CheckBaseClassAccess(QualType Derived, QualType Base, unsigned InaccessibleBaseID, - BasePaths& Paths, SourceLocation AccessLoc, + CXXBasePaths& Paths, SourceLocation AccessLoc, DeclarationName Name); - - + + enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, @@ -2008,8 +2412,12 @@ public: AbstractVariableType, AbstractFieldType }; - - bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, + + bool RequireNonAbstractType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD, + const CXXRecordDecl *CurrentRD = 0); + + bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, AbstractDiagSelID SelID = AbstractNone, const CXXRecordDecl *CurrentRD = 0); @@ -2022,19 +2430,23 @@ public: //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // - virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, - TemplateTy &Template, - const CXXScopeSpec *SS = 0); + virtual TemplateNameKind isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, + const CXXScopeSpec *SS, + TypeTy *ObjectType, + bool EnteringContext, + TemplateTy &Template); bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); - virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, + virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position); - virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, + virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, SourceLocation EqualLoc, SourceLocation DefaultLoc, TypeTy *Default); @@ -2060,21 +2472,30 @@ public: virtual TemplateParamsTy * ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, - SourceLocation TemplateLoc, + SourceLocation TemplateLoc, SourceLocation LAngleLoc, DeclPtrTy *Params, unsigned NumParams, SourceLocation RAngleLoc); bool CheckTemplateParameterList(TemplateParameterList *NewParams, TemplateParameterList *OldParams); - - virtual DeclResult - ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, - SourceLocation KWLoc, const CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, - MultiTemplateParamsArg TemplateParameterLists, - AccessSpecifier AS); - + TemplateParameterList * + MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, + const CXXScopeSpec &SS, + TemplateParameterList **ParamLists, + unsigned NumParamLists, + bool &IsExplicitSpecialization); + + DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + TemplateParameterList *TemplateParams, + AccessSpecifier AS); + + void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, + SourceLocation *TemplateArgLocs, + llvm::SmallVector<TemplateArgument, 16> &TemplateArgs); + QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -2088,32 +2509,31 @@ public: ASTTemplateArgsPtr TemplateArgs, SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc); - + + virtual TypeResult ActOnTagTemplateIdType(TypeResult Type, + TagUseKind TUK, + DeclSpec::TST TagSpec, + SourceLocation TagLoc); + OwningExprResult BuildTemplateIdExpr(TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); - + virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc); - + virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, - const CXXScopeSpec &SS); - - bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, - ClassTemplateSpecializationDecl *PrevDecl, - SourceLocation TemplateNameLoc, - SourceRange ScopeSpecifierRange, - bool PartialSpecialization, - bool ExplicitInstantiation); + const CXXScopeSpec &SS, + TypeTy *ObjectType); bool CheckClassTemplatePartialSpecializationArgs( TemplateParameterList *TemplateParams, @@ -2121,8 +2541,8 @@ public: bool &MirrorsPrimaryTemplate); virtual DeclResult - ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, - SourceLocation KWLoc, + ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, @@ -2133,17 +2553,28 @@ public: AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists); - virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S, + virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); - - virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, + + virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); - + + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + NamedDecl *&PrevDecl); + bool CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl); + virtual DeclResult - ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, - unsigned TagSpec, + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, @@ -2155,14 +2586,21 @@ public: AttributeList *Attr); virtual DeclResult - ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, - unsigned TagSpec, + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); + virtual DeclResult ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + Declarator &D); + bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -2172,16 +2610,16 @@ public: bool PartialTemplateArgs, TemplateArgumentListBuilder &Converted); - bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, + bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgument &Arg, TemplateArgumentListBuilder &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg, SourceLocation ArgLoc); - bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, + bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); - bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, + bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, TemplateArgument &Converted); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg); @@ -2191,9 +2629,8 @@ public: bool IsTemplateTemplateParm = false, SourceLocation TemplateArgLoc = SourceLocation()); - - bool CheckTemplateDeclScope(Scope *S, - MultiTemplateParamsArg &TemplateParameterLists); + + bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); /// \brief Called when the parser has parsed a C++ typename /// specifier, e.g., "typename T::type". @@ -2207,7 +2644,7 @@ public: const IdentifierInfo &II, SourceLocation IdLoc); /// \brief Called when the parser has parsed a C++ typename - /// specifier that ends in a template-id, e.g., + /// specifier that ends in a template-id, e.g., /// "typename MetaFun::template apply<T1, T2>". /// /// \param TypenameLoc the location of the 'typename' keyword @@ -2222,6 +2659,13 @@ public: const IdentifierInfo &II, SourceRange Range); + QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, + DeclarationName Name); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgumentList &Args); + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of @@ -2256,10 +2700,10 @@ public: /// produces a type that does not match the original template /// arguments provided. TDK_NonDeducedMismatch, - /// \brief When performing template argument deduction for a function + /// \brief When performing template argument deduction for a function /// template, there were too many call arguments. TDK_TooManyArguments, - /// \brief When performing template argument deduction for a class + /// \brief When performing template argument deduction for a function /// template, there were too few call arguments. TDK_TooFewArguments, /// \brief The explicitly-specified template arguments were not valid @@ -2290,7 +2734,7 @@ public: } /// \brief Take ownership of the deduced template argument list. - TemplateArgumentList *take() { + TemplateArgumentList *take() { TemplateArgumentList *Result = Deduced; Deduced = 0; return Result; @@ -2343,7 +2787,22 @@ public: DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, TemplateDeductionInfo &Info); - + + TemplateDeductionResult + SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<QualType> &ParamTypes, + QualType *FunctionType, + TemplateDeductionInfo &Info); + + TemplateDeductionResult + FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl<TemplateArgument> &Deduced, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info); + TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, @@ -2352,15 +2811,50 @@ public: Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info); - - void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs, + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + QualType ArgFunctionType, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + QualType ToType, + CXXConversionDecl *&Specialization, + TemplateDeductionInfo &Info); + + FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, + FunctionTemplateDecl *FT2, + TemplatePartialOrderingContext TPOC); + FunctionDecl *getMostSpecialized(FunctionDecl **Specializations, + unsigned NumSpecializations, + TemplatePartialOrderingContext TPOC, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag, + unsigned *Index = 0); + + ClassTemplatePartialSpecializationDecl * + getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2); + + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used); + void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl<bool> &Deduced); - + //===--------------------------------------------------------------------===// // C++ Template Instantiation // - const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D); + MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { @@ -2377,10 +2871,15 @@ public: /// FIXME: Use a TemplateArgumentList DefaultTemplateArgumentInstantiation, - /// We are substituting explicit template arguments provided for + /// We are instantiating a default argument for a function. + /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs + /// provides the template arguments as specified. + DefaultFunctionArgumentInstantiation, + + /// We are substituting explicit template arguments provided for /// a function template. The entity is a FunctionTemplateDecl. ExplicitTemplateArgumentSubstitution, - + /// We are substituting template argument determined as part of /// template argument deduction for either a class template /// partial specialization or a function template. The @@ -2407,6 +2906,9 @@ public: /// template instantiation. SourceRange InstantiationRange; + ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Entity(0), + TemplateArgs(0), NumTemplateArgs(0) {} + friend bool operator==(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { if (X.Kind != Y.Kind) @@ -2422,7 +2924,9 @@ public: case DefaultTemplateArgumentInstantiation: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: + case DefaultFunctionArgumentInstantiation: return X.TemplateArgs == Y.TemplateArgs; + } return true; @@ -2440,7 +2944,7 @@ public: /// requires another template instantiation, additional /// instantiations are pushed onto the stack up to a /// user-configurable limit LangOptions::InstantiationDepth. - llvm::SmallVector<ActiveTemplateInstantiation, 16> + llvm::SmallVector<ActiveTemplateInstantiation, 16> ActiveTemplateInstantiations; /// \brief The last template from which a template instantiation @@ -2486,7 +2990,7 @@ public: unsigned NumTemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, SourceRange InstantiationRange = SourceRange()); - + /// \brief Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. @@ -2496,6 +3000,12 @@ public: unsigned NumTemplateArgs, SourceRange InstantiationRange = SourceRange()); + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ParmVarDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we have finished instantiating this template. void Clear(); @@ -2514,7 +3024,7 @@ public: InstantiatingTemplate(const InstantiatingTemplate&); // not implemented - InstantiatingTemplate& + InstantiatingTemplate& operator=(const InstantiatingTemplate&); // not implemented }; @@ -2541,8 +3051,8 @@ public: ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; } /// \brief Determine whether any SFINAE errors have been trapped. - bool hasErrorOccurred() const { - return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; + bool hasErrorOccurred() const { + return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; } }; @@ -2584,7 +3094,7 @@ public: public: LocalInstantiationScope(Sema &SemaRef) - : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { SemaRef.CurrentInstantiationScope = this; } @@ -2619,85 +3129,89 @@ public: /// \brief An entity for which implicit template instantiation is required. /// - /// The source location associated with the declaration is the first place in + /// The source location associated with the declaration is the first place in /// the source code where the declaration was "used". It is not necessarily - /// the point of instantiation (which will be either before or after the + /// the point of instantiation (which will be either before or after the /// namespace-scope declaration that triggered this implicit instantiation), /// However, it is the location that diagnostics should generally refer to, /// because users will need to know what code triggered the instantiation. typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation; - + /// \brief The queue of implicit template instantiations that are required /// but have not yet been performed. std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations; void PerformPendingImplicitInstantiations(); - - QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs, - SourceLocation Loc, DeclarationName Entity); - - OwningExprResult InstantiateExpr(Expr *E, - const TemplateArgumentList &TemplateArgs); - OwningStmtResult InstantiateStmt(Stmt *S, - const TemplateArgumentList &TemplateArgs); - OwningStmtResult InstantiateCompoundStmt(CompoundStmt *S, - const TemplateArgumentList &TemplateArgs, - bool isStmtExpr); + QualType SubstType(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); - Decl *InstantiateDecl(Decl *D, DeclContext *Owner, - const TemplateArgumentList &TemplateArgs); + OwningExprResult SubstExpr(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs); - bool - InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, - CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs); + OwningStmtResult SubstStmt(Stmt *S, + const MultiLevelTemplateArgumentList &TemplateArgs); + + Decl *SubstDecl(Decl *D, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs); + + bool + SubstBaseSpecifiers(CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs, - bool ExplicitInstantiation); + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, + bool Complain = true); - bool + bool InstantiateClassTemplateSpecialization( ClassTemplateSpecializationDecl *ClassTemplateSpec, - bool ExplicitInstantiation); + TemplateSpecializationKind TSK, + bool Complain = true); void InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, - const TemplateArgumentList &TemplateArgs); + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); void InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, - ClassTemplateSpecializationDecl *ClassTemplateSpec); + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK); NestedNameSpecifier * - InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range, - const TemplateArgumentList &TemplateArgs); + SubstNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range, + const MultiLevelTemplateArgumentList &TemplateArgs); TemplateName - InstantiateTemplateName(TemplateName Name, SourceLocation Loc, - const TemplateArgumentList &TemplateArgs); - TemplateArgument Instantiate(TemplateArgument Arg, - const TemplateArgumentList &TemplateArgs); + SubstTemplateName(TemplateName Name, SourceLocation Loc, + const MultiLevelTemplateArgumentList &TemplateArgs); + TemplateArgument Subst(TemplateArgument Arg, + const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false); - void InstantiateVariableDefinition(VarDecl *Var); + void InstantiateStaticDataMemberDefinition( + SourceLocation PointOfInstantiation, + VarDecl *Var, + bool Recursive = false); + + void InstantiateMemInitializers(CXXConstructorDecl *New, + const CXXConstructorDecl *Tmpl, + const MultiLevelTemplateArgumentList &TemplateArgs); + + NamedDecl *FindInstantiatedDecl(NamedDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs); + DeclContext *FindInstantiatedContext(DeclContext *DC, + const MultiLevelTemplateArgumentList &TemplateArgs); - NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D); - - // Simple function for cloning expressions. - template<typename T> - OwningExprResult Clone(T *E) { - assert(!E->isValueDependent() && !E->isTypeDependent() && - "expression is value or type dependent!"); - return Owned(E->Clone(Context)); - } - // Objective-C declarations. virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, @@ -2708,7 +3222,7 @@ public: unsigned NumProtoRefs, SourceLocation EndProtoLoc, AttributeList *AttrList); - + virtual DeclPtrTy ActOnCompatiblityAlias( SourceLocation AtCompatibilityAliasLoc, IdentifierInfo *AliasName, SourceLocation AliasLocation, @@ -2718,14 +3232,14 @@ public: IdentifierInfo *PName, SourceLocation &PLoc, SourceLocation PrevLoc, const ObjCList<ObjCProtocolDecl> &PList); - + virtual DeclPtrTy ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs, SourceLocation EndProtoLoc, AttributeList *AttrList); - + virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, @@ -2734,78 +3248,82 @@ public: const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, SourceLocation EndProtoLoc); - + virtual DeclPtrTy ActOnStartClassImplementation( SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, + IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc); - + virtual DeclPtrTy ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, - IdentifierInfo *ClassName, + IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc); - + virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, IdentifierInfo **IdentList, unsigned NumElts); - + virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, const IdentifierLocPair *IdentList, unsigned NumElts, AttributeList *attrList); - + virtual void FindProtocolDeclaration(bool WarnOnDeclarations, const IdentifierLocPair *ProtocolId, unsigned NumProtocols, llvm::SmallVectorImpl<DeclPtrTy> &Protocols); - - /// Ensure attributes are consistent with type. + + /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \arg PropertyTy. - void CheckObjCPropertyAttributes(QualType PropertyTy, + void CheckObjCPropertyAttributes(QualType PropertyTy, SourceLocation Loc, unsigned &Attributes); void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC); - void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *Name); void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl); - + + void CompareMethodParamsInBaseAndSuper(Decl *IDecl, + ObjCMethodDecl *MethodDecl, + bool IsInstance); + void MergeProtocolPropertiesIntoClass(Decl *CDecl, DeclPtrTy MergeProtocols); - - void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, + + void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); - + void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, ObjCProtocolDecl *PDecl); - + virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, DeclPtrTy *allMethods = 0, unsigned allNum = 0, DeclPtrTy *allProperties = 0, unsigned pNum = 0, DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); - + virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, DeclPtrTy ClassCategory, bool *OverridingProperty, tok::ObjCKeywordKind MethodImplKind); - - virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc, + + virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind,DeclPtrTy ClassImplDecl, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar); - + virtual DeclPtrTy ActOnMethodDeclaration( SourceLocation BeginLoc, // location of the + or -. SourceLocation EndLoc, // location of the ; or {. - tok::TokenKind MethodType, - DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, + tok::TokenKind MethodType, + DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). @@ -2818,24 +3336,24 @@ public: // Will search "local" class/category implementations for a method decl. // Will also search in class's root looking for instance method. // Returns 0 if no method is found. - ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel, + ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel, ObjCInterfaceDecl *CDecl); ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel, ObjCInterfaceDecl *ClassDecl); - + virtual OwningExprResult ActOnClassPropertyRefExpr( IdentifierInfo &receiverName, IdentifierInfo &propertyName, SourceLocation &receiverNameLoc, SourceLocation &propertyNameLoc); - + // ActOnClassMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from NumArgs. virtual ExprResult ActOnClassMessage( Scope *S, - IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, - SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac, + IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, + SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac, ExprTy **ArgExprs, unsigned NumArgs); // ActOnInstanceMessage - used for both unary and keyword messages. @@ -2843,23 +3361,27 @@ public: // is obtained from NumArgs. virtual ExprResult ActOnInstanceMessage( ExprTy *receiver, Selector Sel, - SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac, + SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac, ExprTy **ArgExprs, unsigned NumArgs); - + /// ActOnPragmaPack - Called on well formed #pragma pack(...). virtual void ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, ExprTy *Alignment, - SourceLocation PragmaLoc, + SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc); - + /// ActOnPragmaUnused - Called on well-formed '#pragma unused'. - virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, - SourceLocation PragmaLoc, + virtual void ActOnPragmaUnused(const Token *Identifiers, + unsigned NumIdentifiers, Scope *curScope, + SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc); + NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II); + void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); + /// ActOnPragmaWeakID - Called on well formed #pragma weak ident. virtual void ActOnPragmaWeakID(IdentifierInfo* WeakName, SourceLocation PragmaLoc, @@ -2875,25 +3397,27 @@ public: /// getPragmaPackAlignment() - Return the current alignment as specified by /// the current #pragma pack directive, or 0 if none is currently active. unsigned getPragmaPackAlignment() const; - + /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. - void ImpCastExprToType(Expr *&Expr, QualType Type, bool isLvalue = false); + void ImpCastExprToType(Expr *&Expr, QualType Type, + CastExpr::CastKind Kind = CastExpr::CK_Unknown, + bool isLvalue = false); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). - Expr *UsualUnaryConversions(Expr *&expr); + Expr *UsualUnaryConversions(Expr *&expr); // DefaultFunctionArrayConversion - converts functions and arrays - // to their respective pointers (C99 6.3.2.1). + // to their respective pointers (C99 6.3.2.1). void DefaultFunctionArrayConversion(Expr *&expr); - + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that - // do not have a prototype. Integer promotions are performed on each + // do not have a prototype. Integer promotions are performed on each // argument, and arguments that have type float are promoted to double. void DefaultArgumentPromotion(Expr *&Expr); @@ -2901,26 +3425,21 @@ public: enum VariadicCallType { VariadicFunction, VariadicBlock, - VariadicMethod + VariadicMethod, + VariadicConstructor }; - + // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will warn if the resulting type is not a POD type. bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT); - + // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary // operators (C99 6.3.1.8). If both operands aren't arithmetic, this - // routine returns the first non-arithmetic type found. The client is + // routine returns the first non-arithmetic type found. The client is // responsible for emitting appropriate error diagnostics. QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr, bool isCompAssign = false); - - /// UsualArithmeticConversionsType - handles the various conversions - /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9) - /// and returns the result type of that conversion. - QualType UsualArithmeticConversionsType(QualType lhs, QualType rhs); - /// AssignConvertType - All of the 'assignment' semantic checks return this /// enum to indicate whether the assignment was allowed. These checks are @@ -2930,15 +3449,15 @@ public: enum AssignConvertType { /// Compatible - the types are compatible according to the standard. Compatible, - + /// PointerToInt - The assignment converts a pointer to an int, which we /// accept as an extension. PointerToInt, - + /// IntToPointer - The assignment converts an int to a pointer, which we /// accept as an extension. IntToPointer, - + /// FunctionVoidPointer - The assignment is between a function pointer and /// void*, which the standard doesn't allow, but we accept as an extension. FunctionVoidPointer, @@ -2960,25 +3479,25 @@ public: /// IncompatibleVectors - The assignment is between two vector types that /// have the same size, which we accept as an extension. IncompatibleVectors, - - /// IntToBlockPointer - The assignment converts an int to a block + + /// IntToBlockPointer - The assignment converts an int to a block /// pointer. We disallow this. IntToBlockPointer, - /// IncompatibleBlockPointer - The assignment is between two block + /// IncompatibleBlockPointer - The assignment is between two block /// pointers types that are not compatible. IncompatibleBlockPointer, - + /// IncompatibleObjCQualifiedId - The assignment is between a qualified /// id type and something else (that is incompatible with it). For example, /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol. IncompatibleObjCQualifiedId, - + /// Incompatible - We reject this conversion outright, it is invalid to /// represent it in the AST. Incompatible }; - + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. @@ -2986,39 +3505,46 @@ public: SourceLocation Loc, QualType DstType, QualType SrcType, Expr *SrcExpr, const char *Flavor); - - /// CheckAssignmentConstraints - Perform type checking for assignment, - /// argument passing, variable initialization, and function return values. + + /// CheckAssignmentConstraints - Perform type checking for assignment, + /// argument passing, variable initialization, and function return values. /// This routine is only used by the following two methods. C99 6.5.16. AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); - - // CheckSingleAssignmentConstraints - Currently used by - // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, + + // CheckSingleAssignmentConstraints - Currently used by + // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, // this routine performs the default function/array converions. - AssignConvertType CheckSingleAssignmentConstraints(QualType lhs, + AssignConvertType CheckSingleAssignmentConstraints(QualType lhs, Expr *&rExpr); // \brief If the lhs type is a transparent union, check whether we // can initialize the transparent union with the given expression. - AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs, + AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs, Expr *&rExpr); - + // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) - AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, + AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType); - + // Helper function for CheckAssignmentConstraints involving two // block pointer types. - AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, + AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, QualType rhsType); bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); - bool PerformImplicitConversion(Expr *&From, QualType ToType, + bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); + + bool PerformImplicitConversion(Expr *&From, QualType ToType, const char *Flavor, bool AllowExplicit = false, bool Elidable = false); - bool PerformImplicitConversion(Expr *&From, QualType ToType, + bool PerformImplicitConversion(Expr *&From, QualType ToType, + const char *Flavor, + bool AllowExplicit, + bool Elidable, + ImplicitConversionSequence& ICS); + bool PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence& ICS, const char *Flavor); bool PerformImplicitConversion(Expr *&From, QualType ToType, @@ -3065,7 +3591,7 @@ public: inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); inline 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 QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc, @@ -3073,19 +3599,20 @@ public: QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal); - + /// type checking primary expressions. QualType CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, - IdentifierInfo &Comp, SourceLocation CmpLoc); - + const IdentifierInfo *Comp, + SourceLocation CmpLoc); + /// type checking declaration initializers (C99 6.7.8) - + bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType, SourceLocation InitLoc,DeclarationName InitEntity, bool DirectInit); bool CheckInitList(InitListExpr *&InitList, QualType &DeclType); bool CheckForConstantInitializer(Expr *e, QualType t); - + bool CheckValueInitialization(QualType Type, SourceLocation Loc); // type checking C++ declaration initializers (C++ [dcl.init]). @@ -3115,48 +3642,70 @@ public: bool& DerivedToBase); bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType, - ImplicitConversionSequence *ICS = 0, - bool SuppressUserConversions = false, - bool AllowExplicit = false, - bool ForceRValue = false); - - /// CheckCastTypes - Check type constraints for casting between types. - bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr); - - // CheckVectorCast - check type constraints for vectors. + SourceLocation DeclLoc, + bool SuppressUserConversions, + bool AllowExplicit, + bool ForceRValue, + ImplicitConversionSequence *ICS = 0); + + /// CheckCastTypes - Check type constraints for casting between types under + /// C semantics, or forward to CXXCheckCStyleCast in C++. + bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr, + CastExpr::CastKind &Kind, + CXXMethodDecl *& ConversionDecl, + bool FunctionalStyle = false); + + // CheckVectorCast - check type constraints for vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. // returns true if the cast is invalid bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty); - - // CheckExtVectorCast - check type constraints for extended vectors. + + // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, // or vectors and the element type of that vector. // returns true if the cast is invalid bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty); - - /// CheckMessageArgumentTypes - Check types in an Obj-C message send. + + /// CXXCheckCStyleCast - Check constraints of a C-style or function-style + /// cast under C++ semantics. + bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, + CastExpr::CastKind &Kind, bool FunctionalStyle, + CXXMethodDecl *&ConversionDecl); + + /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. /// \param [out] ReturnType - The return type of the send. /// \return true iff there were any incompatible types. bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel, ObjCMethodDecl *Method, bool isClassMessage, SourceLocation lbrac, SourceLocation rbrac, - QualType &ReturnType); + QualType &ReturnType); + + /// CheckBooleanCondition - Diagnose problems involving the use of + /// the given expression as a boolean condition (e.g. in an if + /// statement). Also performs the standard function and array + /// decays, possibly changing the input variable. + /// + /// \param Loc - A location associated with the condition, e.g. the + /// 'if' keyword. + /// \return true iff there were any errors + bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc); + + /// DiagnoseAssignmentAsCondition - Given that an expression is + /// being used as a boolean condition, warn if it's an assignment. + void DiagnoseAssignmentAsCondition(Expr *E); /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. bool CheckCXXBooleanCondition(Expr *&CondExpr); - + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. - void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, + void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, unsigned NewWidth, bool NewSign, SourceLocation Loc, unsigned DiagID); - - bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, - bool ForCompare); /// Checks that the Objective-C declaration is declared in the global scope. /// Emits an error and marks the declaration as invalid if it's not declared @@ -3171,23 +3720,67 @@ public: bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0); /// VerifyBitField - verifies that a bit field expression is an ICE and has - /// the correct width, and that the field type is valid. + /// the correct width, and that the field type is valid. /// Returns false on success. - bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, - QualType FieldTy, const Expr *BitWidth); + /// Can optionally return whether the bit-field is of width 0 + bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, + QualType FieldTy, const Expr *BitWidth, + bool *ZeroWidth = 0); + + /// adjustFunctionParamType - Converts the type of a function parameter to a + // type that can be passed as an argument type to + /// ASTContext::getFunctionType. + /// + /// C++ [dcl.fct]p3: "...Any cv-qualifier modifying a parameter type is + /// deleted. Such cv-qualifiers affect only the definition of the parameter + /// within the body of the function; they do not affect the function type. + QualType adjustFunctionParamType(QualType T) const { + if (!Context.getLangOptions().CPlusPlus) + return T; + return + T->isDependentType() ? T.getUnqualifiedType() + : T.getDesugaredType().getUnqualifiedType(); + + } + /// \name Code completion + //@{ + void setCodeCompleteConsumer(CodeCompleteConsumer *CCC); + virtual void CodeCompleteOrdinaryName(Scope *S); + virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, + SourceLocation OpLoc, + bool IsArrow); + virtual void CodeCompleteTag(Scope *S, unsigned TagSpec); + virtual void CodeCompleteCase(Scope *S); + virtual void CodeCompleteCall(Scope *S, ExprTy *Fn, + ExprTy **Args, unsigned NumArgs); + virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, + bool EnteringContext); + virtual void CodeCompleteUsing(Scope *S); + virtual void CodeCompleteUsingDirective(Scope *S); + virtual void CodeCompleteNamespaceDecl(Scope *S); + virtual void CodeCompleteNamespaceAliasDecl(Scope *S); + virtual void CodeCompleteOperatorName(Scope *S); + + virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS); + //@} + //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system private: - Action::OwningExprResult CheckFunctionCall(FunctionDecl *FDecl, - CallExpr *TheCall); - - Action::OwningExprResult CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); + bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); + SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const; + bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall); bool CheckObjCString(Expr *Arg); + + Action::OwningExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); + bool SemaBuiltinUnaryFP(CallExpr *TheCall); bool SemaBuiltinStackAddress(CallExpr *TheCall); public: @@ -3195,19 +3788,20 @@ public: Action::OwningExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); private: - bool SemaBuiltinPrefetch(CallExpr *TheCall); + bool SemaBuiltinPrefetch(CallExpr *TheCall); bool SemaBuiltinObjectSize(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall); + bool SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall); bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg); void CheckPrintfString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg); - void CheckNonNullArguments(const NonNullAttr *NonNull, + void CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall); - void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, + void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg); void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); @@ -3221,12 +3815,12 @@ template <typename T> class ExprOwningPtr : public Action::ExprArg { public: ExprOwningPtr(Sema *S, T *expr) : Action::ExprArg(*S, expr) {} - + void reset(T* p) { Action::ExprArg::operator=(p); } T* get() const { return static_cast<T*>(Action::ExprArg::get()); } T* take() { return static_cast<T*>(Action::ExprArg::take()); } T* release() { return take(); } - + T& operator*() const { return *get(); } T* operator->() const { return get(); } }; diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index bae69ac6dc74a..21f83a560d7c4 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -11,15 +11,16 @@ // //===----------------------------------------------------------------------===// -#include "SemaInherit.h" #include "Sema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclCXX.h" using namespace clang; /// SetMemberAccessSpecifier - Set the access specifier of a member. /// Returns true on error (when the previous member decl access specifier /// is different from the new member decl access specifier). -bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, +bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS) { if (!PrevMemberDecl) { @@ -27,52 +28,49 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, MemberDecl->setAccess(LexicalAS); return false; } - + // C++ [class.access.spec]p3: When a member is redeclared its access // specifier must be same as its initial declaration. if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { - Diag(MemberDecl->getLocation(), - diag::err_class_redeclared_with_different_access) + Diag(MemberDecl->getLocation(), + diag::err_class_redeclared_with_different_access) << MemberDecl << LexicalAS; Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) << PrevMemberDecl << PrevMemberDecl->getAccess(); return true; } - + MemberDecl->setAccess(PrevMemberDecl->getAccess()); return false; } -/// CheckBaseClassAccess - Check that a derived class can access its base class -/// and report an error if it can't. [class.access.base] -bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, - unsigned InaccessibleBaseID, - BasePaths& Paths, SourceLocation AccessLoc, - DeclarationName Name) { +/// Find a class on the derivation path between Derived and Base that is +/// inaccessible. If @p NoPrivileges is true, special access rights (members +/// and friends) are not considered. +const CXXBaseSpecifier *Sema::FindInaccessibleBase( + QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) { Base = Context.getCanonicalType(Base).getUnqualifiedType(); - assert(!Paths.isAmbiguous(Base) && + assert(!Paths.isAmbiguous(Base) && "Can't check base class access if set of paths is ambiguous"); assert(Paths.isRecordingPaths() && "Can't check base class access without recorded paths"); - - if (!getLangOptions().AccessControl) - return false; - - const CXXBaseSpecifier *InacessibleBase = 0; - const CXXRecordDecl* CurrentClassDecl = 0; + + const CXXBaseSpecifier *InaccessibleBase = 0; + + const CXXRecordDecl *CurrentClassDecl = 0; if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl())) CurrentClassDecl = MD->getParent(); - for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); + for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); Path != PathsEnd; ++Path) { - + bool FoundInaccessibleBase = false; - - for (BasePath::const_iterator Element = Path->begin(), + + for (CXXBasePath::const_iterator Element = Path->begin(), ElementEnd = Path->end(); Element != ElementEnd; ++Element) { const CXXBaseSpecifier *Base = Element->Base; - + switch (Base->getAccessSpecifier()) { default: assert(0 && "invalid access specifier"); @@ -81,44 +79,59 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, break; case AS_private: // FIXME: Check if the current function/class is a friend. - if (CurrentClassDecl != Element->Class) + if (NoPrivileges || CurrentClassDecl != Element->Class) FoundInaccessibleBase = true; break; - case AS_protected: + case AS_protected: // FIXME: Implement break; } - + if (FoundInaccessibleBase) { - InacessibleBase = Base; + InaccessibleBase = Base; break; } } - + if (!FoundInaccessibleBase) { // We found a path to the base, our work here is done. - InacessibleBase = 0; - break; + return 0; } } - if (InacessibleBase) { - Diag(AccessLoc, InaccessibleBaseID) + assert(InaccessibleBase && "no path found, but no inaccessible base"); + return InaccessibleBase; +} + +/// CheckBaseClassAccess - Check that a derived class can access its base class +/// and report an error if it can't. [class.access.base] +bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + CXXBasePaths &Paths, SourceLocation AccessLoc, + DeclarationName Name) { + + if (!getLangOptions().AccessControl) + return false; + const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase( + Derived, Base, Paths); + + if (InaccessibleBase) { + Diag(AccessLoc, InaccessibleBaseID) << Derived << Base << Name; - AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten(); - + AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten(); + // If there's no written access specifier, then the inheritance specifier // is implicitly private. if (AS == AS_none) - Diag(InacessibleBase->getSourceRange().getBegin(), + Diag(InaccessibleBase->getSourceRange().getBegin(), diag::note_inheritance_implicitly_private_here); else - Diag(InacessibleBase->getSourceRange().getBegin(), + Diag(InaccessibleBase->getSourceRange().getBegin(), diag::note_inheritance_specifier_here) << AS; return true; } - + return false; } diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 1bf8444c42b74..0a5335a2be05e 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -32,8 +32,8 @@ namespace { /// Stack - Entries in the #pragma pack stack, consisting of saved /// alignments and optional names. stack_ty Stack; - - public: + + public: PragmaPackStack() : Alignment(0) {} void setAlignment(unsigned A) { Alignment = A; } @@ -56,14 +56,14 @@ namespace { bool PragmaPackStack::pop(IdentifierInfo *Name) { if (Stack.empty()) return false; - + // If name is empty just pop top. if (!Name) { Alignment = Stack.back().first; Stack.pop_back(); return true; - } - + } + // Otherwise, find the named record. for (unsigned i = Stack.size(); i != 0; ) { --i; @@ -74,7 +74,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) { return true; } } - + return false; } @@ -93,8 +93,8 @@ unsigned Sema::getPragmaPackAlignment() const { return 0; } -void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, - ExprTy *alignment, SourceLocation PragmaLoc, +void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, + ExprTy *alignment, SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { Expr *Alignment = static_cast<Expr *>(alignment); @@ -102,7 +102,7 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, unsigned AlignmentVal = 0; if (Alignment) { llvm::APSInt Val; - + // pack(0) is like pack(), which just works out since that is what // we use 0 for in PackAttr. if (!Alignment->isIntegerConstantExpr(Val, Context) || @@ -115,12 +115,12 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, AlignmentVal = (unsigned) Val.getZExtValue(); } - + if (PackContext == 0) PackContext = new PragmaPackStack(); - + PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); - + switch (Kind) { case Action::PPK_Default: // pack([n]) Context->setAlignment(AlignmentVal); @@ -140,15 +140,15 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, Context->push(Name); // Set the new alignment if specified. if (Alignment) - Context->setAlignment(AlignmentVal); + Context->setAlignment(AlignmentVal); break; case Action::PPK_Pop: // pack(pop [, id] [, n]) // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack: // "#pragma pack(pop, identifier, n) is undefined" if (Alignment && Name) - Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment); - + Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment); + // Do the pop. if (!Context->pop(Name)) { // If a name was specified then failure indicates the name @@ -170,42 +170,34 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, } } -void Sema::ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, +void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers, + Scope *curScope, SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { - - // Verify that all of the expressions are valid before - // modifying the attributes of any referenced decl. - Expr *ErrorExpr = 0; - - for (unsigned i = 0; i < NumExprs; ++i) { - Expr *Ex = (Expr*) Exprs[i]; - if (!isa<DeclRefExpr>(Ex)) { - ErrorExpr = Ex; - break; - } - Decl *d = cast<DeclRefExpr>(Ex)->getDecl();; + for (unsigned i = 0; i < NumIdentifiers; ++i) { + const Token &Tok = Identifiers[i]; + IdentifierInfo *Name = Tok.getIdentifierInfo(); + LookupResult Lookup; + LookupParsedName(Lookup, curScope, NULL, Name,LookupOrdinaryName, + false, true, Tok.getLocation()); + // FIXME: Handle Lookup.isAmbiguous? - if (!isa<VarDecl>(d) || !cast<VarDecl>(d)->hasLocalStorage()) { - ErrorExpr = Ex; - break; + NamedDecl *ND = Lookup.getAsSingleDecl(Context); + + if (!ND) { + Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) + << Name << SourceRange(Tok.getLocation()); + continue; } - } - - // Delete the expressions if we encountered any error. - if (ErrorExpr) { - Diag(ErrorExpr->getLocStart(), diag::warn_pragma_unused_expected_localvar); - for (unsigned i = 0; i < NumExprs; ++i) - ((Expr*) Exprs[i])->Destroy(Context); - return; - } - - // Otherwise, add the 'unused' attribute to each referenced declaration. - for (unsigned i = 0; i < NumExprs; ++i) { - DeclRefExpr *DR = (DeclRefExpr*) Exprs[i]; - DR->getDecl()->addAttr(::new (Context) UnusedAttr()); - DR->Destroy(Context); + + if (!isa<VarDecl>(ND) || !cast<VarDecl>(ND)->hasLocalStorage()) { + Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar) + << Name << SourceRange(Tok.getLocation()); + continue; + } + + ND->addAttr(::new (Context) UnusedAttr()); } } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp new file mode 100644 index 0000000000000..69d1f92a08323 --- /dev/null +++ b/lib/Sema/SemaCXXCast.cpp @@ -0,0 +1,1128 @@ +//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for C++ named casts. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/ADT/SmallVector.h" +#include <set> +using namespace clang; + +enum TryCastResult { + TC_NotApplicable, ///< The cast method is not applicable. + TC_Success, ///< The cast method is appropriate and successful. + TC_Failed ///< The cast method is appropriate, but failed. A + ///< diagnostic has been emitted. +}; + +enum CastType { + CT_Const, ///< const_cast + CT_Static, ///< static_cast + CT_Reinterpret, ///< reinterpret_cast + CT_Dynamic, ///< dynamic_cast + CT_CStyle, ///< (Type)expr + CT_Functional ///< Type(expr) +}; + +static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange); +static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange, + CastExpr::CastKind &Kind); +static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + CastExpr::CastKind &Kind, + CXXMethodDecl *&ConversionDecl); +static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange, + CastExpr::CastKind &Kind); + +static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); + +// The Try functions attempt a specific way of casting. If they succeed, they +// return TC_Success. If their way of casting is not appropriate for the given +// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic +// to emit if no other way succeeds. If their way of casting is appropriate but +// fails, they return TC_Failed and *must* set diag; they can set it to 0 if +// they emit a specialized diagnostic. +// All diagnostics returned by these functions must expect the same three +// arguments: +// %0: Cast Type (a value from the CastType enumeration) +// %1: Source Type +// %2: Destination Type +static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, + QualType DestType, unsigned &msg); +static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg); +static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg); +static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType, + QualType DestType, bool CStyle, + const SourceRange &OpRange, + QualType OrigSrcType, + QualType OrigDestType, unsigned &msg); +static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, + QualType DestType,bool CStyle, + const SourceRange &OpRange, + unsigned &msg); +static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind, + CXXMethodDecl *&ConversionDecl); +static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind, + CXXMethodDecl *&ConversionDecl); +static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, + bool CStyle, unsigned &msg); +static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind); + +/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. +Action::OwningExprResult +Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, TypeTy *Ty, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, ExprArg E, + SourceLocation RParenLoc) { + Expr *Ex = E.takeAs<Expr>(); + // FIXME: Preserve type source info. + QualType DestType = GetTypeFromParser(Ty); + SourceRange OpRange(OpLoc, RParenLoc); + SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc); + + // If the type is dependent, we won't do the semantic analysis now. + // FIXME: should we check this in a more fine-grained manner? + bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent(); + + switch (Kind) { + default: assert(0 && "Unknown C++ cast!"); + + case tok::kw_const_cast: + if (!TypeDependent) + CheckConstCast(*this, Ex, DestType, OpRange, DestRange); + return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(), + Ex, DestType, OpLoc)); + + case tok::kw_dynamic_cast: { + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (!TypeDependent) + CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind); + return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), + Kind, Ex, DestType, OpLoc)); + } + case tok::kw_reinterpret_cast: { + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (!TypeDependent) + CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); + return Owned(new (Context) CXXReinterpretCastExpr( + DestType.getNonReferenceType(), + Kind, Ex, DestType, OpLoc)); + } + case tok::kw_static_cast: { + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (!TypeDependent) { + CXXMethodDecl *Method = 0; + + CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method); + + if (Method) { + OwningExprResult CastArg + = BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(), + Kind, Method, Owned(Ex)); + if (CastArg.isInvalid()) + return ExprError(); + + Ex = CastArg.takeAs<Expr>(); + } + } + + return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), + Kind, Ex, DestType, OpLoc)); + } + } + + return ExprError(); +} + +/// CastsAwayConstness - Check if the pointer conversion from SrcType to +/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by +/// the cast checkers. Both arguments must denote pointer (possibly to member) +/// types. +bool +CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { + // Casting away constness is defined in C++ 5.2.11p8 with reference to + // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since + // the rules are non-trivial. So first we construct Tcv *...cv* as described + // in C++ 5.2.11p8. + assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) && + "Source type is not pointer or pointer to member."); + assert((DestType->isPointerType() || DestType->isMemberPointerType()) && + "Destination type is not pointer or pointer to member."); + + QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType; + llvm::SmallVector<Qualifiers, 8> cv1, cv2; + + // Find the qualifications. + while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { + cv1.push_back(UnwrappedSrcType.getQualifiers()); + cv2.push_back(UnwrappedDestType.getQualifiers()); + } + assert(cv1.size() > 0 && "Must have at least one pointer level."); + + // Construct void pointers with those qualifiers (in reverse order of + // unwrapping, of course). + QualType SrcConstruct = Self.Context.VoidTy; + QualType DestConstruct = Self.Context.VoidTy; + ASTContext &Context = Self.Context; + for (llvm::SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(), + i2 = cv2.rbegin(); + i1 != cv1.rend(); ++i1, ++i2) { + SrcConstruct + = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1)); + DestConstruct + = Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2)); + } + + // Test if they're compatible. + return SrcConstruct != DestConstruct && + !Self.IsQualificationConversion(SrcConstruct, DestConstruct); +} + +/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. +/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- +/// checked downcasts in class hierarchies. +static void +CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange, CastExpr::CastKind &Kind) { + QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); + DestType = Self.Context.getCanonicalType(DestType); + + // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, + // or "pointer to cv void". + + QualType DestPointee; + const PointerType *DestPointer = DestType->getAs<PointerType>(); + const ReferenceType *DestReference = DestType->getAs<ReferenceType>(); + if (DestPointer) { + DestPointee = DestPointer->getPointeeType(); + } else if (DestReference) { + DestPointee = DestReference->getPointeeType(); + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) + << OrigDestType << DestRange; + return; + } + + const RecordType *DestRecord = DestPointee->getAs<RecordType>(); + if (DestPointee->isVoidType()) { + assert(DestPointer && "Reference to void is not possible"); + } else if (DestRecord) { + if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, + PDiag(diag::err_bad_dynamic_cast_incomplete) + << DestRange)) + return; + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) + << DestPointee.getUnqualifiedType() << DestRange; + return; + } + + // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to + // complete class type, [...]. If T is an lvalue reference type, v shall be + // an lvalue of a complete class type, [...]. If T is an rvalue reference + // type, v shall be an expression having a complete effective class type, + // [...] + + QualType SrcType = Self.Context.getCanonicalType(OrigSrcType); + QualType SrcPointee; + if (DestPointer) { + if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) { + SrcPointee = SrcPointer->getPointeeType(); + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) + << OrigSrcType << SrcExpr->getSourceRange(); + return; + } + } else if (DestReference->isLValueReferenceType()) { + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) + << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + } + SrcPointee = SrcType; + } else { + SrcPointee = SrcType; + } + + const RecordType *SrcRecord = SrcPointee->getAs<RecordType>(); + if (SrcRecord) { + if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, + PDiag(diag::err_bad_dynamic_cast_incomplete) + << SrcExpr->getSourceRange())) + return; + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) + << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); + return; + } + + assert((DestPointer || DestReference) && + "Bad destination non-ptr/ref slipped through."); + assert((DestRecord || DestPointee->isVoidType()) && + "Bad destination pointee slipped through."); + assert(SrcRecord && "Bad source pointee slipped through."); + + // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. + if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) + << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + return; + } + + // C++ 5.2.7p3: If the type of v is the same as the required result type, + // [except for cv]. + if (DestRecord == SrcRecord) { + return; + } + + // C++ 5.2.7p5 + // Upcasts are resolved statically. + if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { + Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, + OpRange.getBegin(), OpRange); + Kind = CastExpr::CK_DerivedToBase; + // Diagnostic already emitted on error. + return; + } + + // C++ 5.2.7p6: Otherwise, v shall be [polymorphic]. + const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context); + assert(SrcDecl && "Definition missing"); + if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) + << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); + } + + // Done. Everything else is run-time checks. + Kind = CastExpr::CK_Dynamic; +} + +/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid. +/// Refer to C++ 5.2.11 for details. const_cast is typically used in code +/// like this: +/// const char *str = "literal"; +/// legacy_function(const_cast\<char*\>(str)); +void +CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, const SourceRange &DestRange) { + if (!DestType->isLValueReferenceType()) + Self.DefaultFunctionArrayConversion(SrcExpr); + + unsigned msg = diag::err_bad_cxx_cast_generic; + if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success + && msg != 0) + Self.Diag(OpRange.getBegin(), msg) << CT_Const + << SrcExpr->getType() << DestType << OpRange; +} + +/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is +/// valid. +/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code +/// like this: +/// char *bytes = reinterpret_cast\<char*\>(int_ptr); +void +CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, const SourceRange &DestRange, + CastExpr::CastKind &Kind) { + if (!DestType->isLValueReferenceType()) + Self.DefaultFunctionArrayConversion(SrcExpr); + + unsigned msg = diag::err_bad_cxx_cast_generic; + if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, + msg, Kind) + != TC_Success && msg != 0) + Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret + << SrcExpr->getType() << DestType << OpRange; +} + + +/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid. +/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making +/// implicit conversions explicit and getting rid of data loss warnings. +void +CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, CastExpr::CastKind &Kind, + CXXMethodDecl *&ConversionDecl) { + // This test is outside everything else because it's the only case where + // a non-lvalue-reference target type does not lead to decay. + // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". + if (DestType->isVoidType()) { + return; + } + + if (!DestType->isLValueReferenceType()) + Self.DefaultFunctionArrayConversion(SrcExpr); + + unsigned msg = diag::err_bad_cxx_cast_generic; + if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false,OpRange, msg, + Kind, ConversionDecl) + != TC_Success && msg != 0) + Self.Diag(OpRange.getBegin(), msg) << CT_Static + << SrcExpr->getType() << DestType << OpRange; +} + +/// TryStaticCast - Check if a static cast can be performed, and do so if +/// possible. If @p CStyle, ignore access restrictions on hierarchy casting +/// and casting away constness. +static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, + QualType DestType, bool CStyle, + const SourceRange &OpRange, unsigned &msg, + CastExpr::CastKind &Kind, + CXXMethodDecl *&ConversionDecl) { + // The order the tests is not entirely arbitrary. There is one conversion + // that can be handled in two different ways. Given: + // struct A {}; + // struct B : public A { + // B(); B(const A&); + // }; + // const A &a = B(); + // the cast static_cast<const B&>(a) could be seen as either a static + // reference downcast, or an explicit invocation of the user-defined + // conversion using B's conversion constructor. + // DR 427 specifies that the downcast is to be applied here. + + // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". + // Done outside this function. + + TryCastResult tcr; + + // C++ 5.2.9p5, reference downcast. + // See the function for details. + // DR 427 specifies that this is to be applied before paragraph 2. + tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle,OpRange,msg); + if (tcr != TC_NotApplicable) + return tcr; + + // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue + // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". + tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg); + if (tcr != TC_NotApplicable) + return tcr; + + // C++ 5.2.9p2: An expression e can be explicitly converted to a type T + // [...] if the declaration "T t(e);" is well-formed, [...]. + tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg, + Kind, ConversionDecl); + if (tcr != TC_NotApplicable) + return tcr; + + // C++ 5.2.9p6: May apply the reverse of any standard conversion, except + // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean + // conversions, subject to further restrictions. + // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal + // of qualification conversions impossible. + // In the CStyle case, the earlier attempt to const_cast should have taken + // care of reverse qualification conversions. + + QualType OrigSrcType = SrcExpr->getType(); + + QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType()); + + // Reverse integral promotion/conversion. All such conversions are themselves + // again integral promotions or conversions and are thus already handled by + // p2 (TryDirectInitialization above). + // (Note: any data loss warnings should be suppressed.) + // The exception is the reverse of enum->integer, i.e. integer->enum (and + // enum->enum). See also C++ 5.2.9p7. + // The same goes for reverse floating point promotion/conversion and + // floating-integral conversions. Again, only floating->enum is relevant. + if (DestType->isEnumeralType()) { + if (SrcType->isComplexType() || SrcType->isVectorType()) { + // Fall through - these cannot be converted. + } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) + return TC_Success; + } + + // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast. + // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance. + tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg); + if (tcr != TC_NotApplicable) + return tcr; + + // Reverse member pointer conversion. C++ 4.11 specifies member pointer + // conversion. C++ 5.2.9p9 has additional information. + // DR54's access restrictions apply here also. + tcr = TryStaticMemberPointerUpcast(Self, SrcType, DestType, CStyle, + OpRange, msg); + if (tcr != TC_NotApplicable) + return tcr; + + // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to + // void*. C++ 5.2.9p10 specifies additional restrictions, which really is + // just the usual constness stuff. + if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) { + QualType SrcPointee = SrcPointer->getPointeeType(); + if (SrcPointee->isVoidType()) { + if (const PointerType *DestPointer = DestType->getAs<PointerType>()) { + QualType DestPointee = DestPointer->getPointeeType(); + if (DestPointee->isIncompleteOrObjectType()) { + // This is definitely the intended conversion, but it might fail due + // to a const violation. + if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { + msg = diag::err_bad_cxx_cast_const_away; + return TC_Failed; + } + return TC_Success; + } + } + } + } + + // We tried everything. Everything! Nothing works! :-( + return TC_NotApplicable; +} + +/// Tests whether a conversion according to N2844 is valid. +TryCastResult +TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, + unsigned &msg) { + // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue + // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". + const RValueReferenceType *R = DestType->getAs<RValueReferenceType>(); + if (!R) + return TC_NotApplicable; + + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) + return TC_NotApplicable; + + // Because we try the reference downcast before this function, from now on + // this is the only cast possibility, so we issue an error if we fail now. + // FIXME: Should allow casting away constness if CStyle. + bool DerivedToBase; + if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(), + DerivedToBase) < + Sema::Ref_Compatible_With_Added_Qualification) { + msg = diag::err_bad_lvalue_to_rvalue_cast; + return TC_Failed; + } + + // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation + // than nothing. + return TC_Success; +} + +/// Tests whether a conversion according to C++ 5.2.9p5 is valid. +TryCastResult +TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, + bool CStyle, const SourceRange &OpRange, + unsigned &msg) { + // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be + // cast to type "reference to cv2 D", where D is a class derived from B, + // if a valid standard conversion from "pointer to D" to "pointer to B" + // exists, cv2 >= cv1, and B is not a virtual base class of D. + // In addition, DR54 clarifies that the base must be accessible in the + // current context. Although the wording of DR54 only applies to the pointer + // variant of this rule, the intent is clearly for it to apply to the this + // conversion as well. + + const ReferenceType *DestReference = DestType->getAs<ReferenceType>(); + if (!DestReference) { + return TC_NotApplicable; + } + bool RValueRef = DestReference->isRValueReferenceType(); + if (!RValueRef && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + // We know the left side is an lvalue reference, so we can suggest a reason. + msg = diag::err_bad_cxx_cast_rvalue; + return TC_NotApplicable; + } + + QualType DestPointee = DestReference->getPointeeType(); + + return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, CStyle, + OpRange, SrcExpr->getType(), DestType, msg); +} + +/// Tests whether a conversion according to C++ 5.2.9p8 is valid. +TryCastResult +TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, + bool CStyle, const SourceRange &OpRange, + unsigned &msg) { + // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class + // type, can be converted to an rvalue of type "pointer to cv2 D", where D + // is a class derived from B, if a valid standard conversion from "pointer + // to D" to "pointer to B" exists, cv2 >= cv1, and B is not a virtual base + // class of D. + // In addition, DR54 clarifies that the base must be accessible in the + // current context. + + const PointerType *DestPointer = DestType->getAs<PointerType>(); + if (!DestPointer) { + return TC_NotApplicable; + } + + const PointerType *SrcPointer = SrcType->getAs<PointerType>(); + if (!SrcPointer) { + msg = diag::err_bad_static_cast_pointer_nonpointer; + return TC_NotApplicable; + } + + return TryStaticDowncast(Self, SrcPointer->getPointeeType(), + DestPointer->getPointeeType(), CStyle, + OpRange, SrcType, DestType, msg); +} + +/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and +/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to +/// DestType, both of which must be canonical, is possible and allowed. +TryCastResult +TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, + bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, + QualType OrigDestType, unsigned &msg) { + // Downcast can only happen in class hierarchies, so we need classes. + if (!DestType->isRecordType() || !SrcType->isRecordType()) { + return TC_NotApplicable; + } + + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle, + /*DetectVirtual=*/true); + if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) { + return TC_NotApplicable; + } + + // Target type does derive from source type. Now we're serious. If an error + // appears now, it's not ignored. + // This may not be entirely in line with the standard. Take for example: + // struct A {}; + // struct B : virtual A { + // B(A&); + // }; + // + // void f() + // { + // (void)static_cast<const B&>(*((A*)0)); + // } + // As far as the standard is concerned, p5 does not apply (A is virtual), so + // p2 should be used instead - "const B& t(*((A*)0));" is perfectly valid. + // However, both GCC and Comeau reject this example, and accepting it would + // mean more complex code if we're to preserve the nice error message. + // FIXME: Being 100% compliant here would be nice to have. + + // Must preserve cv, as always, unless we're in C-style mode. + if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) { + msg = diag::err_bad_cxx_cast_const_away; + return TC_Failed; + } + + if (Paths.isAmbiguous(SrcType.getUnqualifiedType())) { + // This code is analoguous to that in CheckDerivedToBaseConversion, except + // that it builds the paths in reverse order. + // To sum up: record all paths to the base and build a nice string from + // them. Use it to spice up the error message. + if (!Paths.isRecordingPaths()) { + Paths.clear(); + Paths.setRecordingPaths(true); + Self.IsDerivedFrom(DestType, SrcType, Paths); + } + std::string PathDisplayStr; + std::set<unsigned> DisplayedPaths; + for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); + PI != PE; ++PI) { + if (DisplayedPaths.insert(PI->back().SubobjectNumber).second) { + // We haven't displayed a path to this particular base + // class subobject yet. + PathDisplayStr += "\n "; + for (CXXBasePath::const_reverse_iterator EI = PI->rbegin(), + EE = PI->rend(); + EI != EE; ++EI) + PathDisplayStr += EI->Base->getType().getAsString() + " -> "; + PathDisplayStr += DestType.getAsString(); + } + } + + Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast) + << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType() + << PathDisplayStr << OpRange; + msg = 0; + return TC_Failed; + } + + if (Paths.getDetectedVirtual() != 0) { + QualType VirtualBase(Paths.getDetectedVirtual(), 0); + Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual) + << OrigSrcType << OrigDestType << VirtualBase << OpRange; + msg = 0; + return TC_Failed; + } + + if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType, + diag::err_downcast_from_inaccessible_base, Paths, + OpRange.getBegin(), DeclarationName())) { + msg = 0; + return TC_Failed; + } + + return TC_Success; +} + +/// TryStaticMemberPointerUpcast - Tests whether a conversion according to +/// C++ 5.2.9p9 is valid: +/// +/// An rvalue of type "pointer to member of D of type cv1 T" can be +/// converted to an rvalue of type "pointer to member of B of type cv2 T", +/// where B is a base class of D [...]. +/// +TryCastResult +TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, + bool CStyle, const SourceRange &OpRange, + unsigned &msg) { + const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(); + if (!DestMemPtr) + return TC_NotApplicable; + const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>(); + if (!SrcMemPtr) { + msg = diag::err_bad_static_cast_member_pointer_nonmp; + return TC_NotApplicable; + } + + // T == T, modulo cv + if (Self.Context.getCanonicalType( + SrcMemPtr->getPointeeType().getUnqualifiedType()) != + Self.Context.getCanonicalType(DestMemPtr->getPointeeType(). + getUnqualifiedType())) + return TC_NotApplicable; + + // B base of D + QualType SrcClass(SrcMemPtr->getClass(), 0); + QualType DestClass(DestMemPtr->getClass(), 0); + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle, + /*DetectVirtual=*/true); + if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { + return TC_NotApplicable; + } + + // B is a base of D. But is it an allowed base? If not, it's a hard error. + if (Paths.isAmbiguous(DestClass)) { + Paths.clear(); + Paths.setRecordingPaths(true); + bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); + assert(StillOkay); + StillOkay = StillOkay; + std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths); + Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv) + << 1 << SrcClass << DestClass << PathDisplayStr << OpRange; + msg = 0; + return TC_Failed; + } + + if (const RecordType *VBase = Paths.getDetectedVirtual()) { + Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual) + << SrcClass << DestClass << QualType(VBase, 0) << OpRange; + msg = 0; + return TC_Failed; + } + + if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType, + diag::err_downcast_from_inaccessible_base, Paths, + OpRange.getBegin(), DeclarationName())) { + msg = 0; + return TC_Failed; + } + + return TC_Success; +} + +/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2 +/// is valid: +/// +/// An expression e can be explicitly converted to a type T using a +/// @c static_cast if the declaration "T t(e);" is well-formed [...]. +TryCastResult +TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, + bool CStyle, const SourceRange &OpRange, unsigned &msg, + CastExpr::CastKind &Kind, + CXXMethodDecl *&ConversionDecl) { + if (DestType->isRecordType()) { + if (Self.RequireCompleteType(OpRange.getBegin(), DestType, + diag::err_bad_dynamic_cast_incomplete)) { + msg = 0; + return TC_Failed; + } + } + + if (DestType->isReferenceType()) { + // At this point of CheckStaticCast, if the destination is a reference, + // this has to work. There is no other way that works. + // On the other hand, if we're checking a C-style cast, we've still got + // the reinterpret_cast way. In that case, we pass an ICS so we don't + // get error messages. + ImplicitConversionSequence ICS; + bool failed = Self.CheckReferenceInit(SrcExpr, DestType, + OpRange.getBegin(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + CStyle ? &ICS : 0); + if (!failed) + return TC_Success; + if (CStyle) + return TC_NotApplicable; + // If we didn't pass the ICS, we already got an error message. + msg = 0; + return TC_Failed; + } + + // FIXME: To get a proper error from invalid conversions here, we need to + // reimplement more of this. + // FIXME: This does not actually perform the conversion, and thus does not + // check for ambiguity or access. + ImplicitConversionSequence ICS = + Self.TryImplicitConversion(SrcExpr, DestType, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/true, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false, + /*one of user provided casts*/true); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + return TC_NotApplicable; + + if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) { + ConversionDecl = cast<CXXMethodDecl>(ICS.UserDefined.ConversionFunction); + if (isa<CXXConstructorDecl>(ConversionDecl)) + Kind = CastExpr::CK_ConstructorConversion; + else if (isa<CXXConversionDecl>(ConversionDecl)) + Kind = CastExpr::CK_UserDefinedConversion; + } else if (ICS.ConversionKind == + ImplicitConversionSequence::StandardConversion) { + // FIXME: Set the cast kind depending on which types of conversions we have. + } + + return TC_Success; +} + +/// TryConstCast - See if a const_cast from source to destination is allowed, +/// and perform it if it is. +static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, + bool CStyle, unsigned &msg) { + DestType = Self.Context.getCanonicalType(DestType); + QualType SrcType = SrcExpr->getType(); + if (const LValueReferenceType *DestTypeTmp = + DestType->getAs<LValueReferenceType>()) { + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + // Cannot const_cast non-lvalue to lvalue reference type. But if this + // is C-style, static_cast might find a way, so we simply suggest a + // message and tell the parent to keep searching. + msg = diag::err_bad_cxx_cast_rvalue; + return TC_NotApplicable; + } + + // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2 + // [...] if a pointer to T1 can be [cast] to the type pointer to T2. + DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); + SrcType = Self.Context.getPointerType(SrcType); + } + + // 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()) { + // 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 + // conversion to them is simply invalid. + // C++ 5.2.11p3: For two pointer types [...] + if (!CStyle) + msg = diag::err_bad_const_cast_dest; + return TC_NotApplicable; + } + if (DestType->isFunctionPointerType() || + DestType->isMemberFunctionPointerType()) { + // Cannot cast direct function pointers. + // C++ 5.2.11p2: [...] where T is any object type or the void type [...] + // T is the ultimate pointee of source and target type. + if (!CStyle) + msg = diag::err_bad_const_cast_dest; + return TC_NotApplicable; + } + SrcType = Self.Context.getCanonicalType(SrcType); + + // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are + // completely equal. + // FIXME: const_cast should probably not be able to convert between pointers + // to different address spaces. + // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers + // in multi-level pointers may change, but the level count must be the same, + // as must be the final pointee type. + while (SrcType != DestType && + Self.UnwrapSimilarPointerTypes(SrcType, DestType)) { + SrcType = SrcType.getUnqualifiedType(); + DestType = DestType.getUnqualifiedType(); + } + + // Since we're dealing in canonical types, the remainder must be the same. + if (SrcType != DestType) + return TC_NotApplicable; + + return TC_Success; +} + +static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind) { + QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); + + DestType = Self.Context.getCanonicalType(DestType); + QualType SrcType = SrcExpr->getType(); + if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) { + bool LValue = DestTypeTmp->isLValueReferenceType(); + if (LValue && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + // Cannot cast non-lvalue to reference type. See the similar comment in + // const_cast. + msg = diag::err_bad_cxx_cast_rvalue; + return TC_NotApplicable; + } + + // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the + // same effect as the conversion *reinterpret_cast<T*>(&x) with the + // built-in & and * operators. + // This code does this transformation for the checked types. + DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); + SrcType = Self.Context.getPointerType(SrcType); + } + + // Canonicalize source for comparison. + SrcType = Self.Context.getCanonicalType(SrcType); + + const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(), + *SrcMemPtr = SrcType->getAs<MemberPointerType>(); + if (DestMemPtr && SrcMemPtr) { + // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1" + // can be explicitly converted to an rvalue of type "pointer to member + // of Y of type T2" if T1 and T2 are both function types or both object + // types. + if (DestMemPtr->getPointeeType()->isFunctionType() != + SrcMemPtr->getPointeeType()->isFunctionType()) + return TC_NotApplicable; + + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away + // constness. + // A reinterpret_cast followed by a const_cast can, though, so in C-style, + // we accept it. + if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) { + msg = diag::err_bad_cxx_cast_const_away; + return TC_Failed; + } + + // A valid member pointer cast. + return TC_Success; + } + + // See below for the enumeral issue. + if (SrcType->isNullPtrType() && DestType->isIntegralType() && + !DestType->isEnumeralType()) { + // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral + // type large enough to hold it. A value of std::nullptr_t can be + // converted to an integral type; the conversion has the same meaning + // and validity as a conversion of (void*)0 to the integral type. + if (Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType)) { + msg = diag::err_bad_reinterpret_cast_small_int; + return TC_Failed; + } + Kind = CastExpr::CK_PointerToIntegral; + return TC_Success; + } + + bool destIsVector = DestType->isVectorType(); + bool srcIsVector = SrcType->isVectorType(); + if (srcIsVector || destIsVector) { + bool srcIsScalar = SrcType->isIntegralType() && !SrcType->isEnumeralType(); + bool destIsScalar = + DestType->isIntegralType() && !DestType->isEnumeralType(); + + // Check if this is a cast between a vector and something else. + if (!(srcIsScalar && destIsVector) && !(srcIsVector && destIsScalar) && + !(srcIsVector && destIsVector)) + return TC_NotApplicable; + + // If both types have the same size, we can successfully cast. + if (Self.Context.getTypeSize(SrcType) == Self.Context.getTypeSize(DestType)) + return TC_Success; + + if (destIsScalar) + msg = diag::err_bad_cxx_cast_vector_to_scalar_different_size; + else if (srcIsScalar) + msg = diag::err_bad_cxx_cast_scalar_to_vector_different_size; + else + msg = diag::err_bad_cxx_cast_vector_to_vector_different_size; + + return TC_Failed; + } + + bool destIsPtr = DestType->isPointerType(); + bool srcIsPtr = SrcType->isPointerType(); + if (!destIsPtr && !srcIsPtr) { + // Except for std::nullptr_t->integer and lvalue->reference, which are + // handled above, at least one of the two arguments must be a pointer. + return TC_NotApplicable; + } + + if (SrcType == DestType) { + // C++ 5.2.10p2 has a note that mentions that, subject to all other + // restrictions, a cast to the same type is allowed. The intent is not + // entirely clear here, since all other paragraphs explicitly forbid casts + // to the same type. However, the behavior of compilers is pretty consistent + // on this point: allow same-type conversion if the involved types are + // pointers, disallow otherwise. + return TC_Success; + } + + // Note: Clang treats enumeration types as integral types. If this is ever + // changed for C++, the additional check here will be redundant. + if (DestType->isIntegralType() && !DestType->isEnumeralType()) { + assert(srcIsPtr && "One type must be a pointer"); + // C++ 5.2.10p4: A pointer can be explicitly converted to any integral + // type large enough to hold it. + if (Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType)) { + msg = diag::err_bad_reinterpret_cast_small_int; + return TC_Failed; + } + Kind = CastExpr::CK_PointerToIntegral; + return TC_Success; + } + + if (SrcType->isIntegralType() || SrcType->isEnumeralType()) { + assert(destIsPtr && "One type must be a pointer"); + // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly + // converted to a pointer. + Kind = CastExpr::CK_IntegralToPointer; + return TC_Success; + } + + if (!destIsPtr || !srcIsPtr) { + // With the valid non-pointer conversions out of the way, we can be even + // more stringent. + return TC_NotApplicable; + } + + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. + // The C-style cast operator can. + if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) { + msg = diag::err_bad_cxx_cast_const_away; + return TC_Failed; + } + + // Not casting away constness, so the only remaining check is for compatible + // pointer categories. + + if (SrcType->isFunctionPointerType()) { + if (DestType->isFunctionPointerType()) { + // C++ 5.2.10p6: A pointer to a function can be explicitly converted to + // a pointer to a function of a different type. + return TC_Success; + } + + // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to + // an object type or vice versa is conditionally-supported. + // Compilers support it in C++03 too, though, because it's necessary for + // casting the return value of dlsym() and GetProcAddress(). + // FIXME: Conditionally-supported behavior should be configurable in the + // TargetInfo or similar. + if (!Self.getLangOptions().CPlusPlus0x) + Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange; + return TC_Success; + } + + if (DestType->isFunctionPointerType()) { + // See above. + if (!Self.getLangOptions().CPlusPlus0x) + Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange; + return TC_Success; + } + + // C++ 5.2.10p7: A pointer to an object can be explicitly converted to + // a pointer to an object of different type. + // Void pointers are not specified, but supported by every compiler out there. + // So we finish by allowing everything that remains - it's got to be two + // object pointers. + Kind = CastExpr::CK_BitCast; + return TC_Success; +} + +bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, + CastExpr::CastKind &Kind, bool FunctionalStyle, + CXXMethodDecl *&ConversionDecl) { + // This test is outside everything else because it's the only case where + // a non-lvalue-reference target type does not lead to decay. + // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". + if (CastTy->isVoidType()) + return false; + + // If the type is dependent, we won't do any other semantic analysis now. + if (CastTy->isDependentType() || CastExpr->isTypeDependent()) + return false; + + if (!CastTy->isLValueReferenceType()) + DefaultFunctionArrayConversion(CastExpr); + + // C++ [expr.cast]p5: The conversions performed by + // - a const_cast, + // - a static_cast, + // - a static_cast followed by a const_cast, + // - a reinterpret_cast, or + // - a reinterpret_cast followed by a const_cast, + // can be performed using the cast notation of explicit type conversion. + // [...] If a conversion can be interpreted in more than one of the ways + // listed above, the interpretation that appears first in the list is used, + // even if a cast resulting from that interpretation is ill-formed. + // In plain language, this means trying a const_cast ... + unsigned msg = diag::err_bad_cxx_cast_generic; + TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true, + msg); + if (tcr == TC_NotApplicable) { + // ... or if that is not possible, a static_cast, ignoring const, ... + tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, + Kind, ConversionDecl); + if (tcr == TC_NotApplicable) { + // ... and finally a reinterpret_cast, ignoring const. + tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, + Kind); + } + } + + if (tcr != TC_Success && msg != 0) + Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle) + << CastExpr->getType() << CastTy << R; + + return tcr != TC_Success; +} diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index a14bcd5287cd5..10c138c7558f5 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -14,26 +14,89 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; +/// \brief Compute the DeclContext that is associated with the given type. +/// +/// \param T the type for which we are attempting to find a DeclContext. +/// +/// \returns the declaration context represented by the type T, +/// or NULL if the declaration context cannot be computed (e.g., because it is +/// dependent and not the current instantiation). +DeclContext *Sema::computeDeclContext(QualType T) { + if (const TagType *Tag = T->getAs<TagType>()) + return Tag->getDecl(); + + return 0; +} + /// \brief Compute the DeclContext that is associated with the given /// scope specifier. -DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) { +/// +/// \param SS the C++ scope specifier as it appears in the source +/// +/// \param EnteringContext when true, we will be entering the context of +/// this scope specifier, so we can retrieve the declaration context of a +/// class template or class template partial specialization even if it is +/// not the current instantiation. +/// +/// \returns the declaration context represented by the scope specifier @p SS, +/// or NULL if the declaration context cannot be computed (e.g., because it is +/// dependent and not the current instantiation). +DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, + bool EnteringContext) { if (!SS.isSet() || SS.isInvalid()) return 0; - NestedNameSpecifier *NNS + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); if (NNS->isDependent()) { // If this nested-name-specifier refers to the current // instantiation, return its DeclContext. if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS)) return Record; - else - return 0; + + if (EnteringContext) { + if (const TemplateSpecializationType *SpecType + = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) { + // We are entering the context of the nested name specifier, so try to + // match the nested name specifier to either a primary class template + // or a class template partial specialization. + if (ClassTemplateDecl *ClassTemplate + = dyn_cast_or_null<ClassTemplateDecl>( + SpecType->getTemplateName().getAsTemplateDecl())) { + QualType ContextType + = Context.getCanonicalType(QualType(SpecType, 0)); + + // If the type of the nested name specifier is the same as the + // injected class name of the named class template, we're entering + // into that class template definition. + QualType Injected = ClassTemplate->getInjectedClassNameType(Context); + if (Context.hasSameType(Injected, ContextType)) + return ClassTemplate->getTemplatedDecl(); + + // If the type of the nested name specifier is the same as the + // type of one of the class template's class template partial + // specializations, we're entering into the definition of that + // class template partial specialization. + if (ClassTemplatePartialSpecializationDecl *PartialSpec + = ClassTemplate->findPartialSpecialization(ContextType)) + return PartialSpec; + } + } else if (const RecordType *RecordT + = dyn_cast_or_null<RecordType>(NNS->getAsType())) { + // The nested name specifier refers to a member of a class template. + return RecordT->getDecl(); + } + } + + return 0; } switch (NNS->getKind()) { @@ -46,7 +109,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - const TagType *Tag = NNS->getAsType()->getAsTagType(); + const TagType *Tag = NNS->getAsType()->getAs<TagType>(); assert(Tag && "Non-tag type in nested-name-specifier"); return Tag->getDecl(); } break; @@ -63,7 +126,7 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) { if (!SS.isSet() || SS.isInvalid()) return false; - NestedNameSpecifier *NNS + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); return NNS->isDependent(); } @@ -75,7 +138,7 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { if (!isDependentScopeSpecifier(SS)) return false; - NestedNameSpecifier *NNS + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); return getCurrentInstantiationOf(NNS) == 0; } @@ -89,6 +152,9 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { assert(getLangOptions().CPlusPlus && "Only callable in C++"); assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed"); + if (!NNS->getAsType()) + return 0; + QualType T = QualType(NNS->getAsType(), 0); // If the nested name specifier does not refer to a type, then it // does not refer to the current instantiation. @@ -108,7 +174,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { if (!Record) continue; - // If this record type is not dependent, + // If this record type is not dependent, if (!Record->isDependentType()) return 0; @@ -126,27 +192,29 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { // enclosed in <>, // -- in the definition of a nested class of a class template, // the name of the nested class referenced as a member of - // the current instantiation, or + // the current instantiation, or // -- in the definition of a partial specialization, the name // of the class template followed by the template argument // list of the partial specialization enclosed in <>. If // the nth template parameter is a parameter pack, the nth // template argument is a pack expansion (14.6.3) whose - // pattern is the name of the parameter pack. (FIXME) + // pattern is the name of the parameter pack. + // (FIXME: parameter packs) // // All of these options come down to having the // nested-name-specifier type that is equivalent to the // injected-class-name of one of the types that is currently in // our context. - if (Context.getTypeDeclType(Record) == T) + if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) return Record; - + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { - QualType InjectedClassName + QualType InjectedClassName = Template->getInjectedClassNameType(Context); if (T == Context.getCanonicalType(InjectedClassName)) return Template->getTemplatedDecl(); } + // FIXME: check for class template partial specializations } return 0; @@ -164,20 +232,20 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { if (!SS.isSet() || SS.isInvalid()) return false; - - DeclContext *DC = computeDeclContext(SS); + + DeclContext *DC = computeDeclContext(SS, true); if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. - const TagType *TagT = Context.getTypeDeclType(Tag)->getAsTagType(); + const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>(); if (TagT->isBeingDefined()) return false; // The type must be complete. return RequireCompleteType(SS.getRange().getBegin(), Context.getTypeDeclType(Tag), - diag::err_incomplete_nested_name_spec, - SS.getRange()); + PDiag(diag::err_incomplete_nested_name_spec) + << SS.getRange()); } return false; @@ -190,72 +258,222 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, return NestedNameSpecifier::GlobalSpecifier(Context); } -/// ActOnCXXNestedNameSpecifier - Called during parsing of a -/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now -/// we want to resolve "bar::". 'SS' is empty or the previously parsed -/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', -/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. -/// Returns a CXXScopeTy* object representing the C++ scope. -Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, +/// \brief Determines whether the given declaration is an valid acceptable +/// result for name lookup of a nested-name-specifier. +bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) { + if (!SD) + return false; + + // Namespace and namespace aliases are fine. + if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD)) + return true; + + if (!isa<TypeDecl>(SD)) + return false; + + // Determine whether we have a class (or, in C++0x, an enum) or + // a typedef thereof. If so, build the nested-name-specifier. + QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); + if (T->isDependentType()) + return true; + else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + if (TD->getUnderlyingType()->isRecordType() || + (Context.getLangOptions().CPlusPlus0x && + TD->getUnderlyingType()->isEnumeralType())) + return true; + } else if (isa<RecordDecl>(SD) || + (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD))) + return true; + + return false; +} + +/// \brief If the given nested-name-specifier begins with a bare identifier +/// (e.g., Base::), perform name lookup for that identifier as a +/// nested-name-specifier within the given scope, and return the result of that +/// name lookup. +NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { + if (!S || !NNS) + return 0; + + while (NNS->getPrefix()) + NNS = NNS->getPrefix(); + + if (NNS->getKind() != NestedNameSpecifier::Identifier) + return 0; + + LookupResult Found; + LookupName(Found, S, NNS->getAsIdentifier(), LookupNestedNameSpecifierName); + assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); + + NamedDecl *Result = Found.getAsSingleDecl(Context); + if (isAcceptableNestedNameSpecifier(Result)) + return Result; + + return 0; +} + +/// \brief Build a new nested-name-specifier for "identifier::", as described +/// by ActOnCXXNestedNameSpecifier. +/// +/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in +/// that it contains an extra parameter \p ScopeLookupResult, which provides +/// the result of name lookup within the scope of the nested-name-specifier +/// that was computed at template definitino time. +Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, - IdentifierInfo &II) { - NestedNameSpecifier *Prefix + IdentifierInfo &II, + QualType ObjectType, + NamedDecl *ScopeLookupResult, + bool EnteringContext) { + NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - // If the prefix already refers to an unknown specialization, there - // is no name lookup to perform. Just build the resulting - // nested-name-specifier. - if (Prefix && isUnknownSpecialization(SS)) + // Determine where to perform name lookup + DeclContext *LookupCtx = 0; + bool isDependent = false; + if (!ObjectType.isNull()) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); + LookupCtx = computeDeclContext(ObjectType); + isDependent = ObjectType->isDependentType(); + } else if (SS.isSet()) { + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + LookupCtx = computeDeclContext(SS, EnteringContext); + isDependent = isDependentScopeSpecifier(SS); + } + + LookupResult Found; + bool ObjectTypeSearchedInScope = false; + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + + // The declaration context must be complete. + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + return 0; + + LookupQualifiedName(Found, LookupCtx, &II, LookupNestedNameSpecifierName, + false); + + if (!ObjectType.isNull() && Found.getKind() == LookupResult::NotFound) { + // C++ [basic.lookup.classref]p4: + // If the id-expression in a class member access is a qualified-id of + // the form + // + // class-name-or-namespace-name::... + // + // the class-name-or-namespace-name following the . or -> operator is + // looked up both in the context of the entire postfix-expression and in + // the scope of the class of the object expression. If the name is found + // only in the scope of the class of the object expression, the name + // shall refer to a class-name. If the name is found only in the + // context of the entire postfix-expression, the name shall refer to a + // class-name or namespace-name. [...] + // + // Qualified name lookup into a class will not find a namespace-name, + // so we do not need to diagnoste that case specifically. However, + // this qualified name lookup may find nothing. In that case, perform + // unqualified name lookup in the given scope (if available) or + // reconstruct the result from when name lookup was performed at template + // definition time. + if (S) + LookupName(Found, S, &II, LookupNestedNameSpecifierName); + else if (ScopeLookupResult) + Found.addDecl(ScopeLookupResult); + + ObjectTypeSearchedInScope = true; + } + } else if (isDependent) { + // We were not able to compute the declaration context for a dependent + // base object type or prior nested-name-specifier, so this + // nested-name-specifier refers to an unknown specialization. Just build + // a dependent nested-name-specifier. + if (!Prefix) + return NestedNameSpecifier::Create(Context, &II); + return NestedNameSpecifier::Create(Context, Prefix, &II); + } else { + // Perform unqualified name lookup in the current scope. + LookupName(Found, S, &II, LookupNestedNameSpecifierName); + } - NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName); + // FIXME: Deal with ambiguities cleanly. + NamedDecl *SD = Found.getAsSingleDecl(Context); + if (isAcceptableNestedNameSpecifier(SD)) { + if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { + // C++ [basic.lookup.classref]p4: + // [...] If the name is found in both contexts, the + // class-name-or-namespace-name shall refer to the same entity. + // + // We already found the name in the scope of the object. Now, look + // into the current scope (the scope of the postfix-expression) to + // see if we can find the same name there. As above, if there is no + // scope, reconstruct the result from the template instantiation itself. + NamedDecl *OuterDecl; + if (S) { + LookupResult FoundOuter; + LookupName(FoundOuter, S, &II, LookupNestedNameSpecifierName); + // FIXME: Handle ambiguities! + OuterDecl = FoundOuter.getAsSingleDecl(Context); + } else + OuterDecl = ScopeLookupResult; + + if (isAcceptableNestedNameSpecifier(OuterDecl) && + OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && + (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) || + !Context.hasSameType( + Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), + Context.getTypeDeclType(cast<TypeDecl>(SD))))) { + Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) + << &II; + Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) + << ObjectType; + Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); + + // Fall through so that we'll pick the name we found in the object type, + // since that's probably what the user wanted anyway. + } + } - if (SD) { if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, Namespace); - if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) { - // Determine whether we have a class (or, in C++0x, an enum) or - // a typedef thereof. If so, build the nested-name-specifier. - QualType T = Context.getTypeDeclType(Type); - bool AcceptableType = false; - if (T->isDependentType()) - AcceptableType = true; - else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { - if (TD->getUnderlyingType()->isRecordType() || - (getLangOptions().CPlusPlus0x && - TD->getUnderlyingType()->isEnumeralType())) - AcceptableType = true; - } else if (isa<RecordDecl>(Type) || - (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type))) - AcceptableType = true; - - if (AcceptableType) - return NestedNameSpecifier::Create(Context, Prefix, false, - T.getTypePtr()); - } - + // FIXME: It would be nice to maintain the namespace alias name, then + // see through that alias when resolving the nested-name-specifier down to + // a declaration context. if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, + Alias->getNamespace()); - // Fall through to produce an error: we found something that isn't - // a class or a namespace. + QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); + return NestedNameSpecifier::Create(Context, Prefix, false, + T.getTypePtr()); } // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. - if (!SD) - SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName); + if (!SD) { + Found.clear(); + LookupName(Found, S, &II, LookupOrdinaryName); + SD = Found.getAsSingleDecl(Context); + } + unsigned DiagID; if (SD) DiagID = diag::err_expected_class_or_namespace; - else if (SS.isSet()) - DiagID = diag::err_typecheck_no_member; - else + else if (SS.isSet()) { + Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange(); + return 0; + } else DiagID = diag::err_undeclared_var_use; if (SS.isSet()) @@ -266,14 +484,32 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, return 0; } +/// ActOnCXXNestedNameSpecifier - Called during parsing of a +/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now +/// we want to resolve "bar::". 'SS' is empty or the previously parsed +/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', +/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. +/// Returns a CXXScopeTy* object representing the C++ scope. +Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + SourceLocation IdLoc, + SourceLocation CCLoc, + IdentifierInfo &II, + TypeTy *ObjectTypePtr, + bool EnteringContext) { + return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, + QualType::getFromOpaquePtr(ObjectTypePtr), + /*ScopeLookupResult=*/0, EnteringContext); +} + Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, TypeTy *Ty, SourceRange TypeRange, SourceLocation CCLoc) { - NestedNameSpecifier *Prefix + NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - QualType T = QualType::getFromOpaquePtr(Ty); + QualType T = GetTypeFromParser(Ty); return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false, T.getTypePtr()); } @@ -284,9 +520,18 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. -void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { +bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); - EnterDeclaratorContext(S, computeDeclContext(SS)); + if (DeclContext *DC = computeDeclContext(SS, true)) { + // Before we enter a declarator's context, we need to make sure that + // it is a complete declaration context. + if (!DC->isDependentContext() && RequireCompleteDeclContext(SS)) + return true; + + EnterDeclaratorContext(S, DC); + } + + return false; } /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously @@ -296,6 +541,8 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { /// defining scope. void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); - assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!"); - ExitDeclaratorContext(S); + if (SS.isInvalid()) + return; + if (computeDeclContext(SS, true)) + ExitDeclaratorContext(S); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 4eed01872246c..92bf83f0830d0 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements extra semantic analysis beyond what is enforced +// This file implements extra semantic analysis beyond what is enforced // by the C type system. // //===----------------------------------------------------------------------===// @@ -32,14 +32,14 @@ using namespace clang; SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const { assert(!SL->isWide() && "This doesn't work for wide strings yet"); - + // Loop over all of the tokens in this string until we find the one that // contains the byte we're looking for. unsigned TokNo = 0; while (1) { assert(TokNo < SL->getNumConcatenated() && "Invalid byte number!"); SourceLocation StrTokLoc = SL->getStrTokenLoc(TokNo); - + // Get the spelling of the string so that we can get the data that makes up // the string literal, not the identifier for the macro it is potentially // expanded through. @@ -51,65 +51,71 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, std::pair<const char *,const char *> Buffer = SourceMgr.getBufferData(LocInfo.first); const char *StrData = Buffer.first+LocInfo.second; - + // Create a langops struct and enable trigraphs. This is sufficient for // relexing tokens. LangOptions LangOpts; LangOpts.Trigraphs = true; - + // Create a lexer starting at the beginning of this token. Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.first, StrData, Buffer.second); Token TheTok; TheLexer.LexFromRawLexer(TheTok); - + // Use the StringLiteralParser to compute the length of the string in bytes. StringLiteralParser SLP(&TheTok, 1, PP); 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 = + unsigned Offset = StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP); - + // Now that we know the offset of the token in the spelling, use the // preprocessor to get the offset in the original source. return PP.AdvanceToTokenCharacter(StrTokLoc, Offset); } - + // Move to the next string token. ++TokNo; ByteNo -= TokNumBytes; } } +/// CheckablePrintfAttr - does a function call have a "printf" attribute +/// and arguments that merit checking? +bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) { + if (Format->getType() == "printf") return true; + if (Format->getType() == "printf0") { + // printf0 allows null "format" string; if so don't check format/args + unsigned format_idx = Format->getFormatIdx() - 1; + if (format_idx < TheCall->getNumArgs()) { + Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts(); + if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + return true; + } + } + return false; +} -/// CheckFunctionCall - Check a direct function call for various correctness -/// and safety properties not strictly enforced by the C type system. Action::OwningExprResult -Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { +Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { OwningExprResult TheCallResult(Owned(TheCall)); - // Get the IdentifierInfo* for the called function. - IdentifierInfo *FnInfo = FDecl->getIdentifier(); - - // None of the checks below are needed for functions that don't have - // simple names (e.g., C++ conversion functions). - if (!FnInfo) - return move(TheCallResult); - switch (FDecl->getBuiltinID(Context)) { + switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: assert(TheCall->getNumArgs() == 1 && "Wrong # arguments to builtin CFStringMakeConstantString"); if (CheckObjCString(TheCall->getArg(0))) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: if (SemaBuiltinVAStart(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: @@ -118,12 +124,24 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BI__builtin_isunordered: if (SemaBuiltinUnorderedCompare(TheCall)) return ExprError(); - return move(TheCallResult); + break; + case Builtin::BI__builtin_isfinite: + case Builtin::BI__builtin_isinf: + case Builtin::BI__builtin_isinf_sign: + case Builtin::BI__builtin_isnan: + case Builtin::BI__builtin_isnormal: + if (SemaBuiltinUnaryFP(TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_return_address: case Builtin::BI__builtin_frame_address: if (SemaBuiltinStackAddress(TheCall)) return ExprError(); - return move(TheCallResult); + break; + case Builtin::BI__builtin_eh_return_data_regno: + if (SemaBuiltinEHReturnDataRegNo(TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_shufflevector: return SemaBuiltinShuffleVector(TheCall); // TheCall will be freed by the smart pointer here, but that's fine, since @@ -131,15 +149,15 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BI__builtin_prefetch: if (SemaBuiltinPrefetch(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_object_size: if (SemaBuiltinObjectSize(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__builtin_longjmp: if (SemaBuiltinLongjmp(TheCall)) return ExprError(); - return move(TheCallResult); + break; case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_sub: case Builtin::BI__sync_fetch_and_or: @@ -158,61 +176,76 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BI__sync_lock_release: if (SemaBuiltinAtomicOverloaded(TheCall)) return ExprError(); - return move(TheCallResult); + break; } + return move(TheCallResult); +} + +/// CheckFunctionCall - Check a direct function call for various correctness +/// and safety properties not strictly enforced by the C type system. +bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { + // Get the IdentifierInfo* for the called function. + IdentifierInfo *FnInfo = FDecl->getIdentifier(); + + // None of the checks below are needed for functions that don't have + // simple names (e.g., C++ conversion functions). + if (!FnInfo) + return false; + // FIXME: This mechanism should be abstracted to be less fragile and // more efficient. For example, just map function ids to custom // handlers. // Printf checking. if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) { - if (Format->getType() == "printf") { + if (CheckablePrintfAttr(Format, TheCall)) { bool HasVAListArg = Format->getFirstArg() == 0; if (!HasVAListArg) { - if (const FunctionProtoType *Proto - = FDecl->getType()->getAsFunctionProtoType()) + if (const FunctionProtoType *Proto + = FDecl->getType()->getAs<FunctionProtoType>()) HasVAListArg = !Proto->isVariadic(); } CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, HasVAListArg ? 0 : Format->getFirstArg() - 1); } } - for (const Attr *attr = FDecl->getAttrs(); - attr; attr = attr->getNext()) { - if (const NonNullAttr *NonNull = dyn_cast<NonNullAttr>(attr)) - CheckNonNullArguments(NonNull, TheCall); - } - return move(TheCallResult); -} + for (const NonNullAttr *NonNull = FDecl->getAttr<NonNullAttr>(); NonNull; + NonNull = NonNull->getNext<NonNullAttr>()) + CheckNonNullArguments(NonNull, TheCall); -Action::OwningExprResult -Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { + return false; +} - OwningExprResult TheCallResult(Owned(TheCall)); +bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { // Printf checking. const FormatAttr *Format = NDecl->getAttr<FormatAttr>(); if (!Format) - return move(TheCallResult); + return false; + const VarDecl *V = dyn_cast<VarDecl>(NDecl); if (!V) - return move(TheCallResult); + return false; + QualType Ty = V->getType(); if (!Ty->isBlockPointerType()) - return move(TheCallResult); - if (Format->getType() == "printf") { - bool HasVAListArg = Format->getFirstArg() == 0; - if (!HasVAListArg) { - const FunctionType *FT = - Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType(); - if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - HasVAListArg = !Proto->isVariadic(); - } - CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, - HasVAListArg ? 0 : Format->getFirstArg() - 1); + return false; + + if (!CheckablePrintfAttr(Format, TheCall)) + return false; + + bool HasVAListArg = Format->getFirstArg() == 0; + if (!HasVAListArg) { + const FunctionType *FT = + Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) + HasVAListArg = !Proto->isVariadic(); } - return move(TheCallResult); + CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, + HasVAListArg ? 0 : Format->getFirstArg() - 1); + + return false; } /// SemaBuiltinAtomicOverloaded - We have a call to a function like @@ -231,7 +264,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { if (TheCall->getNumArgs() < 1) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 << TheCall->getCallee()->getSourceRange(); - + // Inspect the first argument of the atomic builtin. This should always be // a pointer type, whose element is an integral scalar or pointer type. // Because it is a pointer type, we don't have to worry about any implicit @@ -240,9 +273,9 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { if (!FirstArg->getType()->isPointerType()) return Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) << FirstArg->getType() << FirstArg->getSourceRange(); - - QualType ValType = FirstArg->getType()->getAsPointerType()->getPointeeType(); - if (!ValType->isIntegerType() && !ValType->isPointerType() && + + QualType ValType = FirstArg->getType()->getAs<PointerType>()->getPointeeType(); + if (!ValType->isIntegerType() && !ValType->isPointerType() && !ValType->isBlockPointerType()) return Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr) @@ -254,7 +287,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { #define BUILTIN_ROW(x) \ { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \ Builtin::BI##x##_8, Builtin::BI##x##_16 } - + static const unsigned BuiltinIndices[][5] = { BUILTIN_ROW(__sync_fetch_and_add), BUILTIN_ROW(__sync_fetch_and_sub), @@ -262,21 +295,21 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { BUILTIN_ROW(__sync_fetch_and_and), BUILTIN_ROW(__sync_fetch_and_xor), BUILTIN_ROW(__sync_fetch_and_nand), - + BUILTIN_ROW(__sync_add_and_fetch), BUILTIN_ROW(__sync_sub_and_fetch), BUILTIN_ROW(__sync_and_and_fetch), BUILTIN_ROW(__sync_or_and_fetch), BUILTIN_ROW(__sync_xor_and_fetch), BUILTIN_ROW(__sync_nand_and_fetch), - + BUILTIN_ROW(__sync_val_compare_and_swap), BUILTIN_ROW(__sync_bool_compare_and_swap), BUILTIN_ROW(__sync_lock_test_and_set), BUILTIN_ROW(__sync_lock_release) }; -#undef BUILTIN_ROW - +#undef BUILTIN_ROW + // Determine the index of the size. unsigned SizeIndex; switch (Context.getTypeSize(ValType)/8) { @@ -289,12 +322,12 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { return Diag(DRE->getLocStart(), diag::err_atomic_builtin_pointer_size) << FirstArg->getType() << FirstArg->getSourceRange(); } - + // Each of these builtins has one pointer argument, followed by some number of // values (0, 1 or 2) followed by a potentially empty varags list of stuff // that we ignore. Find out which row of BuiltinIndices to read from as well // as the number of fixed args. - unsigned BuiltinID = FDecl->getBuiltinID(Context); + unsigned BuiltinID = FDecl->getBuiltinID(); unsigned BuiltinIndex, NumFixed = 1; switch (BuiltinID) { default: assert(0 && "Unknown overloaded atomic builtin!"); @@ -304,14 +337,14 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break; case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break; case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break; - + case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break; case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break; case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break; case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break; case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break; case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break; - + case Builtin::BI__sync_val_compare_and_swap: BuiltinIndex = 12; NumFixed = 2; @@ -326,36 +359,37 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { NumFixed = 0; break; } - + // Now that we know how many fixed arguments we expect, first check that we // have at least that many. if (TheCall->getNumArgs() < 1+NumFixed) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 << TheCall->getCallee()->getSourceRange(); - - + + // Get the decl for the concrete builtin from this, we can tell what the // concrete integer type we should convert to is. unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID); IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName); - FunctionDecl *NewBuiltinDecl = + FunctionDecl *NewBuiltinDecl = cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID, TUScope, false, DRE->getLocStart())); const FunctionProtoType *BuiltinFT = - NewBuiltinDecl->getType()->getAsFunctionProtoType(); - ValType = BuiltinFT->getArgType(0)->getAsPointerType()->getPointeeType(); - + NewBuiltinDecl->getType()->getAs<FunctionProtoType>(); + ValType = BuiltinFT->getArgType(0)->getAs<PointerType>()->getPointeeType(); + // If the first type needs to be converted (e.g. void** -> int*), do it now. if (BuiltinFT->getArgType(0) != FirstArg->getType()) { - ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), false); + ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_Unknown, + /*isLvalue=*/false); TheCall->setArg(0, FirstArg); } - + // Next, walk the valid ones promoting to the right type. for (unsigned i = 0; i != NumFixed; ++i) { Expr *Arg = TheCall->getArg(i+1); - + // If the argument is an implicit cast, then there was a promotion due to // "...", just remove it now. if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { @@ -364,32 +398,35 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { ICE->Destroy(Context); TheCall->setArg(i+1, Arg); } - + // GCC does an implicit conversion to the pointer or integer ValType. This // can fail in some cases (1i -> int**), check for this error case now. - if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg)) + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CXXMethodDecl *ConversionDecl = 0; + if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, + ConversionDecl)) return true; - + // Okay, we have something that *can* be converted to the right type. Check // to see if there is a potentially weird extension going on here. This can // happen when you do an atomic operation on something like an char* and // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. - // FIXME: Do this check. - ImpCastExprToType(Arg, ValType, false); + // FIXME: Do this check. + ImpCastExprToType(Arg, ValType, Kind, /*isLvalue=*/false); TheCall->setArg(i+1, Arg); } - + // Switch the DeclRefExpr to refer to the new decl. DRE->setDecl(NewBuiltinDecl); DRE->setType(NewBuiltinDecl->getType()); - + // Set the callee in the CallExpr. // FIXME: This leaks the original parens and implicit casts. Expr *PromotedCall = DRE; UsualUnaryConversions(PromotedCall); TheCall->setCallee(PromotedCall); - + // Change the result type of the call to match the result type of the decl. TheCall->setType(NewBuiltinDecl->getResultType()); @@ -400,7 +437,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { /// CheckObjCString - Checks that the argument to the builtin /// CFString constructor is correct /// FIXME: GCC currently emits the following warning: -/// "warning: input conversion stopped due to an input byte that does not +/// "warning: input conversion stopped due to an input byte that does not /// belong to the input codeset UTF-8" /// Note: It might also make sense to do the UTF-16 conversion here (would /// simplify the backend). @@ -413,10 +450,10 @@ bool Sema::CheckObjCString(Expr *Arg) { << Arg->getSourceRange(); return true; } - + const char *Data = Literal->getStrData(); unsigned Length = Literal->getByteLength(); - + for (unsigned i = 0; i < Length; ++i) { if (!Data[i]) { Diag(getLocationOfStringLiteralByte(Literal, i), @@ -425,7 +462,7 @@ bool Sema::CheckObjCString(Expr *Arg) { break; } } - + return false; } @@ -437,7 +474,7 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << Fn->getSourceRange() - << SourceRange(TheCall->getArg(2)->getLocStart(), + << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); return true; } @@ -460,17 +497,17 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { } else { isVariadic = getCurMethodDecl()->isVariadic(); } - + if (!isVariadic) { Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); return true; } - + // Verify that the second argument to the builtin is the last argument of the // current function or method. bool SecondArgIsLastNamedArgument = false; const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); - + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) { if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) { // FIXME: This isn't correct for methods (results in bogus warning). @@ -485,9 +522,9 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { SecondArgIsLastNamedArgument = PV == LastArg; } } - + if (!SecondArgIsLastNamedArgument) - Diag(TheCall->getArg(1)->getLocStart(), + Diag(TheCall->getArg(1)->getLocStart(), diag::warn_second_parameter_of_va_start_not_last_named_argument); return false; } @@ -499,12 +536,12 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 /*function call*/; if (TheCall->getNumArgs() > 2) - return Diag(TheCall->getArg(2)->getLocStart(), + return Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); - + Expr *OrigArg0 = TheCall->getArg(0); Expr *OrigArg1 = TheCall->getArg(1); @@ -517,18 +554,45 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { // foo(...)". TheCall->setArg(0, OrigArg0); TheCall->setArg(1, OrigArg1); - + if (OrigArg0->isTypeDependent() || OrigArg1->isTypeDependent()) return false; // If the common type isn't a real floating type, then the arguments were // invalid for this operation. if (!Res->isRealFloatingType()) - return Diag(OrigArg0->getLocStart(), + return Diag(OrigArg0->getLocStart(), diag::err_typecheck_call_invalid_ordered_compare) << OrigArg0->getType() << OrigArg1->getType() << SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd()); - + + return false; +} + +/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isnan and +/// friends. This is declared to take (...), so we have to check everything. +bool Sema::SemaBuiltinUnaryFP(CallExpr *TheCall) { + if (TheCall->getNumArgs() < 1) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 /*function call*/; + if (TheCall->getNumArgs() > 1) + return Diag(TheCall->getArg(1)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ + << SourceRange(TheCall->getArg(1)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd()); + + Expr *OrigArg = TheCall->getArg(0); + + if (OrigArg->isTypeDependent()) + return false; + + // This operation requires a floating-point number + if (!OrigArg->getType()->isRealFloatingType()) + return Diag(OrigArg->getLocStart(), + diag::err_typecheck_call_invalid_unary_fp) + << OrigArg->getType() << OrigArg->getSourceRange(); + return false; } @@ -540,7 +604,7 @@ bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) { !TheCall->getArg(0)->isValueDependent() && !TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc)) return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange(); - + return false; } @@ -557,23 +621,23 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { !TheCall->getArg(1)->isTypeDependent()) { QualType FAType = TheCall->getArg(0)->getType(); QualType SAType = TheCall->getArg(1)->getType(); - + if (!FAType->isVectorType() || !SAType->isVectorType()) { Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector) - << SourceRange(TheCall->getArg(0)->getLocStart(), + << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd()); return ExprError(); } - + if (Context.getCanonicalType(FAType).getUnqualifiedType() != Context.getCanonicalType(SAType).getUnqualifiedType()) { Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector) - << SourceRange(TheCall->getArg(0)->getLocStart(), + << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd()); return ExprError(); } - numElements = FAType->getAsVectorType()->getNumElements(); + numElements = FAType->getAs<VectorType>()->getNumElements(); if (TheCall->getNumArgs() != numElements+2) { if (TheCall->getNumArgs() < numElements+2) return ExprError(Diag(TheCall->getLocEnd(), @@ -609,8 +673,8 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { TheCall->setArg(i, 0); } - return Owned(new (Context) ShuffleVectorExpr(exprs.begin(), exprs.size(), - exprs[0]->getType(), + return Owned(new (Context) ShuffleVectorExpr(Context, exprs.begin(), + exprs.size(), exprs[0]->getType(), TheCall->getCallee()->getLocStart(), TheCall->getRParenLoc())); } @@ -634,11 +698,11 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { QualType RWType = Arg->getType(); - const BuiltinType *BT = RWType->getAsBuiltinType(); + const BuiltinType *BT = RWType->getAs<BuiltinType>(); llvm::APSInt Result; if (!BT || BT->getKind() != BuiltinType::Int) return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) - << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + << Arg->getSourceRange(); if (Arg->isValueDependent()) continue; @@ -646,24 +710,36 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { if (!Arg->isIntegerConstantExpr(Result, Context)) return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); - + // FIXME: gcc issues a warning and rewrites these to 0. These // seems especially odd for the third argument since the default // is 3. if (i == 1) { if (Result.getSExtValue() < 0 || Result.getSExtValue() > 1) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) - << "0" << "1" << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + << "0" << "1" << Arg->getSourceRange(); } else { if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) - << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + << "0" << "3" << Arg->getSourceRange(); } } return false; } +/// SemaBuiltinEHReturnDataRegNo - Handle __builtin_eh_return_data_regno, the +/// operand must be an integer constant. +bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) { + llvm::APSInt Result; + if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context)) + return Diag(TheCall->getLocStart(), diag::err_expr_not_ice) + << TheCall->getArg(0)->getSourceRange(); + + return false; +} + + /// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr, /// int type). This simply type checks that type is one of the defined /// constants (0-3). @@ -672,8 +748,8 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { if (Arg->isTypeDependent()) return false; - QualType ArgType = Arg->getType(); - const BuiltinType *BT = ArgType->getAsBuiltinType(); + QualType ArgType = Arg->getType(); + const BuiltinType *BT = ArgType->getAs<BuiltinType>(); llvm::APSInt Result(32); if (!BT || BT->getKind() != BuiltinType::Int) return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument) @@ -737,10 +813,10 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, format_idx, firstDataArg); } - + case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast<DeclRefExpr>(E); - + // As an exception, do not flag errors for variables binding to // const string literals. if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { @@ -749,19 +825,18 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, if (const ArrayType *AT = Context.getAsArrayType(T)) { isConstant = AT->getElementType().isConstant(Context); - } - else if (const PointerType *PT = T->getAsPointerType()) { - isConstant = T.isConstant(Context) && + } else if (const PointerType *PT = T->getAs<PointerType>()) { + isConstant = T.isConstant(Context) && PT->getPointeeType().isConstant(Context); } - + if (isConstant) { const VarDecl *Def = 0; if (const Expr *Init = VD->getDefinition(Def)) return SemaCheckStringLiteral(Init, TheCall, HasVAListArg, format_idx, firstDataArg); } - + // For vprintf* functions (i.e., HasVAListArg==true), we add a // special check to see if the format string is a function parameter // of the function calling the printf function. If the function @@ -784,66 +859,67 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, if (isa<ParmVarDecl>(VD)) return true; } - + return false; } case Stmt::CallExprClass: { const CallExpr *CE = cast<CallExpr>(E); - if (const ImplicitCastExpr *ICE + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE->getCallee())) { if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) { if (const FormatArgAttr *FA = FD->getAttr<FormatArgAttr>()) { unsigned ArgIndex = FA->getFormatIdx(); const Expr *Arg = CE->getArg(ArgIndex - 1); - - return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg, + + return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg, format_idx, firstDataArg); } } } } - + return false; } case Stmt::ObjCStringLiteralClass: case Stmt::StringLiteralClass: { const StringLiteral *StrE = NULL; - + if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E)) StrE = ObjCFExpr->getString(); else StrE = cast<StringLiteral>(E); - + if (StrE) { - CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx, + CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx, firstDataArg); return true; } - + return false; } - + default: return false; } } void -Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall) -{ +Sema::CheckNonNullArguments(const NonNullAttr *NonNull, + const CallExpr *TheCall) { for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end(); i != e; ++i) { const Expr *ArgExpr = TheCall->getArg(*i); - if (ArgExpr->isNullPointerConstant(Context)) + if (ArgExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg) << ArgExpr->getSourceRange(); } } /// CheckPrintfArguments - Check calls to printf (and similar functions) for -/// correct use of format strings. +/// correct use of format strings. /// /// HasVAListArg - A predicate indicating whether the printf-like /// function is passed an explicit va_arg argument (e.g., vprintf) @@ -892,30 +968,30 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall) /// /// For now, we ONLY do (1), (3), (5), (6), (7), and (8). void -Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, +Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg) { const Expr *Fn = TheCall->getCallee(); - // CHECK: printf-like function is called with no format string. + // CHECK: printf-like function is called with no format string. if (format_idx >= TheCall->getNumArgs()) { Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string) << Fn->getSourceRange(); return; } - + const Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts(); - + // CHECK: format string is not a string literal. - // + // // Dynamically generated format strings are difficult to // automatically vet at compile time. Requiring that format strings // are string literals: (1) permits the checking of format strings by // the compiler and thereby (2) can practically remove the source of // many format string exploits. - // Format string can be either ObjC string (e.g. @"%d") or + // Format string can be either ObjC string (e.g. @"%d") or // C string (e.g. "%d") - // ObjC string uses the same format specifiers as C string, so we can use + // ObjC string uses the same format specifiers as C string, so we can use // the same format string checking logic for both ObjC and C strings. if (SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx, firstDataArg)) @@ -924,11 +1000,11 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, // If there are no arguments specified, warn with -Wformat-security, otherwise // warn only with -Wformat-nonliteral. if (TheCall->getNumArgs() == format_idx+1) - Diag(TheCall->getArg(format_idx)->getLocStart(), + Diag(TheCall->getArg(format_idx)->getLocStart(), diag::warn_printf_nonliteral_noargs) << OrigFormatExpr->getSourceRange(); else - Diag(TheCall->getArg(format_idx)->getLocStart(), + Diag(TheCall->getArg(format_idx)->getLocStart(), diag::warn_printf_nonliteral) << OrigFormatExpr->getSourceRange(); } @@ -954,7 +1030,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, // CHECK: empty format string? unsigned StrLen = FExpr->getByteLength(); - + if (StrLen == 0) { Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string) << OrigFormatExpr->getSourceRange(); @@ -967,7 +1043,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, state_OrdChr, state_Conversion } CurrentState = state_OrdChr; - + // numConversions - The number of conversions seen so far. This is // incremented as we traverse the format string. unsigned numConversions = 0; @@ -980,17 +1056,17 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, // Inspect the format string. unsigned StrIdx = 0; - + // LastConversionIdx - Index within the format string where we last saw // a '%' character that starts a new format conversion. unsigned LastConversionIdx = 0; - + for (; StrIdx < StrLen; ++StrIdx) { - + // Is the number of detected conversion conversions greater than // the number of matching data arguments? If so, stop. if (!HasVAListArg && numConversions > numDataArgs) break; - + // Handle "\0" if (Str[StrIdx] == '\0') { // The string returned by getStrData() is not null-terminated, @@ -1000,7 +1076,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, << OrigFormatExpr->getSourceRange(); return; } - + // Ordinary characters (not processing a format conversion). if (CurrentState == state_OrdChr) { if (Str[StrIdx] == '%') { @@ -1012,10 +1088,10 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, // Seen '%'. Now processing a format conversion. switch (Str[StrIdx]) { - // Handle dynamic precision or width specifier. + // Handle dynamic precision or width specifier. case '*': { ++numConversions; - + if (!HasVAListArg) { if (numConversions > numDataArgs) { SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx); @@ -1026,39 +1102,39 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, else Diag(Loc, diag::warn_printf_asterisk_width_missing_arg) << OrigFormatExpr->getSourceRange(); - + // Don't do any more checking. We'll just emit spurious errors. return; } - + // Perform type checking on width/precision specifier. const Expr *E = TheCall->getArg(format_idx+numConversions); - if (const BuiltinType *BT = E->getType()->getAsBuiltinType()) + if (const BuiltinType *BT = E->getType()->getAs<BuiltinType>()) if (BT->getKind() == BuiltinType::Int) break; - + SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx); - + if (Str[StrIdx-1] == '.') Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type) << E->getType() << E->getSourceRange(); else Diag(Loc, diag::warn_printf_asterisk_width_wrong_type) << E->getType() << E->getSourceRange(); - - break; + + break; } } - + // Characters which can terminate a format conversion // (e.g. "%d"). Characters that specify length modifiers or // other flags are handled by the default case below. // - // FIXME: additional checks will go into the following cases. + // FIXME: additional checks will go into the following cases. case 'i': case 'd': - case 'o': - case 'u': + case 'o': + case 'u': case 'x': case 'X': case 'D': @@ -1076,7 +1152,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, case 'C': case 'S': case 's': - case 'p': + case 'p': ++numConversions; CurrentState = state_OrdChr; break; @@ -1092,21 +1168,21 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, CurrentState = state_OrdChr; SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - + Diag(Loc, diag::warn_printf_write_back)<<OrigFormatExpr->getSourceRange(); break; } - + // Handle "%@" case '@': // %@ is allowed in ObjC format strings only. - if(ObjCFExpr != NULL) - CurrentState = state_OrdChr; + if (ObjCFExpr != NULL) + CurrentState = state_OrdChr; else { // Issue a warning: invalid format conversion. - SourceLocation Loc = + SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - + Diag(Loc, diag::warn_printf_invalid_conversion) << std::string(Str+LastConversionIdx, Str+std::min(LastConversionIdx+2, StrLen)) @@ -1114,7 +1190,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, } ++numConversions; break; - + // Handle "%%" case '%': // Sanity check: Was the first "%" character the previous one? @@ -1122,23 +1198,23 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, // conversion, and that the current "%" character is the start // of a new conversion. if (StrIdx - LastConversionIdx == 1) - CurrentState = state_OrdChr; + CurrentState = state_OrdChr; else { // Issue a warning: invalid format conversion. SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - + Diag(Loc, diag::warn_printf_invalid_conversion) << std::string(Str+LastConversionIdx, Str+StrIdx) << OrigFormatExpr->getSourceRange(); - + // This conversion is broken. Advance to the next format // conversion. LastConversionIdx = StrIdx; ++numConversions; } break; - + default: // This case catches all other characters: flags, widths, etc. // We should eventually process those as well. @@ -1150,21 +1226,21 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, // Issue a warning: invalid format conversion. SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - + Diag(Loc, diag::warn_printf_invalid_conversion) << std::string(Str+LastConversionIdx, Str+std::min(LastConversionIdx+2, StrLen)) << OrigFormatExpr->getSourceRange(); return; } - + if (!HasVAListArg) { // CHECK: Does the number of format conversions exceed the number // of data arguments? if (numConversions > numDataArgs) { SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - + Diag(Loc, diag::warn_printf_insufficient_data_args) << OrigFormatExpr->getSourceRange(); } @@ -1187,25 +1263,22 @@ static DeclRefExpr* EvalAddr(Expr* E); void Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { - + // Perform checking for returned stack addresses. if (lhsType->isPointerType() || lhsType->isBlockPointerType()) { if (DeclRefExpr *DR = EvalAddr(RetValExp)) Diag(DR->getLocStart(), diag::warn_ret_stack_addr) << DR->getDecl()->getDeclName() << RetValExp->getSourceRange(); - + // Skip over implicit cast expressions when checking for block expressions. - if (ImplicitCastExpr *IcExpr = - dyn_cast_or_null<ImplicitCastExpr>(RetValExp)) - RetValExp = IcExpr->getSubExpr(); + RetValExp = RetValExp->IgnoreParenCasts(); if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(RetValExp)) if (C->hasBlockDeclRefExprs()) Diag(C->getLocStart(), diag::err_ret_local_block) << C->getSourceRange(); - } - // Perform checking for stack values returned by reference. - else if (lhsType->isReferenceType()) { + } else if (lhsType->isReferenceType()) { + // Perform checking for stack values returned by reference. // Check for a reference to the stack if (DeclRefExpr *DR = EvalVal(RetValExp)) Diag(DR->getLocStart(), diag::warn_ret_stack_ref) @@ -1223,7 +1296,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, /// /// EvalAddr processes expressions that are pointers that are used as /// references (and not L-values). EvalVal handles all other values. -/// At the base case of the recursion is a check for a DeclRefExpr* in +/// At the base case of the recursion is a check for a DeclRefExpr* in /// the refers to a stack variable. /// /// This implementation handles: @@ -1236,11 +1309,11 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, /// * taking the address of an array element where the array is on the stack static DeclRefExpr* EvalAddr(Expr *E) { // We should only be called for evaluating pointer expressions. - assert((E->getType()->isPointerType() || + assert((E->getType()->isAnyPointerType() || E->getType()->isBlockPointerType() || E->getType()->isObjCQualifiedIdType()) && "EvalAddr only works on pointers"); - + // Our "symbolic interpreter" is just a dispatch off the currently // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. @@ -1253,28 +1326,28 @@ static DeclRefExpr* EvalAddr(Expr *E) { // The only unary operator that make sense to handle here // is AddrOf. All others don't make sense as pointers. UnaryOperator *U = cast<UnaryOperator>(E); - + if (U->getOpcode() == UnaryOperator::AddrOf) return EvalVal(U->getSubExpr()); else return NULL; } - + case Stmt::BinaryOperatorClass: { // Handle pointer arithmetic. All other binary operators are not valid // in this context. BinaryOperator *B = cast<BinaryOperator>(E); BinaryOperator::Opcode op = B->getOpcode(); - + if (op != BinaryOperator::Add && op != BinaryOperator::Sub) return NULL; - + Expr *Base = B->getLHS(); // Determine which argument is the real pointer base. It could be // the RHS argument instead of the LHS. if (!Base->getType()->isPointerType()) Base = B->getRHS(); - + assert (Base->getType()->isPointerType()); return EvalAddr(Base); } @@ -1283,7 +1356,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { // valid DeclRefExpr*s. If one of them is valid, we return it. case Stmt::ConditionalOperatorClass: { ConditionalOperator *C = cast<ConditionalOperator>(E); - + // Handle the GNU extension for missing LHS. if (Expr *lhsExpr = C->getLHS()) if (DeclRefExpr* LHS = EvalAddr(lhsExpr)) @@ -1291,7 +1364,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { return EvalAddr(C->getRHS()); } - + // For casts, we need to handle conversions from arrays to // pointer values, and pointer-to-pointer conversions. case Stmt::ImplicitCastExprClass: @@ -1299,7 +1372,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { case Stmt::CXXFunctionalCastExprClass: { Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); QualType T = SubExpr->getType(); - + if (SubExpr->getType()->isPointerType() || SubExpr->getType()->isBlockPointerType() || SubExpr->getType()->isObjCQualifiedIdType()) @@ -1309,7 +1382,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { else return 0; } - + // C++ casts. For dynamic casts, static casts, and const casts, we // are always converting from a pointer-to-pointer, so we just blow // through the cast. In the case the dynamic cast doesn't fail (and @@ -1317,9 +1390,9 @@ static DeclRefExpr* EvalAddr(Expr *E) { // where we return the address of a stack variable. For Reinterpre // FIXME: The comment about is wrong; we're not always converting // from pointer to pointer. I'm guessing that this code should also - // handle references to objects. - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: + // handle references to objects. + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: case Stmt::CXXConstCastExprClass: case Stmt::CXXReinterpretCastExprClass: { Expr *S = cast<CXXNamedCastExpr>(E)->getSubExpr(); @@ -1328,62 +1401,62 @@ static DeclRefExpr* EvalAddr(Expr *E) { else return NULL; } - + // Everything else: we simply don't reason about them. default: return NULL; } } - + /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. static DeclRefExpr* EvalVal(Expr *E) { - + // We should only be called for evaluating non-pointer expressions, or // expressions with a pointer type that are not used as references but instead // are l-values (e.g., DeclRefExpr with a pointer type). - + // Our "symbolic interpreter" is just a dispatch off the currently // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: + case Stmt::DeclRefExprClass: case Stmt::QualifiedDeclRefExprClass: { // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking // at code that refers to a variable's name. We check if it has local // storage within the function, and if so, return the expression. DeclRefExpr *DR = cast<DeclRefExpr>(E); - + if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) - if(V->hasLocalStorage() && !V->getType()->isReferenceType()) return DR; - + if (V->hasLocalStorage() && !V->getType()->isReferenceType()) return DR; + return NULL; } - + case Stmt::ParenExprClass: // Ignore parentheses. return EvalVal(cast<ParenExpr>(E)->getSubExpr()); - + case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here // is Deref. All others don't resolve to a "name." This includes // handling all sorts of rvalues passed to a unary operator. UnaryOperator *U = cast<UnaryOperator>(E); - + if (U->getOpcode() == UnaryOperator::Deref) return EvalAddr(U->getSubExpr()); return NULL; } - + case Stmt::ArraySubscriptExprClass: { // Array subscripts are potential references to data on the stack. We // retrieve the DeclRefExpr* for the array variable if it indeed // has local storage. return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase()); } - + case Stmt::ConditionalOperatorClass: { // For conditional operators we need to see if either the LHS or RHS are // non-NULL DeclRefExpr's. If one is non-NULL, we return it. @@ -1396,18 +1469,18 @@ static DeclRefExpr* EvalVal(Expr *E) { return EvalVal(C->getRHS()); } - + // Accesses to members are potential references to data on the stack. case Stmt::MemberExprClass: { MemberExpr *M = cast<MemberExpr>(E); - + // Check for indirect access. We only want direct field accesses. if (!M->isArrow()) return EvalVal(M->getBase()); else return NULL; } - + // Everything else: we simply don't reason about them. default: return NULL; @@ -1421,7 +1494,7 @@ static DeclRefExpr* EvalVal(Expr *E) { /// to do what the programmer intended. void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { bool EmitWarning = true; - + Expr* LeftExprSansParen = lex->IgnoreParens(); Expr* RightExprSansParen = rex->IgnoreParens(); @@ -1431,8 +1504,8 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RightExprSansParen)) if (DRL->getDecl() == DRR->getDecl()) EmitWarning = false; - - + + // Special case: check for comparisons against literals that can be exactly // represented by APFloat. In such cases, do not emit a warning. This // is a heuristic: often comparison against such literals are used to @@ -1442,25 +1515,24 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) { if (FLL->isExact()) EmitWarning = false; - } - else + } else if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen)){ if (FLR->isExact()) EmitWarning = false; } } - + // Check for comparisons with builtin types. if (EmitWarning) if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen)) if (CL->isBuiltinCall(Context)) EmitWarning = false; - + if (EmitWarning) if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen)) if (CR->isBuiltinCall(Context)) EmitWarning = false; - + // Emit the diagnostic. if (EmitWarning) Diag(loc, diag::warn_floatingpoint_eq) diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp new file mode 100644 index 0000000000000..3981b8d22fa35 --- /dev/null +++ b/lib/Sema/SemaCodeComplete.cpp @@ -0,0 +1,1432 @@ +//===---------------- SemaCodeComplete.cpp - Code Completion ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the code-completion semantic actions. +// +//===----------------------------------------------------------------------===// +#include "Sema.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/AST/ExprCXX.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringExtras.h" +#include <list> +#include <map> +#include <vector> + +using namespace clang; + +/// \brief Set the code-completion consumer for semantic analysis. +void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) { + assert(((CodeCompleter != 0) != (CCC != 0)) && + "Already set or cleared a code-completion consumer?"); + CodeCompleter = CCC; +} + +namespace { + /// \brief A container of code-completion results. + class ResultBuilder { + public: + /// \brief The type of a name-lookup filter, which can be provided to the + /// name-lookup routines to specify which declarations should be included in + /// the result set (when it returns true) and which declarations should be + /// filtered out (returns false). + typedef bool (ResultBuilder::*LookupFilter)(NamedDecl *) const; + + typedef CodeCompleteConsumer::Result Result; + + private: + /// \brief The actual results we have found. + std::vector<Result> Results; + + /// \brief A record of all of the declarations we have found and placed + /// into the result set, used to ensure that no declaration ever gets into + /// the result set twice. + llvm::SmallPtrSet<Decl*, 16> AllDeclsFound; + + /// \brief A mapping from declaration names to the declarations that have + /// this name within a particular scope and their index within the list of + /// results. + typedef std::multimap<DeclarationName, + std::pair<NamedDecl *, unsigned> > ShadowMap; + + /// \brief The semantic analysis object for which results are being + /// produced. + Sema &SemaRef; + + /// \brief If non-NULL, a filter function used to remove any code-completion + /// results that are not desirable. + LookupFilter Filter; + + /// \brief A list of shadow maps, which is used to model name hiding at + /// different levels of, e.g., the inheritance hierarchy. + std::list<ShadowMap> ShadowMaps; + + public: + explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) + : SemaRef(SemaRef), Filter(Filter) { } + + /// \brief Set the filter used for code-completion results. + void setFilter(LookupFilter Filter) { + this->Filter = Filter; + } + + typedef std::vector<Result>::iterator iterator; + iterator begin() { return Results.begin(); } + iterator end() { return Results.end(); } + + Result *data() { return Results.empty()? 0 : &Results.front(); } + unsigned size() const { return Results.size(); } + bool empty() const { return Results.empty(); } + + /// \brief Add a new result to this result set (if it isn't already in one + /// of the shadow maps), or replace an existing result (for, e.g., a + /// redeclaration). + /// + /// \param R the result to add (if it is unique). + /// + /// \param R the context in which this result will be named. + void MaybeAddResult(Result R, DeclContext *CurContext = 0); + + /// \brief Enter into a new scope. + void EnterNewScope(); + + /// \brief Exit from the current scope. + void ExitScope(); + + /// \name Name lookup predicates + /// + /// These predicates can be passed to the name lookup functions to filter the + /// results of name lookup. All of the predicates have the same type, so that + /// + //@{ + bool IsOrdinaryName(NamedDecl *ND) const; + bool IsNestedNameSpecifier(NamedDecl *ND) const; + bool IsEnum(NamedDecl *ND) const; + bool IsClassOrStruct(NamedDecl *ND) const; + bool IsUnion(NamedDecl *ND) const; + bool IsNamespace(NamedDecl *ND) const; + bool IsNamespaceOrAlias(NamedDecl *ND) const; + bool IsType(NamedDecl *ND) const; + bool IsMember(NamedDecl *ND) const; + //@} + }; +} + +/// \brief Determines whether the given hidden result could be found with +/// some extra work, e.g., by qualifying the name. +/// +/// \param Hidden the declaration that is hidden by the currenly \p Visible +/// declaration. +/// +/// \param Visible the declaration with the same name that is already visible. +/// +/// \returns true if the hidden result can be found by some mechanism, +/// false otherwise. +static bool canHiddenResultBeFound(const LangOptions &LangOpts, + NamedDecl *Hidden, NamedDecl *Visible) { + // In C, there is no way to refer to a hidden name. + if (!LangOpts.CPlusPlus) + return false; + + DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext(); + + // There is no way to qualify a name declared in a function or method. + if (HiddenCtx->isFunctionOrMethod()) + return false; + + return HiddenCtx != Visible->getDeclContext()->getLookupContext(); +} + +/// \brief Compute the qualification required to get from the current context +/// (\p CurContext) to the target context (\p TargetContext). +/// +/// \param Context the AST context in which the qualification will be used. +/// +/// \param CurContext the context where an entity is being named, which is +/// typically based on the current scope. +/// +/// \param TargetContext the context in which the named entity actually +/// resides. +/// +/// \returns a nested name specifier that refers into the target context, or +/// NULL if no qualification is needed. +static NestedNameSpecifier * +getRequiredQualification(ASTContext &Context, + DeclContext *CurContext, + DeclContext *TargetContext) { + llvm::SmallVector<DeclContext *, 4> TargetParents; + + for (DeclContext *CommonAncestor = TargetContext; + CommonAncestor && !CommonAncestor->Encloses(CurContext); + CommonAncestor = CommonAncestor->getLookupParent()) { + if (CommonAncestor->isTransparentContext() || + CommonAncestor->isFunctionOrMethod()) + continue; + + TargetParents.push_back(CommonAncestor); + } + + NestedNameSpecifier *Result = 0; + while (!TargetParents.empty()) { + DeclContext *Parent = TargetParents.back(); + TargetParents.pop_back(); + + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent)) + Result = NestedNameSpecifier::Create(Context, Result, Namespace); + else if (TagDecl *TD = dyn_cast<TagDecl>(Parent)) + Result = NestedNameSpecifier::Create(Context, Result, + false, + Context.getTypeDeclType(TD).getTypePtr()); + else + assert(Parent->isTranslationUnit()); + } + + return Result; +} + +void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { + assert(!ShadowMaps.empty() && "Must enter into a results scope"); + + if (R.Kind != Result::RK_Declaration) { + // For non-declaration results, just add the result. + Results.push_back(R); + return; + } + + // Skip unnamed entities. + if (!R.Declaration->getDeclName()) + return; + + // Look through using declarations. + if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration)) + MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier), + CurContext); + + // Handle each declaration in an overload set separately. + if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(R.Declaration)) { + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) + MaybeAddResult(Result(*F, R.Rank, R.Qualifier), CurContext); + + return; + } + + Decl *CanonDecl = R.Declaration->getCanonicalDecl(); + unsigned IDNS = CanonDecl->getIdentifierNamespace(); + + // Friend declarations and declarations introduced due to friends are never + // added as results. + if (isa<FriendDecl>(CanonDecl) || + (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) + return; + + if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) { + // __va_list_tag is a freak of nature. Find it and skip it. + if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list")) + return; + + // Filter out names reserved for the implementation (C99 7.1.3, + // C++ [lib.global.names]). Users don't need to see those. + if (Id->getLength() >= 2) { + const char *Name = Id->getName(); + if (Name[0] == '_' && + (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'))) + return; + } + } + + // C++ constructors are never found by name lookup. + if (isa<CXXConstructorDecl>(CanonDecl)) + return; + + // Filter out any unwanted results. + if (Filter && !(this->*Filter)(R.Declaration)) + return; + + ShadowMap &SMap = ShadowMaps.back(); + ShadowMap::iterator I, IEnd; + for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName()); + I != IEnd; ++I) { + NamedDecl *ND = I->second.first; + unsigned Index = I->second.second; + if (ND->getCanonicalDecl() == CanonDecl) { + // This is a redeclaration. Always pick the newer declaration. + I->second.first = R.Declaration; + Results[Index].Declaration = R.Declaration; + + // Pick the best rank of the two. + Results[Index].Rank = std::min(Results[Index].Rank, R.Rank); + + // We're done. + return; + } + } + + // This is a new declaration in this scope. However, check whether this + // declaration name is hidden by a similarly-named declaration in an outer + // scope. + std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end(); + --SMEnd; + for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) { + for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName()); + I != IEnd; ++I) { + // A tag declaration does not hide a non-tag declaration. + if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag && + (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | + Decl::IDNS_ObjCProtocol))) + continue; + + // Protocols are in distinct namespaces from everything else. + if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) + || (IDNS & Decl::IDNS_ObjCProtocol)) && + I->second.first->getIdentifierNamespace() != IDNS) + continue; + + // The newly-added result is hidden by an entry in the shadow map. + if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration, + I->second.first)) { + // Note that this result was hidden. + R.Hidden = true; + R.QualifierIsInformative = false; + + if (!R.Qualifier) + R.Qualifier = getRequiredQualification(SemaRef.Context, + CurContext, + R.Declaration->getDeclContext()); + } else { + // This result was hidden and cannot be found; don't bother adding + // it. + return; + } + + break; + } + } + + // Make sure that any given declaration only shows up in the result set once. + if (!AllDeclsFound.insert(CanonDecl)) + return; + + // If the filter is for nested-name-specifiers, then this result starts a + // nested-name-specifier. + if ((Filter == &ResultBuilder::IsNestedNameSpecifier) || + (Filter == &ResultBuilder::IsMember && + isa<CXXRecordDecl>(R.Declaration) && + cast<CXXRecordDecl>(R.Declaration)->isInjectedClassName())) + R.StartsNestedNameSpecifier = true; + + // If this result is supposed to have an informative qualifier, add one. + if (R.QualifierIsInformative && !R.Qualifier && + !R.StartsNestedNameSpecifier) { + DeclContext *Ctx = R.Declaration->getDeclContext(); + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace); + else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false, + SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); + else + R.QualifierIsInformative = false; + } + + // Insert this result into the set of results and into the current shadow + // map. + SMap.insert(std::make_pair(R.Declaration->getDeclName(), + std::make_pair(R.Declaration, Results.size()))); + Results.push_back(R); +} + +/// \brief Enter into a new scope. +void ResultBuilder::EnterNewScope() { + ShadowMaps.push_back(ShadowMap()); +} + +/// \brief Exit from the current scope. +void ResultBuilder::ExitScope() { + ShadowMaps.pop_back(); +} + +/// \brief Determines whether this given declaration will be found by +/// ordinary name lookup. +bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { + unsigned IDNS = Decl::IDNS_Ordinary; + if (SemaRef.getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Tag; + + return ND->getIdentifierNamespace() & IDNS; +} + +/// \brief Determines whether the given declaration is suitable as the +/// start of a C++ nested-name-specifier, e.g., a class or namespace. +bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const { + // Allow us to find class templates, too. + if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) + ND = ClassTemplate->getTemplatedDecl(); + + return SemaRef.isAcceptableNestedNameSpecifier(ND); +} + +/// \brief Determines whether the given declaration is an enumeration. +bool ResultBuilder::IsEnum(NamedDecl *ND) const { + return isa<EnumDecl>(ND); +} + +/// \brief Determines whether the given declaration is a class or struct. +bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const { + // Allow us to find class templates, too. + if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) + ND = ClassTemplate->getTemplatedDecl(); + + if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) + return RD->getTagKind() == TagDecl::TK_class || + RD->getTagKind() == TagDecl::TK_struct; + + return false; +} + +/// \brief Determines whether the given declaration is a union. +bool ResultBuilder::IsUnion(NamedDecl *ND) const { + // Allow us to find class templates, too. + if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) + ND = ClassTemplate->getTemplatedDecl(); + + if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) + return RD->getTagKind() == TagDecl::TK_union; + + return false; +} + +/// \brief Determines whether the given declaration is a namespace. +bool ResultBuilder::IsNamespace(NamedDecl *ND) const { + return isa<NamespaceDecl>(ND); +} + +/// \brief Determines whether the given declaration is a namespace or +/// namespace alias. +bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const { + return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND); +} + +/// \brief Brief determines whether the given declaration is a namespace or +/// namespace alias. +bool ResultBuilder::IsType(NamedDecl *ND) const { + return isa<TypeDecl>(ND); +} + +/// \brief Since every declaration found within a class is a member that we +/// care about, always returns true. This predicate exists mostly to +/// communicate to the result builder that we are performing a lookup for +/// member access. +bool ResultBuilder::IsMember(NamedDecl *ND) const { + return true; +} + +// Find the next outer declaration context corresponding to this scope. +static DeclContext *findOuterContext(Scope *S) { + for (S = S->getParent(); S; S = S->getParent()) + if (S->getEntity()) + return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext(); + + return 0; +} + +/// \brief Collect the results of searching for members within the given +/// declaration context. +/// +/// \param Ctx the declaration context from which we will gather results. +/// +/// \param Rank the rank given to results in this declaration context. +/// +/// \param Visited the set of declaration contexts that have already been +/// visited. Declaration contexts will only be visited once. +/// +/// \param Results the result set that will be extended with any results +/// found within this declaration context (and, for a C++ class, its bases). +/// +/// \param InBaseClass whether we are in a base class. +/// +/// \returns the next higher rank value, after considering all of the +/// names within this declaration context. +static unsigned CollectMemberLookupResults(DeclContext *Ctx, + unsigned Rank, + DeclContext *CurContext, + llvm::SmallPtrSet<DeclContext *, 16> &Visited, + ResultBuilder &Results, + bool InBaseClass = false) { + // Make sure we don't visit the same context twice. + if (!Visited.insert(Ctx->getPrimaryContext())) + return Rank; + + // Enumerate all of the results in this context. + typedef CodeCompleteConsumer::Result Result; + Results.EnterNewScope(); + for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; + CurCtx = CurCtx->getNextContext()) { + for (DeclContext::decl_iterator D = CurCtx->decls_begin(), + DEnd = CurCtx->decls_end(); + D != DEnd; ++D) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext); + } + } + + // Traverse the contexts of inherited classes. + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { + for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), + BEnd = Record->bases_end(); + B != BEnd; ++B) { + QualType BaseType = B->getType(); + + // Don't look into dependent bases, because name lookup can't look + // there anyway. + if (BaseType->isDependentType()) + continue; + + const RecordType *Record = BaseType->getAs<RecordType>(); + if (!Record) + continue; + + // FIXME: It would be nice to be able to determine whether referencing + // a particular member would be ambiguous. For example, given + // + // struct A { int member; }; + // struct B { int member; }; + // struct C : A, B { }; + // + // void f(C *c) { c->### } + // accessing 'member' would result in an ambiguity. However, code + // completion could be smart enough to qualify the member with the + // base class, e.g., + // + // c->B::member + // + // or + // + // c->A::member + + // Collect results from this base class (and its bases). + CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited, + Results, /*InBaseClass=*/true); + } + } + + // FIXME: Look into base classes in Objective-C! + + Results.ExitScope(); + return Rank + 1; +} + +/// \brief Collect the results of searching for members within the given +/// declaration context. +/// +/// \param Ctx the declaration context from which we will gather results. +/// +/// \param InitialRank the initial rank given to results in this declaration +/// context. Larger rank values will be used for, e.g., members found in +/// base classes. +/// +/// \param Results the result set that will be extended with any results +/// found within this declaration context (and, for a C++ class, its bases). +/// +/// \returns the next higher rank value, after considering all of the +/// names within this declaration context. +static unsigned CollectMemberLookupResults(DeclContext *Ctx, + unsigned InitialRank, + DeclContext *CurContext, + ResultBuilder &Results) { + llvm::SmallPtrSet<DeclContext *, 16> Visited; + return CollectMemberLookupResults(Ctx, InitialRank, CurContext, Visited, + Results); +} + +/// \brief Collect the results of searching for declarations within the given +/// scope and its parent scopes. +/// +/// \param S the scope in which we will start looking for declarations. +/// +/// \param InitialRank the initial rank given to results in this scope. +/// Larger rank values will be used for results found in parent scopes. +/// +/// \param CurContext the context from which lookup results will be found. +/// +/// \param Results the builder object that will receive each result. +static unsigned CollectLookupResults(Scope *S, + TranslationUnitDecl *TranslationUnit, + unsigned InitialRank, + DeclContext *CurContext, + ResultBuilder &Results) { + if (!S) + return InitialRank; + + // FIXME: Using directives! + + unsigned NextRank = InitialRank; + Results.EnterNewScope(); + if (S->getEntity() && + !((DeclContext *)S->getEntity())->isFunctionOrMethod()) { + // Look into this scope's declaration context, along with any of its + // parent lookup contexts (e.g., enclosing classes), up to the point + // where we hit the context stored in the next outer scope. + DeclContext *Ctx = (DeclContext *)S->getEntity(); + DeclContext *OuterCtx = findOuterContext(S); + + for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; + Ctx = Ctx->getLookupParent()) { + if (Ctx->isFunctionOrMethod()) + continue; + + NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, CurContext, + Results); + } + } else if (!S->getParent()) { + // Look into the translation unit scope. We walk through the translation + // unit's declaration context, because the Scope itself won't have all of + // the declarations if we loaded a precompiled header. + // FIXME: We would like the translation unit's Scope object to point to the + // translation unit, so we don't need this special "if" branch. However, + // doing so would force the normal C++ name-lookup code to look into the + // translation unit decl when the IdentifierInfo chains would suffice. + // Once we fix that problem (which is part of a more general "don't look + // in DeclContexts unless we have to" optimization), we can eliminate the + // TranslationUnit parameter entirely. + NextRank = CollectMemberLookupResults(TranslationUnit, NextRank + 1, + CurContext, Results); + } else { + // Walk through the declarations in this Scope. + for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get()))) + Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank), + CurContext); + } + + NextRank = NextRank + 1; + } + + // Lookup names in the parent scope. + NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank, + CurContext, Results); + Results.ExitScope(); + + return NextRank; +} + +/// \brief Add type specifiers for the current language as keyword results. +static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + Results.MaybeAddResult(Result("short", Rank)); + Results.MaybeAddResult(Result("long", Rank)); + Results.MaybeAddResult(Result("signed", Rank)); + Results.MaybeAddResult(Result("unsigned", Rank)); + Results.MaybeAddResult(Result("void", Rank)); + Results.MaybeAddResult(Result("char", Rank)); + Results.MaybeAddResult(Result("int", Rank)); + Results.MaybeAddResult(Result("float", Rank)); + Results.MaybeAddResult(Result("double", Rank)); + Results.MaybeAddResult(Result("enum", Rank)); + Results.MaybeAddResult(Result("struct", Rank)); + Results.MaybeAddResult(Result("union", Rank)); + + if (LangOpts.C99) { + // C99-specific + Results.MaybeAddResult(Result("_Complex", Rank)); + Results.MaybeAddResult(Result("_Imaginary", Rank)); + Results.MaybeAddResult(Result("_Bool", Rank)); + } + + if (LangOpts.CPlusPlus) { + // C++-specific + Results.MaybeAddResult(Result("bool", Rank)); + Results.MaybeAddResult(Result("class", Rank)); + Results.MaybeAddResult(Result("typename", Rank)); + Results.MaybeAddResult(Result("wchar_t", Rank)); + + if (LangOpts.CPlusPlus0x) { + Results.MaybeAddResult(Result("char16_t", Rank)); + Results.MaybeAddResult(Result("char32_t", Rank)); + Results.MaybeAddResult(Result("decltype", Rank)); + } + } + + // GNU extensions + if (LangOpts.GNUMode) { + // FIXME: Enable when we actually support decimal floating point. + // Results.MaybeAddResult(Result("_Decimal32", Rank)); + // Results.MaybeAddResult(Result("_Decimal64", Rank)); + // Results.MaybeAddResult(Result("_Decimal128", Rank)); + Results.MaybeAddResult(Result("typeof", Rank)); + } +} + +/// \brief Add function parameter chunks to the given code completion string. +static void AddFunctionParameterChunks(ASTContext &Context, + FunctionDecl *Function, + CodeCompletionString *Result) { + CodeCompletionString *CCStr = Result; + + for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) { + ParmVarDecl *Param = Function->getParamDecl(P); + + if (Param->hasDefaultArg()) { + // When we see an optional default argument, put that argument and + // the remaining default arguments into a new, optional string. + CodeCompletionString *Opt = new CodeCompletionString; + CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt)); + CCStr = Opt; + } + + if (P != 0) + CCStr->AddTextChunk(", "); + + // Format the placeholder string. + std::string PlaceholderStr; + if (Param->getIdentifier()) + PlaceholderStr = Param->getIdentifier()->getName(); + + Param->getType().getAsStringInternal(PlaceholderStr, + Context.PrintingPolicy); + + // Add the placeholder string. + CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); + } + + if (const FunctionProtoType *Proto + = Function->getType()->getAs<FunctionProtoType>()) + if (Proto->isVariadic()) + CCStr->AddPlaceholderChunk(", ..."); +} + +/// \brief Add template parameter chunks to the given code completion string. +static void AddTemplateParameterChunks(ASTContext &Context, + TemplateDecl *Template, + CodeCompletionString *Result, + unsigned MaxParameters = 0) { + CodeCompletionString *CCStr = Result; + bool FirstParameter = true; + + TemplateParameterList *Params = Template->getTemplateParameters(); + TemplateParameterList::iterator PEnd = Params->end(); + if (MaxParameters) + PEnd = Params->begin() + MaxParameters; + for (TemplateParameterList::iterator P = Params->begin(); P != PEnd; ++P) { + bool HasDefaultArg = false; + std::string PlaceholderStr; + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { + if (TTP->wasDeclaredWithTypename()) + PlaceholderStr = "typename"; + else + PlaceholderStr = "class"; + + if (TTP->getIdentifier()) { + PlaceholderStr += ' '; + PlaceholderStr += TTP->getIdentifier()->getName(); + } + + HasDefaultArg = TTP->hasDefaultArgument(); + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (NTTP->getIdentifier()) + PlaceholderStr = NTTP->getIdentifier()->getName(); + NTTP->getType().getAsStringInternal(PlaceholderStr, + Context.PrintingPolicy); + HasDefaultArg = NTTP->hasDefaultArgument(); + } else { + assert(isa<TemplateTemplateParmDecl>(*P)); + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + + // Since putting the template argument list into the placeholder would + // be very, very long, we just use an abbreviation. + PlaceholderStr = "template<...> class"; + if (TTP->getIdentifier()) { + PlaceholderStr += ' '; + PlaceholderStr += TTP->getIdentifier()->getName(); + } + + HasDefaultArg = TTP->hasDefaultArgument(); + } + + if (HasDefaultArg) { + // When we see an optional default argument, put that argument and + // the remaining default arguments into a new, optional string. + CodeCompletionString *Opt = new CodeCompletionString; + CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt)); + CCStr = Opt; + } + + if (FirstParameter) + FirstParameter = false; + else + CCStr->AddTextChunk(", "); + + // Add the placeholder string. + CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); + } +} + +/// \brief Add a qualifier to the given code-completion string, if the +/// provided nested-name-specifier is non-NULL. +void AddQualifierToCompletionString(CodeCompletionString *Result, + NestedNameSpecifier *Qualifier, + bool QualifierIsInformative, + ASTContext &Context) { + if (!Qualifier) + return; + + std::string PrintedNNS; + { + llvm::raw_string_ostream OS(PrintedNNS); + Qualifier->print(OS, Context.PrintingPolicy); + } + if (QualifierIsInformative) + Result->AddInformativeChunk(PrintedNNS.c_str()); + else + Result->AddTextChunk(PrintedNNS.c_str()); +} + +/// \brief If possible, create a new code completion string for the given +/// result. +/// +/// \returns Either a new, heap-allocated code completion string describing +/// how to use this result, or NULL to indicate that the string or name of the +/// result is all that is needed. +CodeCompletionString * +CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { + if (Kind != RK_Declaration) + return 0; + + NamedDecl *ND = Declaration; + + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { + CodeCompletionString *Result = new CodeCompletionString; + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); + Result->AddTextChunk(Function->getNameAsString().c_str()); + Result->AddTextChunk("("); + AddFunctionParameterChunks(S.Context, Function, Result); + Result->AddTextChunk(")"); + return Result; + } + + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { + CodeCompletionString *Result = new CodeCompletionString; + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); + FunctionDecl *Function = FunTmpl->getTemplatedDecl(); + Result->AddTextChunk(Function->getNameAsString().c_str()); + + // Figure out which template parameters are deduced (or have default + // arguments). + llvm::SmallVector<bool, 16> Deduced; + S.MarkDeducedTemplateParameters(FunTmpl, Deduced); + unsigned LastDeducibleArgument; + for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; + --LastDeducibleArgument) { + if (!Deduced[LastDeducibleArgument - 1]) { + // C++0x: Figure out if the template argument has a default. If so, + // the user doesn't need to type this argument. + // FIXME: We need to abstract template parameters better! + bool HasDefaultArg = false; + NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam( + LastDeducibleArgument - 1); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + HasDefaultArg = TTP->hasDefaultArgument(); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) + HasDefaultArg = NTTP->hasDefaultArgument(); + else { + assert(isa<TemplateTemplateParmDecl>(Param)); + HasDefaultArg + = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument(); + } + + if (!HasDefaultArg) + break; + } + } + + if (LastDeducibleArgument) { + // Some of the function template arguments cannot be deduced from a + // function call, so we introduce an explicit template argument list + // containing all of the arguments up to the first deducible argument. + Result->AddTextChunk("<"); + AddTemplateParameterChunks(S.Context, FunTmpl, Result, + LastDeducibleArgument); + Result->AddTextChunk(">"); + } + + // Add the function parameters + Result->AddTextChunk("("); + AddFunctionParameterChunks(S.Context, Function, Result); + Result->AddTextChunk(")"); + return Result; + } + + if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) { + CodeCompletionString *Result = new CodeCompletionString; + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); + Result->AddTextChunk(Template->getNameAsString().c_str()); + Result->AddTextChunk("<"); + AddTemplateParameterChunks(S.Context, Template, Result); + Result->AddTextChunk(">"); + return Result; + } + + if (Qualifier || StartsNestedNameSpecifier) { + CodeCompletionString *Result = new CodeCompletionString; + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); + Result->AddTextChunk(ND->getNameAsString().c_str()); + if (StartsNestedNameSpecifier) + Result->AddTextChunk("::"); + return Result; + } + + return 0; +} + +CodeCompletionString * +CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( + unsigned CurrentArg, + Sema &S) const { + CodeCompletionString *Result = new CodeCompletionString; + FunctionDecl *FDecl = getFunction(); + const FunctionProtoType *Proto + = dyn_cast<FunctionProtoType>(getFunctionType()); + if (!FDecl && !Proto) { + // Function without a prototype. Just give the return type and a + // highlighted ellipsis. + const FunctionType *FT = getFunctionType(); + Result->AddTextChunk( + FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); + Result->AddTextChunk("("); + Result->AddPlaceholderChunk("..."); + Result->AddTextChunk("("); + return Result; + } + + if (FDecl) + Result->AddTextChunk(FDecl->getNameAsString().c_str()); + else + Result->AddTextChunk( + Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); + + Result->AddTextChunk("("); + unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs(); + for (unsigned I = 0; I != NumParams; ++I) { + if (I) + Result->AddTextChunk(", "); + + std::string ArgString; + QualType ArgType; + + if (FDecl) { + ArgString = FDecl->getParamDecl(I)->getNameAsString(); + ArgType = FDecl->getParamDecl(I)->getOriginalType(); + } else { + ArgType = Proto->getArgType(I); + } + + ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy); + + if (I == CurrentArg) + Result->AddPlaceholderChunk(ArgString.c_str()); + else + Result->AddTextChunk(ArgString.c_str()); + } + + if (Proto && Proto->isVariadic()) { + Result->AddTextChunk(", "); + if (CurrentArg < NumParams) + Result->AddTextChunk("..."); + else + Result->AddPlaceholderChunk("..."); + } + Result->AddTextChunk(")"); + + return Result; +} + +namespace { + struct SortCodeCompleteResult { + typedef CodeCompleteConsumer::Result Result; + + bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const { + if (X.getNameKind() != Y.getNameKind()) + return X.getNameKind() < Y.getNameKind(); + + return llvm::LowercaseString(X.getAsString()) + < llvm::LowercaseString(Y.getAsString()); + } + + bool operator()(const Result &X, const Result &Y) const { + // Sort first by rank. + if (X.Rank < Y.Rank) + return true; + else if (X.Rank > Y.Rank) + return false; + + // Result kinds are ordered by decreasing importance. + if (X.Kind < Y.Kind) + return true; + else if (X.Kind > Y.Kind) + return false; + + // Non-hidden names precede hidden names. + if (X.Hidden != Y.Hidden) + return !X.Hidden; + + // Non-nested-name-specifiers precede nested-name-specifiers. + if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier) + return !X.StartsNestedNameSpecifier; + + // Ordering depends on the kind of result. + switch (X.Kind) { + case Result::RK_Declaration: + // Order based on the declaration names. + return isEarlierDeclarationName(X.Declaration->getDeclName(), + Y.Declaration->getDeclName()); + + case Result::RK_Keyword: + return strcmp(X.Keyword, Y.Keyword) < 0; + } + + // Silence GCC warning. + return false; + } + }; +} + +static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, + CodeCompleteConsumer::Result *Results, + unsigned NumResults) { + // Sort the results by rank/kind/etc. + std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); + + if (CodeCompleter) + CodeCompleter->ProcessCodeCompleteResults(Results, NumResults); +} + +void Sema::CodeCompleteOrdinaryName(Scope *S) { + ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, + Results); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, + SourceLocation OpLoc, + bool IsArrow) { + if (!BaseE || !CodeCompleter) + return; + + typedef CodeCompleteConsumer::Result Result; + + Expr *Base = static_cast<Expr *>(BaseE); + QualType BaseType = Base->getType(); + + if (IsArrow) { + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + else if (BaseType->isObjCObjectPointerType()) + /*Do nothing*/ ; + else + return; + } + + ResultBuilder Results(*this, &ResultBuilder::IsMember); + unsigned NextRank = 0; + + if (const RecordType *Record = BaseType->getAs<RecordType>()) { + NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, + Record->getDecl(), Results); + + if (getLangOptions().CPlusPlus) { + if (!Results.empty()) { + // The "template" keyword can follow "->" or "." in the grammar. + // However, we only want to suggest the template keyword if something + // is dependent. + bool IsDependent = BaseType->isDependentType(); + if (!IsDependent) { + for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) + if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) { + IsDependent = Ctx->isDependentContext(); + break; + } + } + + if (IsDependent) + Results.MaybeAddResult(Result("template", NextRank++)); + } + + // We could have the start of a nested-name-specifier. Add those + // results as well. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, + CurContext, Results); + } + + // Hand off the results found for code completion. + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + + // We're done! + return; + } +} + +void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { + if (!CodeCompleter) + return; + + typedef CodeCompleteConsumer::Result Result; + ResultBuilder::LookupFilter Filter = 0; + switch ((DeclSpec::TST)TagSpec) { + case DeclSpec::TST_enum: + Filter = &ResultBuilder::IsEnum; + break; + + case DeclSpec::TST_union: + Filter = &ResultBuilder::IsUnion; + break; + + case DeclSpec::TST_struct: + case DeclSpec::TST_class: + Filter = &ResultBuilder::IsClassOrStruct; + break; + + default: + assert(false && "Unknown type specifier kind in CodeCompleteTag"); + return; + } + + ResultBuilder Results(*this, Filter); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + + if (getLangOptions().CPlusPlus) { + // We could have the start of a nested-name-specifier. Add those + // results as well. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, + CurContext, Results); + } + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteCase(Scope *S) { + if (getSwitchStack().empty() || !CodeCompleter) + return; + + SwitchStmt *Switch = getSwitchStack().back(); + if (!Switch->getCond()->getType()->isEnumeralType()) + return; + + // Code-complete the cases of a switch statement over an enumeration type + // by providing the list of + EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl(); + + // Determine which enumerators we have already seen in the switch statement. + // FIXME: Ideally, we would also be able to look *past* the code-completion + // token, in case we are code-completing in the middle of the switch and not + // at the end. However, we aren't able to do so at the moment. + llvm::SmallPtrSet<EnumConstantDecl *, 8> EnumeratorsSeen; + NestedNameSpecifier *Qualifier = 0; + for (SwitchCase *SC = Switch->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + CaseStmt *Case = dyn_cast<CaseStmt>(SC); + if (!Case) + continue; + + Expr *CaseVal = Case->getLHS()->IgnoreParenCasts(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseVal)) + if (EnumConstantDecl *Enumerator + = dyn_cast<EnumConstantDecl>(DRE->getDecl())) { + // We look into the AST of the case statement to determine which + // enumerator was named. Alternatively, we could compute the value of + // the integral constant expression, then compare it against the + // values of each enumerator. However, value-based approach would not + // work as well with C++ templates where enumerators declared within a + // template are type- and value-dependent. + EnumeratorsSeen.insert(Enumerator); + + // If this is a qualified-id, keep track of the nested-name-specifier + // so that we can reproduce it as part of code completion, e.g., + // + // switch (TagD.getKind()) { + // case TagDecl::TK_enum: + // break; + // case XXX + // + // At the XXX, our completions are TagDecl::TK_union, + // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union, + // TK_struct, and TK_class. + if (QualifiedDeclRefExpr *QDRE = dyn_cast<QualifiedDeclRefExpr>(DRE)) + Qualifier = QDRE->getQualifier(); + } + } + + if (getLangOptions().CPlusPlus && !Qualifier && EnumeratorsSeen.empty()) { + // If there are no prior enumerators in C++, check whether we have to + // qualify the names of the enumerators that we suggest, because they + // may not be visible in this scope. + Qualifier = getRequiredQualification(Context, CurContext, + Enum->getDeclContext()); + + // FIXME: Scoped enums need to start with "EnumDecl" as the context! + } + + // Add any enumerators that have not yet been mentioned. + ResultBuilder Results(*this); + Results.EnterNewScope(); + for (EnumDecl::enumerator_iterator E = Enum->enumerator_begin(), + EEnd = Enum->enumerator_end(); + E != EEnd; ++E) { + if (EnumeratorsSeen.count(*E)) + continue; + + Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0, Qualifier)); + } + Results.ExitScope(); + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +namespace { + struct IsBetterOverloadCandidate { + Sema &S; + + public: + explicit IsBetterOverloadCandidate(Sema &S) : S(S) { } + + bool + operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const { + return S.isBetterOverloadCandidate(X, Y); + } + }; +} + +void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, + ExprTy **ArgsIn, unsigned NumArgs) { + if (!CodeCompleter) + return; + + Expr *Fn = (Expr *)FnIn; + Expr **Args = (Expr **)ArgsIn; + + // Ignore type-dependent call expressions entirely. + if (Fn->isTypeDependent() || + Expr::hasAnyTypeDependentArguments(Args, NumArgs)) + return; + + NamedDecl *Function; + DeclarationName UnqualifiedName; + NestedNameSpecifier *Qualifier; + SourceRange QualifierRange; + bool ArgumentDependentLookup; + bool HasExplicitTemplateArgs; + const TemplateArgument *ExplicitTemplateArgs; + unsigned NumExplicitTemplateArgs; + + DeconstructCallFunction(Fn, + Function, UnqualifiedName, Qualifier, QualifierRange, + ArgumentDependentLookup, HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs); + + + // FIXME: What if we're calling something that isn't a function declaration? + // FIXME: What if we're calling a pseudo-destructor? + // FIXME: What if we're calling a member function? + + // Build an overload candidate set based on the functions we find. + OverloadCandidateSet CandidateSet; + AddOverloadedCallCandidates(Function, UnqualifiedName, + ArgumentDependentLookup, HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + Args, NumArgs, + CandidateSet, + /*PartialOverloading=*/true); + + // Sort the overload candidate set by placing the best overloads first. + std::stable_sort(CandidateSet.begin(), CandidateSet.end(), + IsBetterOverloadCandidate(*this)); + + // Add the remaining viable overload candidates as code-completion reslults. + typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; + llvm::SmallVector<ResultCandidate, 8> Results; + + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) { + if (Cand->Viable) + Results.push_back(ResultCandidate(Cand->Function)); + } + CodeCompleter->ProcessOverloadCandidates(NumArgs, Results.data(), + Results.size()); +} + +void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, + bool EnteringContext) { + if (!SS.getScopeRep() || !CodeCompleter) + return; + + DeclContext *Ctx = computeDeclContext(SS, EnteringContext); + if (!Ctx) + return; + + ResultBuilder Results(*this); + unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results); + + // The "template" keyword can follow "::" in the grammar, but only + // put it into the grammar if the nested-name-specifier is dependent. + NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); + if (!Results.empty() && NNS->isDependent()) + Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteUsing(Scope *S) { + if (!CodeCompleter) + return; + + ResultBuilder Results(*this, &ResultBuilder::IsNestedNameSpecifier); + Results.EnterNewScope(); + + // If we aren't in class scope, we could see the "namespace" keyword. + if (!S->isClassScope()) + Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0)); + + // After "using", we can see anything that would start a + // nested-name-specifier. + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, + CurContext, Results); + Results.ExitScope(); + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteUsingDirective(Scope *S) { + if (!CodeCompleter) + return; + + // After "using namespace", we expect to see a namespace name or namespace + // alias. + ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); + Results.EnterNewScope(); + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, + Results); + Results.ExitScope(); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteNamespaceDecl(Scope *S) { + if (!CodeCompleter) + return; + + ResultBuilder Results(*this, &ResultBuilder::IsNamespace); + DeclContext *Ctx = (DeclContext *)S->getEntity(); + if (!S->getParent()) + Ctx = Context.getTranslationUnitDecl(); + + if (Ctx && Ctx->isFileContext()) { + // We only want to see those namespaces that have already been defined + // within this scope, because its likely that the user is creating an + // extended namespace declaration. Keep track of the most recent + // definition of each namespace. + std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest; + for (DeclContext::specific_decl_iterator<NamespaceDecl> + NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end()); + NS != NSEnd; ++NS) + OrigToLatest[NS->getOriginalNamespace()] = *NS; + + // Add the most recent definition (or extended definition) of each + // namespace to the list of results. + Results.EnterNewScope(); + for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator + NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); + NS != NSEnd; ++NS) + Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0), + CurContext); + Results.ExitScope(); + } + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { + if (!CodeCompleter) + return; + + // After "namespace", we expect to see a namespace or alias. + ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, + Results); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteOperatorName(Scope *S) { + if (!CodeCompleter) + return; + + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this, &ResultBuilder::IsType); + Results.EnterNewScope(); + + // Add the names of overloadable operators. +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + if (std::strcmp(Spelling, "?")) \ + Results.MaybeAddResult(Result(Spelling, 0)); +#include "clang/Basic/OperatorKinds.def" + + // Add any type names visible from the current scope + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + + // Add any type specifiers + AddTypeSpecifierResults(getLangOptions(), 0, Results); + + // Add any nested-name-specifiers + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank + 1, + CurContext, Results); + Results.ExitScope(); + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + +void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { + if (!CodeCompleter) + return; + unsigned Attributes = ODS.getPropertyAttributes(); + + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0)); + if (!(Attributes & ObjCDeclSpec::DQ_PR_assign)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0)); + if (!(Attributes & ObjCDeclSpec::DQ_PR_readwrite)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0)); + if (!(Attributes & ObjCDeclSpec::DQ_PR_retain)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0)); + if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0)); + if (!(Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0)); + if (!(Attributes & ObjCDeclSpec::DQ_PR_setter)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("setter", 0)); + if (!(Attributes & ObjCDeclSpec::DQ_PR_getter)) + Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0)); + Results.ExitScope(); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1fd569729a373..606b33f5f74b6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12,28 +12,34 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "SemaInherit.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/Parse/DeclSpec.h" -#include "clang/Basic/TargetInfo.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" -#include "clang/Lex/HeaderSearch.h" -#include "llvm/ADT/SmallSet.h" +#include "clang/Lex/HeaderSearch.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include <algorithm> +#include <cstring> #include <functional> +#include <queue> using namespace clang; /// getDeclName - Return a pretty name for the specified decl if possible, or -/// an empty string if not. This is used for pretty crash reporting. +/// an empty string if not. This is used for pretty crash reporting. std::string Sema::getDeclName(DeclPtrTy d) { Decl *D = d.getAs<Decl>(); if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(D)) @@ -57,7 +63,8 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { /// If name lookup results in an ambiguity, this routine will complain /// and then return NULL. Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS) { + Scope *S, const CXXScopeSpec *SS, + bool isClassName) { // C++ [temp.res]p3: // A qualified-id that refers to a type and in which the // nested-name-specifier depends on a template-parameter (14.6.2) @@ -67,11 +74,20 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. - if (SS && isUnknownSpecialization(*SS)) - return 0; + if (SS && isUnknownSpecialization(*SS)) { + if (!isClassName) + return 0; + + // We know from the grammar that this name refers to a type, so build a + // TypenameType node to describe the type. + // FIXME: Record somewhere that this TypenameType node has no "typename" + // keyword associated with it. + return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), + II, SS->getRange()).getAsOpaquePtr(); + } - LookupResult Result - = LookupParsedName(S, SS, &II, LookupOrdinaryName, false, false); + LookupResult Result; + LookupParsedName(Result, S, SS, &II, LookupOrdinaryName, false, false); NamedDecl *IIDecl = 0; switch (Result.getKind()) { @@ -79,15 +95,21 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::FoundOverloaded: return 0; - case LookupResult::AmbiguousBaseSubobjectTypes: - case LookupResult::AmbiguousBaseSubobjects: - case LookupResult::AmbiguousReference: { + case LookupResult::Ambiguous: { + // Recover from type-hiding ambiguities by hiding the type. We'll + // do the lookup again when looking for an object, and we can + // diagnose the error then. If we don't do this, then the error + // about hiding the type will be immediately followed by an error + // that only makes sense if the identifier was treated like a type. + if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) + return 0; + // Look to see if we have a type anywhere in the list of results. for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end(); Res != ResEnd; ++Res) { if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res)) { - if (!IIDecl || - (*Res)->getLocation().getRawEncoding() < + if (!IIDecl || + (*Res)->getLocation().getRawEncoding() < IIDecl->getLocation().getRawEncoding()) IIDecl = *Res; } @@ -100,7 +122,6 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // perform this lookup again (e.g., as an object name), which // will produce the ambiguity, or will complain that it expected // a type name. - Result.Destroy(); return 0; } @@ -113,17 +134,17 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } case LookupResult::Found: - IIDecl = Result.getAsDecl(); + IIDecl = Result.getFoundDecl(); break; } if (IIDecl) { QualType T; - + if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { // Check whether we can use this type (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - + if (getLangOptions().CPlusPlus) { // C++ [temp.local]p2: // Within the scope of a class template specialization or @@ -143,7 +164,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { // Check whether we can use this interface. (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - + T = Context.getObjCInterfaceType(IDecl); } else return 0; @@ -164,9 +185,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, /// where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. - LookupResult R = LookupName(S, &II, LookupTagName, false, false); + LookupResult R; + LookupName(R, S, &II, LookupTagName, false, false); if (R.getKind() == LookupResult::Found) - if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsDecl())) { + if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsSingleDecl(Context))) { switch (TD->getTagKind()) { case TagDecl::TK_struct: return DeclSpec::TST_struct; case TagDecl::TK_union: return DeclSpec::TST_union; @@ -174,24 +196,60 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { case TagDecl::TK_enum: return DeclSpec::TST_enum; } } - + return DeclSpec::TST_unspecified; } +bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TypeTy *&SuggestedType) { + // We don't have anything to suggest (yet). + SuggestedType = 0; + + // FIXME: Should we move the logic that tries to recover from a missing tag + // (struct, union, enum) from Parser::ParseImplicitInt here, instead? + + if (!SS) + Diag(IILoc, diag::err_unknown_typename) << &II; + else if (DeclContext *DC = computeDeclContext(*SS, false)) + Diag(IILoc, diag::err_typename_nested_not_found) + << &II << DC << SS->getRange(); + else if (isDependentScopeSpecifier(*SS)) { + Diag(SS->getRange().getBegin(), diag::err_typename_missing) + << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() + << SourceRange(SS->getRange().getBegin(), IILoc) + << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(), + "typename "); + SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get(); + } else { + assert(SS && SS->isInvalid() && + "Invalid scope specifier has already been diagnosed"); + } + + return true; +} - +// Determines the context to return to after temporarily entering a +// context. This depends in an unnecessarily complicated way on the +// exact ordering of callbacks from the parser. DeclContext *Sema::getContainingDC(DeclContext *DC) { - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { - // A C++ out-of-line method will return to the file declaration context. - if (MD->isOutOfLine()) - return MD->getLexicalDeclContext(); - - // A C++ inline method is parsed *after* the topmost class it was declared - // in is fully parsed (it's "complete"). - // The parsing of a C++ inline method happens at the declaration context of - // the topmost (non-nested) class it is lexically declared in. - assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record."); - DC = MD->getParent(); + + // Functions defined inline within classes aren't parsed until we've + // finished parsing the top-level class, so the top-level class is + // the context we'll need to return to. + if (isa<FunctionDecl>(DC)) { + DC = DC->getLexicalParent(); + + // A function not defined within a class will always return to its + // lexical context. + if (!isa<CXXRecordDecl>(DC)) + return DC; + + // A C++ inline method/friend is parsed *after* the topmost class + // it was declared in is fully parsed ("complete"); the topmost + // class is the context we need to return to. while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent())) DC = RD; @@ -260,103 +318,84 @@ static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) { } /// Add this decl to the scope shadowed decl chains. -void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { +void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // Move up the scope chain until we find the nearest enclosing // non-transparent context. The declaration will be introduced into this // scope. - while (S->getEntity() && + while (S->getEntity() && ((DeclContext *)S->getEntity())->isTransparentContext()) S = S->getParent(); - S->AddDecl(DeclPtrTy::make(D)); - // Add scoped declarations into their context, so that they can be // found later. Declarations without a context won't be inserted // into any context. - CurContext->addDecl(D); - - // C++ [basic.scope]p4: - // -- exactly one declaration shall declare a class name or - // enumeration name that is not a typedef name and the other - // declarations shall all refer to the same object or - // enumerator, or all refer to functions and function templates; - // in this case the class name or enumeration name is hidden. - if (TagDecl *TD = dyn_cast<TagDecl>(D)) { - // We are pushing the name of a tag (enum or class). - if (CurContext->getLookupContext() - == TD->getDeclContext()->getLookupContext()) { - // We're pushing the tag into the current context, which might - // require some reshuffling in the identifier resolver. - IdentifierResolver::iterator - I = IdResolver.begin(TD->getDeclName()), - IEnd = IdResolver.end(); - if (I != IEnd && isDeclInScope(*I, CurContext, S)) { - NamedDecl *PrevDecl = *I; - for (; I != IEnd && isDeclInScope(*I, CurContext, S); - PrevDecl = *I, ++I) { - if (TD->declarationReplaces(*I)) { - // This is a redeclaration. Remove it from the chain and - // break out, so that we'll add in the shadowed - // declaration. - S->RemoveDecl(DeclPtrTy::make(*I)); - if (PrevDecl == *I) { - IdResolver.RemoveDecl(*I); - IdResolver.AddDecl(TD); - return; - } else { - IdResolver.RemoveDecl(*I); - break; - } - } - } + if (AddToContext) + CurContext->addDecl(D); - // There is already a declaration with the same name in the same - // scope, which is not a tag declaration. It must be found - // before we find the new declaration, so insert the new - // declaration at the end of the chain. - IdResolver.AddShadowedDecl(TD, PrevDecl); - - return; - } - } - } else if ((isa<FunctionDecl>(D) && - AllowOverloadingOfFunction(D, Context)) || - isa<FunctionTemplateDecl>(D)) { - // We are pushing the name of a function or function template, - // which might be an overloaded name. - IdentifierResolver::iterator Redecl - = std::find_if(IdResolver.begin(D->getDeclName()), - IdResolver.end(), - std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces), - D)); - if (Redecl != IdResolver.end() && - S->isDeclScope(DeclPtrTy::make(*Redecl))) { - // There is already a declaration of a function on our - // IdResolver chain. Replace it with this declaration. - S->RemoveDecl(DeclPtrTy::make(*Redecl)); - IdResolver.RemoveDecl(*Redecl); - } - } else if (isa<ObjCInterfaceDecl>(D)) { - // We're pushing an Objective-C interface into the current - // context. If there is already an alias declaration, remove it first. - for (IdentifierResolver::iterator - I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); - I != IEnd; ++I) { - if (isa<ObjCCompatibleAliasDecl>(*I)) { - S->RemoveDecl(DeclPtrTy::make(*I)); - IdResolver.RemoveDecl(*I); - break; - } + // Out-of-line function and variable definitions should not be pushed into + // scope. + if ((isa<FunctionTemplateDecl>(D) && + cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->isOutOfLine()) || + (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isOutOfLine()) || + (isa<VarDecl>(D) && cast<VarDecl>(D)->isOutOfLine())) + return; + + // If this replaces anything in the current scope, + IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), + IEnd = IdResolver.end(); + for (; I != IEnd; ++I) { + if (S->isDeclScope(DeclPtrTy::make(*I)) && D->declarationReplaces(*I)) { + S->RemoveDecl(DeclPtrTy::make(*I)); + IdResolver.RemoveDecl(*I); + + // Should only need to replace one decl. + break; } } + S->AddDecl(DeclPtrTy::make(D)); IdResolver.AddDecl(D); } +bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) { + if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) { + // Look inside the overload set to determine if any of the declarations + // are in scope. (Possibly) build a new overload set containing only + // those declarations that are in scope. + OverloadedFunctionDecl *NewOvl = 0; + bool FoundInScope = false; + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) { + NamedDecl *FD = F->get(); + if (!isDeclInScope(FD, Ctx, S)) { + if (!NewOvl && F != Ovl->function_begin()) { + NewOvl = OverloadedFunctionDecl::Create(Context, + F->get()->getDeclContext(), + F->get()->getDeclName()); + D = NewOvl; + for (OverloadedFunctionDecl::function_iterator + First = Ovl->function_begin(); + First != F; ++First) + NewOvl->addOverload(*First); + } + } else { + FoundInScope = true; + if (NewOvl) + NewOvl->addOverload(*F); + } + } + + return FoundInScope; + } + + return IdResolver.isDeclInScope(D, Ctx, Context, S); +} + void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && - "Scope shouldn't contain decls!"); + "Scope shouldn't contain decls!"); for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); I != E; ++I) { @@ -368,6 +407,12 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; + // Diagnose unused variables in this scope. + if (!D->isUsed() && !D->hasAttr<UnusedAttr>() && isa<VarDecl>(D) && + !isa<ParmVarDecl>(D) && !isa<ImplicitParamDecl>(D) && + D->getDeclContext()->isFunctionOrMethod()) + Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName(); + // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } @@ -378,8 +423,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. - NamedDecl *IDecl = LookupName(TUScope, Id, LookupOrdinaryName); - + NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName); + return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl); } @@ -392,7 +437,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { /// struct S6 { /// enum { BAR } e; /// }; -/// +/// /// void test_S6() { /// struct S6 a; /// a.e = BAR; @@ -408,7 +453,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { /// contain non-field names. Scope *Sema::getNonFieldDeclScope(Scope *S) { while (((S->getFlags() & Scope::DeclScope) == 0) || - (S->getEntity() && + (S->getEntity() && ((DeclContext *)S->getEntity())->isTransparentContext()) || (S->isClassScope() && !getLangOptions().CPlusPlus)) S = S->getParent(); @@ -418,9 +463,9 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) { void Sema::InitBuiltinVaListType() { if (!Context.getBuiltinVaListType().isNull()) return; - + IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); - NamedDecl *VaDecl = LookupName(TUScope, VaIdent, LookupOrdinaryName); + NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, LookupOrdinaryName); TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl); Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); } @@ -438,17 +483,23 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, InitBuiltinVaListType(); ASTContext::GetBuiltinTypeError Error; - QualType R = Context.GetBuiltinType(BID, Error); + QualType R = Context.GetBuiltinType(BID, Error); switch (Error) { case ASTContext::GE_None: // Okay break; - case ASTContext::GE_Missing_FILE: + case ASTContext::GE_Missing_stdio: if (ForRedeclaration) Diag(Loc, diag::err_implicit_decl_requires_stdio) << Context.BuiltinInfo.GetName(BID); return 0; + + case ASTContext::GE_Missing_setjmp: + if (ForRedeclaration) + Diag(Loc, diag::err_implicit_decl_requires_setjmp) + << Context.BuiltinInfo.GetName(BID); + return 0; } if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) { @@ -465,7 +516,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), - Loc, II, R, + Loc, II, R, /*DInfo=*/0, FunctionDecl::Extern, false, /*hasPrototype=*/true); New->setImplicit(); @@ -476,12 +527,13 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, llvm::SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, - FT->getArgType(i), VarDecl::None, 0)); + FT->getArgType(i), /*DInfo=*/0, + VarDecl::None, 0)); New->setParams(Context, Params.data(), Params.size()); } - - AddKnownFunctionAttributes(New); - + + AddKnownFunctionAttributes(New); + // TUScope is the translation-unit scope to insert this function into. // FIXME: This is hideous. We need to teach PushOnScopeChains to // relate Scopes to DeclContexts, and probably eliminate CurContext @@ -493,18 +545,6 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, return New; } -/// GetStdNamespace - This method gets the C++ "std" namespace. This is where -/// everything from the standard library is defined. -NamespaceDecl *Sema::GetStdNamespace() { - if (!StdNamespace) { - IdentifierInfo *StdIdent = &PP.getIdentifierTable().get("std"); - DeclContext *Global = Context.getTranslationUnitDecl(); - Decl *Std = LookupQualifiedName(Global, StdIdent, LookupNamespaceName); - StdNamespace = dyn_cast_or_null<NamespaceDecl>(Std); - } - return StdNamespace; -} - /// MergeTypeDefDecl - We just parsed a typedef 'New' which has the /// same name and scope as a previous declaration 'Old'. Figure out /// how to resolve this situation, merging decls or emitting @@ -515,25 +555,26 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { // don't bother doing any merging checks. if (New->isInvalidDecl() || OldD->isInvalidDecl()) return New->setInvalidDecl(); - - bool objc_types = false; - + // Allow multiple definitions for ObjC built-in typedefs. // FIXME: Verify the underlying types are equivalent! if (getLangOptions().ObjC1) { const IdentifierInfo *TypeID = New->getIdentifier(); switch (TypeID->getLength()) { default: break; - case 2: + case 2: if (!TypeID->isStr("id")) break; - Context.setObjCIdType(Context.getTypeDeclType(New)); - objc_types = true; - break; + Context.ObjCIdRedefinitionType = New->getUnderlyingType(); + // Install the built-in type for 'id', ignoring the current definition. + New->setTypeForDecl(Context.getObjCIdType().getTypePtr()); + return; case 5: if (!TypeID->isStr("Class")) break; - Context.setObjCClassType(Context.getTypeDeclType(New)); + Context.ObjCClassRedefinitionType = New->getUnderlyingType(); + // Install the built-in type for 'Class', ignoring the current definition. + New->setTypeForDecl(Context.getObjCClassType().getTypePtr()); return; case 3: if (!TypeID->isStr("SEL")) @@ -551,14 +592,14 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { // Verify the old decl was also a type. TypeDecl *Old = dyn_cast<TypeDecl>(OldD); if (!Old) { - Diag(New->getLocation(), diag::err_redefinition_different_kind) + Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); if (OldD->getLocation().isValid()) Diag(OldD->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } - // Determine the "old" type we'll use for checking and diagnostics. + // Determine the "old" type we'll use for checking and diagnostics. QualType OldType; if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old)) OldType = OldTypedef->getUnderlyingType(); @@ -568,8 +609,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { // If the typedef types are not identical, reject them in all languages and // with any extensions enabled. - if (OldType != New->getUnderlyingType() && - Context.getCanonicalType(OldType) != + if (OldType != New->getUnderlyingType() && + Context.getCanonicalType(OldType) != Context.getCanonicalType(New->getUnderlyingType())) { Diag(New->getLocation(), diag::err_redefinition_different_typedef) << New->getUnderlyingType() << OldType; @@ -577,8 +618,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } - - if (objc_types || getLangOptions().Microsoft) + + if (getLangOptions().Microsoft) return; // C++ [dcl.typedef]p2: @@ -602,7 +643,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { (Context.getSourceManager().isInSystemHeader(Old->getLocation()) || Context.getSourceManager().isInSystemHeader(New->getLocation()))) return; - + Diag(New->getLocation(), diag::warn_redefinition_of_typedef) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); @@ -611,7 +652,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { /// DeclhasAttr - returns true if decl Declaration already has the target /// attribute. -static bool +static bool DeclHasAttr(const Decl *decl, const Attr *target) { for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext()) if (attr->getKind() == target->getKind()) @@ -651,15 +692,15 @@ struct GNUCompatibleParamWarning { /// /// Returns true if there was an error, false otherwise. bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { - assert(!isa<OverloadedFunctionDecl>(OldD) && + assert(!isa<OverloadedFunctionDecl>(OldD) && "Cannot merge with an overloaded function declaration"); // Verify the old decl was also a function. FunctionDecl *Old = 0; - if (FunctionTemplateDecl *OldFunctionTemplate + if (FunctionTemplateDecl *OldFunctionTemplate = dyn_cast<FunctionTemplateDecl>(OldD)) Old = OldFunctionTemplate->getTemplatedDecl(); - else + else Old = dyn_cast<FunctionDecl>(OldD); if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) @@ -675,12 +716,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { PrevDiag = diag::note_previous_definition; else if (Old->isImplicit()) PrevDiag = diag::note_previous_implicit_declaration; - else + else PrevDiag = diag::note_previous_declaration; - + QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); - + if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) && New->getStorageClass() == FunctionDecl::Static && Old->getStorageClass() != FunctionDecl::Static) { @@ -693,11 +734,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { if (getLangOptions().CPlusPlus) { // (C++98 13.1p2): // Certain function declarations cannot be overloaded: - // -- Function declarations that differ only in the return type + // -- Function declarations that differ only in the return type // cannot be overloaded. - QualType OldReturnType + QualType OldReturnType = cast<FunctionType>(OldQType.getTypePtr())->getResultType(); - QualType NewReturnType + QualType NewReturnType = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); if (OldReturnType != NewReturnType) { Diag(New->getLocation(), diag::err_ovl_diff_return_type); @@ -707,11 +748,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); - if (OldMethod && NewMethod && - OldMethod->getLexicalDeclContext() == - NewMethod->getLexicalDeclContext()) { - // -- Member function declarations with the same name and the - // same parameter types cannot be overloaded if any of them + if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() && + NewMethod->getLexicalDeclContext()->isRecord()) { + // -- Member function declarations with the same name and the + // same parameter types cannot be overloaded if any of them // is a static member function declaration. if (OldMethod->isStatic() || NewMethod->isStatic()) { Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); @@ -732,7 +772,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { NewDiag = diag::err_conv_function_redeclared; else NewDiag = diag::err_member_redeclared; - + Diag(New->getLocation(), NewDiag); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); } @@ -750,8 +790,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // duplicate function decls like "void f(int); void f(enum X);" properly. if (!getLangOptions().CPlusPlus && Context.typesAreCompatible(OldQType, NewQType)) { - const FunctionType *OldFuncType = OldQType->getAsFunctionType(); - const FunctionType *NewFuncType = NewQType->getAsFunctionType(); + const FunctionType *OldFuncType = OldQType->getAs<FunctionType>(); + const FunctionType *NewFuncType = NewQType->getAs<FunctionType>(); const FunctionProtoType *OldProto = 0; if (isa<FunctionNoProtoType>(NewFuncType) && (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) { @@ -769,20 +809,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Synthesize a parameter for each argument type. llvm::SmallVector<ParmVarDecl*, 16> Params; - for (FunctionProtoType::arg_type_iterator - ParamType = OldProto->arg_type_begin(), + for (FunctionProtoType::arg_type_iterator + ParamType = OldProto->arg_type_begin(), ParamEnd = OldProto->arg_type_end(); ParamType != ParamEnd; ++ParamType) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), 0, - *ParamType, VarDecl::None, - 0); + *ParamType, /*DInfo=*/0, + VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); } New->setParams(Context, Params.data(), Params.size()); - } + } return MergeCompatibleFunctionDecls(New, Old); } @@ -800,29 +840,29 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // C99 6.9.1p8. if (!getLangOptions().CPlusPlus && Old->hasPrototype() && !New->hasPrototype() && - New->getType()->getAsFunctionProtoType() && + New->getType()->getAs<FunctionProtoType>() && Old->getNumParams() == New->getNumParams()) { llvm::SmallVector<QualType, 16> ArgTypes; llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings; - const FunctionProtoType *OldProto - = Old->getType()->getAsFunctionProtoType(); - const FunctionProtoType *NewProto - = New->getType()->getAsFunctionProtoType(); - + const FunctionProtoType *OldProto + = Old->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *NewProto + = New->getType()->getAs<FunctionProtoType>(); + // Determine whether this is the GNU C extension. QualType MergedReturn = Context.mergeTypes(OldProto->getResultType(), NewProto->getResultType()); bool LooseCompatible = !MergedReturn.isNull(); - for (unsigned Idx = 0, End = Old->getNumParams(); + for (unsigned Idx = 0, End = Old->getNumParams(); LooseCompatible && Idx != End; ++Idx) { ParmVarDecl *OldParm = Old->getParamDecl(Idx); ParmVarDecl *NewParm = New->getParamDecl(Idx); - if (Context.typesAreCompatible(OldParm->getType(), + if (Context.typesAreCompatible(OldParm->getType(), NewProto->getArgType(Idx))) { ArgTypes.push_back(NewParm->getType()); } else if (Context.typesAreCompatible(OldParm->getType(), NewParm->getType())) { - GNUCompatibleParamWarning Warn + GNUCompatibleParamWarning Warn = { OldParm, NewParm, NewProto->getArgType(Idx) }; Warnings.push_back(Warn); ArgTypes.push_back(NewParm->getType()); @@ -836,7 +876,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { diag::ext_param_promoted_not_compatible_with_prototype) << Warnings[Warn].PromotedType << Warnings[Warn].OldParm->getType(); - Diag(Warnings[Warn].OldParm->getLocation(), + Diag(Warnings[Warn].OldParm->getLocation(), diag::note_previous_declaration); } @@ -851,7 +891,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // A function that has already been declared has been redeclared or defined // with a different type- show appropriate diagnostic - if (unsigned BuiltinID = Old->getBuiltinID(Context)) { + if (unsigned BuiltinID = Old->getBuiltinID()) { // The user has declared a builtin function with an incompatible // signature. if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { @@ -876,7 +916,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } /// \brief Completes the merge of two function declarations that are -/// known to be compatible. +/// known to be compatible. /// /// This routine handles the merging of attributes and other /// properties of function declarations form the old declaration to @@ -889,25 +929,10 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { MergeAttributes(New, Old, Context); // Merge the storage class. - if (Old->getStorageClass() != FunctionDecl::Extern) + if (Old->getStorageClass() != FunctionDecl::Extern && + Old->getStorageClass() != FunctionDecl::None) New->setStorageClass(Old->getStorageClass()); - // Merge "inline" - if (Old->isInline()) - New->setInline(true); - - // If this function declaration by itself qualifies as a C99 inline - // definition (C99 6.7.4p6), but the previous definition did not, - // then the function is not a C99 inline definition. - if (New->isC99InlineDefinition() && !Old->isC99InlineDefinition()) - New->setC99InlineDefinition(false); - else if (Old->isC99InlineDefinition() && !New->isC99InlineDefinition()) { - // Mark all preceding definitions as not being C99 inline definitions. - for (const FunctionDecl *Prev = Old; Prev; - Prev = Prev->getPreviousDeclaration()) - const_cast<FunctionDecl *>(Prev)->setC99InlineDefinition(false); - } - // Merge "pure" flag. if (Old->isPure()) New->setPure(); @@ -915,7 +940,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { // Merge the "deleted" flag. if (Old->isDeleted()) New->setDeleted(); - + if (getLangOptions().CPlusPlus) return MergeCXXFunctionDecl(New, Old); @@ -926,16 +951,16 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { /// and scope as a previous declaration 'Old'. Figure out how to resolve this /// situation, merging decls or emitting diagnostics as appropriate. /// -/// Tentative definition rules (C99 6.9.2p2) are checked by -/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative +/// Tentative definition rules (C99 6.9.2p2) are checked by +/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative /// definitions here, since the initializer hasn't been attached. -/// +/// void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { // If either decl is invalid, make sure the new one is marked invalid and // don't do any other checking. if (New->isInvalidDecl() || OldD->isInvalidDecl()) return New->setInvalidDecl(); - + // Verify the old decl was also a variable. VarDecl *Old = dyn_cast<VarDecl>(OldD); if (!Old) { @@ -952,11 +977,24 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { if (getLangOptions().CPlusPlus) { if (Context.hasSameType(New->getType(), Old->getType())) MergedT = New->getType(); + // C++ [basic.types]p7: + // [...] The declared type of an array object might be an array of + // unknown size and therefore be incomplete at one point in a + // translation unit and complete later on; [...] + else if (Old->getType()->isIncompleteArrayType() && + New->getType()->isArrayType()) { + CanQual<ArrayType> OldArray + = Context.getCanonicalType(Old->getType())->getAs<ArrayType>(); + CanQual<ArrayType> NewArray + = Context.getCanonicalType(New->getType())->getAs<ArrayType>(); + if (OldArray->getElementType() == NewArray->getElementType()) + MergedT = New->getType(); + } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); } if (MergedT.isNull()) { - Diag(New->getLocation(), diag::err_redefinition_different_type) + Diag(New->getLocation(), diag::err_redefinition_different_type) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -970,7 +1008,7 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } - // C99 6.2.2p4: + // C99 6.2.2p4: // For an identifier declared with the storage-class specifier // extern in a scope in which a prior declaration of that // identifier is visible,23) if the prior declaration specifies @@ -989,7 +1027,7 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { } // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. - + // FIXME: The test for external storage here seems wrong? We still // need to check for mismatches. if (!New->hasExternalStorage() && !New->isFileVarDecl() && @@ -1013,6 +1051,214 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { New->setPreviousDeclaration(Old); } +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// MaybeFallThrough iff we might or might not fall off the end and +/// NeverFallThrough iff we never fall off the end of the statement. We assume +/// that functions not marked noreturn will return. +Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { + llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context)); + + // FIXME: They should never return 0, fix that, delete this code. + if (cfg == 0) + return NeverFallThrough; + // The CFG leaves in dead things, and we don't want to dead code paths to + // confuse us, so we mark all live things first. + std::queue<CFGBlock*> workq; + llvm::BitVector live(cfg->getNumBlockIDs()); + // Prep work queue + workq.push(&cfg->getEntry()); + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + live.set(item->getBlockID()); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + workq.push(*I); + } + } + } + + // Now we know what is live, we check the live precessors of the exit block + // and look for fall through paths, being careful to ignore normal returns, + // and exceptional paths. + bool HasLiveReturn = false; + bool HasFakeEdge = false; + bool HasPlainEdge = false; + for (CFGBlock::succ_iterator I=cfg->getExit().pred_begin(), + E = cfg->getExit().pred_end(); + I != E; + ++I) { + CFGBlock& B = **I; + if (!live[B.getBlockID()]) + continue; + if (B.size() == 0) { + // A labeled empty statement, or the entry block... + HasPlainEdge = true; + continue; + } + Stmt *S = B[B.size()-1]; + if (isa<ReturnStmt>(S)) { + HasLiveReturn = true; + continue; + } + if (isa<ObjCAtThrowStmt>(S)) { + HasFakeEdge = true; + continue; + } + if (isa<CXXThrowExpr>(S)) { + HasFakeEdge = true; + continue; + } + bool NoReturnEdge = false; + if (CallExpr *C = dyn_cast<CallExpr>(S)) { + Expr *CEE = C->getCallee()->IgnoreParenCasts(); + if (CEE->getType().getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) { + if (FD->hasAttr<NoReturnAttr>()) { + NoReturnEdge = true; + HasFakeEdge = true; + } + } + } + } + // FIXME: Add noreturn message sends. + if (NoReturnEdge == false) + HasPlainEdge = true; + } + if (!HasPlainEdge) + return NeverFallThrough; + if (HasFakeEdge || HasLiveReturn) + return MaybeFallThrough; + // This says AlwaysFallThrough for calls to functions that are not marked + // noreturn, that don't return. If people would like this warning to be more + // accurate, such functions should be marked as noreturn. + return AlwaysFallThrough; +} + +/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a +/// function that should return a value. Check that we don't fall off the end +/// of a noreturn function. We assume that functions and blocks not marked +/// noreturn will return. +void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If the result type of the function is a dependent type, we don't know + // whether it will be void or not, so don't + if (FD->getResultType()->isDependentType()) + return; + if (FD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (MD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) + == Diagnostic::Ignored || ReturnsVoid) + && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) + == Diagnostic::Ignored || !HasNoReturn) + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Function try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(Body)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); + break; + case NeverFallThrough: + if (ReturnsVoid) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); + break; + } + } +} + +/// CheckFallThroughForBlock - Check that we don't fall off the end of a block +/// that should return a value. Check that we don't fall off the end of a +/// noreturn block. We assume that functions and blocks not marked noreturn +/// will return. +void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (const FunctionType *FT = BlockTy->getPointeeType()->getAs<FunctionType>()) { + if (FT->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FT->getNoReturnAttr()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if (ReturnsVoid + && !HasNoReturn + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Funtion try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(Body)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); + break; + case NeverFallThrough: + if (ReturnsVoid) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); + break; + } + } +} + /// 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 @@ -1034,10 +1280,10 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { Param->setInvalidDecl(); HasInvalidParm = true; } - + // C99 6.9.1p5: If the declarator includes a parameter type list, the // declaration of each parameter shall include an identifier. - if (Param->getIdentifier() == 0 && + if (Param->getIdentifier() == 0 && !Param->isImplicit() && !getLangOptions().CPlusPlus) Diag(Param->getLocation(), diag::err_parameter_name_omitted); @@ -1056,17 +1302,31 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { // FIXME: Warn on useless const/volatile // FIXME: Warn on useless static/extern/typedef/private_extern/mutable // FIXME: Warn on useless attributes + Decl *TagD = 0; TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { - if (!DS.getTypeRep()) // We probably had an error + TagD = static_cast<Decl *>(DS.getTypeRep()); + + if (!TagD) // We probably had an error return DeclPtrTy(); - Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep())); + // Note that the above type specs guarantee that the + // type rep is a Decl, whereas in many of the others + // it's a Type. + Tag = dyn_cast<TagDecl>(TagD); } + if (DS.isFriendSpecified()) { + // If we're dealing with a class template decl, assume that the + // template routines are handling it. + if (TagD && isa<ClassTemplateDecl>(TagD)) + return DeclPtrTy(); + return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); + } + if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { if (!Record->getDeclName() && Record->isDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { @@ -1084,8 +1344,8 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { if (Record->getDeclName() && getLangOptions().Microsoft) return DeclPtrTy::make(Tag); } - - if (!DS.isMissingDeclaratorOk() && + + if (!DS.isMissingDeclaratorOk() && DS.getTypeSpecType() != DeclSpec::TST_error) { // Warn about typedefs of enums without names, since this is an // extension in both Microsoft an GNU. @@ -1100,7 +1360,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { << DS.getSourceRange(); return DeclPtrTy(); } - + return DeclPtrTy::make(Tag); } @@ -1127,14 +1387,16 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - NamedDecl *PrevDecl = LookupQualifiedName(Owner, (*F)->getDeclName(), - LookupOrdinaryName, true); + LookupResult R; + LookupQualifiedName(R, Owner, (*F)->getDeclName(), + LookupOrdinaryName, true); + NamedDecl *PrevDecl = R.getAsSingleDecl(Context); if (PrevDecl && !isa<TagDecl>(PrevDecl)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be // distinct from the names of any other entity in the // scope in which the anonymous union is declared. - unsigned diagKind + unsigned diagKind = AnonRecord->isUnion()? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; Diag((*F)->getLocation(), diagKind) @@ -1152,10 +1414,10 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, IdResolver.AddDecl(*F); } } else if (const RecordType *InnerRecordType - = (*F)->getType()->getAsRecordType()) { + = (*F)->getType()->getAs<RecordType>()) { RecordDecl *InnerRecord = InnerRecordType->getDecl(); if (InnerRecord->isAnonymousStructOrUnion()) - Invalid = Invalid || + Invalid = Invalid || InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord); } } @@ -1166,7 +1428,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, /// ActOnAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a GNU C extension; anonymous structures -/// are a GNU C and GNU C++ extension. +/// are a GNU C and GNU C++ extension. Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, RecordDecl *Record) { DeclContext *Owner = Record->getDeclContext(); @@ -1176,40 +1438,42 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Diag(Record->getLocation(), diag::ext_anonymous_union); else if (!Record->isUnion()) Diag(Record->getLocation(), diag::ext_anonymous_struct); - + // C and C++ require different kinds of checks for anonymous // structs/unions. bool Invalid = false; if (getLangOptions().CPlusPlus) { const char* PrevSpec = 0; + unsigned DiagID; // C++ [class.union]p3: // Anonymous unions declared in a named namespace or in the // global namespace shall be declared static. if (DS.getStorageClassSpec() != DeclSpec::SCS_static && (isa<TranslationUnitDecl>(Owner) || - (isa<NamespaceDecl>(Owner) && + (isa<NamespaceDecl>(Owner) && cast<NamespaceDecl>(Owner)->getDeclName()))) { Diag(Record->getLocation(), diag::err_anonymous_union_not_static); Invalid = true; // Recover by adding 'static'. - DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), PrevSpec); - } + DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), + PrevSpec, DiagID); + } // C++ [class.union]p3: // A storage class is not allowed in a declaration of an // anonymous union in a class scope. else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && isa<RecordDecl>(Owner)) { - Diag(DS.getStorageClassSpecLoc(), + Diag(DS.getStorageClassSpecLoc(), diag::err_anonymous_union_with_storage_spec); Invalid = true; // Recover by removing the storage specifier. DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(), - PrevSpec); + PrevSpec, DiagID); } - // C++ [class.union]p2: + // C++ [class.union]p2: // The member-specification of an anonymous union shall only // define non-static data members. [Note: nested types and // functions cannot be declared within an anonymous union. ] @@ -1255,7 +1519,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; } } - } + } if (!Record->isUnion() && !Owner->isRecord()) { Diag(Record->getLocation(), diag::err_anonymous_struct_not_member) @@ -1263,12 +1527,14 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; } - // Create a declaration for this anonymous struct/union. + // Create a declaration for this anonymous struct/union. NamedDecl *Anon = 0; if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) { Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(), - /*IdentifierInfo=*/0, + /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), + // FIXME: Type source info. + /*DInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS_public); if (getLangOptions().CPlusPlus) @@ -1293,9 +1559,11 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, } Anon = VarDecl::Create(Context, Owner, Record->getLocation(), - /*IdentifierInfo=*/0, + /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - SC, DS.getSourceRange().getBegin()); + // FIXME: Type source info. + /*DInfo=*/0, + SC); } Anon->setImplicit(); @@ -1315,7 +1583,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // members of this anonymous struct/union type, because otherwise // the members could be injected twice: once by DeclContext when it // builds its lookup table, and once by - // InjectAnonymousStructOrUnionMembers. + // InjectAnonymousStructOrUnionMembers. Record->setAnonymousStructOrUnion(true); if (Invalid) @@ -1338,28 +1606,39 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) { return DeclarationName(D.getIdentifier()); case Declarator::DK_Constructor: { - QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); - Ty = Context.getCanonicalType(Ty); - return Context.DeclarationNames.getCXXConstructorName(Ty); + QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Ty)); } case Declarator::DK_Destructor: { - QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); - Ty = Context.getCanonicalType(Ty); - return Context.DeclarationNames.getCXXDestructorName(Ty); + QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); + return Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(Ty)); } case Declarator::DK_Conversion: { // FIXME: We'd like to keep the non-canonical type for diagnostics! - QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); - Ty = Context.getCanonicalType(Ty); - return Context.DeclarationNames.getCXXConversionFunctionName(Ty); + QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); + return Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(Ty)); } case Declarator::DK_Operator: assert(D.getIdentifier() == 0 && "operator names have no identifier"); return Context.DeclarationNames.getCXXOperatorName( D.getOverloadedOperator()); + + case Declarator::DK_TemplateId: { + TemplateName Name + = TemplateName::getFromVoidPointer(D.getTemplateId()->Template); + if (TemplateDecl *Template = Name.getAsTemplateDecl()) + return Template->getDeclName(); + if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) + return Ovl->getDeclName(); + + return DeclarationName(); + } } assert(false && "Unknown name kind"); @@ -1389,8 +1668,8 @@ static bool isNearlyMatchingFunction(ASTContext &Context, return true; } -Sema::DeclPtrTy -Sema::HandleDeclarator(Scope *S, Declarator &D, +Sema::DeclPtrTy +Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition) { DeclarationName Name = GetNameForDeclarator(D); @@ -1404,18 +1683,44 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, << D.getDeclSpec().getSourceRange() << D.getSourceRange(); return DeclPtrTy(); } - + // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. while ((S->getFlags() & Scope::DeclScope) == 0 || (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); - + + // If this is an out-of-line definition of a member of a class template + // or class template partial specialization, we may need to rebuild the + // type specifier in the declarator. See RebuildTypeInCurrentInstantiation() + // for more information. + // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can + // handle expressions properly. + DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec()); + if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() && + isDependentScopeSpecifier(D.getCXXScopeSpec()) && + (DS.getTypeSpecType() == DeclSpec::TST_typename || + DS.getTypeSpecType() == DeclSpec::TST_typeofType || + DS.getTypeSpecType() == DeclSpec::TST_typeofExpr || + DS.getTypeSpecType() == DeclSpec::TST_decltype)) { + if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) { + // FIXME: Preserve type source info. + QualType T = GetTypeFromParser(DS.getTypeRep()); + EnterDeclaratorContext(S, DC); + T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name); + ExitDeclaratorContext(S); + if (T.isNull()) + return DeclPtrTy(); + DS.UpdateTypeRep(T.getAsOpaquePtr()); + } + } + DeclContext *DC; NamedDecl *PrevDecl; NamedDecl *New; - QualType R = GetTypeForDeclarator(D, S); + DeclaratorInfo *DInfo = 0; + QualType R = GetTypeForDeclarator(D, S, &DInfo); // See if this is a redefinition of a variable in the same scope. if (D.getCXXScopeSpec().isInvalid()) { @@ -1431,20 +1736,43 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) /* Do nothing*/; else if (R->isFunctionType()) { - if (CurContext->isFunctionOrMethod()) + if (CurContext->isFunctionOrMethod() || + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) NameKind = LookupRedeclarationWithLinkage; } else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) NameKind = LookupRedeclarationWithLinkage; + else if (CurContext->getLookupContext()->isTranslationUnit() && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) + NameKind = LookupRedeclarationWithLinkage; DC = CurContext; - PrevDecl = LookupName(S, Name, NameKind, true, - D.getDeclSpec().getStorageClassSpec() != - DeclSpec::SCS_static, - D.getIdentifierLoc()); + LookupResult R; + LookupName(R, S, Name, NameKind, true, + NameKind == LookupRedeclarationWithLinkage, + D.getIdentifierLoc()); + PrevDecl = R.getAsSingleDecl(Context); } else { // Something like "int foo::x;" - DC = computeDeclContext(D.getCXXScopeSpec()); - // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ? - PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true); + DC = computeDeclContext(D.getCXXScopeSpec(), true); + + if (!DC) { + // If we could not compute the declaration context, it's because the + // declaration context is dependent but does not refer to a class, + // class template, or class template partial specialization. Complain + // and return early, to avoid the coming semantic disaster. + Diag(D.getIdentifierLoc(), + diag::err_template_qualified_declarator_no_match) + << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep() + << D.getCXXScopeSpec().getRange(); + return DeclPtrTy(); + } + + if (!DC->isDependentContext() && + RequireCompleteDeclContext(D.getCXXScopeSpec())) + return DeclPtrTy(); + + LookupResult Res; + LookupQualifiedName(Res, DC, Name, LookupOrdinaryName, true); + PrevDecl = Res.getAsSingleDecl(Context); // C++ 7.3.1.2p2: // Members (including explicit specializations of templates) of a named @@ -1467,11 +1795,11 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, // // In this case, PrevDecl will point to the overload set // containing the two f's declared in X, but neither of them - // matches. + // matches. // First check whether we named the global scope. if (isa<TranslationUnitDecl>(DC)) { - Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope) + Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope) << Name << D.getCXXScopeSpec().getRange(); } else if (!CurContext->Encloses(DC)) { // The qualifying scope doesn't enclose the original declaration. @@ -1480,7 +1808,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, SourceRange R = D.getCXXScopeSpec().getRange(); if (isa<FunctionDecl>(CurContext)) Diag(L, diag::err_invalid_declarator_in_function) << Name << R; - else + else Diag(L, diag::err_invalid_declarator_scope) << Name << cast<NamedDecl>(DC) << R; D.setInvalidType(); @@ -1489,10 +1817,10 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. - if (!D.isInvalidType()) + if (!D.isInvalidType()) if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl)) D.setInvalidType(); - + // Just pretend that we didn't see the previous declaration. PrevDecl = 0; } @@ -1511,24 +1839,28 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, Diag(D.getIdentifierLoc(), diag::err_template_typedef); return DeclPtrTy(); } - - New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration); + + New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, PrevDecl, Redeclaration); } else if (R->isFunctionType()) { - New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl, + New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, PrevDecl, move(TemplateParamLists), IsFunctionDefinition, Redeclaration); } else { - New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration); + New = ActOnVariableDeclarator(S, D, DC, R, DInfo, PrevDecl, + move(TemplateParamLists), + Redeclaration); } if (New == 0) return DeclPtrTy(); - - // If this has an identifier and is not an invalid redeclaration, - // add it to the scope stack. - if (Name && !(Redeclaration && New->isInvalidDecl())) + + // If this has an identifier and is not an invalid redeclaration or + // function template specialization, add it to the scope stack. + if (Name && !(Redeclaration && New->isInvalidDecl()) && + !(isa<FunctionDecl>(New) && + cast<FunctionDecl>(New)->isFunctionTemplateSpecialization())) PushOnScopeChains(New, S); - + return DeclPtrTy::make(New); } @@ -1544,14 +1876,16 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, // constant expression folding, like struct {char x[(int)(char*)2];} SizeIsNegative = false; - if (const PointerType* PTy = dyn_cast<PointerType>(T)) { + QualifierCollector Qs; + const Type *Ty = Qs.strip(T); + + if (const PointerType* PTy = dyn_cast<PointerType>(Ty)) { QualType Pointee = PTy->getPointeeType(); QualType FixedType = TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); - FixedType.setCVRQualifiers(T.getCVRQualifiers()); - return FixedType; + return Qs.apply(FixedType); } const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T); @@ -1560,7 +1894,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, // FIXME: We should probably handle this case if (VLATy->getElementType()->isVariablyModifiedType()) return QualType(); - + Expr::EvalResult EvalResult; if (!VLATy->getSizeExpr() || !VLATy->getSizeExpr()->Evaluate(EvalResult, Context) || @@ -1568,9 +1902,18 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, return QualType(); llvm::APSInt &Res = EvalResult.Val.getInt(); - if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) - return Context.getConstantArrayType(VLATy->getElementType(), - Res, ArrayType::Normal, 0); + if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) { + Expr* ArySizeExpr = VLATy->getSizeExpr(); + // FIXME: here we could "steal" (how?) ArySizeExpr from the VLA, + // so as to transfer ownership to the ConstantArrayWithExpr. + // Alternatively, we could "clone" it (how?). + // Since we don't know how to do things above, we just use the + // very same Expr*. + return Context.getConstantArrayWithExprType(VLATy->getElementType(), + Res, ArySizeExpr, + ArrayType::Normal, 0, + VLATy->getBracketsRange()); + } SizeIsNegative = true; return QualType(); @@ -1578,7 +1921,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, /// \brief Register the given locally-scoped external C declaration so /// that it can be found later for redeclarations -void +void Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl, Scope *S) { assert(ND->getLexicalDeclContext()->isFunctionOrMethod() && @@ -1609,21 +1952,22 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { // FIXME: We should probably indicate the identifier in question to avoid // confusion for constructs like "inline int a(), b;" if (D.getDeclSpec().isInlineSpecified()) - Diag(D.getDeclSpec().getInlineSpecLoc(), + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function); if (D.getDeclSpec().isVirtualSpecified()) - Diag(D.getDeclSpec().getVirtualSpecLoc(), + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_non_function); if (D.getDeclSpec().isExplicitSpecified()) - Diag(D.getDeclSpec().getExplicitSpecLoc(), + Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_non_function); } NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, Decl* PrevDecl, bool &Redeclaration) { + QualType R, DeclaratorInfo *DInfo, + NamedDecl* PrevDecl, bool &Redeclaration) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) @@ -1645,7 +1989,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypedefDecl *NewTD = ParseTypedefDecl(S, D, R); if (!NewTD) return 0; - + if (D.isInvalidType()) NewTD->setInvalidDecl(); @@ -1663,7 +2007,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType T = NewTD->getUnderlyingType(); if (T->isVariablyModifiedType()) { CurFunctionNeedsScopeChecking = true; - + if (S->getFnParent() == 0) { bool SizeIsNegative; QualType FixedTy = @@ -1682,6 +2026,19 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } } + + // If this is the C FILE type, notify the AST context. + if (IdentifierInfo *II = NewTD->getIdentifier()) + if (!NewTD->isInvalidDecl() && + NewTD->getDeclContext()->getLookupContext()->isTranslationUnit()) { + if (II->isStr("FILE")) + Context.setFILEDecl(NewTD); + else if (II->isStr("jmp_buf")) + Context.setjmp_bufDecl(NewTD); + else if (II->isStr("sigjmp_buf")) + Context.setsigjmp_bufDecl(NewTD); + } + return NewTD; } @@ -1697,13 +2054,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// /// \param PrevDecl the previous declaration found by name /// lookup -/// +/// /// \param DC the context in which the new declaration is being /// declared. /// /// \returns true if PrevDecl is an out-of-scope previous declaration /// for a new delcaration with the same name. -static bool +static bool isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, ASTContext &Context) { if (!PrevDecl) @@ -1737,10 +2094,10 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, OuterContext = OuterContext->getParent(); while (!PrevOuterContext->isFileContext()) PrevOuterContext = PrevOuterContext->getParent(); - + // The previous declaration is in a different namespace, so it // isn't the same function. - if (OuterContext->getPrimaryContext() != + if (OuterContext->getPrimaryContext() != PrevOuterContext->getPrimaryContext()) return false; } @@ -1752,7 +2109,9 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R,NamedDecl* PrevDecl, + QualType R, DeclaratorInfo *DInfo, + NamedDecl* PrevDecl, + MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration) { DeclarationName Name = GetNameForDeclarator(D); @@ -1792,7 +2151,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // C99 6.9p2: The storage-class specifiers auto and register shall not // appear in the declaration specifiers in an external declaration. if (SC == VarDecl::Auto || SC == VarDecl::Register) { - + // If this is a register variable with an asm label specified, then this // is a GNU extension. if (SC == VarDecl::Register && D.getAsmLabel()) @@ -1805,7 +2164,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (DC->isRecord() && !CurContext->isRecord()) { // This is an out-of-line definition of a static data member. if (SC == VarDecl::Static) { - Diag(D.getDeclSpec().getStorageClassSpecLoc(), + Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << CodeModificationHint::CreateRemoval( SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); @@ -1815,22 +2174,48 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (SC == VarDecl::Static) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { if (RD->isLocalClass()) - Diag(D.getIdentifierLoc(), + Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_local_class) << Name << RD->getDeclName(); } } - - - // The variable can not - NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, SC, - // FIXME: Move to DeclGroup... - D.getDeclSpec().getSourceRange().getBegin()); + + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. + bool isExplicitSpecialization = false; + if (TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getSourceRange().getBegin(), + D.getCXXScopeSpec(), + (TemplateParameterList**)TemplateParamLists.get(), + TemplateParamLists.size(), + isExplicitSpecialization)) { + if (TemplateParams->size() > 0) { + // There is no such thing as a variable template. + Diag(D.getIdentifierLoc(), diag::err_template_variable) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); + return 0; + } else { + // There is an extraneous 'template<>' for this variable. Complain + // about it, but allow the declaration of the variable. + Diag(TemplateParams->getTemplateLoc(), + diag::err_template_variable_noparams) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); + + isExplicitSpecialization = true; + } + } + + NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, DInfo, SC); if (D.isInvalidType()) NewVD->setInvalidDecl(); - + if (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); @@ -1850,7 +2235,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. - StringLiteral *SE = cast<StringLiteral>(E); + StringLiteral *SE = cast<StringLiteral>(E); NewVD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(), SE->getByteLength()))); } @@ -1861,8 +2246,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) && !(NewVD->hasLinkage() && isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) - PrevDecl = 0; - + PrevDecl = 0; + // Merge the decl with the existing one if appropriate. if (PrevDecl) { if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) { @@ -1875,16 +2260,31 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } else if (D.getCXXScopeSpec().isSet()) { // No previous declaration in the qualifying scope. - Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member) - << Name << D.getCXXScopeSpec().getRange(); + Diag(D.getIdentifierLoc(), diag::err_no_member) + << Name << computeDeclContext(D.getCXXScopeSpec(), true) + << D.getCXXScopeSpec().getRange(); NewVD->setInvalidDecl(); } CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration); + // This is an explicit specialization of a static data member. Check it. + if (isExplicitSpecialization && !NewVD->isInvalidDecl() && + CheckMemberSpecialization(NewVD, PrevDecl)) + NewVD->setInvalidDecl(); + + // attributes declared post-definition are currently ignored + if (PrevDecl) { + const VarDecl *Def = 0, *PrevVD = dyn_cast<VarDecl>(PrevDecl); + if (PrevVD->getDefinition(Def) && D.hasAttributes()) { + Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition); + Diag(Def->getLocation(), diag::note_previous_definition); + } + } + // If this is a locally-scoped extern C variable, update the map of // such variables. - if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) && + if (CurContext->isFunctionOrMethod() && NewVD->isExternC() && !NewVD->isInvalidDecl()) RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S); @@ -1906,17 +2306,17 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) return; - + QualType T = NewVD->getType(); if (T->isObjCInterfaceType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object); return NewVD->setInvalidDecl(); } - + // The variable can not have an abstract class type. if (RequireNonAbstractType(NewVD->getLocation(), T, - diag::err_abstract_type_in_decl, + diag::err_abstract_type_in_decl, AbstractVariableType)) return NewVD->setInvalidDecl(); @@ -1934,21 +2334,22 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); bool isVM = T->isVariablyModifiedType(); - if (isVM || NewVD->hasAttr<CleanupAttr>()) + if (isVM || NewVD->hasAttr<CleanupAttr>() || + NewVD->hasAttr<BlocksAttr>()) CurFunctionNeedsScopeChecking = true; - + if ((isVM && NewVD->hasLinkage()) || (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); - + if (FixedTy.isNull() && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); - // FIXME: This won't give the correct result for - // int a[10][n]; + // FIXME: This won't give the correct result for + // int a[10][n]; SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange(); - + if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope) << SizeRange; @@ -1959,8 +2360,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; return NewVD->setInvalidDecl(); - } - + } + if (FixedTy.isNull()) { if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); @@ -1968,12 +2369,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); return NewVD->setInvalidDecl(); } - + Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); NewVD->setType(FixedTy); } - if (!PrevDecl && NewVD->isExternC(Context)) { + if (!PrevDecl && NewVD->isExternC()) { // Since we did not find anything by this name and we're declaring // an extern "C" variable, look for a non-visible extern "C" // declaration with the same name. @@ -1993,7 +2394,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); return NewVD->setInvalidDecl(); } - + if (isVM && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); return NewVD->setInvalidDecl(); @@ -2005,9 +2406,43 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, } } -NamedDecl* +static bool isUsingDecl(Decl *D) { + return isa<UsingDecl>(D) || isa<UnresolvedUsingDecl>(D); +} + +/// \brief Data used with FindOverriddenMethod +struct FindOverriddenMethodData { + Sema *S; + CXXMethodDecl *Method; +}; + +/// \brief Member lookup function that determines whether a given C++ +/// method overrides a method in a base class, to be used with +/// CXXRecordDecl::lookupInBases(). +static bool FindOverriddenMethod(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *UserData) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + FindOverriddenMethodData *Data + = reinterpret_cast<FindOverriddenMethodData*>(UserData); + for (Path.Decls = BaseRecord->lookup(Data->Method->getDeclName()); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*Path.Decls.first)) { + OverloadedFunctionDecl::function_iterator MatchedDecl; + if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, MatchedDecl)) + return true; + } + } + + return false; +} + +NamedDecl* Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, NamedDecl* PrevDecl, + QualType R, DeclaratorInfo *DInfo, + NamedDecl* PrevDecl, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration) { assert(R.getTypePtr()->isFunctionType()); @@ -2019,7 +2454,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, case DeclSpec::SCS_auto: case DeclSpec::SCS_register: case DeclSpec::SCS_mutable: - Diag(D.getDeclSpec().getStorageClassSpecLoc(), + Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_typecheck_sclass_func); D.setInvalidType(); break; @@ -2032,11 +2467,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // block scope shall have no explicit storage-class specifier // other than extern // See also (C++ [dcl.stc]p4). - Diag(D.getDeclSpec().getStorageClassSpecLoc(), + Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_block_func); SC = FunctionDecl::None; } else - SC = FunctionDecl::Static; + SC = FunctionDecl::Static; break; } case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break; @@ -2045,35 +2480,43 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + bool isFriend = D.getDeclSpec().isFriendSpecified(); bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. + // the class has been completely parsed. if (!DC->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), - R->getAsFunctionType()->getResultType(), - diag::err_abstract_type_in_decl, + RequireNonAbstractType(D.getIdentifierLoc(), + R->getAs<FunctionType>()->getResultType(), + diag::err_abstract_type_in_decl, AbstractReturnType)) D.setInvalidType(); - + // Do not allow returning a objc interface by-value. - if (R->getAsFunctionType()->getResultType()->isObjCInterfaceType()) { + if (R->getAs<FunctionType>()->getResultType()->isObjCInterfaceType()) { Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_passed_returned_by_value) << 0 - << R->getAsFunctionType()->getResultType(); + << R->getAs<FunctionType>()->getResultType(); D.setInvalidType(); } - // Check that we can declare a template here. - if (TemplateParamLists.size() && - CheckTemplateDeclScope(S, TemplateParamLists)) - return 0; - bool isVirtualOkay = false; FunctionDecl *NewFD; + + if (isFriend) { + // DC is the namespace in which the function is being declared. + assert((DC->isFileContext() || PrevDecl) && "previously-undeclared " + "friend function being created in a non-namespace context"); + + // C++ [class.friend]p5 + // A function can be defined in a friend declaration of a + // class . . . . Such a function is implicitly inline. + isInline |= IsFunctionDefinition; + } + if (D.getKind() == Declarator::DK_Constructor) { // This is a C++ constructor declaration. assert(DC->isRecord() && @@ -2082,19 +2525,19 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, R = CheckConstructorDeclarator(D, R, SC); // Create the new declaration - NewFD = CXXConstructorDecl::Create(Context, + NewFD = CXXConstructorDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getIdentifierLoc(), Name, R, + D.getIdentifierLoc(), Name, R, DInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); } else if (D.getKind() == Declarator::DK_Destructor) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = CheckDestructorDeclarator(D, SC); - + NewFD = CXXDestructorDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getIdentifierLoc(), Name, R, + D.getIdentifierLoc(), Name, R, isInline, /*isImplicitlyDeclared=*/false); @@ -2105,10 +2548,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create a FunctionDecl to satisfy the function definition parsing // code path. NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, SC, isInline, - /*hasPrototype=*/true, - // FIXME: Move to DeclGroup... - D.getDeclSpec().getSourceRange().getBegin()); + Name, R, DInfo, SC, isInline, + /*hasPrototype=*/true); D.setInvalidType(); } } else if (D.getKind() == Declarator::DK_Conversion) { @@ -2117,29 +2558,29 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, diag::err_conv_function_not_member); return 0; } - + CheckConversionDeclarator(D, R, SC); NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getIdentifierLoc(), Name, R, + D.getIdentifierLoc(), Name, R, DInfo, isInline, isExplicit); - + isVirtualOkay = true; } else if (DC->isRecord()) { // If the of the function is the same as the name of the record, then this - // must be an invalid constructor that has a return type. - // (The parser checks for a return type and makes the declarator a + // must be an invalid constructor that has a return type. + // (The parser checks for a return type and makes the declarator a // constructor if it has no return type). - // must have an invalid constructor that has a return type + // must have an invalid constructor that has a return type if (Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); return 0; } - + // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getIdentifierLoc(), Name, R, + D.getIdentifierLoc(), Name, R, DInfo, (SC == FunctionDecl::Static), isInline); isVirtualOkay = (SC != FunctionDecl::Static); @@ -2150,44 +2591,56 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // - there is a prototype in the declarator, or // - the type R of the function is some kind of typedef or other reference // to a type name (which eventually refers to a function type). - bool HasPrototype = + bool HasPrototype = getLangOptions().CPlusPlus || (D.getNumTypeObjects() && D.getTypeObject(0).Fun.hasPrototype) || (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); - + NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, SC, isInline, HasPrototype, - // FIXME: Move to DeclGroup... - D.getDeclSpec().getSourceRange().getBegin()); + Name, R, DInfo, SC, isInline, HasPrototype); } if (D.isInvalidType()) NewFD->setInvalidDecl(); - + // Set the lexical context. If the declarator has a C++ - // scope specifier, the lexical context will be different - // from the semantic context. + // scope specifier, or is the object of a friend declaration, the + // lexical context will be different from the semantic context. NewFD->setLexicalDeclContext(CurContext); - // If there is a template parameter list, then we are dealing with a - // template declaration or specialization. + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. FunctionTemplateDecl *FunctionTemplate = 0; - if (TemplateParamLists.size()) { - // FIXME: member templates! - TemplateParameterList *TemplateParams - = static_cast<TemplateParameterList *>(*TemplateParamLists.release()); - + bool isExplicitSpecialization = false; + bool isFunctionTemplateSpecialization = false; + if (TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getSourceRange().getBegin(), + D.getCXXScopeSpec(), + (TemplateParameterList**)TemplateParamLists.get(), + TemplateParamLists.size(), + isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // This is a function template - FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext, + + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + return 0; + + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), Name, TemplateParams, NewFD); + FunctionTemplate->setLexicalDeclContext(CurContext); NewFD->setDescribedFunctionTemplate(FunctionTemplate); } else { - // FIXME: Handle function template specializations + // This is a function template specialization. + isFunctionTemplateSpecialization = true; } + + // FIXME: Free this memory properly. + TemplateParamLists.release(); } // C++ [dcl.fct.spec]p5: @@ -2197,7 +2650,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // if (isVirtual && !NewFD->isInvalidDecl()) { if (!isVirtualOkay) { - Diag(D.getDeclSpec().getVirtualSpecLoc(), + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_non_function); } else if (!CurContext->isRecord()) { // 'virtual' was specified outside of the class. @@ -2210,28 +2663,47 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC); CurClass->setAggregate(false); CurClass->setPOD(false); + CurClass->setEmpty(false); CurClass->setPolymorphic(true); CurClass->setHasTrivialConstructor(false); + CurClass->setHasTrivialCopyConstructor(false); + CurClass->setHasTrivialCopyAssignment(false); + } + } + + if (isFriend) { + if (FunctionTemplate) { + FunctionTemplate->setObjectOfFriendDecl( + /* PreviouslyDeclared= */ PrevDecl != NULL); + FunctionTemplate->setAccess(AS_public); } + else + NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL); + + NewFD->setAccess(AS_public); } + if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) { // Look for virtual methods in base classes that this method might override. - - BasePaths Paths; - if (LookupInBases(cast<CXXRecordDecl>(DC), - MemberLookupCriteria(NewMD), Paths)) { - for (BasePaths::decl_iterator I = Paths.found_decls_begin(), + CXXBasePaths Paths; + FindOverriddenMethodData Data; + Data.Method = NewMD; + Data.S = this; + if (cast<CXXRecordDecl>(DC)->lookupInBases(&FindOverriddenMethod, &Data, + Paths)) { + for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), E = Paths.found_decls_end(); I != E; ++I) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { - if (!CheckOverridingFunctionReturnType(NewMD, OldMD)) + if (!CheckOverridingFunctionReturnType(NewMD, OldMD) && + !CheckOverridingFunctionExceptionSpec(NewMD, OldMD)) NewMD->addOverriddenMethod(OldMD); } } } } - - if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) && + + if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) && !CurContext->isRecord()) { // C++ [class.static]p1: // A data or function member of a class may be declared static @@ -2240,7 +2712,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Complain about the 'static' specifier if it's on an out-of-line // member function definition. - Diag(D.getDeclSpec().getStorageClassSpecLoc(), + Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << CodeModificationHint::CreateRemoval( SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); @@ -2249,7 +2721,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. - StringLiteral *SE = cast<StringLiteral>(E); + StringLiteral *SE = cast<StringLiteral>(E); NewFD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(), SE->getByteLength()))); } @@ -2278,11 +2750,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(Param->getLocation(), diag::err_param_typedef_of_void); // FIXME: Leaks decl? } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) - Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>()); + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); + assert(Param->getDeclContext() != NewFD && "Was set before ?"); + Param->setDeclContext(NewFD); + Params.push_back(Param); + } } - - } else if (const FunctionProtoType *FT = R->getAsFunctionProtoType()) { + + } else if (const FunctionProtoType *FT = R->getAs<FunctionProtoType>()) { // When we're declaring a function with a typedef, typeof, etc as in the // following example, we'll need to synthesize (unnamed) // parameters for use in the declaration. @@ -2291,13 +2767,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // typedef void fn(int); // fn f; // @endcode - + // Synthesize a parameter for each argument type. for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), AE = FT->arg_type_end(); AI != AE; ++AI) { ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, SourceLocation(), 0, - *AI, VarDecl::None, 0); + *AI, /*DInfo=*/0, + VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); } @@ -2307,7 +2784,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Context, Params.data(), Params.size()); - + // If name lookup finds a previous declaration that is not in the // same scope as the new declaration, this may still be an // acceptable redeclaration. @@ -2316,27 +2793,80 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) PrevDecl = 0; + // If the declarator is a template-id, translate the parser's template + // argument list into our AST format. + bool HasExplicitTemplateArgs = false; + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + SourceLocation LAngleLoc, RAngleLoc; + if (D.getKind() == Declarator::DK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getTemplateId(); + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateArgs); + TemplateArgsPtr.release(); + + HasExplicitTemplateArgs = true; + LAngleLoc = TemplateId->LAngleLoc; + RAngleLoc = TemplateId->RAngleLoc; + + if (FunctionTemplate) { + // FIXME: Diagnose function template with explicit template + // arguments. + HasExplicitTemplateArgs = false; + } else if (!isFunctionTemplateSpecialization && + !D.getDeclSpec().isFriendSpecified()) { + // We have encountered something that the user meant to be a + // specialization (because it has explicitly-specified template + // arguments) but that was not introduced with a "template<>" (or had + // too few of them). + Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) + << CodeModificationHint::CreateInsertion( + D.getDeclSpec().getSourceRange().getBegin(), + "template<> "); + isFunctionTemplateSpecialization = true; + } + } + + if (isFunctionTemplateSpecialization) { + if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs, + LAngleLoc, TemplateArgs.data(), + TemplateArgs.size(), RAngleLoc, + PrevDecl)) + NewFD->setInvalidDecl(); + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) && + CheckMemberSpecialization(NewFD, PrevDecl)) + NewFD->setInvalidDecl(); + // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); + CheckFunctionDeclaration(NewFD, PrevDecl, isExplicitSpecialization, + Redeclaration, /*FIXME:*/OverloadableAttrRequired); if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). - if (!IsFunctionDefinition) { + // Note that this is not the case for explicit specializations of + // function templates or member functions of class templates, per + // C++ [temp.expl.spec]p2. + if (!IsFunctionDefinition && !isFriend && + !isFunctionTemplateSpecialization && !isExplicitSpecialization) { Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); - } else if (!Redeclaration && (!PrevDecl || !isa<UsingDecl>(PrevDecl))) { + } else if (!Redeclaration && (!PrevDecl || !isUsingDecl(PrevDecl))) { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there - // was no such member function declared (C++ [class.mfct]p2, + // was no such member function declared (C++ [class.mfct]p2, // C++ [namespace.memdef]p2). For example: - // + // // class X { // void f() const; - // }; + // }; // // void X::f() { } // ill-formed // @@ -2344,12 +2874,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // matches (e.g., those that differ only in cv-qualifiers and // whether the parameter types are references). Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) - << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange(); + << Name << DC << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); - - LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName, - true); - assert(!Prev.isAmbiguous() && + + LookupResult Prev; + LookupQualifiedName(Prev, DC, Name, LookupOrdinaryName, true); + assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); Func != FuncEnd; ++Func) { @@ -2357,7 +2887,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD)) Diag((*Func)->getLocation(), diag::note_member_def_close_match); } - + PrevDecl = 0; } } @@ -2367,6 +2897,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // FIXME: This needs to happen before we merge declarations. Then, // let attribute merging cope with attribute conflicts. ProcessDeclAttributes(S, NewFD, D); + + // attributes declared post-definition are currently ignored + if (Redeclaration && PrevDecl) { + const FunctionDecl *Def, *PrevFD = dyn_cast<FunctionDecl>(PrevDecl); + if (PrevFD && PrevFD->getBody(Def) && D.hasAttributes()) { + Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition); + Diag(Def->getLocation(), diag::note_previous_definition); + } + } + AddKnownFunctionAttributes(NewFD); if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) { @@ -2375,14 +2915,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) << Redeclaration << NewFD; if (PrevDecl) - Diag(PrevDecl->getLocation(), + Diag(PrevDecl->getLocation(), diag::note_attribute_overloadable_prev_overload); NewFD->addAttr(::new (Context) OverloadableAttr()); } // If this is a locally-scoped extern C function, update the // map of such names. - if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context) + if (CurContext->isFunctionOrMethod() && NewFD->isExternC() && !NewFD->isInvalidDecl()) RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S); @@ -2391,10 +2931,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate && NewFD->isInvalidDecl()) FunctionTemplate->setInvalidDecl(); - + if (FunctionTemplate) return FunctionTemplate; - + return NewFD; } @@ -2408,8 +2948,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// that have been instantiated via C++ template instantiation (called /// via InstantiateDecl). /// +/// \param IsExplicitSpecialiation whether this new function declaration is +/// an explicit specialization of the previous declaration. +/// /// This sets NewFD->isInvalidDecl() to true if there was an error. void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, + bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired) { // If NewFD is already known erroneous, don't do any of this checking. @@ -2423,51 +2967,11 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, return NewFD->setInvalidDecl(); } - // Semantic checking for this function declaration (in isolation). - if (getLangOptions().CPlusPlus) { - // C++-specific checks. - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { - CheckConstructor(Constructor); - } else if (isa<CXXDestructorDecl>(NewFD)) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent()); - Record->setUserDeclaredDestructor(true); - // C++ [class]p4: A POD-struct is an aggregate class that has [...] no - // user-defined destructor. - Record->setPOD(false); - - // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly- - // declared destructor. - Record->setHasTrivialDestructor(false); - } else if (CXXConversionDecl *Conversion - = dyn_cast<CXXConversionDecl>(NewFD)) - ActOnConversionDeclarator(Conversion); - - // Extra checking for C++ overloaded operators (C++ [over.oper]). - if (NewFD->isOverloadedOperator() && - CheckOverloadedOperatorDeclaration(NewFD)) - return NewFD->setInvalidDecl(); - } - - // C99 6.7.4p6: - // [... ] For a function with external linkage, the following - // restrictions apply: [...] If all of the file scope declarations - // for a function in a translation unit include the inline - // function specifier without extern, then the definition in that - // translation unit is an inline definition. An inline definition - // does not provide an external definition for the function, and - // does not forbid an external definition in another translation - // unit. - // - // Here we determine whether this function, in isolation, would be a - // C99 inline definition. MergeCompatibleFunctionDecls looks at - // previous declarations. - if (NewFD->isInline() && getLangOptions().C99 && - NewFD->getStorageClass() == FunctionDecl::None && - NewFD->getDeclContext()->getLookupContext()->isTranslationUnit()) - NewFD->setC99InlineDefinition(true); + if (NewFD->isMain()) + CheckMain(NewFD); // Check for a previous declaration of this name. - if (!PrevDecl && NewFD->isExternC(Context)) { + if (!PrevDecl && NewFD->isExternC()) { // Since we did not find anything by this name and we're declaring // an extern "C" function, look for a non-visible extern "C" // declaration with the same name. @@ -2492,24 +2996,23 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, // Functions marked "overloadable" must have a prototype (that // we can't get through declaration merging). - if (!NewFD->getType()->getAsFunctionProtoType()) { + if (!NewFD->getType()->getAs<FunctionProtoType>()) { Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) << NewFD; Redeclaration = true; // Turn this into a variadic function with no parameters. QualType R = Context.getFunctionType( - NewFD->getType()->getAsFunctionType()->getResultType(), + NewFD->getType()->getAs<FunctionType>()->getResultType(), 0, 0, true, 0); NewFD->setType(R); return NewFD->setInvalidDecl(); } } - if (PrevDecl && - (!AllowOverloadingOfFunction(PrevDecl, Context) || - !IsOverload(NewFD, PrevDecl, MatchedDecl)) && - !isa<UsingDecl>(PrevDecl)) { + if (PrevDecl && + (!AllowOverloadingOfFunction(PrevDecl, Context) || + !IsOverload(NewFD, PrevDecl, MatchedDecl)) && !isUsingDecl(PrevDecl)) { Redeclaration = true; Decl *OldDecl = PrevDecl; @@ -2519,23 +3022,160 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, OldDecl = *MatchedDecl; // NewFD and OldDecl represent declarations that need to be - // merged. + // merged. if (MergeFunctionDecl(NewFD, OldDecl)) return NewFD->setInvalidDecl(); if (FunctionTemplateDecl *OldTemplateDecl - = dyn_cast<FunctionTemplateDecl>(OldDecl)) - NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); - else + = dyn_cast<FunctionTemplateDecl>(OldDecl)) { + NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); + FunctionTemplateDecl *NewTemplateDecl + = NewFD->getDescribedFunctionTemplate(); + assert(NewTemplateDecl && "Template/non-template mismatch"); + if (CXXMethodDecl *Method + = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) { + Method->setAccess(OldTemplateDecl->getAccess()); + NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); + } + + // If this is an explicit specialization of a member that is a function + // template, mark it as a member specialization. + if (IsExplicitSpecialization && + NewTemplateDecl->getInstantiatedFromMemberTemplate()) { + NewTemplateDecl->setMemberSpecialization(); + assert(OldTemplateDecl->isMemberSpecialization()); + } + } else { + if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions + NewFD->setAccess(OldDecl->getAccess()); NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); + } } } - // In C++, check default arguments now that we have merged decls. Unless - // the lexical context is the class, because in this case this is done - // during delayed parsing anyway. - if (getLangOptions().CPlusPlus && !CurContext->isRecord()) - CheckCXXDefaultArguments(NewFD); + // Semantic checking for this function declaration (in isolation). + if (getLangOptions().CPlusPlus) { + // C++-specific checks. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { + CheckConstructor(Constructor); + } else if (isa<CXXDestructorDecl>(NewFD)) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent()); + QualType ClassType = Context.getTypeDeclType(Record); + if (!ClassType->isDependentType()) { + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(ClassType)); + if (NewFD->getDeclName() != Name) { + Diag(NewFD->getLocation(), diag::err_destructor_name); + return NewFD->setInvalidDecl(); + } + } + Record->setUserDeclaredDestructor(true); + // C++ [class]p4: A POD-struct is an aggregate class that has [...] no + // user-defined destructor. + Record->setPOD(false); + + // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly- + // declared destructor. + // FIXME: C++0x: don't do this for "= default" destructors + Record->setHasTrivialDestructor(false); + } else if (CXXConversionDecl *Conversion + = dyn_cast<CXXConversionDecl>(NewFD)) + ActOnConversionDeclarator(Conversion); + + // Extra checking for C++ overloaded operators (C++ [over.oper]). + if (NewFD->isOverloadedOperator() && + CheckOverloadedOperatorDeclaration(NewFD)) + return NewFD->setInvalidDecl(); + + // In C++, check default arguments now that we have merged decls. Unless + // the lexical context is the class, because in this case this is done + // during delayed parsing anyway. + if (!CurContext->isRecord()) + CheckCXXDefaultArguments(NewFD); + } +} + +void Sema::CheckMain(FunctionDecl* FD) { + // C++ [basic.start.main]p3: A program that declares main to be inline + // or static is ill-formed. + // C99 6.7.4p4: In a hosted environment, the inline function specifier + // shall not appear in a declaration of main. + // static main is not an error under C99, but we should warn about it. + bool isInline = FD->isInline(); + bool isStatic = FD->getStorageClass() == FunctionDecl::Static; + if (isInline || isStatic) { + unsigned diagID = diag::warn_unusual_main_decl; + if (isInline || getLangOptions().CPlusPlus) + diagID = diag::err_unusual_main_decl; + + int which = isStatic + (isInline << 1) - 1; + Diag(FD->getLocation(), diagID) << which; + } + + QualType T = FD->getType(); + assert(T->isFunctionType() && "function decl is not of function type"); + const FunctionType* FT = T->getAs<FunctionType>(); + + if (!Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) { + // TODO: add a replacement fixit to turn the return type into 'int'. + Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint); + FD->setInvalidDecl(true); + } + + // Treat protoless main() as nullary. + if (isa<FunctionNoProtoType>(FT)) return; + + const FunctionProtoType* FTP = cast<const FunctionProtoType>(FT); + unsigned nparams = FTP->getNumArgs(); + assert(FD->getNumParams() == nparams); + + if (nparams > 3) { + Diag(FD->getLocation(), diag::err_main_surplus_args) << nparams; + FD->setInvalidDecl(true); + nparams = 3; + } + + // FIXME: a lot of the following diagnostics would be improved + // if we had some location information about types. + + QualType CharPP = + Context.getPointerType(Context.getPointerType(Context.CharTy)); + QualType Expected[] = { Context.IntTy, CharPP, CharPP }; + + for (unsigned i = 0; i < nparams; ++i) { + QualType AT = FTP->getArgType(i); + + bool mismatch = true; + + if (Context.hasSameUnqualifiedType(AT, Expected[i])) + mismatch = false; + else if (Expected[i] == CharPP) { + // As an extension, the following forms are okay: + // char const ** + // char const * const * + // char * const * + + QualifierCollector qs; + const PointerType* PT; + if ((PT = qs.strip(AT)->getAs<PointerType>()) && + (PT = qs.strip(PT->getPointeeType())->getAs<PointerType>()) && + (QualType(qs.strip(PT->getPointeeType()), 0) == Context.CharTy)) { + qs.removeConst(); + mismatch = !qs.empty(); + } + } + + if (mismatch) { + Diag(FD->getLocation(), diag::err_main_arg_wrong) << i << Expected[i]; + // TODO: suggest replacing given type with expected type + FD->setInvalidDecl(true); + } + } + + if (nparams == 1 && !FD->isInvalidDecl()) { + Diag(FD->getLocation(), diag::warn_main_one_arg); + } } bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { @@ -2554,8 +3194,8 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { return true; } -void Sema::AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init) { - AddInitializerToDecl(dcl, init.release(), /*DirectInit=*/false); +void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init) { + AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false); } /// AddInitializerToDecl - Adds the initializer Init to the @@ -2567,7 +3207,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { // the initializer. if (RealDecl == 0) return; - + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { // With declarators parsed the way they are, the parser cannot // distinguish between a normal initializer and a pure-specifier. @@ -2616,7 +3256,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { const VarDecl *Def = 0; if (VDecl->getDefinition(Def)) { - Diag(VDecl->getLocation(), diag::err_redefinition) + Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); Diag(Def->getLocation(), diag::note_previous_definition); VDecl->setInvalidDecl(); @@ -2639,7 +3279,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), VDecl->getDeclName(), DirectInit)) VDecl->setInvalidDecl(); - + // C++ 3.6.2p2, allow dynamic initialization of static initializers. // Don't check invalid declarations to avoid emitting useless diagnostics. if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) { @@ -2647,7 +3287,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { CheckForConstantInitializer(Init, DclT); } } - } else if (VDecl->isStaticDataMember() && + } else if (VDecl->isStaticDataMember() && VDecl->getLexicalDeclContext()->isRecord()) { // This is an in-class initialization for a static data member, e.g., // @@ -2663,7 +3303,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { // if it declares a static member (9.4) of const integral or // const enumeration type, see 9.4.2. QualType T = VDecl->getType(); - if (!T->isDependentType() && + if (!T->isDependentType() && (!Context.getCanonicalType(T).isConstQualified() || !T->isIntegralType())) { Diag(VDecl->getLocation(), diag::err_member_initialization) @@ -2678,7 +3318,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { if (!Init->isTypeDependent() && !Init->getType()->isIntegralType()) { // We have a non-dependent, non-integral or enumeration type. - Diag(Init->getSourceRange().getBegin(), + Diag(Init->getSourceRange().getBegin(), diag::err_in_class_initializer_non_integral_type) << Init->getType() << Init->getSourceRange(); VDecl->setInvalidDecl(); @@ -2701,7 +3341,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), VDecl->getDeclName(), DirectInit)) VDecl->setInvalidDecl(); - + // C++ 3.6.2p2, allow dynamic initialization of static initializers. // Don't check invalid declarations to avoid emitting useless diagnostics. if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) { @@ -2710,14 +3350,16 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { } } // If the type changed, it means we had an incomplete type that was - // completed by the initializer. For example: + // completed by the initializer. For example: // int ary[] = { 1, 3, 5 }; // "ary" transitions from a VariableArrayType to a ConstantArrayType. if (!VDecl->isInvalidDecl() && (DclT != SavT)) { VDecl->setType(DclT); Init->setType(DclT); } - + + Init = MaybeCreateCXXExprWithTemporaries(Init, + /*ShouldDestroyTemporaries=*/true); // Attach the initializer to the decl. VDecl->setInit(Context, Init); @@ -2725,17 +3367,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { // remove it from the set of tentative definitions. if (VDecl->getPreviousDeclaration() && VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) { - llvm::DenseMap<DeclarationName, VarDecl *>::iterator Pos - = TentativeDefinitions.find(VDecl->getDeclName()); - assert(Pos != TentativeDefinitions.end() && - "Unrecorded tentative definition?"); - TentativeDefinitions.erase(Pos); + bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName()); + assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted; } return; } -void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) { +void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, + bool TypeContainsUndeducedAuto) { Decl *RealDecl = dcl.getAs<Decl>(); // If there is no declaration, there was an error parsing it. Just ignore it. @@ -2746,8 +3386,20 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) { QualType Type = Var->getType(); // Record tentative definitions. - if (Var->isTentativeDefinition(Context)) - TentativeDefinitions[Var->getDeclName()] = Var; + if (Var->isTentativeDefinition(Context)) { + std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool> + InsertPair = + TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var)); + + // Keep the latest definition in the map. If we see 'int i; int i;' we + // want the second one in the map. + InsertPair.first->second = Var; + + // However, for the list, we don't care about the order, just make sure + // that there are no dupes for a given declaration name. + if (InsertPair.second) + TentativeDefinitionList.push_back(Var->getDeclName()); + } // C++ [dcl.init.ref]p3: // The initializer can be omitted for a reference only in a @@ -2763,46 +3415,72 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) { return; } + // C++0x [dcl.spec.auto]p3 + if (TypeContainsUndeducedAuto) { + Diag(Var->getLocation(), diag::err_auto_var_requires_init) + << Var->getDeclName() << Type; + Var->setInvalidDecl(); + return; + } + + // C++ [temp.expl.spec]p15: + // An explicit specialization of a static data member of a template is a + // definition if the declaration includes an initializer; otherwise, it + // is a declaration. + if (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember() && + Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + // C++ [dcl.init]p9: - // // If no initializer is specified for an object, and the object // is of (possibly cv-qualified) non-POD class type (or array // thereof), the object shall be default-initialized; if the // object is of const-qualified type, the underlying class type // shall have a user-declared default constructor. + // + // FIXME: Diagnose the "user-declared default constructor" bit. if (getLangOptions().CPlusPlus) { QualType InitType = Type; if (const ArrayType *Array = Context.getAsArrayType(Type)) InitType = Array->getElementType(); - if ((!Var->hasExternalStorage() && !Var->isExternC(Context)) && + if ((!Var->hasExternalStorage() && !Var->isExternC()) && InitType->isRecordType() && !InitType->isDependentType()) { - CXXRecordDecl *RD = - cast<CXXRecordDecl>(InitType->getAsRecordType()->getDecl()); - CXXConstructorDecl *Constructor = 0; - if (!RequireCompleteType(Var->getLocation(), InitType, - diag::err_invalid_incomplete_type_use)) - Constructor - = PerformInitializationByConstructor(InitType, 0, 0, + if (!RequireCompleteType(Var->getLocation(), InitType, + diag::err_invalid_incomplete_type_use)) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(InitType, + MultiExprArg(*this, 0, 0), Var->getLocation(), SourceRange(Var->getLocation(), Var->getLocation()), Var->getDeclName(), - IK_Default); - if (!Constructor) + IK_Default, + ConstructorArgs); + + // FIXME: Location info for the variable initialization? + if (!Constructor) + Var->setInvalidDecl(); + else { + // FIXME: Cope with initialization of arrays + if (!Constructor->isTrivial() && + InitializeVarWithConstructor(Var, Constructor, InitType, + move_arg(ConstructorArgs))) + Var->setInvalidDecl(); + + FinalizeVarWithDestructor(Var, InitType); + } + } else { Var->setInvalidDecl(); - else { - if (!RD->hasTrivialConstructor()) - InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0); - // FIXME. Must do all that is needed to destroy the object - // on scope exit. For now, just mark the destructor as used. - MarkDestructorReferenced(Var->getLocation(), InitType); } } } #if 0 // FIXME: Temporarily disabled because we are not properly parsing - // linkage specifications on declarations, e.g., + // linkage specifications on declarations, e.g., // // extern "C" const CGPoint CGPointerZero; // @@ -2844,7 +3522,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, for (unsigned i = 0; i != NumDecls; ++i) if (Decl *D = Group[i].getAs<Decl>()) Decls.push_back(D); - + // Perform semantic analysis that depends on having fully processed both // the declarator and initializer. for (unsigned i = 0, e = Decls.size(); i != e; ++i) { @@ -2852,38 +3530,40 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (!IDecl) continue; QualType T = IDecl->getType(); - + // Block scope. C99 6.7p7: If an identifier for an object is declared with // no linkage (C99 6.2.2p6), the type for the object shall be complete... if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) { if (!IDecl->isInvalidDecl() && - RequireCompleteType(IDecl->getLocation(), T, + RequireCompleteType(IDecl->getLocation(), T, diag::err_typecheck_decl_incomplete_type)) IDecl->setInvalidDecl(); } - // File scope. C99 6.9.2p2: A declaration of an identifier for and + // File scope. C99 6.9.2p2: A declaration of an identifier for an // object that has file scope without an initializer, and without a // storage-class specifier or with the storage-class specifier "static", // constitutes a tentative definition. Note: A tentative definition with // external linkage is valid (C99 6.2.2p5). - if (IDecl->isTentativeDefinition(Context)) { - QualType CheckType = T; - unsigned DiagID = diag::err_typecheck_decl_incomplete_type; - - const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(T); - if (ArrayT) { - CheckType = ArrayT->getElementType(); - DiagID = diag::err_illegal_decl_array_incomplete_type; - } - - if (IDecl->isInvalidDecl()) { - // Do nothing with invalid declarations - } else if ((ArrayT || IDecl->getStorageClass() == VarDecl::Static) && - RequireCompleteType(IDecl->getLocation(), CheckType, DiagID)) { + if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) { + if (const IncompleteArrayType *ArrayT + = Context.getAsIncompleteArrayType(T)) { + if (RequireCompleteType(IDecl->getLocation(), + ArrayT->getElementType(), + diag::err_illegal_decl_array_incomplete_type)) + IDecl->setInvalidDecl(); + } else if (IDecl->getStorageClass() == VarDecl::Static) { // C99 6.9.2p3: If the declaration of an identifier for an object is - // a tentative definition and has internal linkage (C99 6.2.2p3), the + // a tentative definition and has internal linkage (C99 6.2.2p3), the // declared type shall not be an incomplete type. - IDecl->setInvalidDecl(); + // NOTE: code such as the following + // static struct s; + // struct s { int a; }; + // is accepted by gcc. Hence here we issue a warning instead of + // an error and we do not invalidate the static declaration. + // NOTE: to avoid multiple warnings, only check the first declaration. + if (IDecl->getPreviousDeclaration() == 0) + RequireCompleteType(IDecl->getLocation(), T, + diag::ext_typecheck_decl_incomplete_type); } } } @@ -2894,7 +3574,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, /// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() /// to introduce parameters into function prototype scope. -Sema::DeclPtrTy +Sema::DeclPtrTy Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); @@ -2917,10 +3597,12 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // parameter (C++ only). if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); - + + DeclaratorInfo *DInfo = 0; TagDecl *OwnedDecl = 0; - QualType parmDeclType = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedDecl); - + QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, + &OwnedDecl); + if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. @@ -2933,7 +3615,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // among each other. Here they can only shadow globals, which is ok. IdentifierInfo *II = D.getIdentifier(); if (II) { - if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) { + if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { if (PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -2951,26 +3633,26 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Parameters can not be abstract class types. // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!CurContext->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, + // the class has been completely parsed. + if (!CurContext->isRecord() && + RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, diag::err_abstract_type_in_decl, AbstractParamType)) D.setInvalidType(true); QualType T = adjustParameterType(parmDeclType); - + ParmVarDecl *New; if (T == parmDeclType) // parameter type did not need adjustment - New = ParmVarDecl::Create(Context, CurContext, + New = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, - parmDeclType, StorageClass, + parmDeclType, DInfo, StorageClass, 0); else // keep track of both the adjusted and unadjusted types - New = OriginalParmVarDecl::Create(Context, CurContext, - D.getIdentifierLoc(), II, T, + New = OriginalParmVarDecl::Create(Context, CurContext, + D.getIdentifierLoc(), II, T, DInfo, parmDeclType, StorageClass, 0); - + if (D.isInvalidType()) New->setInvalidDecl(); @@ -2981,14 +3663,25 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; New->setInvalidDecl(); } - + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) << D.getCXXScopeSpec().getRange(); New->setInvalidDecl(); } - + + // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage + // duration shall not be qualified by an address-space qualifier." + // Since all parameters have automatic store duration, they can not have + // an address space. + if (T.getAddressSpace() != 0) { + Diag(D.getIdentifierLoc(), + diag::err_arg_with_address_space); + New->setInvalidDecl(); + } + + // Add the parameter declaration into this scope. S->AddDecl(DeclPtrTy::make(New)); if (II) @@ -3025,14 +3718,15 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, // type. DeclSpec DS; const char* PrevSpec; // unused - DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, - PrevSpec); + unsigned DiagID; // unused + DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, + PrevSpec, DiagID); Declarator ParamD(DS, Declarator::KNRTypeListContext); ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc); FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD); } } - } + } } Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, @@ -3043,12 +3737,12 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; if (FTI.hasPrototype) { - // FIXME: Diagnose arguments without names in C. + // FIXME: Diagnose arguments without names in C. } - + Scope *ParentScope = FnBodyScope->getParent(); - DeclPtrTy DP = HandleDeclarator(ParentScope, D, + DeclPtrTy DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg(*this), /*IsFunctionDefinition=*/true); return ActOnStartOfFunctionDef(FnBodyScope, DP); @@ -3057,10 +3751,16 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { if (!D) return D; - FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>()); + FunctionDecl *FD = 0; + + if (FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>(D.getAs<Decl>())) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(D.getAs<Decl>()); CurFunctionNeedsScopeChecking = false; - + // See if this is a redefinition. const FunctionDecl *Definition; if (FD->getBody(Definition)) { @@ -3069,7 +3769,7 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { } // Builtin functions cannot be defined. - if (unsigned BuiltinID = FD->getBuiltinID(Context)) { + if (unsigned BuiltinID = FD->getBuiltinID()) { if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { Diag(FD->getLocation(), diag::err_builtin_definition) << FD; FD->setInvalidDecl(); @@ -3126,7 +3826,7 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // Checking attributes of current function definition // dllimport attribute. - if (FD->getAttr<DLLImportAttr>() && + if (FD->getAttr<DLLImportAttr>() && (!FD->getAttr<DLLExportAttr>())) { // dllimport attribute cannot be applied to definition. if (!(FD->getAttr<DLLImportAttr>())->isInherited()) { @@ -3155,23 +3855,39 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, bool IsInstantiation) { Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); - if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) { + + FunctionDecl *FD = 0; + FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl); + if (FunTmpl) + FD = FunTmpl->getTemplatedDecl(); + else + FD = dyn_cast_or_null<FunctionDecl>(dcl); + + if (FD) { FD->setBody(Body); - + if (FD->isMain()) + // C and C++ allow for main to automagically return 0. + // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. + FD->setHasImplicitReturnZero(true); + else + CheckFallThroughForFunctionDef(FD, Body); + if (!FD->isInvalidDecl()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); - + // C++ [basic.def.odr]p2: // [...] A virtual member function is used if it is not pure. [...] if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) if (Method->isVirtual() && !Method->isPure()) MarkDeclarationReferenced(Method->getLocation(), Method); - + assert(FD == getCurFunctionDecl() && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - + CheckFallThroughForFunctionDef(MD, Body); + MD->setEndLoc(Body->getLocEnd()); + if (!MD->isInvalidDecl()) DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); } else { @@ -3184,21 +3900,21 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Verify and clean out per-function state. assert(&getLabelMap() == &FunctionLabelMap && "Didn't pop block right?"); - + // Check goto/label use. for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator I = FunctionLabelMap.begin(), E = FunctionLabelMap.end(); I != E; ++I) { LabelStmt *L = I->second; - + // Verify that we have no forward references left. If so, there was a goto // or address of a label taken, but no definition of it. Label fwd // definitions are indicated with a null substmt. if (L->getSubStmt() != 0) continue; - + // Emit error. Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); - + // At this point, we have gotos that use the bogus label. Stitch it into // the function body so that they aren't leaked and that the AST is well // formed. @@ -3207,7 +3923,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, L->Destroy(Context); continue; } - + // Otherwise, the body is valid: we want to stitch the label decl into the // function somewhere so that it is properly owned and so that the goto // has a valid target. Do this by creating a new compound stmt with the @@ -3231,17 +3947,20 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, if (CurFunctionNeedsScopeChecking) DiagnoseInvalidJumps(Body); - // C++ constructors that have function-try-blocks can't have return statements - // in the handlers of that block. (C++ [except.handle]p14) Verify this. - if (isa<CXXConstructorDecl>(dcl) && isa<CXXTryStmt>(Body)) + // C++ constructors that have function-try-blocks can't have return + // statements in the handlers of that block. (C++ [except.handle]p14) + // Verify this. + if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); + if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) + computeBaseOrMembersToDestroy(Destructor); return D; } /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). -NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, +NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S) { // Before we produce a declaration for an implicitly defined // function, see whether there was a locally-scoped declaration of @@ -3256,25 +3975,26 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, } // Extension in C99. Legal in C90, but warn about it. - if (getLangOptions().C99) + static const unsigned int BuiltinLen = strlen("__builtin_"); + if (II.getLength() > BuiltinLen && + std::equal(II.getName(), II.getName() + BuiltinLen, "__builtin_")) + Diag(Loc, diag::warn_builtin_unknown) << &II; + else if (getLangOptions().C99) Diag(Loc, diag::ext_implicit_function_decl) << &II; else Diag(Loc, diag::warn_implicit_function_decl) << &II; - - // FIXME: handle stuff like: - // void foo() { extern float X(); } - // void bar() { X(); } <-- implicit decl for X in another scope. // Set a Declarator for the implicit definition: int foo(); const char *Dummy; DeclSpec DS; - bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy); + unsigned DiagID; + bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID); Error = Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0, 0, 0, false, SourceLocation(), - false, 0,0,0, Loc, D), + false, 0,0,0, Loc, Loc, D), SourceLocation()); D.SetIdentifier(&II, Loc); @@ -3282,8 +4002,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, DeclContext *PrevDC = CurContext; CurContext = Context.getTranslationUnitDecl(); - - FunctionDecl *FD = + + FunctionDecl *FD = dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D).getAs<Decl>()); FD->setImplicit(); @@ -3306,7 +4026,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { // If this is a built-in function, map its builtin attributes to // actual attributes. - if (unsigned BuiltinID = FD->getBuiltinID(Context)) { + if (unsigned BuiltinID = FD->getBuiltinID()) { // Handle printf-formatting attributes. unsigned FormatIdx; bool HasVAListArg; @@ -3324,15 +4044,18 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (!FD->getAttr<ConstAttr>()) FD->addAttr(::new (Context) ConstAttr()); } + + if (Context.BuiltinInfo.isNoReturn(BuiltinID)) + FD->addAttr(::new (Context) NoReturnAttr()); } IdentifierInfo *Name = FD->getIdentifier(); if (!Name) return; - if ((!getLangOptions().CPlusPlus && + if ((!getLangOptions().CPlusPlus && FD->getDeclContext()->isTranslationUnit()) || (isa<LinkageSpecDecl>(FD->getDeclContext()) && - cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() == + cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() == LinkageSpecDecl::lang_c)) { // Okay: this could be a libc/libm/Objective-C function we know // about. @@ -3340,13 +4063,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { return; if (Name->isStr("NSLog") || Name->isStr("NSLogv")) { + // FIXME: NSLog and NSLogv should be target specific if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) { // FIXME: We known better than our headers. const_cast<FormatAttr *>(Format)->setType("printf"); - } else + } else FD->addAttr(::new (Context) FormatAttr("printf", 1, Name->isStr("NSLogv") ? 0 : 2)); } else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) { + // FIXME: asprintf and vasprintf aren't C99 functions. Should they be + // target-specific builtins, perhaps? if (!FD->getAttr<FormatAttr>()) FD->addAttr(::new (Context) FormatAttr("printf", 2, Name->isStr("vasprintf") ? 0 : 3)); @@ -3356,16 +4082,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - + // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, D.getIdentifierLoc(), - D.getIdentifier(), + D.getIdentifier(), T); - - if (TagType *TT = dyn_cast<TagType>(T)) { + + if (const TagType *TT = T->getAs<TagType>()) { TagDecl *TD = TT->getDecl(); - + // If the TagDecl that the TypedefDecl points to is an anonymous decl // keep track of the TypedefDecl. if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) @@ -3382,7 +4108,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) { /// as a redeclaration of the given tag declaration. /// /// \returns true if the new tag kind is acceptable, false otherwise. -bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, +bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, TagDecl::TagKind NewTag, SourceLocation NewTagLoc, const IdentifierInfo &Name) { @@ -3402,7 +4128,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, TagDecl::TagKind 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)) { // Warn about the struct/class tag mismatch. @@ -3423,33 +4149,58 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. -/// TagSpec indicates what kind of tag this is. TK indicates whether this is a +/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. -Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, +Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, - bool &OwnedDecl) { + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent) { // If this is not a definition, it must have a name. - assert((Name != 0 || TK == TK_Definition) && + assert((Name != 0 || TUK == TUK_Definition) && "Nameless record must be a definition!"); OwnedDecl = false; - 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; - case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break; + TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec); + + // FIXME: Check explicit specializations more carefully. + bool isExplicitSpecialization = false; + if (TUK != TUK_Reference) { + if (TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, + (TemplateParameterList**)TemplateParameterLists.get(), + TemplateParameterLists.size(), + isExplicitSpecialization)) { + if (TemplateParams->size() > 0) { + // This is a declaration or definition of a class template (which may + // be a member of another template). + OwnedDecl = false; + DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, + SS, Name, NameLoc, Attr, + TemplateParams, + AS); + TemplateParameterLists.release(); + return Result.get(); + } else { + // The "template<>" header is extraneous. + Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) + << ElaboratedType::getNameForTagKind(Kind) << Name; + isExplicitSpecialization = true; + } + } + + TemplateParameterLists.release(); } - + DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; NamedDecl *PrevDecl = 0; - + bool isStdBadAlloc = false; bool Invalid = false; + bool RedeclarationOnly = (TUK != TUK_Reference); + if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). @@ -3459,18 +4210,35 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, goto CreateNewDecl; } + // If this is a friend or a reference to a class in a dependent + // context, don't try to make a decl for it. + if (TUK == TUK_Friend || TUK == TUK_Reference) { + DC = computeDeclContext(SS, false); + if (!DC) { + IsDependent = true; + return DeclPtrTy(); + } + } + if (RequireCompleteDeclContext(SS)) return DeclPtrTy::make((Decl *)0); - DC = computeDeclContext(SS); + DC = computeDeclContext(SS, true); SearchDC = DC; // Look-up name inside 'foo::'. - PrevDecl - = dyn_cast_or_null<TagDecl>( - LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl()); + LookupResult R; + LookupQualifiedName(R, DC, Name, LookupTagName, RedeclarationOnly); + + if (R.isAmbiguous()) { + DiagnoseAmbiguousLookup(R, Name, NameLoc, SS.getRange()); + return DeclPtrTy(); + } + + if (R.getKind() == LookupResult::Found) + PrevDecl = dyn_cast<TagDecl>(R.getFoundDecl()); // A tag 'foo::bar' must already exist. - if (PrevDecl == 0) { + if (!PrevDecl) { Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); Name = 0; Invalid = true; @@ -3482,8 +4250,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, // FIXME: We're looking into outer scopes here, even when we // shouldn't be. Doing so can result in ambiguities that we // shouldn't be diagnosing. - LookupResult R = LookupName(S, Name, LookupTagName, - /*RedeclarationOnly=*/(TK != TK_Reference)); + LookupResult R; + LookupName(R, S, Name, LookupTagName, RedeclarationOnly); if (R.isAmbiguous()) { DiagnoseAmbiguousLookup(R, Name, NameLoc); // FIXME: This is not best way to recover from case like: @@ -3494,11 +4262,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, Name = 0; PrevDecl = 0; Invalid = true; - } - else - PrevDecl = R; + } else + PrevDecl = R.getAsSingleDecl(Context); - if (!getLangOptions().CPlusPlus && TK != TK_Reference) { + if (!getLangOptions().CPlusPlus && TUK != TUK_Reference) { // FIXME: This makes sure that we ignore the contexts associated // with C structs, unions, and enums when looking for a matching // tag declaration or definition. See the similar lookup tweak @@ -3515,23 +4282,37 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, PrevDecl = 0; } + if (getLangOptions().CPlusPlus && Name && DC && StdNamespace && + DC->Equals(StdNamespace) && Name->isStr("bad_alloc")) { + // This is a declaration of or a reference to "std::bad_alloc". + isStdBadAlloc = true; + + if (!PrevDecl && StdBadAlloc) { + // std::bad_alloc has been implicitly declared (but made invisible to + // name lookup). Fill in this implicit declaration as the previous + // declaration, so that the declarations get chained appropriately. + PrevDecl = StdBadAlloc; + } + } + if (PrevDecl) { // Check whether the previous declaration is usable. (void)DiagnoseUseOfDecl(PrevDecl, NameLoc); - + if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. - if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) { + if (TUK == TUK_Reference || TUK == TUK_Friend || + isDeclInScope(PrevDecl, SearchDC, S)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { - bool SafeToContinue + bool SafeToContinue = (PrevTagDecl->getTagKind() != TagDecl::TK_enum && Kind != TagDecl::TK_enum); if (SafeToContinue) - Diag(KWLoc, diag::err_use_with_wrong_tag) + Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << CodeModificationHint::CreateReplacement(SourceRange(KWLoc), PrevTagDecl->getKindName()); @@ -3539,7 +4320,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; Diag(PrevDecl->getLocation(), diag::note_previous_use); - if (SafeToContinue) + if (SafeToContinue) Kind = PrevTagDecl->getTagKind(); else { // Recover by making this an anonymous redefinition. @@ -3556,27 +4337,35 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, // for the consumer of this Decl to know it doesn't own it. // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. - if (TK == TK_Reference) + if (TUK == TUK_Reference || TUK == TUK_Friend) return DeclPtrTy::make(PrevDecl); // Diagnose attempts to redefine a tag. - if (TK == TK_Definition) { + if (TUK == TUK_Definition) { if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) { - Diag(NameLoc, diag::err_redefinition) << Name; - Diag(Def->getLocation(), diag::note_previous_definition); - // If this is a redefinition, recover by making this - // struct be anonymous, which will make any later - // references get the previous definition. - Name = 0; - PrevDecl = 0; - Invalid = true; + // If we're defining a specialization and the previous definition + // is from an implicit instantiation, don't emit an error + // here; we'll catch this in the general case below. + if (!isExplicitSpecialization || + !isa<CXXRecordDecl>(Def) || + cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) { + Diag(NameLoc, diag::err_redefinition) << Name; + Diag(Def->getLocation(), diag::note_previous_definition); + // If this is a redefinition, recover by making this + // struct be anonymous, which will make any later + // references get the previous definition. + Name = 0; + PrevDecl = 0; + Invalid = true; + } } else { // If the type is currently being defined, complain // about a nested redefinition. TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); if (Tag->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; - Diag(PrevTagDecl->getLocation(), + Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); Name = 0; PrevDecl = 0; @@ -3589,10 +4378,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, } } // If we get here we have (another) forward declaration or we - // have a definition. Just create a new decl. + // have a definition. Just create a new decl. + } else { // If we get here, this is a definition of a new tag type in a nested - // scope, e.g. "struct foo; void bar() { struct foo; }", just create a + // scope, e.g. "struct foo; void bar() { struct foo; }", just create a // new decl/type. We set PrevDecl to NULL so that the entities // have distinct types. PrevDecl = 0; @@ -3617,10 +4407,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, PrevDecl = 0; } } - } else if (TK == TK_Reference && SS.isEmpty() && Name && + } else if (TUK == TUK_Reference && SS.isEmpty() && Name && (Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) { // C++ [basic.scope.pdecl]p5: - // -- for an elaborated-type-specifier of the form + // -- for an elaborated-type-specifier of the form // // class-key identifier // @@ -3641,26 +4431,38 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, // // Find the context where we'll be declaring the tag. // FIXME: We would like to maintain the current DeclContext as the - // lexical context, + // lexical context, while (SearchDC->isRecord()) SearchDC = SearchDC->getParent(); // Find the scope where we'll be declaring the tag. - while (S->isClassScope() || + while (S->isClassScope() || (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) || ((S->getFlags() & Scope::DeclScope) == 0) || - (S->getEntity() && + (S->getEntity() && ((DeclContext *)S->getEntity())->isTransparentContext())) S = S->getParent(); + + } else if (TUK == TUK_Friend && SS.isEmpty() && Name) { + // C++ [namespace.memdef]p3: + // If a friend declaration in a non-local class first declares a + // class or function, the friend class or function is a member of + // the innermost enclosing namespace. + while (!SearchDC->isFileContext()) + SearchDC = SearchDC->getParent(); + + // The entity of a decl scope is a DeclContext; see PushDeclContext. + while (S->getEntity() != SearchDC) + S = S->getParent(); } CreateNewDecl: - + // If there is an identifier, use the location of the identifier as the // location of the decl, otherwise use the location of the struct/union // keyword. SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; - + // Otherwise, create a new declaration. If there is a previous // declaration of the same entity, the two will be linked via // PrevDecl. @@ -3669,10 +4471,10 @@ CreateNewDecl: if (Kind == TagDecl::TK_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, + New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc, cast_or_null<EnumDecl>(PrevDecl)); // If this is an undefined enum, warn. - if (TK != TK_Definition && !Invalid) { + if (TUK != TUK_Definition && !Invalid) { unsigned DK = getLangOptions().CPlusPlus? diag::err_forward_ref_enum : diag::ext_forward_ref_enum; Diag(Loc, DK); @@ -3682,12 +4484,15 @@ CreateNewDecl: // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // struct X { int A; } D; D should chain to X. - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus) { // FIXME: Look for a way to use RecordDecl for simple structs. - New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, + New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, cast_or_null<CXXRecordDecl>(PrevDecl)); - else - New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, + + if (isStdBadAlloc && (!StdBadAlloc || StdBadAlloc->isImplicit())) + StdBadAlloc = cast<CXXRecordDecl>(New); + } else + New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, cast_or_null<RecordDecl>(PrevDecl)); } @@ -3704,7 +4509,7 @@ CreateNewDecl: // the #pragma tokens are effectively skipped over during the // parsing of the struct). if (unsigned Alignment = getPragmaPackAlignment()) - New->addAttr(::new (Context) PackedAttr(Alignment * 8)); + New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8)); } if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) { @@ -3713,12 +4518,14 @@ CreateNewDecl: // shall not be declared with the same name as a typedef-name // that is declared in that scope and refers to a type other // than the class or enumeration itself. - LookupResult Lookup = LookupName(S, Name, LookupOrdinaryName, true); + LookupResult Lookup; + LookupName(Lookup, S, Name, LookupOrdinaryName, true); TypedefDecl *PrevTypedef = 0; - if (Lookup.getKind() == LookupResult::Found) - PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl()); + if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context)) + PrevTypedef = dyn_cast<TypedefDecl>(Prev); - if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) && + NamedDecl *PrevTypedefNamed = PrevTypedef; + if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) && Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != Context.getCanonicalType(Context.getTypeDeclType(New))) { Diag(Loc, diag::err_tag_definition_of_typedef) @@ -3729,6 +4536,11 @@ CreateNewDecl: } } + // If this is a specialization of a member class (of a class template), + // check the specialization. + if (isExplicitSpecialization && CheckMemberSpecialization(New, PrevDecl)) + Invalid = true; + if (Invalid) New->setInvalidDecl(); @@ -3744,21 +4556,45 @@ CreateNewDecl: // lexical context will be different from the semantic context. New->setLexicalDeclContext(CurContext); + // Mark this as a friend decl if applicable. + if (TUK == TUK_Friend) + New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevDecl != NULL); + // Set the access specifier. - if (!Invalid) + if (!Invalid && TUK != TUK_Friend) SetMemberAccessSpecifier(New, PrevDecl, AS); - if (TK == TK_Definition) + if (TUK == TUK_Definition) New->startDefinition(); - + // If this has an identifier, add it to the scope stack. - if (Name) { + if (TUK == TUK_Friend) { + // We might be replacing an existing declaration in the lookup tables; + // if so, borrow its access specifier. + if (PrevDecl) + New->setAccess(PrevDecl->getAccess()); + + // Friend tag decls are visible in fairly strange ways. + if (!CurContext->isDependentContext()) { + DeclContext *DC = New->getDeclContext()->getLookupContext(); + DC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) + PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); + } + } else if (Name) { S = getNonFieldDeclScope(S); PushOnScopeChains(New, S); } else { CurContext->addDecl(New); } + // If this is the C FILE type, notify the AST context. + if (IdentifierInfo *II = New->getIdentifier()) + if (!New->isInvalidDecl() && + New->getDeclContext()->getLookupContext()->isTranslationUnit() && + II->isStr("FILE")) + Context.setFILEDecl(New); + OwnedDecl = true; return DeclPtrTy::make(New); } @@ -3774,7 +4610,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { FieldCollector->StartClass(); if (Record->getIdentifier()) { - // C++ [class]p2: + // C++ [class]p2: // [...] The class-name is also inserted into the scope of the // class itself; this is known as the injected-class-name. For // purposes of access checking, the injected-class-name is treated @@ -3782,21 +4618,25 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { CXXRecordDecl *InjectedClassName = CXXRecordDecl::Create(Context, Record->getTagKind(), CurContext, Record->getLocation(), - Record->getIdentifier(), Record); + Record->getIdentifier(), + Record->getTagKeywordLoc(), + Record); InjectedClassName->setImplicit(); InjectedClassName->setAccess(AS_public); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) InjectedClassName->setDescribedClassTemplate(Template); PushOnScopeChains(InjectedClassName, S); - assert(InjectedClassName->isInjectedClassName() && + assert(InjectedClassName->isInjectedClassName() && "Broken injected-class-name"); } } } -void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) { +void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, + SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); + Tag->setRBraceLoc(RBraceLoc); if (isa<CXXRecordDecl>(Tag)) FieldCollector->FinishClass(); @@ -3809,9 +4649,13 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) { } // Note that FieldName may be null for anonymous bitfields. -bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, - QualType FieldTy, const Expr *BitWidth) { - +bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, + QualType FieldTy, const Expr *BitWidth, + bool *ZeroWidth) { + // Default to true; that shouldn't confuse checks for emptiness + if (ZeroWidth) + *ZeroWidth = true; + // C99 6.7.2.1p4 - verify the field type. // C++ 9.6p3: A bit-field shall have integral or enumeration type. if (!FieldTy->isDependentType() && !FieldTy->isIntegralType()) { @@ -3834,13 +4678,16 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, if (VerifyIntegerConstantExpression(BitWidth, &Value)) return true; + if (Value != 0 && ZeroWidth) + *ZeroWidth = false; + // Zero-width bitfield is ok for anonymous field. if (Value == 0 && FieldName) return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName; - + if (Value.isSigned() && Value.isNegative()) { if (FieldName) - return Diag(FieldLoc, diag::err_bitfield_has_negative_width) + return Diag(FieldLoc, diag::err_bitfield_has_negative_width) << FieldName << Value.toString(10); return Diag(FieldLoc, diag::err_anon_bitfield_has_negative_width) << Value.toString(10); @@ -3863,7 +4710,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, /// ActOnField - Each field of a struct/union/class is passed into this in order /// to create a FieldDecl object for it. Sema::DeclPtrTy Sema::ActOnField(Scope *S, DeclPtrTy TagD, - SourceLocation DeclStart, + SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD.getAs<Decl>()), DeclStart, D, static_cast<Expr*>(BitfieldWidth), @@ -3880,8 +4727,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); - - QualType T = GetTypeForDeclarator(D, S); + + DeclaratorInfo *DInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &DInfo); if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); @@ -3890,7 +4738,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true); + NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. @@ -3902,10 +4750,12 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) PrevDecl = 0; - FieldDecl *NewFD - = CheckFieldDecl(II, T, Record, Loc, - D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable, - BitWidth, AS, PrevDecl, &D); + bool Mutable + = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); + SourceLocation TSSL = D.getSourceRange().getBegin(); + FieldDecl *NewFD + = CheckFieldDecl(II, T, DInfo, Record, Loc, Mutable, BitWidth, TSSL, + AS, PrevDecl, &D); if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. @@ -3926,10 +4776,12 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, /// /// \returns a new FieldDecl. /// -/// \todo The Declarator argument is a hack. It will be removed once -FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, +/// \todo The Declarator argument is a hack. It will be removed once +FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, + DeclaratorInfo *DInfo, RecordDecl *Record, SourceLocation Loc, - bool Mutable, Expr *BitWidth, + bool Mutable, Expr *BitWidth, + SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { IdentifierInfo *II = Name.getAsIdentifierInfo(); @@ -3957,25 +4809,26 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, Diag(Loc, diag::err_typecheck_negative_array_size); else Diag(Loc, diag::err_typecheck_field_variable_size); - T = Context.IntTy; InvalidDecl = true; } } - + // Fields can not have abstract class types - if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, + if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, AbstractFieldType)) InvalidDecl = true; - + + bool ZeroWidth = false; // If this is declared as a bit-field, check the bit-field. - if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) { + if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) { InvalidDecl = true; DeleteExpr(BitWidth); BitWidth = 0; + ZeroWidth = false; } - - FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth, - Mutable); + + FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, DInfo, + BitWidth, Mutable); if (InvalidDecl) NewFD->setInvalidDecl(); @@ -3985,8 +4838,61 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, NewFD->setInvalidDecl(); } - if (getLangOptions().CPlusPlus && !T->isPODType()) - cast<CXXRecordDecl>(Record)->setPOD(false); + if (getLangOptions().CPlusPlus) { + QualType EltTy = Context.getBaseElementType(T); + + CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record); + + if (!T->isPODType()) + CXXRecord->setPOD(false); + if (!ZeroWidth) + CXXRecord->setEmpty(false); + + if (const RecordType *RT = EltTy->getAs<RecordType>()) { + CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl()); + + if (!RDecl->hasTrivialConstructor()) + CXXRecord->setHasTrivialConstructor(false); + if (!RDecl->hasTrivialCopyConstructor()) + CXXRecord->setHasTrivialCopyConstructor(false); + if (!RDecl->hasTrivialCopyAssignment()) + CXXRecord->setHasTrivialCopyAssignment(false); + if (!RDecl->hasTrivialDestructor()) + CXXRecord->setHasTrivialDestructor(false); + + // C++ 9.5p1: An object of a class with a non-trivial + // constructor, a non-trivial copy constructor, a non-trivial + // destructor, or a non-trivial copy assignment operator + // cannot be a member of a union, nor can an array of such + // objects. + // TODO: C++0x alters this restriction significantly. + if (Record->isUnion()) { + // We check for copy constructors before constructors + // because otherwise we'll never get complaints about + // copy constructors. + + const CXXSpecialMember invalid = (CXXSpecialMember) -1; + + CXXSpecialMember member; + if (!RDecl->hasTrivialCopyConstructor()) + member = CXXCopyConstructor; + else if (!RDecl->hasTrivialConstructor()) + member = CXXDefaultConstructor; + else if (!RDecl->hasTrivialCopyAssignment()) + member = CXXCopyAssignment; + else if (!RDecl->hasTrivialDestructor()) + member = CXXDestructor; + else + member = invalid; + + if (member != invalid) { + Diag(Loc, diag::err_illegal_union_member) << Name << member; + DiagnoseNontrivial(RT, member); + NewFD->setInvalidDecl(); + } + } + } + } // FIXME: We need to pass in the attributes given an AST // representation, not a parser representation. @@ -4013,7 +4919,131 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, return NewFD; } -/// TranslateIvarVisibility - Translate visibility from a token ID to an +/// DiagnoseNontrivial - Given that a class has a non-trivial +/// special member, figure out why. +void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { + QualType QT(T, 0U); + CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl()); + + // Check whether the member was user-declared. + switch (member) { + case CXXDefaultConstructor: + if (RD->hasUserDeclaredConstructor()) { + typedef CXXRecordDecl::ctor_iterator ctor_iter; + for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce; ++ci) + if (!ci->isImplicitlyDefined(Context)) { + SourceLocation CtorLoc = ci->getLocation(); + Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + + assert(0 && "found no user-declared constructors"); + return; + } + break; + + case CXXCopyConstructor: + if (RD->hasUserDeclaredCopyConstructor()) { + SourceLocation CtorLoc = + RD->getCopyConstructor(Context, 0)->getLocation(); + Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + + case CXXCopyAssignment: + if (RD->hasUserDeclaredCopyAssignment()) { + // FIXME: this should use the location of the copy + // assignment, not the type. + SourceLocation TyLoc = RD->getSourceRange().getBegin(); + Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + + case CXXDestructor: + if (RD->hasUserDeclaredDestructor()) { + SourceLocation DtorLoc = RD->getDestructor(Context)->getLocation(); + Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + } + + typedef CXXRecordDecl::base_class_iterator base_iter; + + // Virtual bases and members inhibit trivial copying/construction, + // but not trivial destruction. + if (member != CXXDestructor) { + // Check for virtual bases. vbases includes indirect virtual bases, + // so we just iterate through the direct bases. + for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) + if (bi->isVirtual()) { + SourceLocation BaseLoc = bi->getSourceRange().getBegin(); + Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1; + return; + } + + // Check for virtual methods. + typedef CXXRecordDecl::method_iterator meth_iter; + for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; + ++mi) { + if (mi->isVirtual()) { + SourceLocation MLoc = mi->getSourceRange().getBegin(); + Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0; + return; + } + } + } + + bool (CXXRecordDecl::*hasTrivial)() const; + switch (member) { + case CXXDefaultConstructor: + hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break; + case CXXCopyConstructor: + hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break; + case CXXCopyAssignment: + hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break; + case CXXDestructor: + hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break; + default: + assert(0 && "unexpected special member"); return; + } + + // Check for nontrivial bases (and recurse). + for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) { + const RecordType *BaseRT = bi->getType()->getAs<RecordType>(); + assert(BaseRT); + CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl()); + if (!(BaseRecTy->*hasTrivial)()) { + SourceLocation BaseLoc = bi->getSourceRange().getBegin(); + Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member; + DiagnoseNontrivial(BaseRT, member); + return; + } + } + + // Check for nontrivial members (and recurse). + typedef RecordDecl::field_iterator field_iter; + for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe; + ++fi) { + QualType EltTy = Context.getBaseElementType((*fi)->getType()); + if (const RecordType *EltRT = EltTy->getAs<RecordType>()) { + CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl()); + + if (!(EltRD->*hasTrivial)()) { + SourceLocation FLoc = (*fi)->getLocation(); + Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member; + DiagnoseNontrivial(EltRT, member); + return; + } + } + } + + assert(0 && "found no explanation for non-trivial member"); +} + +/// TranslateIvarVisibility - Translate visibility from a token ID to an /// AST enum value. static ObjCIvarDecl::AccessControl TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { @@ -4026,24 +5056,25 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { } } -/// ActOnIvar - Each ivar field of an objective-c class is passed into this +/// ActOnIvar - Each ivar field of an objective-c class is passed into this /// in order to create an IvarDecl object for it. Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, - SourceLocation DeclStart, + SourceLocation DeclStart, DeclPtrTy IntfDecl, Declarator &D, ExprTy *BitfieldWidth, tok::ObjCKeywordKind Visibility) { - + IdentifierInfo *II = D.getIdentifier(); Expr *BitWidth = (Expr*)BitfieldWidth; SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); - + // FIXME: Unnamed fields can be handled in various different ways, for // example, unnamed unions inject all members into the struct namespace! - - QualType T = GetTypeForDeclarator(D, S); - + + DeclaratorInfo *DInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &DInfo); + if (BitWidth) { // 6.7.2.1p3, 6.7.2.1p4 if (VerifyBitField(Loc, II, T, BitWidth)) { @@ -4053,43 +5084,42 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, } } else { // Not a bitfield. - + // validate II. - + } - + // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_typecheck_ivar_variable_size); D.setInvalidType(); } - + // Get the visibility (access control) for this ivar. - ObjCIvarDecl::AccessControl ac = + ObjCIvarDecl::AccessControl ac = Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) : ObjCIvarDecl::None; // Must set ivar's DeclContext to its enclosing interface. Decl *EnclosingDecl = IntfDecl.getAs<Decl>(); DeclContext *EnclosingContext; - if (ObjCImplementationDecl *IMPDecl = + if (ObjCImplementationDecl *IMPDecl = dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { // Case of ivar declared in an implementation. Context is that of its class. ObjCInterfaceDecl* IDecl = IMPDecl->getClassInterface(); assert(IDecl && "No class- ActOnIvar"); EnclosingContext = cast_or_null<DeclContext>(IDecl); - } - else + } else EnclosingContext = dyn_cast<DeclContext>(EnclosingDecl); assert(EnclosingContext && "null DeclContext for ivar - ActOnIvar"); - + // Construct the decl. - ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, - EnclosingContext, Loc, II, T,ac, - (Expr *)BitfieldWidth); - + ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, + EnclosingContext, Loc, II, T, + DInfo, ac, (Expr *)BitfieldWidth); + if (II) { - NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true); + NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa<TagDecl>(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; @@ -4100,7 +5130,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // Process attributes attached to the ivar. ProcessDeclAttributes(S, NewID, D); - + if (D.isInvalidType()) NewID->setInvalidDecl(); @@ -4121,7 +5151,7 @@ void Sema::ActOnFields(Scope* S, AttributeList *Attr) { Decl *EnclosingDecl = RecDecl.getAs<Decl>(); assert(EnclosingDecl && "missing record or interface decl"); - + // If the decl this is being inserted into is invalid, then it may be a // redeclaration or some other bogus case. Don't try to add fields to it. if (EnclosingDecl->isInvalidDecl()) { @@ -4129,7 +5159,7 @@ void Sema::ActOnFields(Scope* S, return; } - + // Verify that all the fields are okay. unsigned NumNamedMembers = 0; llvm::SmallVector<FieldDecl*, 32> RecFields; @@ -4137,7 +5167,7 @@ void Sema::ActOnFields(Scope* S, RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); for (unsigned i = 0; i != NumFields; ++i) { FieldDecl *FD = cast<FieldDecl>(Fields[i].getAs<Decl>()); - + // Get the type for the field. Type *FDTy = FD->getType().getTypePtr(); @@ -4145,12 +5175,12 @@ void Sema::ActOnFields(Scope* S, // Remember all fields written by the user. RecFields.push_back(FD); } - + // If the field is already invalid for some reason, don't emit more // diagnostics about it. if (FD->isInvalidDecl()) continue; - + // C99 6.7.2.1p2: // A structure or union shall not contain a member with // incomplete or function type (hence, a structure shall not @@ -4182,13 +5212,13 @@ void Sema::ActOnFields(Scope* S, if (Record) Record->setHasFlexibleArrayMember(true); } else if (!FDTy->isDependentType() && - RequireCompleteType(FD->getLocation(), FD->getType(), + RequireCompleteType(FD->getLocation(), FD->getType(), diag::err_field_incomplete)) { // Incomplete type FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (const RecordType *FDTTy = FDTy->getAsRecordType()) { + } else if (const RecordType *FDTTy = FDTy->getAs<RecordType>()) { if (FDTTy->getDecl()->hasFlexibleArrayMember()) { // If this is a member of a union, then entire union becomes "flexible". if (Record && Record->isUnion()) { @@ -4210,13 +5240,20 @@ void Sema::ActOnFields(Scope* S, } } } + if (Record && FDTTy->getDecl()->hasObjectMember()) + Record->setHasObjectMember(true); } else if (FDTy->isObjCInterfaceType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } + } else if (getLangOptions().ObjC1 && + getLangOptions().getGCMode() != LangOptions::NonGC && + Record && + (FD->getType()->isObjCObjectPointerType() || + FD->getType().isObjCGCStrong())) + Record->setHasObjectMember(true); // Keep track of the number of named members. if (FD->getIdentifier()) ++NumNamedMembers; @@ -4239,7 +5276,7 @@ void Sema::ActOnFields(Scope* S, // Must enforce the rule that ivars in the base classes may not be // duplicates. if (ID->getSuperClass()) { - for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(), + for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(), IVE = ID->ivar_end(); IVI != IVE; ++IVI) { ObjCIvarDecl* Ivar = (*IVI); @@ -4253,7 +5290,7 @@ void Sema::ActOnFields(Scope* S, } } } - } else if (ObjCImplementationDecl *IMPDecl = + } else if (ObjCImplementationDecl *IMPDecl = dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); for (unsigned I = 0, N = RecFields.size(); I != N; ++I) @@ -4294,7 +5331,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, EltTy = Val->getType(); } } - + if (!Val) { if (LastEnumConst) { // Assign the last value + 1. @@ -4304,7 +5341,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // Check for overflow on increment. if (EnumVal < LastEnumConst->getInitVal()) Diag(IdLoc, diag::warn_enum_value_overflow); - + EltTy = LastEnumConst->getType(); } else { // First value, set to zero. @@ -4312,10 +5349,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy))); } } - + val.release(); return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, - Val, EnumVal); + Val, EnumVal); } @@ -4332,10 +5369,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. S = getNonFieldDeclScope(S); - + // Verify that there isn't already something declared with this name in this // scope. - NamedDecl *PrevDecl = LookupName(S, Id, LookupOrdinaryName); + NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); @@ -4371,28 +5408,34 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, DeclPtrTy EnumDeclX, - DeclPtrTy *Elements, unsigned NumElements) { + DeclPtrTy *Elements, unsigned NumElements, + Scope *S, AttributeList *Attr) { EnumDecl *Enum = cast<EnumDecl>(EnumDeclX.getAs<Decl>()); QualType EnumType = Context.getTypeDeclType(Enum); - + + if (Attr) + ProcessDeclAttributeList(S, Enum, Attr); + // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. unsigned IntWidth = Context.Target.getIntWidth(); - + unsigned CharWidth = Context.Target.getCharWidth(); + unsigned ShortWidth = Context.Target.getShortWidth(); + // Verify that all the values are okay, compute the size of the values, and // reverse the list. unsigned NumNegativeBits = 0; unsigned NumPositiveBits = 0; - + // Keep track of whether all elements have type int. bool AllElementsInt = true; - + for (unsigned i = 0; i != NumElements; ++i) { EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>()); if (!ECD) continue; // Already issued a diagnostic. - + // If the enum value doesn't fit in an int, emit an extension warning. const llvm::APSInt &InitVal = ECD->getInitVal(); assert(InitVal.getBitWidth() >= IntWidth && @@ -4405,7 +5448,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, Diag(ECD->getLocation(), diag::ext_enum_value_not_int) << InitVal.toString(10); } - + // Keep track of the size of positive and negative values. if (InitVal.isUnsigned() || InitVal.isNonNegative()) NumPositiveBits = std::max(NumPositiveBits, @@ -4416,28 +5459,39 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Keep track of whether every enum element has type int (very commmon). if (AllElementsInt) - AllElementsInt = ECD->getType() == Context.IntTy; + AllElementsInt = ECD->getType() == Context.IntTy; } - + // Figure out the type that should be used for this enum. - // FIXME: Support attribute(packed) on enums and -fshort-enums. + // FIXME: Support -fshort-enums. QualType BestType; unsigned BestWidth; - + + bool Packed = Enum->getAttr<PackedAttr>() ? true : false; + if (NumNegativeBits) { - // If there is a negative value, figure out the smallest integer type (of + // If there is a negative value, figure out the smallest integer type (of // int/long/longlong) that fits. - if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { + // If it's packed, check also if it fits a char or a short. + if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) { + BestType = Context.SignedCharTy; + BestWidth = CharWidth; + } else if (Packed && NumNegativeBits <= ShortWidth && + NumPositiveBits < ShortWidth) { + BestType = Context.ShortTy; + BestWidth = ShortWidth; + } + else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { BestType = Context.IntTy; BestWidth = IntWidth; } else { BestWidth = Context.Target.getLongWidth(); - + if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) BestType = Context.LongTy; else { BestWidth = Context.Target.getLongLongWidth(); - + if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) Diag(Enum->getLocation(), diag::warn_enum_too_large); BestType = Context.LongLongTy; @@ -4446,7 +5500,15 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } else { // If there is no negative value, figure out which of uint, ulong, ulonglong // fits. - if (NumPositiveBits <= IntWidth) { + // If it's packed, check also if it fits a char or a short. + if (Packed && NumPositiveBits <= CharWidth) { + BestType = Context.UnsignedCharTy; + BestWidth = CharWidth; + } else if (Packed && NumPositiveBits <= ShortWidth) { + BestType = Context.UnsignedShortTy; + BestWidth = ShortWidth; + } + else if (NumPositiveBits <= IntWidth) { BestType = Context.UnsignedIntTy; BestWidth = IntWidth; } else if (NumPositiveBits <= @@ -4459,7 +5521,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, BestType = Context.UnsignedLongLongTy; } } - + // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (unsigned i = 0; i != NumElements; ++i) { @@ -4481,7 +5543,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, if (getLangOptions().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its - // enumeration. + // enumeration. ECD->setType(EnumType); continue; // Already int type. } @@ -4508,7 +5570,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, if (getLangOptions().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its - // enumeration. + // enumeration. ECD->setType(EnumType); continue; } else { @@ -4521,20 +5583,22 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, InitVal.extOrTrunc(NewWidth); InitVal.setIsSigned(NewSign); ECD->setInitVal(InitVal); - + // Adjust the Expr initializer and type. if (ECD->getInitExpr()) - ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, ECD->getInitExpr(), + ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, + CastExpr::CK_Unknown, + ECD->getInitExpr(), /*isLvalue=*/false)); if (getLangOptions().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its - // enumeration. + // enumeration. ECD->setType(EnumType); else ECD->setType(NewTy); } - + Enum->completeDefinition(Context, BestType); } @@ -4551,15 +5615,15 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { - Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName); + Decl *PrevDecl = LookupSingleName(TUScope, Name, LookupOrdinaryName); - // FIXME: This implementation is an ugly hack! if (PrevDecl) { PrevDecl->addAttr(::new (Context) WeakAttr()); - return; + } else { + (void)WeakUndeclaredIdentifiers.insert( + std::pair<IdentifierInfo*,WeakInfo> + (Name, WeakInfo((IdentifierInfo*)0, NameLoc))); } - Diag(PragmaLoc, diag::err_unsupported_pragma_weak); - return; } void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, @@ -4567,14 +5631,15 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { - Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName); + Decl *PrevDecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName); + WeakInfo W = WeakInfo(Name, NameLoc); - // FIXME: This implementation is an ugly hack! if (PrevDecl) { - PrevDecl->addAttr(::new (Context) AliasAttr(AliasName->getName())); - PrevDecl->addAttr(::new (Context) WeakAttr()); - return; + if (!PrevDecl->hasAttr<AliasAttr>()) + if (NamedDecl *ND = dyn_cast<NamedDecl>(PrevDecl)) + DeclApplyPragmaWeak(TUScope, ND, W); + } else { + (void)WeakUndeclaredIdentifiers.insert( + std::pair<IdentifierInfo*,WeakInfo>(AliasName, W)); } - Diag(PragmaLoc, diag::err_unsupported_pragma_weak); - return; } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 2b71df722459b..50ebb49e7d5b4 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -17,46 +17,53 @@ #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" #include "clang/Parse/DeclSpec.h" -#include <llvm/ADT/StringExtras.h> +#include "llvm/ADT/StringExtras.h" using namespace clang; //===----------------------------------------------------------------------===// // Helper functions //===----------------------------------------------------------------------===// -static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) { +static const FunctionType *getFunctionType(const Decl *d, + bool blocksToo = true) { QualType Ty; - if (ValueDecl *decl = dyn_cast<ValueDecl>(d)) + if (const ValueDecl *decl = dyn_cast<ValueDecl>(d)) Ty = decl->getType(); - else if (FieldDecl *decl = dyn_cast<FieldDecl>(d)) + else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d)) Ty = decl->getType(); - else if (TypedefDecl* decl = dyn_cast<TypedefDecl>(d)) + else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d)) Ty = decl->getUnderlyingType(); else return 0; - + if (Ty->isFunctionPointerType()) - Ty = Ty->getAsPointerType()->getPointeeType(); + Ty = Ty->getAs<PointerType>()->getPointeeType(); else if (blocksToo && Ty->isBlockPointerType()) - Ty = Ty->getAsBlockPointerType()->getPointeeType(); + Ty = Ty->getAs<BlockPointerType>()->getPointeeType(); - return Ty->getAsFunctionType(); + return Ty->getAs<FunctionType>(); } // FIXME: We should provide an abstraction around a method or function // to provide the following bits of information. /// isFunctionOrMethod - Return true if the given decl has function +/// type (function or function-typed variable). +static bool isFunction(const Decl *d) { + return getFunctionType(d, false) != NULL; +} + +/// isFunctionOrMethod - Return true if the given decl has function /// type (function or function-typed variable) or an Objective-C /// method. -static bool isFunctionOrMethod(Decl *d) { - return getFunctionType(d, false) || isa<ObjCMethodDecl>(d); +static bool isFunctionOrMethod(const Decl *d) { + return isFunction(d)|| isa<ObjCMethodDecl>(d); } /// isFunctionOrMethodOrBlock - Return true if the given decl has function /// type (function or function-typed variable) or an Objective-C /// method or a block. -static bool isFunctionOrMethodOrBlock(Decl *d) { +static bool isFunctionOrMethodOrBlock(const Decl *d) { if (isFunctionOrMethod(d)) return true; // check for block is more involved. @@ -70,7 +77,7 @@ static bool isFunctionOrMethodOrBlock(Decl *d) { /// hasFunctionProto - Return true if the given decl has a argument /// information. This decl should have already passed /// isFunctionOrMethod or isFunctionOrMethodOrBlock. -static bool hasFunctionProto(Decl *d) { +static bool hasFunctionProto(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) return isa<FunctionProtoType>(FnTy); else { @@ -82,7 +89,7 @@ static bool hasFunctionProto(Decl *d) { /// getFunctionOrMethodNumArgs - Return number of function or method /// arguments. It is an error to call this on a K&R function (use /// hasFunctionProto first). -static unsigned getFunctionOrMethodNumArgs(Decl *d) { +static unsigned getFunctionOrMethodNumArgs(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) return cast<FunctionProtoType>(FnTy)->getNumArgs(); if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) @@ -90,22 +97,22 @@ static unsigned getFunctionOrMethodNumArgs(Decl *d) { return cast<ObjCMethodDecl>(d)->param_size(); } -static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) { +static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) { if (const FunctionType *FnTy = getFunctionType(d)) return cast<FunctionProtoType>(FnTy)->getArgType(Idx); if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) return BD->getParamDecl(Idx)->getType(); - + return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType(); } -static QualType getFunctionOrMethodResultType(Decl *d) { +static QualType getFunctionOrMethodResultType(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) return cast<FunctionProtoType>(FnTy)->getResultType(); return cast<ObjCMethodDecl>(d)->getResultType(); } -static bool isFunctionOrMethodVariadic(Decl *d) { +static bool isFunctionOrMethodVariadic(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) { const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); return proto->isVariadic(); @@ -117,30 +124,30 @@ static bool isFunctionOrMethodVariadic(Decl *d) { } static inline bool isNSStringType(QualType T, ASTContext &Ctx) { - const PointerType *PT = T->getAsPointerType(); + const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); if (!PT) return false; - - const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAsObjCInterfaceType(); + + const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>(); if (!ClsT) return false; - + IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier(); - + // FIXME: Should we walk the chain of classes? return ClsName == &Ctx.Idents.get("NSString") || ClsName == &Ctx.Idents.get("NSMutableString"); } static inline bool isCFStringType(QualType T, ASTContext &Ctx) { - const PointerType *PT = T->getAsPointerType(); + const PointerType *PT = T->getAs<PointerType>(); if (!PT) return false; - const RecordType *RT = PT->getPointeeType()->getAsRecordType(); + const RecordType *RT = PT->getPointeeType()->getAs<RecordType>(); if (!RT) return false; - + const RecordDecl *RD = RT->getDecl(); if (RD->getTagKind() != TagDecl::TK_struct) return false; @@ -156,14 +163,14 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { // least add some helper functions to check most argument patterns (# // and types of args). -static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, +static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, const AttributeList &Attr, Sema &S) { TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d); if (tDecl == 0) { S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef); return; } - + QualType curType = tDecl->getUnderlyingType(); Expr *sizeExpr; @@ -187,21 +194,20 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc()); if (!T.isNull()) { tDecl->setUnderlyingType(T); - + // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(tDecl); } } -/// HandleVectorSizeAttribute - this attribute is only applicable to -/// integral and float scalars, although arrays, pointers, and function -/// return values are allowed in conjunction with this construct. Aggregates -/// with this attribute are invalid, even if they are of the same size as a -/// corresponding scalar. -/// The raw attribute should contain precisely 1 argument, the vector size -/// for the variable, measured in bytes. If curType and rawAttr are well -/// formed, this routine will return a new vector type. +/// HandleVectorSizeAttribute - this attribute is only applicable to integral +/// and float scalars, although arrays, pointers, and function return values are +/// allowed in conjunction with this construct. Aggregates with this attribute +/// are invalid, even if they are of the same size as a corresponding scalar. +/// The raw attribute should contain precisely 1 argument, the vector size for +/// the variable, measured in bytes. If curType and rawAttr are well formed, +/// this routine will return a new vector type. static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { QualType CurType; if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) @@ -213,7 +219,7 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { << "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc()); return; } - + // Check the attribute arugments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -226,8 +232,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { << "vector_size" << sizeExpr->getSourceRange(); return; } - // navigate to the base type - we need to provide for vector pointers, - // vector arrays, and functions returning vectors. + // navigate to the base type - we need to provide for vector pointers, vector + // arrays, and functions returning vectors. if (CurType->isPointerType() || CurType->isArrayType() || CurType->isFunctionType()) { S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType; @@ -252,8 +258,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { } unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); // vecSize is specified in bytes - convert to bits. - unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8); - + unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8); + // the vector size needs to be an integral multiple of the type size. if (vectorSize % typeSize) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) @@ -265,14 +271,14 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { << sizeExpr->getSourceRange(); return; } - + // Success! Instantiate the vector type, the number of elements is > 0, and // not required to be a power of 2, unlike GCC. CurType = S.Context.getVectorType(CurType, vectorSize/typeSize); - + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) VD->setType(CurType); - else + else cast<TypedefDecl>(D)->setUnderlyingType(CurType); } @@ -282,9 +288,9 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + if (TagDecl *TD = dyn_cast<TagDecl>(d)) - TD->addAttr(::new (S.Context) PackedAttr(1)); + TD->addAttr(::new (S.Context) PackedAttr); else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) { // If the alignment is less than or equal to 8 bits, the packed attribute // has no effect. @@ -293,7 +299,7 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) << Attr.getName() << FD->getType(); else - FD->addAttr(::new (S.Context) PackedAttr(1)); + FD->addAttr(::new (S.Context) PackedAttr); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } @@ -304,7 +310,7 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + // The IBOutlet attribute only applies to instance variables of Objective-C // classes. if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d)) @@ -314,23 +320,23 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) { } 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 + // GCC ignores the nonnull attribute on K&R style function prototypes, so we + // ignore it as well if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; } - + unsigned NumArgs = getFunctionOrMethodNumArgs(d); // The nonnull attribute only applies to pointers. llvm::SmallVector<unsigned, 10> NonNullArgs; - + for (AttributeList::arg_iterator I=Attr.arg_begin(), E=Attr.arg_end(); I!=E; ++I) { - - + + // The argument must be an integer constant expression. Expr *Ex = static_cast<Expr *>(*I); llvm::APSInt ArgNum(32); @@ -339,38 +345,38 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { << "nonnull" << Ex->getSourceRange(); return; } - + unsigned x = (unsigned) ArgNum.getZExtValue(); - + if (x < 1 || x > NumArgs) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) << "nonnull" << I.getArgNum() << Ex->getSourceRange(); return; } - + --x; // Is the function argument a pointer type? - QualType T = getFunctionOrMethodArgType(d, x); - if (!T->isPointerType() && !T->isBlockPointerType()) { + QualType T = getFunctionOrMethodArgType(d, x); + if (!T->isAnyPointerType() && !T->isBlockPointerType()) { // FIXME: Should also highlight argument in decl. S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only) << "nonnull" << Ex->getSourceRange(); continue; } - + NonNullArgs.push_back(x); } - - // If no arguments were specified to __attribute__((nonnull)) then all - // pointer arguments have a nonnull attribute. + + // If no arguments were specified to __attribute__((nonnull)) then all pointer + // arguments have a nonnull attribute. if (NonNullArgs.empty()) { for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) { QualType T = getFunctionOrMethodArgType(d, I); - if (T->isPointerType() || T->isBlockPointerType()) + if (T->isAnyPointerType() || T->isBlockPointerType()) NonNullArgs.push_back(I); } - + if (NonNullArgs.empty()) { S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); return; @@ -389,26 +395,26 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - + Expr *Arg = static_cast<Expr*>(Attr.getArg(0)); Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - + if (Str == 0 || Str->isWide()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "alias" << 1; return; } - + const char *Alias = Str->getStrData(); unsigned AliasLen = Str->getByteLength(); - + // FIXME: check if target symbol exists in current file - + d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen))); } -static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, +static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { @@ -421,10 +427,28 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, << Attr.getName() << 0 /*function*/; return; } - + d->addAttr(::new (S.Context) AlwaysInlineAttr()); } +static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) { + QualType RetTy = FD->getResultType(); + if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { + d->addAttr(::new (S.Context) MallocAttr()); + return; + } + } + + S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); +} + static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. @@ -441,18 +465,18 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, return false; } } - + return true; } static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (HandleCommonNoReturnAttr(d, Attr, S)) + if (HandleCommonNoReturnAttr(d, Attr, S)) d->addAttr(::new (S.Context) NoReturnAttr()); } static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (HandleCommonNoReturnAttr(d, Attr, S)) + if (HandleCommonNoReturnAttr(d, Attr, S)) d->addAttr(::new (S.Context) AnalyzerNoReturnAttr()); } @@ -462,13 +486,13 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } - + d->addAttr(::new (S.Context) UnusedAttr()); } @@ -478,7 +502,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + if (const VarDecl *VD = dyn_cast<VarDecl>(d)) { if (VD->hasLocalStorage() || VD->hasExternalStorage()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used"; @@ -489,7 +513,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << 2 /*variable and function*/; return; } - + d->addAttr(::new (S.Context) UsedAttr()); } @@ -499,7 +523,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << "0 or 1"; return; - } + } int priority = 65535; // FIXME: Do not hardcode such constants. if (Attr.getNumArgs() > 0) { @@ -512,7 +536,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { } priority = Idx.getZExtValue(); } - + if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; @@ -528,7 +552,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << "0 or 1"; return; - } + } int priority = 65535; // FIXME: Do not hardcode such constants. if (Attr.getNumArgs() > 0) { @@ -541,7 +565,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { } priority = Idx.getZExtValue(); } - + if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; @@ -557,7 +581,7 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + d->addAttr(::new (S.Context) DeprecatedAttr()); } @@ -567,7 +591,7 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + d->addAttr(::new (S.Context) UnavailableAttr()); } @@ -577,21 +601,21 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - + Expr *Arg = static_cast<Expr*>(Attr.getArg(0)); Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - + if (Str == 0 || Str->isWide()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "visibility" << 1; return; } - + const char *TypeStr = Str->getStrData(); unsigned TypeLen = Str->getByteLength(); VisibilityAttr::VisibilityTypes type; - + if (TypeLen == 7 && !memcmp(TypeStr, "default", 7)) type = VisibilityAttr::DefaultVisibility; else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6)) @@ -604,7 +628,7 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr; return; } - + d->addAttr(::new (S.Context) VisibilityAttr(type)); } @@ -614,13 +638,13 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D); if (OCI == 0) { S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface); return; } - + D->addAttr(::new (S.Context) ObjCExceptionAttr()); } @@ -632,7 +656,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isPointerType() || - !T->getAsPointerType()->getPointeeType()->isRecordType()) { + !T->getAs<PointerType>()->getPointeeType()->isRecordType()) { S.Diag(TD->getLocation(), diag::err_nsobject_attribute); return; } @@ -640,7 +664,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { D->addAttr(::new (S.Context) ObjCNSObjectAttr()); } -static void +static void HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -656,17 +680,17 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) { } static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (!Attr.getParameterName()) { + if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "blocks" << 1; return; } - + if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - + BlocksAttr::BlocksAttrTypes type; if (Attr.getParameterName()->isStr("byref")) type = BlocksAttr::ByRef; @@ -675,7 +699,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { << "blocks" << Attr.getParameterName(); return; } - + d->addAttr(::new (S.Context) BlocksAttr(type)); } @@ -685,8 +709,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << "0, 1 or 2"; return; - } - + } + int sentinel = 0; if (Attr.getNumArgs() > 0) { Expr *E = static_cast<Expr *>(Attr.getArg(0)); @@ -697,7 +721,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } sentinel = Idx.getZExtValue(); - + if (sentinel < 0) { S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero) << E->getSourceRange(); @@ -715,7 +739,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } nullPos = Idx.getZExtValue(); - + if (nullPos > 1 || nullPos < 0) { // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. @@ -726,39 +750,38 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { } if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) { - const FunctionType *FT = FD->getType()->getAsFunctionType(); + const FunctionType *FT = FD->getType()->getAs<FunctionType>(); assert(FT && "FunctionDecl has non-function type?"); - + if (isa<FunctionNoProtoType>(FT)) { S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments); return; } - + if (!cast<FunctionProtoType>(FT)->isVariadic()) { S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; - } + } } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) { if (!MD->isVariadic()) { S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } } else if (isa<BlockDecl>(d)) { - // Note! BlockDecl is typeless. Variadic diagnostics - // will be issued by the caller. + // Note! BlockDecl is typeless. Variadic diagnostics will be issued by the + // caller. ; } else if (const VarDecl *V = dyn_cast<VarDecl>(d)) { QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { - const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d) - : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType(); + const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d) + : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (!cast<FunctionProtoType>(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; return; } - } - else { + } else { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 6 /*function, method or block */; return; @@ -785,7 +808,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) << Attr.getName() << 0 /*function*/; return; } - + Fn->addAttr(::new (S.Context) WarnUnusedResultAttr()); } @@ -796,13 +819,26 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } + /* weak only applies to non-static declarations */ + bool isStatic = false; + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + isStatic = VD->getStorageClass() == VarDecl::Static; + } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + isStatic = FD->getStorageClass() == FunctionDecl::Static; + } + if (isStatic) { + S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) << + dyn_cast<NamedDecl>(D)->getNameAsString(); + return; + } + // TODO: could also be applied to methods? if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } - + D->addAttr(::new (S.Context) WeakAttr()); } @@ -811,7 +847,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; - } + } // weak_import only applies to variable & function declarations. bool isDef = false; @@ -830,7 +866,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Merge should handle any subsequent violations. if (isDef) { - S.Diag(Attr.getLoc(), + S.Diag(Attr.getLoc(), diag::warn_attribute_weak_import_invalid_on_definition) << "weak_import" << 2 /*variable and function*/; return; @@ -904,8 +940,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - // Currently, the dllexport attribute is ignored for inlined functions, - // unless the -fkeep-inline-functions flag has been used. Warning is emitted; + // Currently, the dllexport attribute is ignored for inlined functions, unless + // the -fkeep-inline-functions flag has been used. Warning is emitted; if (FD->isInline()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; @@ -947,15 +983,25 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Make sure that there is a string literal as the sections's single // argument. - StringLiteral *SE = - dyn_cast<StringLiteral>(static_cast<Expr *>(Attr.getArg(0))); + Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0)); + StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr); if (!SE) { - // FIXME - S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string); + S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section"; + return; + } + + std::string SectionStr(SE->getStrData(), SE->getByteLength()); + + // If the target wants to validate the section specifier, make it happen. + std::string Error = S.Context.Target.isValidSectionSpecifier(SectionStr); + if (Error.empty()) { + D->addAttr(::new (S.Context) SectionAttr(SectionStr)); return; } - D->addAttr(::new (S.Context) SectionAttr(std::string(SE->getStrData(), - SE->getByteLength()))); + + S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target) + << Error; + } static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1011,7 +1057,7 @@ static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + d->addAttr(::new (S.Context) NoThrowAttr()); } @@ -1021,7 +1067,7 @@ static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + d->addAttr(::new (S.Context) ConstAttr()); } @@ -1031,7 +1077,7 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + d->addAttr(::new (S.Context) PureAttr()); } @@ -1039,33 +1085,34 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Match gcc which ignores cleanup attrs when compiling C++. if (S.getLangOptions().CPlusPlus) return; - - if (!Attr.getParameterName()) { + + if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - + if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - + VarDecl *VD = dyn_cast<VarDecl>(d); - + if (!VD || !VD->hasLocalStorage()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup"; return; } - + // Look up the function - NamedDecl *CleanupDecl = S.LookupName(S.TUScope, Attr.getParameterName(), - Sema::LookupOrdinaryName); + NamedDecl *CleanupDecl + = S.LookupSingleName(S.TUScope, Attr.getParameterName(), + Sema::LookupOrdinaryName); if (!CleanupDecl) { S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) << Attr.getParameterName(); return; } - + FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl); if (!FD) { S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) << @@ -1078,24 +1125,24 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { Attr.getParameterName(); return; } - + // We're currently more strict than GCC about what function types we accept. // If this ever proves to be a problem it should be easy to fix. QualType Ty = S.Context.getPointerType(VD->getType()); QualType ParamTy = FD->getParamDecl(0)->getType(); if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) { - S.Diag(Attr.getLoc(), + S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_func_arg_incompatible_type) << Attr.getParameterName() << ParamTy << Ty; return; } - + d->addAttr(::new (S.Context) CleanupAttr(FD)); } -/// Handle __attribute__((format_arg((idx)))) attribute -/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { +/// Handle __attribute__((format_arg((idx)))) attribute based on +/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; @@ -1105,9 +1152,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << 0 /*function*/; return; } - // FIXME: in C++ the implicit 'this' function parameter also counts. - // this is needed in order to be compatible with GCC - // the index must start with 1. + // FIXME: in C++ the implicit 'this' function parameter also counts. this is + // needed in order to be compatible with GCC the index must start with 1. unsigned NumArgs = getFunctionOrMethodNumArgs(d); unsigned FirstIdx = 1; // checks for the 2nd argument @@ -1118,46 +1164,46 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { << "format" << 2 << IdxExpr->getSourceRange(); return; } - + if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) << "format" << 2 << IdxExpr->getSourceRange(); return; } - + unsigned ArgIdx = Idx.getZExtValue() - 1; - + // make sure the format string is really a string QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); - + bool not_nsstring_type = !isNSStringType(Ty, S.Context); if (not_nsstring_type && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || - !Ty->getAsPointerType()->getPointeeType()->isCharType())) { + !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { // FIXME: Should highlight the actual expression that has the wrong type. S.Diag(Attr.getLoc(), diag::err_format_attribute_not) - << (not_nsstring_type ? "a string type" : "an NSString") + << (not_nsstring_type ? "a string type" : "an NSString") << IdxExpr->getSourceRange(); return; - } + } Ty = getFunctionOrMethodResultType(d); if (!isNSStringType(Ty, S.Context) && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || - !Ty->getAsPointerType()->getPointeeType()->isCharType())) { + !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { // FIXME: Should highlight the actual expression that has the wrong type. S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not) - << (not_nsstring_type ? "string type" : "NSString") + << (not_nsstring_type ? "string type" : "NSString") << IdxExpr->getSourceRange(); return; - } - + } + d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue())); } -/// Handle __attribute__((format(type,idx,firstarg))) attributes -/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +/// Handle __attribute__((format(type,idx,firstarg))) attributes based on +/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!Attr.getParameterName()) { @@ -1177,9 +1223,6 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - // FIXME: in C++ the implicit 'this' function parameter also counts. - // this is needed in order to be compatible with GCC - // the index must start in 1 and the limit is numargs+1 unsigned NumArgs = getFunctionOrMethodNumArgs(d); unsigned FirstIdx = 1; @@ -1197,19 +1240,23 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { bool is_NSString = false; bool is_strftime = false; bool is_CFString = false; - + switch (FormatLen) { default: break; case 5: Supported = !memcmp(Format, "scanf", 5); break; case 6: Supported = !memcmp(Format, "printf", 6); break; - case 7: Supported = !memcmp(Format, "strfmon", 7); break; + case 7: Supported = !memcmp(Format, "printf0", 7) || + !memcmp(Format, "strfmon", 7) || + !memcmp(Format, "cmn_err", 7); break; case 8: Supported = (is_strftime = !memcmp(Format, "strftime", 8)) || (is_NSString = !memcmp(Format, "NSString", 8)) || + !memcmp(Format, "vcmn_err", 8) || + !memcmp(Format, "zcmn_err", 8) || (is_CFString = !memcmp(Format, "CFString", 8)); break; } - + if (!Supported) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "format" << Attr.getParameterName()->getName(); @@ -1225,6 +1272,16 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } + // FIXME: We should handle the implicit 'this' parameter in a more generic + // way that can be used for other arguments. + bool HasImplicitThisParam = false; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(d)) { + if (MD->isInstance()) { + HasImplicitThisParam = true; + NumArgs++; + } + } + if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) << "format" << 2 << IdxExpr->getSourceRange(); @@ -1233,7 +1290,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // FIXME: Do we need to bounds check? unsigned ArgIdx = Idx.getZExtValue() - 1; - + + if (HasImplicitThisParam) ArgIdx--; + // make sure the format string is really a string QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); @@ -1251,9 +1310,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_format_attribute_not) << "an NSString" << IdxExpr->getSourceRange(); return; - } + } } else if (!Ty->isPointerType() || - !Ty->getAsPointerType()->getPointeeType()->isCharType()) { + !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) { // FIXME: Should highlight the actual expression that has the wrong type. S.Diag(Attr.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange(); @@ -1321,7 +1380,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, } if (!RD->isDefinition()) { - S.Diag(Attr.getLoc(), + S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_not_definition); return; } @@ -1336,7 +1395,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, FieldDecl *FirstField = *Field; QualType FirstType = FirstField->getType(); if (FirstType->isFloatingType() || FirstType->isVectorType()) { - S.Diag(FirstField->getLocation(), + S.Diag(FirstField->getLocation(), diag::warn_transparent_union_attribute_floating); return; } @@ -1349,13 +1408,13 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, S.Context.getTypeAlign(FieldType) != FirstAlign) { // Warn if we drop the attribute. bool isSize = S.Context.getTypeSize(FieldType) != FirstSize; - unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType) + unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType) : S.Context.getTypeAlign(FieldType); - S.Diag(Field->getLocation(), + S.Diag(Field->getLocation(), diag::warn_transparent_union_attribute_field_size_align) << isSize << Field->getDeclName() << FieldBits; unsigned FirstBits = isSize? FirstSize : FirstAlign; - S.Diag(FirstField->getLocation(), + S.Diag(FirstField->getLocation(), diag::note_transparent_union_first_field_size_align) << isSize << FirstBits; return; @@ -1371,13 +1430,13 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - Expr *argExpr = static_cast<Expr *>(Attr.getArg(0)); - StringLiteral *SE = dyn_cast<StringLiteral>(argExpr); - + Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0)); + StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr); + // Make sure that there is a string literal as the annotation's single // argument. if (!SE) { - S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string); + S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(), @@ -1399,7 +1458,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) AlignedAttr(Align)); return; } - + Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Alignment(32); if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) { @@ -1408,7 +1467,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) { - S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two) + S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two) << alignmentExpr->getSourceRange(); return; } @@ -1416,13 +1475,12 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8)); } -/// HandleModeAttr - This attribute modifies the width of a decl with -/// primitive type. -/// -/// Despite what would be logical, the mode attribute is a decl attribute, -/// not a type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make -/// 'G' be HImode, not an intermediate pointer. +/// HandleModeAttr - This attribute modifies the width of a decl with primitive +/// type. /// +/// Despite what would be logical, the mode attribute is a decl attribute, not a +/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be +/// HImode, not an intermediate pointer. static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { // This attribute isn't documented, but glibc uses it. It changes // the width of an int or unsigned int to the specified size. @@ -1495,7 +1553,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - if (!OldTy->getAsBuiltinType() && !OldTy->isComplexType()) + if (!OldTy->getAs<BuiltinType>() && !OldTy->isComplexType()) S.Diag(Attr.getLoc(), diag::err_mode_not_primitive); else if (IntegerMode) { if (!OldTy->isIntegralType()) @@ -1581,7 +1639,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { cast<ValueDecl>(D)->setType(NewTy); } -static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() > 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; @@ -1593,24 +1651,24 @@ static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << 0 /*function*/; return; } - - d->addAttr(::new (S.Context) NodebugAttr()); + + d->addAttr(::new (S.Context) NoDebugAttr()); } -static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; } - - d->addAttr(::new (S.Context) NoinlineAttr()); + + d->addAttr(::new (S.Context) NoInlineAttr()); } static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1619,19 +1677,19 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - + FunctionDecl *Fn = dyn_cast<FunctionDecl>(d); if (Fn == 0) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; } - + if (!Fn->isInline()) { S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); return; } - + d->addAttr(::new (S.Context) GNUInlineAttr()); } @@ -1679,23 +1737,26 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, Sema &S) { QualType RetTy; - + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) RetTy = MD->getResultType(); else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) RetTy = FD->getResultType(); else { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 3 /* function or method */; + SourceLocation L = Attr.getLoc(); + S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(L, L) << Attr.getName() << 3 /* function or method */; return; } - - if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) { - S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type) - << Attr.getName(); - return; + + if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>() + || RetTy->getAs<ObjCObjectPointerType>())) { + SourceLocation L = Attr.getLoc(); + S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(L, L) << Attr.getName(); + return; } - + switch (Attr.getKind()) { default: assert(0 && "invalid ownership attribute"); @@ -1716,7 +1777,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it. -static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) { +static void ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) { if (Attr.isDeclspecAttribute()) // FIXME: Try to deal with __declspec attributes! return; @@ -1724,14 +1786,15 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break; case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: - // Ignore these, these are type attributes, handled by ProcessTypeAttributes. + // Ignore these, these are type attributes, handled by + // ProcessTypeAttributes. break; case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; - case AttributeList::AT_always_inline: + case AttributeList::AT_always_inline: HandleAlwaysInlineAttr (D, Attr, S); break; case AttributeList::AT_analyzer_noreturn: - HandleAnalyzerNoReturnAttr (D, Attr, S); break; + HandleAnalyzerNoReturnAttr (D, Attr, S); break; case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break; @@ -1746,6 +1809,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break; case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; + case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break; case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; @@ -1783,10 +1847,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break; case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break; case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break; - case AttributeList::AT_nodebug: HandleNodebugAttr (D, Attr, S); break; - case AttributeList::AT_noinline: HandleNoinlineAttr (D, Attr, S); break; + case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break; + case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break; case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break; - case AttributeList::IgnoredAttribute: + case AttributeList::IgnoredAttribute: case AttributeList::AT_no_instrument_function: // Interacts with -pg. // Just ignore break; @@ -1805,14 +1869,66 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *Attr } } +/// DeclClonePragmaWeak - clone existing decl (maybe definition), +/// #pragma weak needs a non-definition decl and source may not have one +NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { + assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND)); + NamedDecl *NewD = 0; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), + FD->getLocation(), DeclarationName(II), + FD->getType(), FD->getDeclaratorInfo()); + } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { + NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), + VD->getLocation(), II, + VD->getType(), VD->getDeclaratorInfo(), + VD->getStorageClass()); + } + return NewD; +} + +/// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak +/// applied to it, possibly with an alias. +void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { + if (W.getUsed()) return; // only do this once + W.setUsed(true); + if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) + IdentifierInfo *NDId = ND->getIdentifier(); + NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias()); + NewD->addAttr(::new (Context) AliasAttr(NDId->getName())); + NewD->addAttr(::new (Context) WeakAttr()); + WeakTopLevelDecl.push_back(NewD); + // FIXME: "hideous" code from Sema::LazilyCreateBuiltin + // to insert Decl at TU scope, sorry. + DeclContext *SavedContext = CurContext; + CurContext = Context.getTranslationUnitDecl(); + PushOnScopeChains(NewD, S); + CurContext = SavedContext; + } else { // just add weak to existing + ND->addAttr(::new (Context) WeakAttr()); + } +} + /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in /// it, apply them to D. This is a bit tricky because PD can have attributes /// specified in many different places, and we need to find and apply them all. void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { + // Handle #pragma weak + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + if (ND->hasLinkage()) { + WeakInfo W = WeakUndeclaredIdentifiers.lookup(ND->getIdentifier()); + if (W != WeakInfo()) { + // Identifier referenced by #pragma weak before it was declared + DeclApplyPragmaWeak(S, ND, W); + WeakUndeclaredIdentifiers[ND->getIdentifier()] = W; + } + } + } + // Apply decl attributes from the DeclSpec if present. if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes()) ProcessDeclAttributeList(S, D, Attrs); - + // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: // int *__attr__(x)** D; @@ -1820,7 +1936,7 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) ProcessDeclAttributeList(S, D, Attrs); - + // Finally, apply any attributes on the decl itself. if (const AttributeList *Attrs = PD.getAttributes()) ProcessDeclAttributeList(S, D, Attrs); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 75ceb19165550..acb2a67770285 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12,18 +12,20 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "SemaInherit.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include <algorithm> // for std::equal #include <map> +#include <set> using namespace clang; @@ -37,13 +39,13 @@ namespace { /// contains any ill-formed subexpressions. For example, this will /// diagnose the use of local variables or parameters within the /// default argument expression. - class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor + class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor : public StmtVisitor<CheckDefaultArgumentVisitor, bool> { Expr *DefaultArg; Sema *S; public: - CheckDefaultArgumentVisitor(Expr *defarg, Sema *s) + CheckDefaultArgumentVisitor(Expr *defarg, Sema *s) : DefaultArg(defarg), S(s) {} bool VisitExpr(Expr *Node); @@ -54,7 +56,7 @@ namespace { /// VisitExpr - Visit all of the children of this expression. bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) { bool IsInvalid = false; - for (Stmt::child_iterator I = Node->child_begin(), + for (Stmt::child_iterator I = Node->child_begin(), E = Node->child_end(); I != E; ++I) IsInvalid |= Visit(*I); return IsInvalid; @@ -74,7 +76,7 @@ namespace { // evaluated. Parameters of a function declared before a default // argument expression are in scope and can hide namespace and // class member names. - return S->Diag(DRE->getSourceRange().getBegin(), + return S->Diag(DRE->getSourceRange().getBegin(), diag::err_param_default_argument_references_param) << Param->getDeclName() << DefaultArg->getSourceRange(); } else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) { @@ -82,7 +84,7 @@ namespace { // Local variables shall not be used in default argument // expressions. if (VDecl->isBlockVarDecl()) - return S->Diag(DRE->getSourceRange().getBegin(), + return S->Diag(DRE->getSourceRange().getBegin(), diag::err_param_default_argument_references_local) << VDecl->getDeclName() << DefaultArg->getSourceRange(); } @@ -101,15 +103,48 @@ namespace { } } +bool +Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, + SourceLocation EqualLoc) { + QualType ParamType = Param->getType(); + + if (RequireCompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type)) { + Param->setInvalidDecl(); + return true; + } + + Expr *Arg = (Expr *)DefaultArg.get(); + + // C++ [dcl.fct.default]p5 + // A default argument expression is implicitly converted (clause + // 4) to the parameter type. The default argument expression has + // the same semantic constraints as the initializer expression in + // a declaration of a variable of the parameter type, using the + // copy-initialization semantics (8.5). + if (CheckInitializerTypes(Arg, ParamType, EqualLoc, + Param->getDeclName(), /*DirectInit=*/false)) + return true; + + Arg = MaybeCreateCXXExprWithTemporaries(Arg, /*DestroyTemps=*/false); + + // Okay: add the default argument to the parameter + Param->setDefaultArg(Arg); + + DefaultArg.release(); + + return false; +} + /// ActOnParamDefaultArgument - Check whether the default argument /// provided for a function parameter is well-formed. If so, attach it /// to the parameter declaration. void -Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, +Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, ExprArg defarg) { if (!param || !defarg.get()) return; - + ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); UnparsedDefaultArgLocs.erase(Param); @@ -124,25 +159,6 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, return; } - // C++ [dcl.fct.default]p5 - // A default argument expression is implicitly converted (clause - // 4) to the parameter type. The default argument expression has - // the same semantic constraints as the initializer expression in - // a declaration of a variable of the parameter type, using the - // copy-initialization semantics (8.5). - Expr *DefaultArgPtr = DefaultArg.get(); - bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType, - EqualLoc, - Param->getDeclName(), - /*DirectInit=*/false); - if (DefaultArgPtr != DefaultArg.get()) { - DefaultArg.take(); - DefaultArg.reset(DefaultArgPtr); - } - if (DefaultInitFailed) { - return; - } - // Check that the default argument is well-formed CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this); if (DefaultArgChecker.Visit(DefaultArg.get())) { @@ -150,27 +166,23 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, return; } - DefaultArgPtr = MaybeCreateCXXExprWithTemporaries(DefaultArg.take(), - /*DestroyTemps=*/false); - - // Okay: add the default argument to the parameter - Param->setDefaultArg(DefaultArgPtr); + SetParamDefaultArgument(Param, move(DefaultArg), EqualLoc); } /// ActOnParamUnparsedDefaultArgument - We've seen a default /// argument for a function parameter, but we can't parse it yet /// because we're inside a class definition. Note that this default /// argument will be parsed later. -void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param, +void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, SourceLocation ArgLoc) { if (!param) return; - + ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); if (Param) Param->setUnparsedDefaultArg(); - + UnparsedDefaultArgLocs[Param] = ArgLoc; } @@ -179,11 +191,11 @@ void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param, void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) { if (!param) return; - + ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); - + Param->setInvalidDecl(); - + UnparsedDefaultArgLocs.erase(Param); } @@ -230,7 +242,6 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { bool Invalid = false; // C++ [dcl.fct.default]p4: - // // For non-template functions, default arguments can be added in // later declarations of a function in the same // scope. Declarations in different scopes have completely @@ -242,25 +253,97 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { // arguments supplied in this or previous declarations. A // default argument shall not be redefined by a later // declaration (not even to the same value). + // + // C++ [dcl.fct.default]p6: + // Except for member functions of class templates, the default arguments + // in a member function definition that appears outside of the class + // definition are added to the set of default arguments provided by the + // member function declaration in the class definition. for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) { ParmVarDecl *OldParam = Old->getParamDecl(p); ParmVarDecl *NewParam = New->getParamDecl(p); - if(OldParam->getDefaultArg() && NewParam->getDefaultArg()) { - Diag(NewParam->getLocation(), + if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) { + Diag(NewParam->getLocation(), diag::err_param_default_argument_redefinition) - << NewParam->getDefaultArg()->getSourceRange(); - Diag(OldParam->getLocation(), diag::note_previous_definition); + << NewParam->getDefaultArgRange(); + + // Look for the function declaration where the default argument was + // actually written, which may be a declaration prior to Old. + for (FunctionDecl *Older = Old->getPreviousDeclaration(); + Older; Older = Older->getPreviousDeclaration()) { + if (!Older->getParamDecl(p)->hasDefaultArg()) + break; + + OldParam = Older->getParamDecl(p); + } + + Diag(OldParam->getLocation(), diag::note_previous_definition) + << OldParam->getDefaultArgRange(); Invalid = true; - } else if (OldParam->getDefaultArg()) { + } else if (OldParam->hasDefaultArg()) { // Merge the old default argument into the new parameter - NewParam->setDefaultArg(OldParam->getDefaultArg()); + if (OldParam->hasUninstantiatedDefaultArg()) + NewParam->setUninstantiatedDefaultArg( + OldParam->getUninstantiatedDefaultArg()); + else + NewParam->setDefaultArg(OldParam->getDefaultArg()); + } else if (NewParam->hasDefaultArg()) { + if (New->getDescribedFunctionTemplate()) { + // Paragraph 4, quoted above, only applies to non-template functions. + Diag(NewParam->getLocation(), + diag::err_param_default_argument_template_redecl) + << NewParam->getDefaultArgRange(); + Diag(Old->getLocation(), diag::note_template_prev_declaration) + << false; + } else if (New->getTemplateSpecializationKind() + != TSK_ImplicitInstantiation && + New->getTemplateSpecializationKind() != TSK_Undeclared) { + // C++ [temp.expr.spec]p21: + // Default function arguments shall not be specified in a declaration + // or a definition for one of the following explicit specializations: + // - the explicit specialization of a function template; + // - the explicit specialization of a member function template; + // - the explicit specialization of a member function of a class + // template where the class template specialization to which the + // member function specialization belongs is implicitly + // instantiated. + Diag(NewParam->getLocation(), diag::err_template_spec_default_arg) + << (New->getTemplateSpecializationKind() ==TSK_ExplicitSpecialization) + << New->getDeclName() + << NewParam->getDefaultArgRange(); + } else if (New->getDeclContext()->isDependentContext()) { + // C++ [dcl.fct.default]p6 (DR217): + // Default arguments for a member function of a class template shall + // be specified on the initial declaration of the member function + // within the class template. + // + // Reading the tea leaves a bit in DR217 and its reference to DR205 + // leads me to the conclusion that one cannot add default function + // arguments for an out-of-line definition of a member function of a + // dependent type. + int WhichKind = 2; + if (CXXRecordDecl *Record + = dyn_cast<CXXRecordDecl>(New->getDeclContext())) { + if (Record->getDescribedClassTemplate()) + WhichKind = 0; + else if (isa<ClassTemplatePartialSpecializationDecl>(Record)) + WhichKind = 1; + else + WhichKind = 2; + } + + Diag(NewParam->getLocation(), + diag::err_param_default_argument_member_template_redecl) + << WhichKind + << NewParam->getDefaultArgRange(); + } } } if (CheckEquivalentExceptionSpec( - Old->getType()->getAsFunctionProtoType(), Old->getLocation(), - New->getType()->getAsFunctionProtoType(), New->getLocation())) { + Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), + New->getType()->getAs<FunctionProtoType>(), New->getLocation())) { Invalid = true; } @@ -277,7 +360,7 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { // Find first parameter with a default argument for (p = 0; p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); - if (Param->getDefaultArg()) + if (Param->hasDefaultArg()) break; } @@ -288,19 +371,19 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { // declarations. A default argument shall not be redefined // by a later declaration (not even to the same value). unsigned LastMissingDefaultArg = 0; - for(; p < NumParams; ++p) { + for (; p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); - if (!Param->getDefaultArg()) { + if (!Param->hasDefaultArg()) { if (Param->isInvalidDecl()) /* We already complained about this parameter. */; else if (Param->getIdentifier()) - Diag(Param->getLocation(), + Diag(Param->getLocation(), diag::err_param_default_argument_missing_name) << Param->getIdentifier(); else - Diag(Param->getLocation(), + Diag(Param->getLocation(), diag::err_param_default_argument_missing); - + LastMissingDefaultArg = p; } } @@ -329,7 +412,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, const CXXScopeSpec *SS) { CXXRecordDecl *CurDecl; if (SS && SS->isSet() && !SS->isInvalid()) { - DeclContext *DC = computeDeclContext(*SS); + DeclContext *DC = computeDeclContext(*SS, true); CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC); } else CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); @@ -340,7 +423,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, return false; } -/// \brief Check the validity of a C++ base class specifier. +/// \brief Check the validity of a C++ base class specifier. /// /// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics /// and returns NULL otherwise. @@ -348,7 +431,7 @@ CXXBaseSpecifier * Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - QualType BaseType, + QualType BaseType, SourceLocation BaseLoc) { // C++ [class.union]p1: // A union shall not have base classes. @@ -359,7 +442,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, } if (BaseType->isDependentType()) - return new CXXBaseSpecifier(SpecifierRange, Virtual, + return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == RecordDecl::TK_class, Access, BaseType); @@ -379,16 +462,21 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // C++ [class.derived]p2: // The class-name in a base-specifier shall not be an incompletely // defined class. - if (RequireCompleteType(BaseLoc, BaseType, diag::err_incomplete_base_class, - SpecifierRange)) + if (RequireCompleteType(BaseLoc, BaseType, + PDiag(diag::err_incomplete_base_class) + << SpecifierRange)) return 0; - // If the base class is polymorphic, the new one is, too. - RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl(); + // If the base class is polymorphic or isn't empty, the new one is/isn't, too. + RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl(); assert(BaseDecl && "Record type has no declaration"); BaseDecl = BaseDecl->getDefinition(Context); assert(BaseDecl && "Base type is not incomplete, but has no definition"); - if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic()) + CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl); + assert(CXXBaseDecl && "Base type is not a C++ type"); + if (!CXXBaseDecl->isEmpty()) + Class->setEmpty(false); + if (CXXBaseDecl->isPolymorphic()) Class->setPolymorphic(true); // C++ [dcl.init.aggr]p1: @@ -400,33 +488,59 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // C++ [class.ctor]p5: // A constructor is trivial if its class has no virtual base classes. Class->setHasTrivialConstructor(false); + + // C++ [class.copy]p6: + // A copy constructor is trivial if its class has no virtual base classes. + Class->setHasTrivialCopyConstructor(false); + + // C++ [class.copy]p11: + // A copy assignment operator is trivial if its class has no virtual + // base classes. + Class->setHasTrivialCopyAssignment(false); + + // C++0x [meta.unary.prop] is_empty: + // T is a class type, but not a union type, with ... no virtual base + // classes + Class->setEmpty(false); } else { // C++ [class.ctor]p5: - // A constructor is trivial if all the direct base classes of its + // A constructor is trivial if all the direct base classes of its // class have trivial constructors. - Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)-> - hasTrivialConstructor()); + if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor()) + Class->setHasTrivialConstructor(false); + + // C++ [class.copy]p6: + // A copy constructor is trivial if all the direct base classes of its + // class have trivial copy constructors. + if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor()) + Class->setHasTrivialCopyConstructor(false); + + // C++ [class.copy]p11: + // A copy assignment operator is trivial if all the direct base classes + // of its class have trivial copy assignment operators. + if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment()) + Class->setHasTrivialCopyAssignment(false); } // C++ [class.ctor]p3: // A destructor is trivial if all the direct base classes of its class // have trivial destructors. - Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)-> - hasTrivialDestructor()); - + if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor()) + Class->setHasTrivialDestructor(false); + // Create the base specifier. // FIXME: Allocate via ASTContext? - return new CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == RecordDecl::TK_class, + return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, + Class->getTagKind() == RecordDecl::TK_class, Access, BaseType); } /// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is /// one entry in the base class list of a class specifier, for -/// example: -/// class foo : public bar, virtual private baz { +/// example: +/// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. -Sema::BaseResult +Sema::BaseResult Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, TypeTy *basetype, SourceLocation BaseLoc) { @@ -435,12 +549,12 @@ Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, AdjustDeclIfTemplate(classdecl); CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>()); - QualType BaseType = QualType::getFromOpaquePtr(basetype); + QualType BaseType = GetTypeFromParser(basetype); if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, Virtual, Access, BaseType, BaseLoc)) return BaseSpec; - + return true; } @@ -461,7 +575,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, unsigned NumGoodBases = 0; bool Invalid = false; for (unsigned idx = 0; idx < NumBases; ++idx) { - QualType NewBaseType + QualType NewBaseType = Context.getCanonicalType(Bases[idx]->getType()); NewBaseType = NewBaseType.getUnqualifiedType(); @@ -476,7 +590,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, // Delete the duplicate base class specifier; we're going to // overwrite its pointer later. - delete Bases[idx]; + Context.Deallocate(Bases[idx]); Invalid = true; } else { @@ -492,7 +606,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, // Delete the remaining (good) base class specifiers, since their // data has been copied into the CXXRecordDecl. for (unsigned idx = 0; idx < NumGoodBases; ++idx) - delete Bases[idx]; + Context.Deallocate(Bases[idx]); return Invalid; } @@ -500,7 +614,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, /// ActOnBaseSpecifiers - Attach the given base specifiers to the /// class, after checking whether there are any duplicate base /// classes. -void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, +void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, unsigned NumBases) { if (!ClassDecl || !Bases || !NumBases) return; @@ -510,6 +624,139 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, (CXXBaseSpecifier**)(Bases), NumBases); } +/// \brief Determine whether the type \p Derived is a C++ class that is +/// derived from the type \p Base. +bool Sema::IsDerivedFrom(QualType Derived, QualType Base) { + if (!getLangOptions().CPlusPlus) + return false; + + const RecordType *DerivedRT = Derived->getAs<RecordType>(); + if (!DerivedRT) + return false; + + const RecordType *BaseRT = Base->getAs<RecordType>(); + if (!BaseRT) + return false; + + CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl()); + CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl()); + return DerivedRD->isDerivedFrom(BaseRD); +} + +/// \brief Determine whether the type \p Derived is a C++ class that is +/// derived from the type \p Base. +bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { + if (!getLangOptions().CPlusPlus) + return false; + + const RecordType *DerivedRT = Derived->getAs<RecordType>(); + if (!DerivedRT) + return false; + + const RecordType *BaseRT = Base->getAs<RecordType>(); + if (!BaseRT) + return false; + + CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl()); + CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl()); + return DerivedRD->isDerivedFrom(BaseRD, Paths); +} + +/// 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 +/// that all of the base classes are accessible). Returns true +/// and emits a diagnostic if the code is ill-formed, returns false +/// otherwise. Loc is the location where this routine should point to +/// if there is an error, and Range is the source range to highlight +/// if there is an error. +bool +Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + unsigned AmbigiousBaseConvID, + SourceLocation Loc, SourceRange Range, + DeclarationName Name) { + // First, determine whether the path from Derived to Base is + // ambiguous. This is slightly more expensive than checking whether + // the Derived to Base conversion exists, because here we need to + // explore multiple paths to determine if there is an ambiguity. + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths); + assert(DerivationOkay && + "Can only be used with a derived-to-base conversion"); + (void)DerivationOkay; + + if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { + // Check that the base class can be accessed. + return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc, + Name); + } + + // We know that the derived-to-base conversion is ambiguous, and + // we're going to produce a diagnostic. Perform the derived-to-base + // search just one more time to compute all of the possible paths so + // that we can print them out. This is more expensive than any of + // the previous derived-to-base checks we've done, but at this point + // performance isn't as much of an issue. + Paths.clear(); + Paths.setRecordingPaths(true); + bool StillOkay = IsDerivedFrom(Derived, Base, Paths); + assert(StillOkay && "Can only be used with a derived-to-base conversion"); + (void)StillOkay; + + // Build up a textual representation of the ambiguous paths, e.g., + // D -> B -> A, that will be used to illustrate the ambiguous + // conversions in the diagnostic. We only print one of the paths + // to each base class subobject. + std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); + + Diag(Loc, AmbigiousBaseConvID) + << Derived << Base << PathDisplayStr << Range << Name; + return true; +} + +bool +Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, + SourceLocation Loc, SourceRange Range) { + return CheckDerivedToBaseConversion(Derived, Base, + diag::err_conv_to_inaccessible_base, + diag::err_ambiguous_derived_to_base_conv, + Loc, Range, DeclarationName()); +} + + +/// @brief Builds a string representing ambiguous paths from a +/// specific derived class to different subobjects of the same base +/// class. +/// +/// This function builds a string that can be used in error messages +/// to show the different paths that one can take through the +/// inheritance hierarchy to go from the derived class to different +/// subobjects of a base class. The result looks something like this: +/// @code +/// struct D -> struct B -> struct A +/// struct D -> struct C -> struct A +/// @endcode +std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { + std::string PathDisplayStr; + std::set<unsigned> DisplayedPaths; + for (CXXBasePaths::paths_iterator Path = Paths.begin(); + Path != Paths.end(); ++Path) { + if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) { + // We haven't displayed a path to this particular base + // class subobject yet. + PathDisplayStr += "\n "; + PathDisplayStr += Context.getTypeDeclType(Paths.getOrigin()).getAsString(); + for (CXXBasePath::const_iterator Element = Path->begin(); + Element != Path->end(); ++Element) + PathDisplayStr += " -> " + Element->Base->getType().getAsString(); + } + } + + return PathDisplayStr; +} + //===----------------------------------------------------------------------===// // C++ class member Handling //===----------------------------------------------------------------------===// @@ -520,6 +767,7 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, /// any. Sema::DeclPtrTy Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, ExprTy *InitExpr, bool Deleted) { const DeclSpec &DS = D.getDeclSpec(); DeclarationName Name = GetNameForDeclarator(D); @@ -529,6 +777,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool isFunc = D.isFunctionDeclarator(); + assert(!DS.isFriendSpecified()); + // C++ 9.2p6: A member shall not be declared to have automatic storage // duration (auto, register) or with the extern storage-class-specifier. // C++ 7.1.1p8: The mutable specifier can be applied only to names of class @@ -546,7 +796,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function); else Diag(DS.getThreadSpecLoc(), diag::err_mutable_function); - + // FIXME: It would be nicer if the keyword was ignored only for this // declarator. Otherwise we could get follow-up errors. D.getMutableDeclSpec().ClearStorageClassSpecs(); @@ -585,7 +835,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // typedef int f(); // f a; // - QualType TDType = QualType::getFromOpaquePtr(DS.getTypeRep()); + QualType TDType = GetTypeFromParser(DS.getTypeRep()); isFunc = TDType->isFunctionType(); } @@ -595,11 +845,13 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Decl *Member; if (isInstField) { + // FIXME: Check for template parameters! Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, AS); assert(Member && "HandleField never returns null"); } else { - Member = ActOnDeclarator(S, D).getAs<Decl>(); + Member = HandleDeclarator(S, D, move(TemplateParameterLists), false) + .getAs<Decl>(); if (!Member) { if (BitWidth) DeleteExpr(BitWidth); return DeclPtrTy(); @@ -622,16 +874,21 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // A function typedef ("typedef int f(); f a;"). // C++ 9.6p3: A bit-field shall have integral or enumeration type. Diag(Loc, diag::err_not_integral_type_bitfield) - << Name << cast<ValueDecl>(Member)->getType() + << Name << cast<ValueDecl>(Member)->getType() << BitWidth->getSourceRange(); } - + DeleteExpr(BitWidth); BitWidth = 0; Member->setInvalidDecl(); } Member->setAccess(AS); + + // If we have declared a member function template, set the access of the + // templated declaration as well. + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member)) + FunTmpl->getTemplatedDecl()->setAccess(AS); } assert((Name || isInstField) && "No identifier for non-field ?"); @@ -649,7 +906,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } /// ActOnMemInitializer - Handle a C++ member initializer. -Sema::MemInitResult +Sema::MemInitResult Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, Scope *S, const CXXScopeSpec &SS, @@ -662,8 +919,10 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, SourceLocation RParenLoc) { if (!ConstructorD) return true; - - CXXConstructorDecl *Constructor + + AdjustDeclIfTemplate(ConstructorD); + + CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ConstructorD.getAs<Decl>()); if (!Constructor) { // The user wrote a constructor initializer on a function that is @@ -688,141 +947,657 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!SS.getScopeRep() && !TemplateTypeTy) { // Look for a member, first. FieldDecl *Member = 0; - DeclContext::lookup_result Result + DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); if (Result.first != Result.second) Member = dyn_cast<FieldDecl>(*Result.first); // FIXME: Handle members of an anonymous union. - if (Member) { - // FIXME: Perform direct initialization of the member. - return new CXXBaseOrMemberInitializer(Member, (Expr **)Args, NumArgs, - IdLoc); - } + if (Member) + return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, + RParenLoc); } // It didn't name a member, so see if it names a class. - TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy + TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy : getTypeName(*MemberOrBase, IdLoc, S, &SS); if (!BaseTy) return Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc, RParenLoc); - - QualType BaseType = QualType::getFromOpaquePtr(BaseTy); - if (!BaseType->isRecordType() && !BaseType->isDependentType()) - return Diag(IdLoc, diag::err_base_init_does_not_name_class) - << BaseType << SourceRange(IdLoc, RParenLoc); - // C++ [class.base.init]p2: - // [...] Unless the mem-initializer-id names a nonstatic data - // member of the constructor’s class or a direct or virtual base - // of that class, the mem-initializer is ill-formed. A - // mem-initializer-list can initialize a base class using any - // name that denotes that base class type. - - // First, check for a direct base class. - const CXXBaseSpecifier *DirectBaseSpec = 0; - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - if (Context.getCanonicalType(BaseType).getUnqualifiedType() == - Context.getCanonicalType(Base->getType()).getUnqualifiedType()) { - // We found a direct base of this type. That's what we're - // initializing. - DirectBaseSpec = &*Base; - break; + QualType BaseType = GetTypeFromParser(BaseTy); + + return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc, + RParenLoc, ClassDecl); +} + +Sema::MemInitResult +Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc) { + bool HasDependentArg = false; + for (unsigned i = 0; i < NumArgs; i++) + HasDependentArg |= Args[i]->isTypeDependent(); + + CXXConstructorDecl *C = 0; + QualType FieldType = Member->getType(); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (FieldType->isDependentType()) { + // Can't check init for dependent type. + } else if (FieldType->getAs<RecordType>()) { + if (!HasDependentArg) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + + C = PerformInitializationByConstructor(FieldType, + MultiExprArg(*this, + (void**)Args, + NumArgs), + IdLoc, + SourceRange(IdLoc, RParenLoc), + Member->getDeclName(), IK_Direct, + ConstructorArgs); + + if (C) { + // Take over the constructor arguments as our own. + NumArgs = ConstructorArgs.size(); + Args = (Expr **)ConstructorArgs.take(); + } } + } else if (NumArgs != 1 && NumArgs != 0) { + return Diag(IdLoc, diag::err_mem_initializer_mismatch) + << Member->getDeclName() << SourceRange(IdLoc, RParenLoc); + } else if (!HasDependentArg) { + Expr *NewExp; + if (NumArgs == 0) { + if (FieldType->isReferenceType()) { + Diag(IdLoc, diag::err_null_intialized_reference_member) + << Member->getDeclName(); + return Diag(Member->getLocation(), diag::note_declared_at); + } + NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc); + NumArgs = 1; + } + else + NewExp = (Expr*)Args[0]; + if (PerformCopyInitialization(NewExp, FieldType, "passing")) + return true; + Args[0] = NewExp; } - - // Check for a virtual base class. - // FIXME: We might be able to short-circuit this if we know in advance that - // there are no virtual bases. - const CXXBaseSpecifier *VirtualBaseSpec = 0; - if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { - // We haven't found a base yet; search the class hierarchy for a - // virtual base class. - BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) { - for (BasePaths::paths_iterator Path = Paths.begin(); - Path != Paths.end(); ++Path) { - if (Path->back().Base->isVirtual()) { - VirtualBaseSpec = Path->back().Base; - break; + // FIXME: Perform direct initialization of the member. + return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, + NumArgs, C, IdLoc, RParenLoc); +} + +Sema::MemInitResult +Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, + unsigned NumArgs, SourceLocation IdLoc, + SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) { + bool HasDependentArg = false; + for (unsigned i = 0; i < NumArgs; i++) + HasDependentArg |= Args[i]->isTypeDependent(); + + if (!BaseType->isDependentType()) { + if (!BaseType->isRecordType()) + return Diag(IdLoc, diag::err_base_init_does_not_name_class) + << BaseType << SourceRange(IdLoc, RParenLoc); + + // C++ [class.base.init]p2: + // [...] Unless the mem-initializer-id names a nonstatic data + // member of the constructor’s class or a direct or virtual base + // of that class, the mem-initializer is ill-formed. A + // mem-initializer-list can initialize a base class using any + // name that denotes that base class type. + + // First, check for a direct base class. + const CXXBaseSpecifier *DirectBaseSpec = 0; + for (CXXRecordDecl::base_class_const_iterator Base = + ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { + if (Context.getCanonicalType(BaseType).getUnqualifiedType() == + Context.getCanonicalType(Base->getType()).getUnqualifiedType()) { + // We found a direct base of this type. That's what we're + // initializing. + DirectBaseSpec = &*Base; + break; + } + } + + // Check for a virtual base class. + // FIXME: We might be able to short-circuit this if we know in advance that + // there are no virtual bases. + const CXXBaseSpecifier *VirtualBaseSpec = 0; + if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { + // We haven't found a base yet; search the class hierarchy for a + // virtual base class. + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) { + for (CXXBasePaths::paths_iterator Path = Paths.begin(); + Path != Paths.end(); ++Path) { + if (Path->back().Base->isVirtual()) { + VirtualBaseSpec = Path->back().Base; + break; + } } } } + + // C++ [base.class.init]p2: + // If a mem-initializer-id is ambiguous because it designates both + // a direct non-virtual base class and an inherited virtual base + // class, the mem-initializer is ill-formed. + if (DirectBaseSpec && VirtualBaseSpec) + return Diag(IdLoc, diag::err_base_init_direct_and_virtual) + << BaseType << SourceRange(IdLoc, RParenLoc); + // 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 + // mem-initializer is ill-formed. + if (!DirectBaseSpec && !VirtualBaseSpec) + return Diag(IdLoc, diag::err_not_direct_base_or_virtual) + << BaseType << ClassDecl->getNameAsCString() + << SourceRange(IdLoc, RParenLoc); } - // C++ [base.class.init]p2: - // If a mem-initializer-id is ambiguous because it designates both - // a direct non-virtual base class and an inherited virtual base - // class, the mem-initializer is ill-formed. - if (DirectBaseSpec && VirtualBaseSpec) - return Diag(IdLoc, diag::err_base_init_direct_and_virtual) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); - // 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 - // mem-initializer is ill-formed. - if (!DirectBaseSpec && !VirtualBaseSpec) - return Diag(IdLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() - << SourceRange(IdLoc, RParenLoc); - + CXXConstructorDecl *C = 0; + if (!BaseType->isDependentType() && !HasDependentArg) { + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(BaseType)); + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + + C = PerformInitializationByConstructor(BaseType, + MultiExprArg(*this, + (void**)Args, NumArgs), + IdLoc, SourceRange(IdLoc, RParenLoc), + Name, IK_Direct, + ConstructorArgs); + if (C) { + // Take over the constructor arguments as our own. + NumArgs = ConstructorArgs.size(); + Args = (Expr **)ConstructorArgs.take(); + } + } + + return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, + NumArgs, C, IdLoc, RParenLoc); +} + +void +Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers, + llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, + llvm::SmallVectorImpl<FieldDecl *>&Fields) { + // We need to build the initializer AST according to order of construction + // and not what user specified in the Initializers list. + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext()); + llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; + llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; + bool HasDependentBaseInit = false; + + for (unsigned i = 0; i < NumInitializers; i++) { + CXXBaseOrMemberInitializer *Member = Initializers[i]; + if (Member->isBaseInitializer()) { + if (Member->getBaseClass()->isDependentType()) + HasDependentBaseInit = true; + AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; + } else { + AllBaseFields[Member->getMember()] = Member; + } + } + + if (HasDependentBaseInit) { + // FIXME. This does not preserve the ordering of the initializers. + // Try (with -Wreorder) + // template<class X> struct A {}; + // template<class X> struct B : A<X> { + // B() : x1(10), A<X>() {} + // int x1; + // }; + // B<int> x; + // On seeing one dependent type, we should essentially exit this routine + // while preserving user-declared initializer list. When this routine is + // called during instantiatiation process, this routine will rebuild the + // oderdered initializer list correctly. + + // If we have a dependent base initialization, we can't determine the + // association between initializers and bases; just dump the known + // initializers into the list, and don't try to deal with other bases. + for (unsigned i = 0; i < NumInitializers; i++) { + CXXBaseOrMemberInitializer *Member = Initializers[i]; + if (Member->isBaseInitializer()) + AllToInit.push_back(Member); + } + } else { + // Push virtual bases before others. + for (CXXRecordDecl::base_class_iterator VBase = + ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); VBase != E; ++VBase) { + if (VBase->getType()->isDependentType()) + continue; + if (CXXBaseOrMemberInitializer *Value = + AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { + CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) + MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); + AllToInit.push_back(Value); + } + else { + CXXRecordDecl *VBaseDecl = + cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null"); + CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); + if (!Ctor) + Bases.push_back(VBase); + else + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + + CXXBaseOrMemberInitializer *Member = + new (Context) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0, + Ctor, + SourceLocation(), + SourceLocation()); + AllToInit.push_back(Member); + } + } + + 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. + if (Base->isVirtual()) + continue; + // Skip dependent types. + if (Base->getType()->isDependentType()) + continue; + if (CXXBaseOrMemberInitializer *Value = + AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { + CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) + MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); + AllToInit.push_back(Value); + } + else { + CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context); + if (!Ctor) + Bases.push_back(Base); + else + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + + CXXBaseOrMemberInitializer *Member = + new (Context) CXXBaseOrMemberInitializer(Base->getType(), 0, 0, + BaseDecl->getDefaultConstructor(Context), + SourceLocation(), + SourceLocation()); + AllToInit.push_back(Member); + } + } + } + + // non-static data members. + 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)) { + QualType FT = (*Field)->getType(); + if (const RecordType* RT = FT->getAs<RecordType>()) { + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RT->getDecl()); + assert(FieldRecDecl && "setBaseOrMemberInitializers - BaseDecl null"); + if (CXXConstructorDecl *Ctor = + FieldRecDecl->getDefaultConstructor(Context)) + MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); + } + AllToInit.push_back(Value); + continue; + } + + QualType FT = Context.getBaseElementType((*Field)->getType()); + if (const RecordType* RT = FT->getAs<RecordType>()) { + CXXConstructorDecl *Ctor = + cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context); + if (!Ctor && !FT->isDependentType()) + Fields.push_back(*Field); + CXXBaseOrMemberInitializer *Member = + new (Context) CXXBaseOrMemberInitializer((*Field), 0, 0, + Ctor, + SourceLocation(), + SourceLocation()); + AllToInit.push_back(Member); + if (Ctor) + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) { + Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) + << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); + Diag((*Field)->getLocation(), diag::note_declared_at); + } + } + else if (FT->isReferenceType()) { + Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) + << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName(); + Diag((*Field)->getLocation(), diag::note_declared_at); + } + else if (FT.isConstQualified()) { + Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) + << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); + Diag((*Field)->getLocation(), diag::note_declared_at); + } + } + + NumInitializers = AllToInit.size(); + if (NumInitializers > 0) { + Constructor->setNumBaseOrMemberInitializers(NumInitializers); + CXXBaseOrMemberInitializer **baseOrMemberInitializers = + new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; + + Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); + for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) + baseOrMemberInitializers[Idx] = AllToInit[Idx]; + } +} + +void +Sema::BuildBaseOrMemberInitializers(ASTContext &C, + CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers + ) { + llvm::SmallVector<CXXBaseSpecifier *, 4>Bases; + llvm::SmallVector<FieldDecl *, 4>Members; + + setBaseOrMemberInitializers(Constructor, + Initializers, NumInitializers, Bases, Members); + for (unsigned int i = 0; i < Bases.size(); i++) + Diag(Bases[i]->getSourceRange().getBegin(), + diag::err_missing_default_constructor) << 0 << Bases[i]->getType(); + for (unsigned int i = 0; i < Members.size(); i++) + Diag(Members[i]->getLocation(), diag::err_missing_default_constructor) + << 1 << Members[i]->getType(); +} + +static void *GetKeyForTopLevelField(FieldDecl *Field) { + // For anonymous unions, use the class declaration as the key. + if (const RecordType *RT = Field->getType()->getAs<RecordType>()) { + if (RT->getDecl()->isAnonymousStructOrUnion()) + return static_cast<void *>(RT->getDecl()); + } + return static_cast<void *>(Field); +} + +static void *GetKeyForBase(QualType BaseType) { + if (const RecordType *RT = BaseType->getAs<RecordType>()) + return (void *)RT; + + assert(0 && "Unexpected base type!"); + return 0; +} - return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs, - IdLoc); +static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, + bool MemberMaybeAnon = false) { + // For fields injected into the class via declaration of an anonymous union, + // use its anonymous union class declaration as the unique key. + if (Member->isMemberInitializer()) { + FieldDecl *Field = Member->getMember(); + + // After BuildBaseOrMemberInitializers call, Field is the anonymous union + // data member of the class. Data member used in the initializer list is + // in AnonUnionMember field. + if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) + Field = Member->getAnonUnionMember(); + if (Field->getDeclContext()->isRecord()) { + RecordDecl *RD = cast<RecordDecl>(Field->getDeclContext()); + if (RD->isAnonymousStructOrUnion()) + return static_cast<void *>(RD); + } + return static_cast<void *>(Field); + } + + return GetKeyForBase(QualType(Member->getBaseClass(), 0)); } -void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, +void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits) { if (!ConstructorDecl) return; - - CXXConstructorDecl *Constructor + + AdjustDeclIfTemplate(ConstructorDecl); + + CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>()); - + if (!Constructor) { Diag(ColonLoc, diag::err_only_constructors_take_base_inits); return; } - llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members; - bool err = false; + + if (!Constructor->isDependentContext()) { + llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members; + bool err = false; + for (unsigned i = 0; i < NumMemInits; i++) { + CXXBaseOrMemberInitializer *Member = + static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]); + void *KeyToMember = GetKeyForMember(Member); + CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; + if (!PrevMember) { + PrevMember = Member; + continue; + } + if (FieldDecl *Field = Member->getMember()) + Diag(Member->getSourceLocation(), + diag::error_multiple_mem_initialization) + << Field->getNameAsString(); + else { + Type *BaseClass = Member->getBaseClass(); + assert(BaseClass && "ActOnMemInitializers - neither field or base"); + Diag(Member->getSourceLocation(), + diag::error_multiple_base_initialization) + << QualType(BaseClass, 0); + } + Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) + << 0; + err = true; + } + + if (err) + return; + } + + BuildBaseOrMemberInitializers(Context, Constructor, + reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits), + NumMemInits); + + if (Constructor->isDependentContext()) + return; + + if (Diags.getDiagnosticLevel(diag::warn_base_initialized) == + Diagnostic::Ignored && + Diags.getDiagnosticLevel(diag::warn_field_initialized) == + Diagnostic::Ignored) + return; + + // Also issue warning if order of ctor-initializer list does not match order + // of 1) base class declarations and 2) order of non-static data members. + llvm::SmallVector<const void*, 32> AllBaseOrMembers; + + CXXRecordDecl *ClassDecl + = cast<CXXRecordDecl>(Constructor->getDeclContext()); + // Push virtual bases before others. + for (CXXRecordDecl::base_class_iterator VBase = + ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); VBase != E; ++VBase) + AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType())); + + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) { + // Virtuals are alread in the virtual base list and are constructed + // first. + if (Base->isVirtual()) + continue; + AllBaseOrMembers.push_back(GetKeyForBase(Base->getType())); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + E = ClassDecl->field_end(); Field != E; ++Field) + AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field)); + + int Last = AllBaseOrMembers.size(); + int curIndex = 0; + CXXBaseOrMemberInitializer *PrevMember = 0; for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = + CXXBaseOrMemberInitializer *Member = static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]); - void *KeyToMember = Member->getBaseOrMember(); - // For fields injected into the class via declaration of an anonymous union, - // use its anonymous union class declaration as the unique key. - if (FieldDecl *Field = Member->getMember()) - if (Field->getDeclContext()->isRecord() && - cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()) - KeyToMember = static_cast<void *>(Field->getDeclContext()); - CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; - if (!PrevMember) { - PrevMember = Member; - continue; + void *MemberInCtorList = GetKeyForMember(Member, true); + + for (; curIndex < Last; curIndex++) + if (MemberInCtorList == AllBaseOrMembers[curIndex]) + break; + if (curIndex == Last) { + assert(PrevMember && "Member not in member list?!"); + // Initializer as specified in ctor-initializer list is out of order. + // Issue a warning diagnostic. + if (PrevMember->isBaseInitializer()) { + // Diagnostics is for an initialized base class. + Type *BaseClass = PrevMember->getBaseClass(); + Diag(PrevMember->getSourceLocation(), + diag::warn_base_initialized) + << QualType(BaseClass, 0); + } else { + FieldDecl *Field = PrevMember->getMember(); + Diag(PrevMember->getSourceLocation(), + diag::warn_field_initialized) + << Field->getNameAsString(); + } + // Also the note! + if (FieldDecl *Field = Member->getMember()) + Diag(Member->getSourceLocation(), + diag::note_fieldorbase_initialized_here) << 0 + << Field->getNameAsString(); + else { + Type *BaseClass = Member->getBaseClass(); + Diag(Member->getSourceLocation(), + diag::note_fieldorbase_initialized_here) << 1 + << QualType(BaseClass, 0); + } + for (curIndex = 0; curIndex < Last; curIndex++) + if (MemberInCtorList == AllBaseOrMembers[curIndex]) + break; } - if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::error_multiple_mem_initialization) - << Field->getNameAsString(); - else { - Type *BaseClass = Member->getBaseClass(); - assert(BaseClass && "ActOnMemInitializers - neither field or base"); - Diag(Member->getSourceLocation(), - diag::error_multiple_base_initialization) - << BaseClass->getDesugaredType(true); + PrevMember = Member; + } +} + +void +Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) { + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext()); + llvm::SmallVector<uintptr_t, 32> AllToDestruct; + + for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); VBase != E; ++VBase) { + if (VBase->getType()->isDependentType()) + continue; + // Skip over virtual bases which have trivial destructors. + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context)) + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast<CXXDestructorDecl*>(Dtor)); + + uintptr_t Member = + reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr()) + | CXXDestructorDecl::VBASE; + AllToDestruct.push_back(Member); + } + for (CXXRecordDecl::base_class_iterator Base = + ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) { + if (Base->isVirtual()) + continue; + if (Base->getType()->isDependentType()) + continue; + // Skip over virtual bases which have trivial destructors. + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context)) + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast<CXXDestructorDecl*>(Dtor)); + uintptr_t Member = + reinterpret_cast<uintptr_t>(Base->getType().getTypePtr()) + | CXXDestructorDecl::DRCTNONVBASE; + AllToDestruct.push_back(Member); + } + + // non-static data members. + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + E = ClassDecl->field_end(); Field != E; ++Field) { + QualType FieldType = Context.getBaseElementType((*Field)->getType()); + + if (const RecordType* RT = FieldType->getAs<RecordType>()) { + // Skip over virtual bases which have trivial destructors. + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) + continue; + if (const CXXDestructorDecl *Dtor = + FieldClassDecl->getDestructor(Context)) + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast<CXXDestructorDecl*>(Dtor)); + uintptr_t Member = reinterpret_cast<uintptr_t>(*Field); + AllToDestruct.push_back(Member); } - Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) - << 0; - err = true; } - if (!err) - Constructor->setBaseOrMemberInitializers(Context, - reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits), - NumMemInits); + + unsigned NumDestructions = AllToDestruct.size(); + if (NumDestructions > 0) { + Destructor->setNumBaseOrMemberDestructions(NumDestructions); + uintptr_t *BaseOrMemberDestructions = + new (Context) uintptr_t [NumDestructions]; + // Insert in reverse order. + for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx) + BaseOrMemberDestructions[i++] = AllToDestruct[Idx]; + Destructor->setBaseOrMemberDestructions(BaseOrMemberDestructions); + } +} + +void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { + if (!CDtorDecl) + return; + + AdjustDeclIfTemplate(CDtorDecl); + + if (CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>())) + BuildBaseOrMemberInitializers(Context, + Constructor, + (CXXBaseOrMemberInitializer **)0, 0); } namespace { @@ -836,58 +1611,58 @@ namespace { private: MethodList Methods; - + void Collect(const CXXRecordDecl* RD, MethodList& Methods); - + public: - PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD) + PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD) : Context(Ctx) { - + MethodList List; Collect(RD, List); - + // Copy the temporary list to methods, and make sure to ignore any // null entries. for (size_t i = 0, e = List.size(); i != e; ++i) { if (List[i]) Methods.push_back(List[i]); - } + } } - + bool empty() const { return Methods.empty(); } - + MethodList::const_iterator methods_begin() { return Methods.begin(); } MethodList::const_iterator methods_end() { return Methods.end(); } }; - - void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD, + + void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD, MethodList& Methods) { // First, collect the pure virtual methods for the base classes. for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { - if (const RecordType *RT = Base->getType()->getAsRecordType()) { + if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); if (BaseDecl && BaseDecl->isAbstract()) Collect(BaseDecl, Methods); } } - + // Next, zero out any pure virtual methods that this class overrides. typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy; - + MethodSetTy OverriddenMethods; size_t MethodsSize = Methods.size(); - for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end(); + for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end(); i != e; ++i) { // Traverse the record, looking for methods. if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) { - // If the method is pre virtual, add it to the methods vector. + // If the method is pure virtual, add it to the methods vector. if (MD->isPure()) { Methods.push_back(MD); continue; } - + // Otherwise, record all the overridden methods in our set. for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { @@ -896,82 +1671,92 @@ namespace { } } } - - // Now go through the methods and zero out all the ones we know are + + // Now go through the methods and zero out all the ones we know are // overridden. for (size_t i = 0, e = MethodsSize; i != e; ++i) { if (OverriddenMethods.count(Methods[i])) Methods[i] = 0; } - + } } -bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, + +bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, AbstractDiagSelID SelID, const CXXRecordDecl *CurrentRD) { - + if (SelID == -1) + return RequireNonAbstractType(Loc, T, + PDiag(DiagID), CurrentRD); + else + return RequireNonAbstractType(Loc, T, + PDiag(DiagID) << SelID, CurrentRD); +} + +bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD, + const CXXRecordDecl *CurrentRD) { if (!getLangOptions().CPlusPlus) return false; - + if (const ArrayType *AT = Context.getAsArrayType(T)) - return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID, + return RequireNonAbstractType(Loc, AT->getElementType(), PD, CurrentRD); - - if (const PointerType *PT = T->getAsPointerType()) { + + if (const PointerType *PT = T->getAs<PointerType>()) { // Find the innermost pointer type. - while (const PointerType *T = PT->getPointeeType()->getAsPointerType()) + while (const PointerType *T = PT->getPointeeType()->getAs<PointerType>()) PT = T; - + if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType())) - return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID, - CurrentRD); + return RequireNonAbstractType(Loc, AT->getElementType(), PD, CurrentRD); } - - const RecordType *RT = T->getAsRecordType(); + + const RecordType *RT = T->getAs<RecordType>(); if (!RT) return false; - + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); if (!RD) return false; if (CurrentRD && CurrentRD != RD) return false; - + if (!RD->isAbstract()) return false; - - Diag(Loc, DiagID) << RD->getDeclName() << SelID; - + + Diag(Loc, PD) << RD->getDeclName(); + // Check if we've already emitted the list of pure virtual functions for this // class. if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD)) return true; - + PureVirtualMethodCollector Collector(Context, RD); - - for (PureVirtualMethodCollector::MethodList::const_iterator I = + + for (PureVirtualMethodCollector::MethodList::const_iterator I = Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) { const CXXMethodDecl *MD = *I; - - Diag(MD->getLocation(), diag::note_pure_virtual_function) << + + Diag(MD->getLocation(), diag::note_pure_virtual_function) << MD->getDeclName(); } if (!PureVirtualClassDiagSet) PureVirtualClassDiagSet.reset(new RecordDeclSetTy); PureVirtualClassDiagSet->insert(RD); - + return true; } namespace { - class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser + class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser : public DeclVisitor<AbstractClassUsageDiagnoser, bool> { Sema &SemaRef; CXXRecordDecl *AbstractClass; - + bool VisitDeclContext(const DeclContext *DC) { bool Invalid = false; @@ -981,7 +1766,7 @@ namespace { return Invalid; } - + public: AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac) : SemaRef(SemaRef), AbstractClass(ac) { @@ -992,36 +1777,36 @@ namespace { if (FD->isThisDeclarationADefinition()) { // No need to do the check if we're in a definition, because it requires // that the return/param types are complete. - // because that requires + // because that requires return VisitDeclContext(FD); } - + // Check the return type. - QualType RTy = FD->getType()->getAsFunctionType()->getResultType(); - bool Invalid = + QualType RTy = FD->getType()->getAs<FunctionType>()->getResultType(); + bool Invalid = SemaRef.RequireNonAbstractType(FD->getLocation(), RTy, diag::err_abstract_type_in_decl, Sema::AbstractReturnType, AbstractClass); - for (FunctionDecl::param_const_iterator I = FD->param_begin(), + for (FunctionDecl::param_const_iterator I = FD->param_begin(), E = FD->param_end(); I != E; ++I) { const ParmVarDecl *VD = *I; - Invalid |= + Invalid |= SemaRef.RequireNonAbstractType(VD->getLocation(), - VD->getOriginalType(), - diag::err_abstract_type_in_decl, + VD->getOriginalType(), + diag::err_abstract_type_in_decl, Sema::AbstractParamType, AbstractClass); } return Invalid; } - + bool VisitDecl(const Decl* D) { if (const DeclContext *DC = dyn_cast<DeclContext>(D)) return VisitDeclContext(DC); - + return false; } }; @@ -1033,7 +1818,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, SourceLocation RBrac) { if (!TagDecl) return; - + AdjustDeclIfTemplate(TagDecl); ActOnFields(S, RLoc, TagDecl, (DeclPtrTy*)FieldCollector->getCurFields(), @@ -1044,37 +1829,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, // Collect all the pure virtual methods and see if this is an abstract // class after all. PureVirtualMethodCollector Collector(Context, RD); - if (!Collector.empty()) + if (!Collector.empty()) RD->setAbstract(true); } - - if (RD->isAbstract()) + + if (RD->isAbstract()) AbstractClassUsageDiagnoser(*this, RD); - - if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) { - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - // All the nonstatic data members must have trivial constructors. - QualType FTy = i->getType(); - while (const ArrayType *AT = Context.getAsArrayType(FTy)) - FTy = AT->getElementType(); - - if (const RecordType *RT = FTy->getAsRecordType()) { - CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl()); - - if (!FieldRD->hasTrivialConstructor()) - RD->setHasTrivialConstructor(false); - if (!FieldRD->hasTrivialDestructor()) - RD->setHasTrivialDestructor(false); - - // If RD has neither a trivial constructor nor a trivial destructor - // we don't need to continue checking. - if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor()) - break; - } - } - } - + if (!RD->isDependentType()) AddImplicitlyDeclaredMembersToClass(RD); } @@ -1085,8 +1846,8 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { - QualType ClassType = Context.getTypeDeclType(ClassDecl); - ClassType = Context.getCanonicalType(ClassType); + CanQualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); // FIXME: Implicit declarations have exception specifications, which are // the union of the specifications of the implicitly called functions. @@ -1098,18 +1859,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // user-declared constructor for class X, a default constructor is // implicitly declared. An implicitly-declared default constructor // is an inline public member of its class. - DeclarationName Name + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(ClassType); - CXXConstructorDecl *DefaultCon = + CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(Context.VoidTy, 0, 0, false, 0), + /*DInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true); DefaultCon->setAccess(AS_public); DefaultCon->setImplicit(); + DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); ClassDecl->addDecl(DefaultCon); } @@ -1133,8 +1896,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); HasConstCopyConstructor && Base != ClassDecl->bases_end(); ++Base) { const CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); - HasConstCopyConstructor + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + HasConstCopyConstructor = BaseClassDecl->hasConstCopyConstructor(Context); } @@ -1148,10 +1911,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { QualType FieldType = (*Field)->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { - const CXXRecordDecl *FieldClassDecl + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { + const CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); - HasConstCopyConstructor + HasConstCopyConstructor = FieldClassDecl->hasConstCopyConstructor(Context); } } @@ -1167,7 +1930,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // An implicitly-declared copy constructor is an inline public // member of its class. - DeclarationName Name + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(ClassType); CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(Context, ClassDecl, @@ -1175,17 +1938,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Context.getFunctionType(Context.VoidTy, &ArgType, 1, false, 0), + /*DInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true); CopyConstructor->setAccess(AS_public); CopyConstructor->setImplicit(); + CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, ClassDecl->getLocation(), /*IdentifierInfo=*/0, - ArgType, VarDecl::None, 0); + ArgType, /*DInfo=*/0, + VarDecl::None, 0); CopyConstructor->setParams(Context, &FromParam, 1); ClassDecl->addDecl(CopyConstructor); } @@ -1213,8 +1979,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) { const CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); - HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context); + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + const CXXMethodDecl *MD = 0; + HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context, + MD); } // -- for all the nonstatic data members of X that are of a class @@ -1227,11 +1995,12 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { QualType FieldType = (*Field)->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { const CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); + const CXXMethodDecl *MD = 0; HasConstCopyAssignment - = FieldClassDecl->hasConstCopyAssignment(Context); + = FieldClassDecl->hasConstCopyAssignment(Context, MD); } } @@ -1253,15 +2022,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(RetType, &ArgType, 1, false, 0), - /*isStatic=*/false, /*isInline=*/true); + /*DInfo=*/0, /*isStatic=*/false, /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); + CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); + CopyAssignment->setCopyAssignment(true); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassDecl->getLocation(), /*IdentifierInfo=*/0, - ArgType, VarDecl::None, 0); + ArgType, /*DInfo=*/0, + VarDecl::None, 0); CopyAssignment->setParams(Context, &FromParam, 1); // Don't call addedAssignmentOperator. There is no way to distinguish an @@ -1274,9 +2046,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. - DeclarationName Name + DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); - CXXDestructorDecl *Destructor + CXXDestructorDecl *Destructor = CXXDestructorDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(Context.VoidTy, @@ -1285,16 +2057,25 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setImplicit(); + Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); ClassDecl->addDecl(Destructor); } } void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) { - TemplateDecl *Template = TemplateD.getAs<TemplateDecl>(); - if (!Template) + Decl *D = TemplateD.getAs<Decl>(); + if (!D) + return; + + TemplateParameterList *Params = 0; + if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) + Params = Template->getTemplateParameters(); + else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) + Params = PartialSpec->getTemplateParameters(); + else return; - TemplateParameterList *Params = Template->getTemplateParameters(); for (TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); Param != ParamEnd; ++Param) { @@ -1317,10 +2098,12 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) { void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { if (!MethodD) return; - + + AdjustDeclIfTemplate(MethodD); + CXXScopeSpec SS; FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>()); - QualType ClassTy + QualType ClassTy = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); SS.setScopeRep( NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr())); @@ -1335,7 +2118,7 @@ void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) { if (!ParamD) return; - + ParmVarDecl *Param = cast<ParmVarDecl>(ParamD.getAs<Decl>()); // If this parameter has an unparsed default argument, clear it out @@ -1357,10 +2140,12 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) { void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { if (!MethodD) return; - + + AdjustDeclIfTemplate(MethodD); + FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>()); CXXScopeSpec SS; - QualType ClassTy + QualType ClassTy = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); SS.setScopeRep( NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr())); @@ -1408,26 +2193,26 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, D.setInvalidType(); SC = FunctionDecl::None; } - + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; if (FTI.TypeQuals != 0) { - if (FTI.TypeQuals & QualType::Const) + if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Volatile) + if (FTI.TypeQuals & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Restrict) + if (FTI.TypeQuals & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "restrict" << SourceRange(D.getIdentifierLoc()); } - + // Rebuild the function type "R" without any type qualifiers (in // case any of the errors above fired) and with "void" as the // return type, since constructors don't have return types. We // *always* have to do this, because GetTypeForDeclarator will // put in a result type of "int" when none was specified. - const FunctionProtoType *Proto = R->getAsFunctionProtoType(); + const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), Proto->getNumArgs(), Proto->isVariadic(), 0); @@ -1437,7 +2222,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, /// well-formedness, issuing any diagnostics required. Returns true if /// the constructor declarator is invalid. void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { - CXXRecordDecl *ClassDecl + CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(Constructor->getDeclContext()); if (!ClassDecl) return Constructor->setInvalidDecl(); @@ -1448,8 +2233,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { // either there are no other parameters or else all other // parameters have default arguments. if (!Constructor->isInvalidDecl() && - ((Constructor->getNumParams() == 1) || - (Constructor->getNumParams() > 1 && + ((Constructor->getNumParams() == 1) || + (Constructor->getNumParams() > 1 && Constructor->getParamDecl(1)->hasDefaultArg()))) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); @@ -1460,12 +2245,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { Constructor->setInvalidDecl(); } } - + // Notify the class that we've added a constructor. ClassDecl->addedConstructor(Context, Constructor); } -static inline bool +static inline bool FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) { return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && FTI.ArgInfo[0].Param && @@ -1485,7 +2270,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, // (7.1.3); however, a typedef-name that names a class shall not // be used as the identifier in the declarator for a destructor // declaration. - QualType DeclaratorType = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); + QualType DeclaratorType = GetTypeFromParser(D.getDeclaratorIdType()); if (isa<TypedefType>(DeclaratorType)) { Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType; @@ -1521,16 +2306,16 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); } - + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; if (FTI.TypeQuals != 0 && !D.isInvalidType()) { - if (FTI.TypeQuals & QualType::Const) + if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Volatile) + if (FTI.TypeQuals & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Restrict) + if (FTI.TypeQuals & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "restrict" << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); @@ -1545,7 +2330,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, D.setInvalidType(); } - // Make sure the destructor isn't variadic. + // Make sure the destructor isn't variadic. if (FTI.isVariadic) { Diag(D.getIdentifierLoc(), diag::err_destructor_variadic); D.setInvalidType(); @@ -1569,8 +2354,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC) { // C++ [class.conv.fct]p1: // Neither parameter types nor return type can be specified. The - // type of a conversion function (8.3.5) is “function taking no - // parameter returning conversion-type-id.” + // type of a conversion function (8.3.5) is "function taking no + // parameter returning conversion-type-id." if (SC == FunctionDecl::Static) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member) @@ -1594,7 +2379,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, } // Make sure we don't have any parameters. - if (R->getAsFunctionProtoType()->getNumArgs() > 0) { + if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) { Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); // Delete the parameters. @@ -1602,8 +2387,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, D.setInvalidType(); } - // Make sure the conversion function isn't variadic. - if (R->getAsFunctionProtoType()->isVariadic() && !D.isInvalidType()) { + // Make sure the conversion function isn't variadic. + if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); D.setInvalidType(); } @@ -1611,7 +2396,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); + QualType ConvType = GetTypeFromParser(D.getDeclaratorIdType()); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -1624,13 +2409,13 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // Rebuild the function type "R" without any parameters (in case any // of the errors above fired) and with the conversion type as the - // return type. - R = Context.getFunctionType(ConvType, 0, 0, false, - R->getAsFunctionProtoType()->getTypeQuals()); + // return type. + R = Context.getFunctionType(ConvType, 0, 0, false, + R->getAs<FunctionProtoType>()->getTypeQuals()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) - Diag(D.getDeclSpec().getExplicitSpecLoc(), + Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::warn_explicit_conversion_functions) << SourceRange(D.getDeclSpec().getExplicitSpecLoc()); } @@ -1642,9 +2427,6 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { assert(Conversion && "Expected to receive a conversion function declaration"); - // Set the lexical context of this conversion function - Conversion->setLexicalDeclContext(CurContext); - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext()); // Make sure we aren't redeclaring the conversion function. @@ -1658,9 +2440,9 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { // or to (possibly cv-qualified) void. // FIXME: Suppress this warning if the conversion function ends up being a // virtual function that overrides a virtual function in a base class. - QualType ClassType + QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); - if (const ReferenceType *ConvTypeRef = ConvType->getAsReferenceType()) + if (const ReferenceType *ConvTypeRef = ConvType->getAs<ReferenceType>()) ConvType = ConvTypeRef->getPointeeType(); if (ConvType->isRecordType()) { ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType(); @@ -1676,20 +2458,26 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { } if (Conversion->getPreviousDeclaration()) { + const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration(); + if (FunctionTemplateDecl *ConversionTemplate + = Conversion->getDescribedFunctionTemplate()) + ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration(); OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator + for (OverloadedFunctionDecl::function_iterator Conv = Conversions->function_begin(), ConvEnd = Conversions->function_end(); Conv != ConvEnd; ++Conv) { - if (*Conv - == cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) { + if (*Conv == ExpectedPrevDecl) { *Conv = Conversion; return DeclPtrTy::make(Conversion); } } assert(Conversion->isInvalidDecl() && "Conversion should not get here."); - } else - ClassDecl->addConversionFunction(Context, Conversion); + } else if (FunctionTemplateDecl *ConversionTemplate + = Conversion->getDescribedFunctionTemplate()) + ClassDecl->addConversionFunction(ConversionTemplate); + else if (!Conversion->getPrimaryTemplate()) // ignore specializations + ClassDecl->addConversionFunction(Conversion); return DeclPtrTy::make(Conversion); } @@ -1718,9 +2506,9 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // original-namespace-definition is the name of the namespace. Subsequently // in that declarative region, it is treated as an original-namespace-name. - NamedDecl *PrevDecl = LookupName(DeclRegionScope, II, LookupOrdinaryName, - true); - + NamedDecl *PrevDecl + = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, true); + if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { // This is an extended namespace definition. // Attach this namespace decl to the chain of extended namespace @@ -1728,7 +2516,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, OrigNS->setNextNamespace(Namespc); Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace()); - // Remove the previous declaration from the scope. + // Remove the previous declaration from the scope. if (DeclRegionScope->isDeclScope(DeclPtrTy::make(OrigNS))) { IdResolver.RemoveDecl(OrigNS); DeclRegionScope->RemoveDecl(DeclPtrTy::make(OrigNS)); @@ -1740,11 +2528,57 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, Diag(PrevDecl->getLocation(), diag::note_previous_definition); Namespc->setInvalidDecl(); // Continue on to push Namespc as current DeclContext and return it. - } + } else if (II->isStr("std") && + CurContext->getLookupContext()->isTranslationUnit()) { + // This is the first "real" definition of the namespace "std", so update + // our cache of the "std" namespace to point at this definition. + if (StdNamespace) { + // We had already defined a dummy namespace "std". Link this new + // namespace definition to the dummy namespace "std". + StdNamespace->setNextNamespace(Namespc); + StdNamespace->setLocation(IdentLoc); + Namespc->setOriginalNamespace(StdNamespace->getOriginalNamespace()); + } + + // Make our StdNamespace cache point at the first real definition of the + // "std" namespace. + StdNamespace = Namespc; + } PushOnScopeChains(Namespc, DeclRegionScope); } else { - // FIXME: Handle anonymous namespaces + // Anonymous namespaces. + + // C++ [namespace.unnamed]p1. An unnamed-namespace-definition + // behaves as if it were replaced by + // namespace unique { /* empty body */ } + // using namespace unique; + // namespace unique { namespace-body } + // where all occurrences of 'unique' in a translation unit are + // replaced by the same identifier and this identifier differs + // from all other identifiers in the entire program. + + // We just create the namespace with an empty name and then add an + // implicit using declaration, just like the standard suggests. + // + // CodeGen enforces the "universally unique" aspect by giving all + // declarations semantically contained within an anonymous + // namespace internal linkage. + + assert(Namespc->isAnonymousNamespace()); + CurContext->addDecl(Namespc); + + UsingDirectiveDecl* UD + = UsingDirectiveDecl::Create(Context, CurContext, + /* 'using' */ LBrace, + /* 'namespace' */ SourceLocation(), + /* qualifier */ SourceRange(), + /* NNS */ NULL, + /* identifier */ SourceLocation(), + Namespc, + /* Ancestor */ CurContext); + UD->setImplicit(); + CurContext->addDecl(UD); } // Although we could have an invalid decl (i.e. the namespace name is a @@ -1781,13 +2615,14 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, UsingDirectiveDecl *UDir = 0; // Lookup namespace name. - LookupResult R = LookupParsedName(S, &SS, NamespcName, - LookupNamespaceName, false); + LookupResult R; + LookupParsedName(R, S, &SS, NamespcName, LookupNamespaceName, false); if (R.isAmbiguous()) { DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc); return DeclPtrTy(); } - if (NamedDecl *NS = R) { + if (!R.empty()) { + NamedDecl *NS = R.getFoundDecl(); assert(isa<NamespaceDecl>(NS) && "expected namespace decl"); // C++ [namespace.udir]p1: // A using-directive specifies that the names in the nominated @@ -1796,8 +2631,8 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, // unqualified name lookup (3.4.1), the names appear as if they // were declared in the nearest enclosing namespace which // contains both the using-directive and the nominated - // namespace. [Note: in this context, “contains” means “contains - // directly or indirectly”. ] + // namespace. [Note: in this context, "contains" means "contains + // directly or indirectly". ] // Find enclosing context containing both using-directive and // nominated namespace. @@ -1805,9 +2640,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, while (CommonAncestor && !CommonAncestor->Encloses(CurContext)) CommonAncestor = CommonAncestor->getParent(); - UDir = UsingDirectiveDecl::Create(Context, + UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, - NamespcLoc, + NamespcLoc, SS.getRange(), (NestedNameSpecifier *)SS.getScopeRep(), IdentLoc, @@ -1837,45 +2672,124 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, - SourceLocation UsingLoc, - const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, - AttributeList *AttrList, - bool IsTypeName) { - assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); + AccessSpecifier AS, + SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *TargetName, + OverloadedOperatorKind Op, + AttributeList *AttrList, + bool IsTypeName) { assert((TargetName || Op) && "Invalid TargetName."); - assert(IdentLoc.isValid() && "Invalid TargetName location."); assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); - UsingDecl *UsingAlias = 0; - DeclarationName Name; if (TargetName) Name = TargetName; else Name = Context.DeclarationNames.getCXXOperatorName(Op); - - // Lookup target name. - LookupResult R = LookupParsedName(S, &SS, Name, LookupOrdinaryName, false); - if (NamedDecl *NS = R) { - if (IsTypeName && !isa<TypeDecl>(NS)) { - Diag(IdentLoc, diag::err_using_typename_non_type); - } - UsingAlias = UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(), - NS->getLocation(), UsingLoc, NS, - static_cast<NestedNameSpecifier *>(SS.getScopeRep()), - IsTypeName); - PushOnScopeChains(UsingAlias, S); - } else { - Diag(IdentLoc, diag::err_using_requires_qualname) << SS.getRange(); + NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, IdentLoc, + Name, AttrList, IsTypeName); + if (UD) { + PushOnScopeChains(UD, S); + UD->setAccess(AS); } + return DeclPtrTy::make(UD); +} + +NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + DeclarationName Name, + AttributeList *AttrList, + bool IsTypeName) { + assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); + assert(IdentLoc.isValid() && "Invalid TargetName location."); + // FIXME: We ignore attributes for now. delete AttrList; - return DeclPtrTy::make(UsingAlias); + + if (SS.isEmpty()) { + Diag(IdentLoc, diag::err_using_requires_qualname); + return 0; + } + + NestedNameSpecifier *NNS = + static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + + if (isUnknownSpecialization(SS)) { + return UnresolvedUsingDecl::Create(Context, CurContext, UsingLoc, + SS.getRange(), NNS, + IdentLoc, Name, IsTypeName); + } + + DeclContext *LookupContext = 0; + + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) { + // C++0x N2914 [namespace.udecl]p3: + // A using-declaration used as a member-declaration shall refer to a member + // of a base class of the class being defined, shall refer to a member of an + // anonymous union that is a member of a base class of the class being + // defined, or shall refer to an enumerator for an enumeration type that is + // a member of a base class of the class being defined. + const Type *Ty = NNS->getAsType(); + if (!Ty || !IsDerivedFrom(Context.getTagDeclType(RD), QualType(Ty, 0))) { + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_a_base_class) + << NNS << RD->getDeclName(); + return 0; + } + + QualType BaseTy = Context.getCanonicalType(QualType(Ty, 0)); + LookupContext = BaseTy->getAs<RecordType>()->getDecl(); + } else { + // C++0x N2914 [namespace.udecl]p8: + // A using-declaration for a class member shall be a member-declaration. + if (NNS->getKind() == NestedNameSpecifier::TypeSpec) { + Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member) + << SS.getRange(); + return 0; + } + + // C++0x N2914 [namespace.udecl]p9: + // In a using-declaration, a prefix :: refers to the global namespace. + if (NNS->getKind() == NestedNameSpecifier::Global) + LookupContext = Context.getTranslationUnitDecl(); + else + LookupContext = NNS->getAsNamespace(); + } + + + // Lookup target name. + LookupResult R; + LookupQualifiedName(R, LookupContext, Name, LookupOrdinaryName); + + if (R.empty()) { + Diag(IdentLoc, diag::err_no_member) + << Name << LookupContext << SS.getRange(); + return 0; + } + + // FIXME: handle ambiguity? + NamedDecl *ND = R.getAsSingleDecl(Context); + + if (IsTypeName && !isa<TypeDecl>(ND)) { + Diag(IdentLoc, diag::err_using_typename_non_type); + return 0; + } + + // C++0x N2914 [namespace.udecl]p6: + // A using-declaration shall not name a namespace. + if (isa<NamespaceDecl>(ND)) { + Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) + << SS.getRange(); + return 0; + } + + return UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(), + ND->getLocation(), UsingLoc, ND, NNS, IsTypeName); } /// getNamespaceDecl - Returns the namespace a decl represents. If the decl @@ -1886,26 +2800,29 @@ static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) { return dyn_cast_or_null<NamespaceDecl>(D); } -Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, +Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, const CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { - + // Lookup the namespace name. - LookupResult R = LookupParsedName(S, &SS, Ident, LookupNamespaceName, false); + LookupResult R; + LookupParsedName(R, S, &SS, Ident, LookupNamespaceName, false); // Check if we have a previous declaration with the same name. - if (NamedDecl *PrevDecl = LookupName(S, Alias, LookupOrdinaryName, true)) { + if (NamedDecl *PrevDecl + = LookupSingleName(S, Alias, LookupOrdinaryName, true)) { if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { - // We already have an alias with the same name that points to the same + // We already have an alias with the same name that points to the same // namespace, so don't create a new one. - if (!R.isAmbiguous() && AD->getNamespace() == getNamespaceDecl(R)) + if (!R.isAmbiguous() && !R.empty() && + AD->getNamespace() == getNamespaceDecl(R.getFoundDecl())) return DeclPtrTy(); } - + unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition : diag::err_redefinition_different_kind; Diag(AliasLoc, DiagID) << Alias; @@ -1917,18 +2834,18 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, DiagnoseAmbiguousLookup(R, Ident, IdentLoc); return DeclPtrTy(); } - - if (!R) { + + if (R.empty()) { Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange(); return DeclPtrTy(); } - + NamespaceAliasDecl *AliasDecl = - NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc, - Alias, SS.getRange(), + NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc, + Alias, SS.getRange(), (NestedNameSpecifier *)SS.getScopeRep(), - IdentLoc, R); - + IdentLoc, R.getFoundDecl()); + CurContext->addDecl(AliasDecl); return DeclPtrTy::make(AliasDecl); } @@ -1938,11 +2855,11 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() && !Constructor->isUsed()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); - + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext()); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); - // Before the implicitly-declared default constructor for a class is + // Before the implicitly-declared default constructor for a class is // implicitly defined, all the implicitly-declared default constructors // for its base class and its non-static data members shall have been // implicitly defined. @@ -1950,16 +2867,16 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (!BaseClassDecl->hasTrivialConstructor()) { - if (CXXConstructorDecl *BaseCtor = + if (CXXConstructorDecl *BaseCtor = BaseClassDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(CurrentLocation, BaseCtor); else { - Diag(CurrentLocation, diag::err_defining_default_ctor) - << Context.getTagDeclType(ClassDecl) << 1 + Diag(CurrentLocation, diag::err_defining_default_ctor) + << Context.getTagDeclType(ClassDecl) << 0 << Context.getTagDeclType(BaseClassDecl); - Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl) + Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl) << Context.getTagDeclType(BaseClassDecl); err = true; } @@ -1970,32 +2887,31 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, QualType FieldType = Context.getCanonicalType((*Field)->getType()); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); if (!FieldClassDecl->hasTrivialConstructor()) { - if (CXXConstructorDecl *FieldCtor = + if (CXXConstructorDecl *FieldCtor = FieldClassDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(CurrentLocation, FieldCtor); else { - Diag(CurrentLocation, diag::err_defining_default_ctor) - << Context.getTagDeclType(ClassDecl) << 0 << + Diag(CurrentLocation, diag::err_defining_default_ctor) + << Context.getTagDeclType(ClassDecl) << 1 << Context.getTagDeclType(FieldClassDecl); - Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl) + Diag((*Field)->getLocation(), diag::note_field_decl); + Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl) << Context.getTagDeclType(FieldClassDecl); err = true; } } - } - else if (FieldType->isReferenceType()) { - Diag(CurrentLocation, diag::err_unintialized_member) - << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString(); + } else if (FieldType->isReferenceType()) { + Diag(CurrentLocation, diag::err_unintialized_member) + << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); err = true; - } - else if (FieldType.isConstQualified()) { - Diag(CurrentLocation, diag::err_unintialized_member) - << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString(); + } else if (FieldType.isConstQualified()) { + Diag(CurrentLocation, diag::err_unintialized_member) + << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); err = true; } @@ -2007,47 +2923,47 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, - CXXDestructorDecl *Destructor) { + CXXDestructorDecl *Destructor) { assert((Destructor->isImplicit() && !Destructor->isUsed()) && "DefineImplicitDestructor - call it for implicit default dtor"); - + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext()); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); // C++ [class.dtor] p5 - // Before the implicitly-declared default destructor for a class is + // Before the implicitly-declared default destructor for a class is // implicitly defined, all the implicitly-declared default destructors // for its base class and its non-static data members shall have been // implicitly defined. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (!BaseClassDecl->hasTrivialDestructor()) { - if (CXXDestructorDecl *BaseDtor = + if (CXXDestructorDecl *BaseDtor = const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context))) MarkDeclarationReferenced(CurrentLocation, BaseDtor); else - assert(false && + assert(false && "DefineImplicitDestructor - missing dtor in a base class"); } } - + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { QualType FieldType = Context.getCanonicalType((*Field)->getType()); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); if (!FieldClassDecl->hasTrivialDestructor()) { - if (CXXDestructorDecl *FieldDtor = + if (CXXDestructorDecl *FieldDtor = const_cast<CXXDestructorDecl*>( FieldClassDecl->getDestructor(Context))) MarkDeclarationReferenced(CurrentLocation, FieldDtor); else - assert(false && + assert(false && "DefineImplicitDestructor - missing dtor in class of a data member"); } } @@ -2061,10 +2977,10 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, MethodDecl->getOverloadedOperator() == OO_Equal && !MethodDecl->isUsed()) && "DefineImplicitOverloadedAssign - call it for implicit assignment op"); - + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MethodDecl->getDeclContext()); - + // C++[class.copy] p12 // Before the implicitly-declared copy assignment operator for a class is // implicitly defined, all implicitly-declared copy assignment operators @@ -2074,8 +2990,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); - if (CXXMethodDecl *BaseAssignOpMethod = + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXMethodDecl *BaseAssignOpMethod = getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl)) MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); } @@ -2084,30 +3000,28 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, QualType FieldType = Context.getCanonicalType((*Field)->getType()); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (CXXMethodDecl *FieldAssignOpMethod = + if (CXXMethodDecl *FieldAssignOpMethod = getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl)) MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); - } - else if (FieldType->isReferenceType()) { - Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString(); - Diag((*Field)->getLocation(), diag::note_declared_at); + } else if (FieldType->isReferenceType()) { + Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) + << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); + Diag(Field->getLocation(), diag::note_declared_at); Diag(CurrentLocation, diag::note_first_required_here); err = true; - } - else if (FieldType.isConstQualified()) { - Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString(); - Diag((*Field)->getLocation(), diag::note_declared_at); + } else if (FieldType.isConstQualified()) { + Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) + << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); + Diag(Field->getLocation(), diag::note_declared_at); Diag(CurrentLocation, diag::note_first_required_here); err = true; } } if (!err) - MethodDecl->setUsed(); + MethodDecl->setUsed(); } CXXMethodDecl * @@ -2116,24 +3030,22 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl, QualType LHSType = Context.getTypeDeclType(ClassDecl); QualType RHSType(LHSType); // If class's assignment operator argument is const/volatile qualified, - // look for operator = (const/volatile B&). Otherwise, look for + // look for operator = (const/volatile B&). Otherwise, look for // operator = (B&). - if (ParmDecl->getType().isConstQualified()) - RHSType.addConst(); - if (ParmDecl->getType().isVolatileQualified()) - RHSType.addVolatile(); - ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl, - LHSType, + RHSType = Context.getCVRQualifiedType(RHSType, + ParmDecl->getType().getCVRQualifiers()); + ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl, + LHSType, SourceLocation())); - ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl, - RHSType, + ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl, + RHSType, SourceLocation())); Expr *Args[2] = { &*LHS, &*RHS }; OverloadCandidateSet CandidateSet; - AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, + AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; - if (BestViableFunction(CandidateSet, + if (BestViableFunction(CandidateSet, ClassDecl->getLocation(), Best) == OR_Success) return cast<CXXMethodDecl>(Best->Function); assert(false && @@ -2144,24 +3056,24 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl, void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *CopyConstructor, unsigned TypeQuals) { - assert((CopyConstructor->isImplicit() && + assert((CopyConstructor->isImplicit() && CopyConstructor->isCopyConstructor(Context, TypeQuals) && !CopyConstructor->isUsed()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); - + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CopyConstructor->getDeclContext()); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); // C++ [class.copy] p209 - // Before the implicitly-declared copy constructor for a class is + // Before the implicitly-declared copy constructor for a class is // implicitly defined, all the implicitly-declared copy constructors // for its base class and its non-static data members shall have been // implicitly defined. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); - if (CXXConstructorDecl *BaseCopyCtor = + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXConstructorDecl *BaseCopyCtor = BaseClassDecl->getCopyConstructor(Context, TypeQuals)) MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); } @@ -2171,10 +3083,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, QualType FieldType = Context.getCanonicalType((*Field)->getType()); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (CXXConstructorDecl *FieldCopyCtor = + if (CXXConstructorDecl *FieldCopyCtor = FieldClassDecl->getCopyConstructor(Context, TypeQuals)) MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor); } @@ -2182,27 +3094,92 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CopyConstructor->setUsed(); } -void Sema::InitializeVarWithConstructor(VarDecl *VD, +Sema::OwningExprResult +Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, + MultiExprArg ExprArgs) { + bool Elidable = false; + + // C++ [class.copy]p15: + // Whenever a temporary class object is copied using a copy constructor, and + // this object and the copy have the same cv-unqualified type, an + // implementation is permitted to treat the original and the copy as two + // different ways of referring to the same object and not perform a copy at + // all, even if the class copy constructor or destructor have side effects. + + // FIXME: Is this enough? + if (Constructor->isCopyConstructor(Context)) { + Expr *E = ((Expr **)ExprArgs.get())[0]; + while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E)) + E = BE->getSubExpr(); + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getCastKind() == CastExpr::CK_NoOp) + E = ICE->getSubExpr(); + + if (isa<CallExpr>(E) || isa<CXXTemporaryObjectExpr>(E)) + Elidable = true; + } + + return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, + Elidable, move(ExprArgs)); +} + +/// BuildCXXConstructExpr - Creates a complete call to a constructor, +/// including handling of its default argument expressions. +Sema::OwningExprResult +Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, bool Elidable, + MultiExprArg ExprArgs) { + unsigned NumExprs = ExprArgs.size(); + Expr **Exprs = (Expr **)ExprArgs.release(); + + return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor, + Elidable, Exprs, NumExprs)); +} + +Sema::OwningExprResult +Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor, + QualType Ty, + SourceLocation TyBeginLoc, + MultiExprArg Args, + SourceLocation RParenLoc) { + unsigned NumExprs = Args.size(); + Expr **Exprs = (Expr **)Args.release(); + + return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty, + TyBeginLoc, Exprs, + NumExprs, RParenLoc)); +} + + +bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - QualType DeclInitType, - Expr **Exprs, unsigned NumExprs) { - Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor, - false, Exprs, NumExprs); + QualType DeclInitType, + MultiExprArg Exprs) { + OwningExprResult TempResult = + BuildCXXConstructExpr(VD->getLocation(), DeclInitType, Constructor, + move(Exprs)); + if (TempResult.isInvalid()) + return true; + + Expr *Temp = TempResult.takeAs<Expr>(); MarkDeclarationReferenced(VD->getLocation(), Constructor); + Temp = MaybeCreateCXXExprWithTemporaries(Temp, /*DestroyTemps=*/true); VD->setInit(Context, Temp); + + return false; } -void Sema::MarkDestructorReferenced(SourceLocation Loc, QualType DeclInitType) -{ +void Sema::FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>( - DeclInitType->getAsRecordType()->getDecl()); + DeclInitType->getAs<RecordType>()->getDecl()); if (!ClassDecl->hasTrivialDestructor()) - if (CXXDestructorDecl *Destructor = + if (CXXDestructorDecl *Destructor = const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context))) - MarkDeclarationReferenced(Loc, Destructor); + MarkDeclarationReferenced(VD->getLocation(), Destructor); } -/// AddCXXDirectInitializerToDecl - This action is called immediately after +/// AddCXXDirectInitializerToDecl - This action is called immediately after /// ActOnDeclarator, when a C++ direct initializer is present. /// e.g: "int x(1);" void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, @@ -2218,7 +3195,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, // the initializer. if (RealDecl == 0) return; - + VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl); if (!VDecl) { Diag(RealDecl->getLocation(), diag::err_illegal_initializer); @@ -2226,9 +3203,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, return; } - // FIXME: Need to handle dependent types and expressions here. - - // We will treat direct-initialization as a copy-initialization: + // We will represent direct-initialization similarly to copy-initialization: // int x(1); -as-> int x = 1; // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); // @@ -2238,6 +3213,24 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, // exactly form was it (like the CodeGen) can handle both cases without // special case code. + // If either the declaration has a dependent type or if any of the expressions + // is type-dependent, we represent the initialization via a ParenListExpr for + // later use during template instantiation. + if (VDecl->getType()->isDependentType() || + Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) { + // Let clients know that initialization was done with a direct initializer. + VDecl->setCXXDirectInitializer(true); + + // Store the initialization expressions as a ParenListExpr. + unsigned NumExprs = Exprs.size(); + VDecl->setInit(Context, + new (Context) ParenListExpr(Context, LParenLoc, + (Expr **)Exprs.release(), + NumExprs, RParenLoc)); + return; + } + + // C++ 8.5p11: // The form of initialization (using parentheses or '=') is generally // insignificant, but does matter when the entity being initialized has a @@ -2254,23 +3247,25 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, } if (VDecl->getType()->isRecordType()) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + CXXConstructorDecl *Constructor = PerformInitializationByConstructor(DeclInitType, - (Expr **)Exprs.get(), NumExprs, + move(Exprs), VDecl->getLocation(), SourceRange(VDecl->getLocation(), RParenLoc), VDecl->getDeclName(), - IK_Direct); + IK_Direct, + ConstructorArgs); if (!Constructor) RealDecl->setInvalidDecl(); else { VDecl->setCXXDirectInitializer(true); - InitializeVarWithConstructor(VDecl, Constructor, DeclInitType, - (Expr**)Exprs.release(), NumExprs); - // FIXME. Must do all that is needed to destroy the object - // on scope exit. For now, just mark the destructor as used. - MarkDestructorReferenced(VDecl->getLocation(), DeclInitType); + if (InitializeVarWithConstructor(VDecl, Constructor, DeclInitType, + move_arg(ConstructorArgs))) + RealDecl->setInvalidDecl(); + FinalizeVarWithDestructor(VDecl, DeclInitType); } return; } @@ -2291,31 +3286,41 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, /*DirectInit=*/true); } -/// PerformInitializationByConstructor - Perform initialization by -/// constructor (C++ [dcl.init]p14), which may occur as part of -/// direct-initialization or copy-initialization. We are initializing -/// an object of type @p ClassType with the given arguments @p -/// Args. @p Loc is the location in the source code where the -/// initializer occurs (e.g., a declaration, member initializer, -/// functional cast, etc.) while @p Range covers the whole -/// initialization. @p InitEntity is the entity being initialized, -/// which may by the name of a declaration or a type. @p Kind is the -/// kind of initialization we're performing, which affects whether -/// explicit constructors will be considered. When successful, returns -/// the constructor that will be used to perform the initialization; -/// when the initialization fails, emits a diagnostic and returns -/// null. +/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which +/// may occur as part of direct-initialization or copy-initialization. +/// +/// \param ClassType the type of the object being initialized, which must have +/// class type. +/// +/// \param ArgsPtr the arguments provided to initialize the object +/// +/// \param Loc the source location where the initialization occurs +/// +/// \param Range the source range that covers the entire initialization +/// +/// \param InitEntity the name of the entity being initialized, if known +/// +/// \param Kind the type of initialization being performed +/// +/// \param ConvertedArgs a vector that will be filled in with the +/// appropriately-converted arguments to the constructor (if initialization +/// succeeded). +/// +/// \returns the constructor used to initialize the object, if successful. +/// Otherwise, emits a diagnostic and returns NULL. CXXConstructorDecl * Sema::PerformInitializationByConstructor(QualType ClassType, - Expr **Args, unsigned NumArgs, + MultiExprArg ArgsPtr, SourceLocation Loc, SourceRange Range, DeclarationName InitEntity, - InitializationKind Kind) { - const RecordType *ClassRec = ClassType->getAsRecordType(); + InitializationKind Kind, + ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) { + const RecordType *ClassRec = ClassType->getAs<RecordType>(); assert(ClassRec && "Can only initialize a class type here"); - - // C++ [dcl.init]p14: - // + Expr **Args = (Expr **)ArgsPtr.get(); + unsigned NumArgs = ArgsPtr.size(); + + // C++ [dcl.init]p14: // If the initialization is direct-initialization, or if it is // copy-initialization where the cv-unqualified version of the // source type is the same class as, or a derived class of, the @@ -2330,17 +3335,31 @@ Sema::PerformInitializationByConstructor(QualType ClassType, OverloadCandidateSet CandidateSet; // Add constructors to the overload set. - DeclarationName ConstructorName + DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType.getUnqualifiedType())); DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con); + if (ConstructorTmpl) + Constructor + = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast<CXXConstructorDecl>(*Con); + if ((Kind == IK_Direct) || - (Kind == IK_Copy && Constructor->isConvertingConstructor()) || - (Kind == IK_Default && Constructor->isDefaultConstructor())) - AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + (Kind == IK_Copy && + Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || + (Kind == IK_Default && Constructor->isDefaultConstructor())) { + if (ConstructorTmpl) + AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, + Args, NumArgs, CandidateSet); + else + AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } } // FIXME: When we decide not to synthesize the implicitly-declared @@ -2349,9 +3368,10 @@ Sema::PerformInitializationByConstructor(QualType ClassType, OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Loc, Best)) { case OR_Success: - // We found a constructor. Return it. - return cast<CXXConstructorDecl>(Best->Function); - + // We found a constructor. Break out so that we can convert the arguments + // appropriately. + break; + case OR_No_Viable_Function: if (InitEntity) Diag(Loc, diag::err_ovl_no_viable_function_in_init) @@ -2361,7 +3381,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType, << ClassType << Range; PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); return 0; - + case OR_Ambiguous: if (InitEntity) Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range; @@ -2382,8 +3402,85 @@ Sema::PerformInitializationByConstructor(QualType ClassType, PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); return 0; } + + // Convert the arguments, fill in default arguments, etc. + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); + if (CompleteConstructorCall(Constructor, move(ArgsPtr), Loc, ConvertedArgs)) + return 0; - return 0; + return Constructor; +} + +/// \brief Given a constructor and the set of arguments provided for the +/// constructor, convert the arguments and add any required default arguments +/// to form a proper call to this constructor. +/// +/// \returns true if an error occurred, false otherwise. +bool +Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, + MultiExprArg ArgsPtr, + SourceLocation Loc, + ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) { + // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall. + unsigned NumArgs = ArgsPtr.size(); + Expr **Args = (Expr **)ArgsPtr.get(); + + const FunctionProtoType *Proto + = Constructor->getType()->getAs<FunctionProtoType>(); + assert(Proto && "Constructor without a prototype?"); + unsigned NumArgsInProto = Proto->getNumArgs(); + unsigned NumArgsToCheck = NumArgs; + + // If too few arguments are available, we'll fill in the rest with defaults. + if (NumArgs < NumArgsInProto) { + NumArgsToCheck = NumArgsInProto; + ConvertedArgs.reserve(NumArgsInProto); + } else { + ConvertedArgs.reserve(NumArgs); + if (NumArgs > NumArgsInProto) + NumArgsToCheck = NumArgsInProto; + } + + // Convert arguments + for (unsigned i = 0; i != NumArgsToCheck; i++) { + QualType ProtoArgType = Proto->getArgType(i); + + Expr *Arg; + if (i < NumArgs) { + Arg = Args[i]; + + // Pass the argument. + if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) + return true; + + Args[i] = 0; + } else { + ParmVarDecl *Param = Constructor->getParamDecl(i); + + OwningExprResult DefArg = BuildCXXDefaultArgExpr(Loc, Constructor, Param); + if (DefArg.isInvalid()) + return true; + + Arg = DefArg.takeAs<Expr>(); + } + + ConvertedArgs.push_back(Arg); + } + + // If this is a variadic call, handle args passed through "...". + if (Proto->isVariadic()) { + // Promote the arguments (C99 6.5.2.2p7). + for (unsigned i = NumArgsInProto; i != NumArgs; i++) { + Expr *Arg = Args[i]; + if (DefaultVariadicArgumentPromotion(Arg, VariadicConstructor)) + return true; + + ConvertedArgs.push_back(Arg); + Args[i] = 0; + } + } + + return false; } /// CompareReferenceRelationship - Compare the two types T1 and T2 to @@ -2393,8 +3490,8 @@ Sema::PerformInitializationByConstructor(QualType ClassType, /// reference (C++ [dcl.ref.init]p4). Neither type can be a reference /// type, and the first type (T1) is the pointee type of the reference /// type being initialized. -Sema::ReferenceCompareResult -Sema::CompareReferenceRelationship(QualType T1, QualType T2, +Sema::ReferenceCompareResult +Sema::CompareReferenceRelationship(QualType T1, QualType T2, bool& DerivedToBase) { assert(!T1->isReferenceType() && "T1 must be the pointee type of the reference type"); @@ -2406,8 +3503,8 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2, QualType UnqualT2 = T2.getUnqualifiedType(); // C++ [dcl.init.ref]p4: - // Given types “cv1 T1” and “cv2 T2,” “cv1 T1” is - // reference-related to “cv2 T2” if T1 is the same type as T2, or + // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is + // reference-related to "cv2 T2" if T1 is the same type as T2, or // T1 is a base class of T2. if (UnqualT1 == UnqualT2) DerivedToBase = false; @@ -2420,7 +3517,7 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2, // least). // C++ [dcl.init.ref]p4: - // "cv1 T1” is reference-compatible with “cv2 T2” if T1 is + // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is // reference-related to T2 and cv1 is the same cv-qualification // as, or greater cv-qualification than, cv2. For purposes of // overload resolution, cases for which cv1 is greater @@ -2450,27 +3547,28 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2, /// When @p AllowExplicit, we also permit explicit user-defined /// conversion functions. /// When @p ForceRValue, we unconditionally treat the initializer as an rvalue. -bool +bool Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, - ImplicitConversionSequence *ICS, + SourceLocation DeclLoc, bool SuppressUserConversions, - bool AllowExplicit, bool ForceRValue) { + bool AllowExplicit, bool ForceRValue, + ImplicitConversionSequence *ICS) { assert(DeclType->isReferenceType() && "Reference init needs a reference"); - QualType T1 = DeclType->getAsReferenceType()->getPointeeType(); + QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); QualType T2 = Init->getType(); // If the initializer is the address of an overloaded function, try // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. if (Context.getCanonicalType(T2) == Context.OverloadTy) { - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, ICS != 0); if (Fn) { // Since we're performing this reference-initialization for // real, update the initializer with the resulting function. if (!ICS) { - if (DiagnoseUseOfDecl(Fn, Init->getSourceRange().getBegin())) + if (DiagnoseUseOfDecl(Fn, DeclLoc)) return true; FixOverloadedFunctionReference(Init, Fn); @@ -2485,7 +3583,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, bool DerivedToBase = false; Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : Init->isLvalue(Context); - ReferenceCompareResult RefRelationship + ReferenceCompareResult RefRelationship = CompareReferenceRelationship(T1, T2, DerivedToBase); // Most paths end in a failed conversion. @@ -2493,8 +3591,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, ICS->ConversionKind = ImplicitConversionSequence::BadConversion; // C++ [dcl.init.ref]p5: - // A reference to type “cv1 T1” is initialized by an expression - // of type “cv2 T2” as follows: + // A reference to type "cv1 T1" is initialized by an expression + // of type "cv2 T2" as follows: // -- If the initializer expression @@ -2505,14 +3603,14 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // A&& r = b; if (isRValRef && InitLvalue == Expr::LV_Valid) { if (!ICS) - Diag(Init->getSourceRange().getBegin(), diag::err_lvalue_to_rvalue_ref) + Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) << Init->getSourceRange(); return true; } bool BindsDirectly = false; - // -- is an lvalue (but is not a bit-field), and “cv1 T1” is - // reference-compatible with “cv2 T2,” or + // -- is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or // // Note that the bit-field check is skipped if we are just computing // the implicit conversion sequence (C++ [over.best.ics]p2). @@ -2546,40 +3644,54 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, return false; } else { // Perform the conversion. - // FIXME: Binding to a subobject of the lvalue is going to require more - // AST annotation than this. - ImpCastExprToType(Init, T1, /*isLvalue=*/true); + CastExpr::CastKind CK = CastExpr::CK_NoOp; + if (DerivedToBase) + CK = CastExpr::CK_DerivedToBase; + else if(CheckExceptionSpecCompatibility(Init, T1)) + return true; + ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true); } } // -- has a class type (i.e., T2 is a class type) and can be - // implicitly converted to an lvalue of type “cv3 T3,” - // where “cv1 T1” is reference-compatible with “cv3 T3” + // implicitly converted to an lvalue of type "cv3 T3," + // where "cv1 T1" is reference-compatible with "cv3 T3" // 92) (this conversion is selected by enumerating the // applicable conversion functions (13.3.1.6) and choosing // the best one through overload resolution (13.3)), - if (!isRValRef && !SuppressUserConversions && T2->isRecordType()) { - // FIXME: Look for conversions in base classes! - CXXRecordDecl *T2RecordDecl - = dyn_cast<CXXRecordDecl>(T2->getAsRecordType()->getDecl()); + if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && + !RequireCompleteType(SourceLocation(), T2, 0)) { + CXXRecordDecl *T2RecordDecl + = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); OverloadCandidateSet CandidateSet; - OverloadedFunctionDecl *Conversions - = T2RecordDecl->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator Func + OverloadedFunctionDecl *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator Func = Conversions->function_begin(); Func != Conversions->function_end(); ++Func) { - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); - + FunctionTemplateDecl *ConvTemplate + = dyn_cast<FunctionTemplateDecl>(*Func); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(*Func); + // If the conversion function doesn't return a reference type, // it can't be considered for this conversion. if (Conv->getConversionType()->isLValueReferenceType() && - (AllowExplicit || !Conv->isExplicit())) - AddConversionCandidate(Conv, Init, DeclType, CandidateSet); + (AllowExplicit || !Conv->isExplicit())) { + if (ConvTemplate) + AddTemplateConversionCandidate(ConvTemplate, Init, DeclType, + CandidateSet); + else + AddConversionCandidate(Conv, Init, DeclType, CandidateSet); + } } OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Init->getLocStart(), Best)) { + switch (BestViableFunction(CandidateSet, DeclLoc, Best)) { case OR_Success: // This is a direct binding. BindsDirectly = true; @@ -2604,17 +3716,33 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, "Expected a direct reference binding!"); return false; } else { - // Perform the conversion. - // FIXME: Binding to a subobject of the lvalue is going to require more - // AST annotation than this. - ImpCastExprToType(Init, T1, /*isLvalue=*/true); + OwningExprResult InitConversion = + BuildCXXCastArgument(DeclLoc, QualType(), + CastExpr::CK_UserDefinedConversion, + cast<CXXMethodDecl>(Best->Function), + Owned(Init)); + Init = InitConversion.takeAs<Expr>(); + + if (CheckExceptionSpecCompatibility(Init, T1)) + return true; + ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion, + /*isLvalue=*/true); } break; case OR_Ambiguous: - assert(false && "Ambiguous reference binding conversions not implemented."); + if (ICS) { + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); + Cand != CandidateSet.end(); ++Cand) + if (Cand->Viable) + ICS->ConversionFunctionSet.push_back(Cand->Function); + break; + } + Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType() + << Init->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); return true; - + case OR_No_Viable_Function: case OR_Deleted: // There was no suitable conversion, or we found a deleted @@ -2622,7 +3750,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, break; } } - + if (BindsDirectly) { // C++ [dcl.init.ref]p4: // [...] In all cases where the reference-related or @@ -2636,9 +3764,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // complain about errors, because we should not be checking for // ambiguity (or inaccessibility) unless the reference binding // actually happens. - if (DerivedToBase) - return CheckDerivedToBaseConversion(T2, T1, - Init->getSourceRange().getBegin(), + if (DerivedToBase) + return CheckDerivedToBaseConversion(T2, T1, DeclLoc, Init->getSourceRange()); else return false; @@ -2647,25 +3774,24 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // -- Otherwise, the reference shall be to a non-volatile const // type (i.e., cv1 shall be const), or the reference shall be an // rvalue reference and the initializer expression shall be an rvalue. - if (!isRValRef && T1.getCVRQualifiers() != QualType::Const) { + if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { if (!ICS) - Diag(Init->getSourceRange().getBegin(), - diag::err_not_reference_to_const_init) + Diag(DeclLoc, diag::err_not_reference_to_const_init) << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value") << T2 << Init->getSourceRange(); return true; } // -- If the initializer expression is an rvalue, with T2 a - // class type, and “cv1 T1” is reference-compatible with - // “cv2 T2,” the reference is bound in one of the + // class type, and "cv1 T1" is reference-compatible with + // "cv2 T2," the reference is bound in one of the // following ways (the choice is implementation-defined): // // -- The reference is bound to the object represented by // the rvalue (see 3.10) or to a sub-object within that // object. // - // -- A temporary of type “cv1 T2” [sic] is created, and + // -- A temporary of type "cv1 T2" [sic] is created, and // a constructor is called to copy the entire rvalue // object into the temporary. The reference is bound to // the temporary or to a sub-object within the @@ -2693,14 +3819,17 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, ICS->Standard.RRefBinding = isRValRef; ICS->Standard.CopyConstructor = 0; } else { - // FIXME: Binding to a subobject of the rvalue is going to require more - // AST annotation than this. - ImpCastExprToType(Init, T1, /*isLvalue=*/false); + CastExpr::CastKind CK = CastExpr::CK_NoOp; + if (DerivedToBase) + CK = CastExpr::CK_DerivedToBase; + else if(CheckExceptionSpecCompatibility(Init, T1)) + return true; + ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false); } return false; } - // -- Otherwise, a temporary of type “cv1 T1” is created and + // -- Otherwise, a temporary of type "cv1 T1" is created and // initialized from the initializer expression using the // rules for a non-reference copy initialization (8.5). The // reference is then bound to the temporary. If T1 is @@ -2713,8 +3842,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // added qualification. But that wasn't the case, so the reference // initialization fails. if (!ICS) - Diag(Init->getSourceRange().getBegin(), - diag::err_reference_init_drops_quals) + Diag(DeclLoc, diag::err_reference_init_drops_quals) << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value") << T2 << Init->getSourceRange(); return true; @@ -2728,8 +3856,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (SuppressUserConversions && RefRelationship == Ref_Incompatible && (T1->isRecordType() || T2->isRecordType())) { if (!ICS) - Diag(Init->getSourceRange().getBegin(), - diag::err_typecheck_convert_incompatible) + Diag(DeclLoc, diag::err_typecheck_convert_incompatible) << DeclType << Init->getType() << "initializing" << Init->getSourceRange(); return true; } @@ -2737,7 +3864,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // Actually try to convert the initializer to T1. if (ICS) { // C++ [over.ics.ref]p2: - // + // // When a parameter of reference type is not bound directly to // an argument expression, the conversion sequence is the one // required to convert the argument expression to the @@ -2747,19 +3874,48 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // the argument expression. Any difference in top-level // cv-qualification is subsumed by the initialization itself // and does not constitute a conversion. - *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions); + *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + // Of course, that's still a reference binding. if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) { ICS->Standard.ReferenceBinding = true; ICS->Standard.RRefBinding = isRValRef; - } else if(ICS->ConversionKind == + } else if (ICS->ConversionKind == ImplicitConversionSequence::UserDefinedConversion) { ICS->UserDefined.After.ReferenceBinding = true; ICS->UserDefined.After.RRefBinding = isRValRef; } return ICS->ConversionKind == ImplicitConversionSequence::BadConversion; } else { - return PerformImplicitConversion(Init, T1, "initializing"); + ImplicitConversionSequence Conversions; + bool badConversion = PerformImplicitConversion(Init, T1, "initializing", + false, false, + Conversions); + if (badConversion) { + if ((Conversions.ConversionKind == + ImplicitConversionSequence::BadConversion) + && !Conversions.ConversionFunctionSet.empty()) { + Diag(DeclLoc, + diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange(); + for (int j = Conversions.ConversionFunctionSet.size()-1; + j >= 0; j--) { + FunctionDecl *Func = Conversions.ConversionFunctionSet[j]; + Diag(Func->getLocation(), diag::err_ovl_candidate); + } + } + else { + if (isRValRef) + Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) + << Init->getSourceRange(); + else + Diag(DeclLoc, diag::err_invalid_initialization) + << DeclType << Init->getType() << Init->getSourceRange(); + } + } + return badConversion; } } @@ -2772,7 +3928,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { OverloadedOperatorKind Op = FnDecl->getOverloadedOperator(); - // C++ [over.oper]p5: + // C++ [over.oper]p5: // The allocation and deallocation functions, operator new, // operator new[], operator delete and operator delete[], are // described completely in 3.7.3. The attributes and restrictions @@ -2815,13 +3971,13 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // An operator function cannot have default arguments (8.3.6), // except where explicitly stated below. // - // Only the function-call operator allows default arguments + // Only the function-call operator allows default arguments // (C++ [over.call]p1). if (Op != OO_Call) { for (FunctionDecl::param_iterator Param = FnDecl->param_begin(); Param != FnDecl->param_end(); ++Param) { if ((*Param)->hasUnparsedDefaultArg()) - return Diag((*Param)->getLocation(), + return Diag((*Param)->getLocation(), diag::err_operator_overload_default_arg) << FnDecl->getDeclName(); else if (Expr *DefArg = (*Param)->getDefaultArg()) @@ -2846,7 +4002,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // [...] Operator functions cannot have more or fewer parameters // than the number required for the corresponding operator, as // described in the rest of this subclause. - unsigned NumParams = FnDecl->getNumParams() + unsigned NumParams = FnDecl->getNumParams() + (isa<CXXMethodDecl>(FnDecl)? 1 : 0); if (Op != OO_Call && ((NumParams == 1 && !CanBeUnaryOperator) || @@ -2870,7 +4026,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // Overloaded operators other than operator() cannot be variadic. if (Op != OO_Call && - FnDecl->getType()->getAsFunctionProtoType()->isVariadic()) { + FnDecl->getType()->getAs<FunctionProtoType>()->isVariadic()) { return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic) << FnDecl->getDeclName(); } @@ -2895,12 +4051,12 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { if ((Op == OO_PlusPlus || Op == OO_MinusMinus) && NumParams == 2) { ParmVarDecl *LastParam = FnDecl->getParamDecl(FnDecl->getNumParams() - 1); bool ParamIsInt = false; - if (const BuiltinType *BT = LastParam->getType()->getAsBuiltinType()) + if (const BuiltinType *BT = LastParam->getType()->getAs<BuiltinType>()) ParamIsInt = BT->getKind() == BuiltinType::Int; if (!ParamIsInt) return Diag(LastParam->getLocation(), - diag::err_operator_overload_post_incdec_must_be_int) + diag::err_operator_overload_post_incdec_must_be_int) << LastParam->getType() << (Op == OO_MinusMinus); } @@ -2910,6 +4066,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { assert(isa<CXXMethodDecl>(FnDecl) && "Overloaded = not member, but not filtered."); CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); + Method->setCopyAssignment(true); Method->getParent()->addedAssignmentOperator(Context, Method); } @@ -2938,11 +4095,11 @@ Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, Diag(LangLoc, diag::err_bad_language); return DeclPtrTy(); } - + // FIXME: Add all the various semantics of linkage specifications - + LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, - LangLoc, Language, + LangLoc, Language, LBraceLoc.isValid()); CurContext->addDecl(D); PushDeclContext(S, D); @@ -2965,6 +4122,7 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S, /// occurs within a C++ catch clause, returning the newly-created /// variable. VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, + DeclaratorInfo *DInfo, IdentifierInfo *Name, SourceLocation Loc, SourceRange Range) { @@ -2980,7 +4138,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, // The exception-declaration shall not denote a pointer or reference to an // incomplete type, other than [cv] void*. // N2844 forbids rvalue references. - if(!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) { + if (!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) { Diag(Loc, diag::err_catch_rvalue_ref) << Range; Invalid = true; } @@ -2988,11 +4146,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, QualType BaseType = ExDeclType; int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference unsigned DK = diag::err_catch_incomplete; - if (const PointerType *Ptr = BaseType->getAsPointerType()) { + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { BaseType = Ptr->getPointeeType(); Mode = 1; DK = diag::err_catch_incomplete_ptr; - } else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) { + } else if (const ReferenceType *Ref = BaseType->getAs<ReferenceType>()) { // For the purpose of error recovery, we treat rvalue refs like lvalue refs. BaseType = Ref->getPointeeType(); Mode = 2; @@ -3002,7 +4160,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) Invalid = true; - if (!Invalid && !ExDeclType->isDependentType() && + if (!Invalid && !ExDeclType->isDependentType() && RequireNonAbstractType(Loc, ExDeclType, diag::err_abstract_type_in_decl, AbstractVariableType)) @@ -3013,9 +4171,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, // FIXME: Need to check for abstract classes. - VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, VarDecl::None, - Range.getBegin()); + VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, + Name, ExDeclType, DInfo, VarDecl::None); if (Invalid) ExDecl->setInvalidDecl(); @@ -3026,11 +4183,12 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch /// handler. Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { - QualType ExDeclType = GetTypeForDeclarator(D, S); + DeclaratorInfo *DInfo = 0; + QualType ExDeclType = GetTypeForDeclarator(D, S, &DInfo); bool Invalid = D.isInvalidType(); IdentifierInfo *II = D.getIdentifier(); - if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) { + if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration. assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl))); @@ -3046,14 +4204,14 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { Invalid = true; } - VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, + VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, DInfo, D.getIdentifier(), D.getIdentifierLoc(), D.getDeclSpec().getSourceRange()); if (Invalid) ExDecl->setInvalidDecl(); - + // Add the exception declaration into this scope. if (II) PushOnScopeChains(ExDecl, S); @@ -3064,11 +4222,11 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { return DeclPtrTy::make(ExDecl); } -Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, +Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, ExprArg assertexpr, ExprArg assertmessageexpr) { Expr *AssertExpr = (Expr *)assertexpr.get(); - StringLiteral *AssertMessage = + StringLiteral *AssertMessage = cast<StringLiteral>((Expr *)assertmessageexpr.get()); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) { @@ -3080,32 +4238,305 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, } if (Value == 0) { - std::string str(AssertMessage->getStrData(), + std::string str(AssertMessage->getStrData(), AssertMessage->getByteLength()); - Diag(AssertLoc, diag::err_static_assert_failed) + Diag(AssertLoc, diag::err_static_assert_failed) << str << AssertExpr->getSourceRange(); } } - + assertexpr.release(); assertmessageexpr.release(); - Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc, + Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc, AssertExpr, AssertMessage); - + CurContext->addDecl(Decl); return DeclPtrTy::make(Decl); } -bool Sema::ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, DeclPtrTy Dcl) { - if (!(S->getFlags() & Scope::ClassScope)) { - Diag(FriendLoc, diag::err_friend_decl_outside_class); - return true; +/// Handle a friend type declaration. This works in tandem with +/// ActOnTag. +/// +/// Notes on friend class templates: +/// +/// We generally treat friend class declarations as if they were +/// declaring a class. So, for example, the elaborated type specifier +/// in a friend declaration is required to obey the restrictions of a +/// class-head (i.e. no typedefs in the scope chain), template +/// parameters are required to match up with simple template-ids, &c. +/// However, unlike when declaring a template specialization, it's +/// okay to refer to a template specialization without an empty +/// template parameter declaration, e.g. +/// friend class A<T>::B<unsigned>; +/// We permit this as a special case; if there are any template +/// parameters present at all, require proper matching, i.e. +/// template <> template <class T> friend class A<int>::B; +Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, + const DeclSpec &DS, + MultiTemplateParamsArg TempParams) { + SourceLocation Loc = DS.getSourceRange().getBegin(); + + assert(DS.isFriendSpecified()); + assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); + + // Try to convert the decl specifier to a type. This works for + // friend templates because ActOnTag never produces a ClassTemplateDecl + // for a TUK_Friend. + bool invalid = false; + QualType SourceTy; + QualType T = ConvertDeclSpecToType(DS, Loc, invalid, SourceTy); + if (invalid) return DeclPtrTy(); + + // This is definitely an error in C++98. It's probably meant to + // be forbidden in C++0x, too, but the specification is just + // poorly written. + // + // The problem is with declarations like the following: + // template <T> friend A<T>::foo; + // where deciding whether a class C is a friend or not now hinges + // on whether there exists an instantiation of A that causes + // 'foo' to equal C. There are restrictions on class-heads + // (which we declare (by fiat) elaborated friend declarations to + // be) that makes this tractable. + // + // FIXME: handle "template <> friend class A<T>;", which + // is possibly well-formed? Who even knows? + if (TempParams.size() && !isa<ElaboratedType>(T)) { + Diag(Loc, diag::err_tagless_friend_type_template) + << DS.getSourceRange(); + return DeclPtrTy(); } - - return false; + + // C++ [class.friend]p2: + // An elaborated-type-specifier shall be used in a friend declaration + // for a class.* + // * The class-key of the elaborated-type-specifier is required. + // This is one of the rare places in Clang where it's legitimate to + // ask about the "spelling" of the type. + if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) { + // If we evaluated the type to a record type, suggest putting + // a tag in front. + if (const RecordType *RT = T->getAs<RecordType>()) { + RecordDecl *RD = RT->getDecl(); + + std::string InsertionText = std::string(" ") + RD->getKindName(); + + Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type) + << (unsigned) RD->getTagKind() + << T + << SourceRange(DS.getFriendSpecLoc()) + << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(), + InsertionText); + return DeclPtrTy(); + }else { + Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) + << DS.getSourceRange(); + return DeclPtrTy(); + } + } + + // Enum types cannot be friends. + if (T->getAs<EnumType>()) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend) + << SourceRange(DS.getFriendSpecLoc()); + return DeclPtrTy(); + } + + // C++98 [class.friend]p1: A friend of a class is a function + // or class that is not a member of the class . . . + // But that's a silly restriction which nobody implements for + // inner classes, and C++0x removes it anyway, so we only report + // this (as a warning) if we're being pedantic. + if (!getLangOptions().CPlusPlus0x) + if (const RecordType *RT = T->getAs<RecordType>()) + if (RT->getDecl()->getDeclContext() == CurContext) + Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class); + + Decl *D; + if (TempParams.size()) + D = FriendTemplateDecl::Create(Context, CurContext, Loc, + TempParams.size(), + (TemplateParameterList**) TempParams.release(), + T.getTypePtr(), + DS.getFriendSpecLoc()); + else + D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(), + DS.getFriendSpecLoc()); + D->setAccess(AS_public); + CurContext->addDecl(D); + + return DeclPtrTy::make(D); +} + +Sema::DeclPtrTy +Sema::ActOnFriendFunctionDecl(Scope *S, + Declarator &D, + bool IsDefinition, + MultiTemplateParamsArg TemplateParams) { + const DeclSpec &DS = D.getDeclSpec(); + + assert(DS.isFriendSpecified()); + assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); + + SourceLocation Loc = D.getIdentifierLoc(); + DeclaratorInfo *DInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &DInfo); + + // C++ [class.friend]p1 + // A friend of a class is a function or class.... + // Note that this sees through typedefs, which is intended. + // It *doesn't* see through dependent types, which is correct + // according to [temp.arg.type]p3: + // If a declaration acquires a function type through a + // type dependent on a template-parameter and this causes + // a declaration that does not use the syntactic form of a + // function declarator to have a function type, the program + // is ill-formed. + if (!T->isFunctionType()) { + Diag(Loc, diag::err_unexpected_friend); + + // It might be worthwhile to try to recover by creating an + // appropriate declaration. + return DeclPtrTy(); + } + + // C++ [namespace.memdef]p3 + // - If a friend declaration in a non-local class first declares a + // class or function, the friend class or function is a member + // of the innermost enclosing namespace. + // - The name of the friend is not found by simple name lookup + // until a matching declaration is provided in that namespace + // scope (either before or after the class declaration granting + // friendship). + // - If a friend function is called, its name may be found by the + // name lookup that considers functions from namespaces and + // classes associated with the types of the function arguments. + // - When looking for a prior declaration of a class or a function + // declared as a friend, scopes outside the innermost enclosing + // namespace scope are not considered. + + CXXScopeSpec &ScopeQual = D.getCXXScopeSpec(); + DeclarationName Name = GetNameForDeclarator(D); + assert(Name); + + // The context we found the declaration in, or in which we should + // create the declaration. + DeclContext *DC; + + // FIXME: handle local classes + + // Recover from invalid scope qualifiers as if they just weren't there. + NamedDecl *PrevDecl = 0; + if (!ScopeQual.isInvalid() && ScopeQual.isSet()) { + // FIXME: RequireCompleteDeclContext + DC = computeDeclContext(ScopeQual); + + // FIXME: handle dependent contexts + if (!DC) return DeclPtrTy(); + + LookupResult R; + LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true); + PrevDecl = R.getAsSingleDecl(Context); + + // If searching in that context implicitly found a declaration in + // a different context, treat it like it wasn't found at all. + // TODO: better diagnostics for this case. Suggesting the right + // qualified scope would be nice... + if (!PrevDecl || !PrevDecl->getDeclContext()->Equals(DC)) { + D.setInvalidType(); + Diag(Loc, diag::err_qualified_friend_not_found) << Name << T; + return DeclPtrTy(); + } + + // C++ [class.friend]p1: A friend of a class is a function or + // class that is not a member of the class . . . + if (DC->Equals(CurContext)) + Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + + // Otherwise walk out to the nearest namespace scope looking for matches. + } else { + // TODO: handle local class contexts. + + DC = CurContext; + while (true) { + // Skip class contexts. If someone can cite chapter and verse + // for this behavior, that would be nice --- it's what GCC and + // EDG do, and it seems like a reasonable intent, but the spec + // really only says that checks for unqualified existing + // declarations should stop at the nearest enclosing namespace, + // not that they should only consider the nearest enclosing + // namespace. + while (DC->isRecord()) + DC = DC->getParent(); + + LookupResult R; + LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true); + PrevDecl = R.getAsSingleDecl(Context); + + // TODO: decide what we think about using declarations. + if (PrevDecl) + break; + + if (DC->isFileContext()) break; + DC = DC->getParent(); + } + + // C++ [class.friend]p1: A friend of a class is a function or + // class that is not a member of the class . . . + // C++0x changes this for both friend types and functions. + // Most C++ 98 compilers do seem to give an error here, so + // we do, too. + if (PrevDecl && DC->Equals(CurContext) && !getLangOptions().CPlusPlus0x) + Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + } + + if (DC->isFileContext()) { + // This implies that it has to be an operator or function. + if (D.getKind() == Declarator::DK_Constructor || + D.getKind() == Declarator::DK_Destructor || + D.getKind() == Declarator::DK_Conversion) { + Diag(Loc, diag::err_introducing_special_friend) << + (D.getKind() == Declarator::DK_Constructor ? 0 : + D.getKind() == Declarator::DK_Destructor ? 1 : 2); + return DeclPtrTy(); + } + } + + bool Redeclaration = false; + NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, PrevDecl, + move(TemplateParams), + IsDefinition, + Redeclaration); + if (!ND) return DeclPtrTy(); + + assert(ND->getDeclContext() == DC); + assert(ND->getLexicalDeclContext() == CurContext); + + // Add the function declaration to the appropriate lookup tables, + // adjusting the redeclarations list as necessary. We don't + // want to do this yet if the friending class is dependent. + // + // Also update the scope-based lookup if the target context's + // lookup context is in lexical scope. + if (!CurContext->isDependentContext()) { + DC = DC->getLookupContext(); + DC->makeDeclVisibleInContext(ND, /* Recoverable=*/ false); + if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) + PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false); + } + + FriendDecl *FrD = FriendDecl::Create(Context, CurContext, + D.getIdentifierLoc(), ND, + DS.getFriendSpecLoc()); + FrD->setAccess(AS_public); + CurContext->addDecl(FrD); + + return DeclPtrTy::make(ND); } void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) { + AdjustDeclIfTemplate(dcl); + Decl *Dcl = dcl.getAs<Decl>(); FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl); if (!Fn) { @@ -3142,21 +4573,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { } } -bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, +bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - QualType NewTy = New->getType()->getAsFunctionType()->getResultType(); - QualType OldTy = Old->getType()->getAsFunctionType()->getResultType(); + QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType(); + QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType(); QualType CNewTy = Context.getCanonicalType(NewTy); QualType COldTy = Context.getCanonicalType(OldTy); - if (CNewTy == COldTy && + if (CNewTy == COldTy && CNewTy.getCVRQualifiers() == COldTy.getCVRQualifiers()) return false; - + // Check if the return types are covariant QualType NewClassTy, OldClassTy; - + /// Both types must be pointers or references to classes. if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) { if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) { @@ -3169,14 +4600,14 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, OldClassTy = OldRT->getPointeeType(); } } - + // The return types aren't either both pointers or references to a class type. if (NewClassTy.isNull()) { - Diag(New->getLocation(), + Diag(New->getLocation(), diag::err_different_return_type_for_overriding_virtual_function) << New->getDeclName() << NewTy << OldTy; Diag(Old->getLocation(), diag::note_overridden_virtual_function); - + return true; } @@ -3189,9 +4620,9 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } - + // Check if we the conversion from derived to base is valid. - if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, + if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, diag::err_covariant_return_inaccessible_base, diag::err_covariant_return_ambiguous_derived_to_base_conv, // FIXME: Should this point to the return type? @@ -3200,7 +4631,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return true; } } - + // The qualifiers of the return types must be the same. if (CNewTy.getCVRQualifiers() != COldTy.getCVRQualifiers()) { Diag(New->getLocation(), @@ -3209,7 +4640,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; }; - + // The new class type must have the same or less qualifiers as the old type. if (NewClassTy.isMoreQualifiedThan(OldClassTy)) { @@ -3219,7 +4650,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; }; - + return false; } @@ -3229,6 +4660,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, /// static data member of class X, names should be looked up in the scope of /// class X. void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) { + AdjustDeclIfTemplate(Dcl); + Decl *D = Dcl.getAs<Decl>(); // If there is no declaration, there was an error parsing it. if (D == 0) @@ -3238,13 +4671,13 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) { // int foo::bar; if (!D->isOutOfLine()) return; - + // C++ [basic.lookup.unqual]p13 // // A name used in the definition of a static data member of class X // (after the qualified-id of the static member) is looked up as if the name // was used in a member function of X. - + // Change current context into the context of the initializing declaration. EnterDeclaratorContext(S, D->getDeclContext()); } @@ -3252,6 +4685,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) { /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an /// initializer for the declaration 'Dcl'. void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) { + AdjustDeclIfTemplate(Dcl); + Decl *D = Dcl.getAs<Decl>(); // If there is no declaration, there was an error parsing it. if (D == 0) diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 5cf48d6da0c86..22a517934c7ef 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -25,10 +25,10 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, if (GetterMethod && GetterMethod->getResultType() != property->getType()) { AssignConvertType result = Incompatible; - if (Context.isObjCObjectPointerType(property->getType())) + if (property->getType()->isObjCObjectPointerType()) result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType()); if (result != Compatible) { - Diag(Loc, diag::warn_accessor_property_type_mismatch) + Diag(Loc, diag::warn_accessor_property_type_mismatch) << property->getDeclName() << GetterMethod->getSelector(); Diag(GetterMethod->getLocation(), diag::note_declared_at); @@ -43,7 +43,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { assert(getCurMethodDecl() == 0 && "Method parsing confused"); ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D.getAs<Decl>()); - + // If we don't have a valid method decl, simply return. if (!MDecl) return; @@ -55,7 +55,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { AddInstanceMethodToGlobalPool(MDecl); else AddFactoryMethodToGlobalPool(MDecl); - + // Allow all of Sema to see that we are entering a method definition. PushDeclContext(FnBodyScope, MDecl); @@ -64,7 +64,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { // Insert the invisible arguments, self and _cmd! MDecl->createImplicitParams(Context, MDecl->getClassInterface()); - + PushOnScopeChains(MDecl->getSelfDecl(), FnBodyScope); PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope); @@ -82,9 +82,9 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, SourceLocation EndProtoLoc, AttributeList *AttrList) { assert(ClassName && "Missing class identifier"); - + // Check for another declaration kind with the same name. - NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName); + NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl); @@ -96,7 +96,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); } - + ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); if (IDecl) { // Class already seen. Is it a forward declaration? @@ -111,72 +111,78 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, } else { IDecl->setLocation(AtInterfaceLoc); IDecl->setForwardDecl(false); + IDecl->setClassLoc(ClassLoc); } } else { - IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, + IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName, ClassLoc); if (AttrList) ProcessDeclAttributeList(TUScope, IDecl, AttrList); - + PushOnScopeChains(IDecl, TUScope); } - + if (SuperName) { // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupName(TUScope, SuperName, LookupOrdinaryName); - - ObjCInterfaceDecl *SuperClassDecl = - dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); - - // Diagnose classes that inherit from deprecated classes. - if (SuperClassDecl) - (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); - - if (PrevDecl && SuperClassDecl == 0) { - // The previous declaration was not a class decl. Check if we have a - // 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->getAsObjCInterfaceType()->getDecl()) - SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName); + if (PrevDecl == IDecl) { + Diag(SuperLoc, diag::err_recursive_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + IDecl->setLocEnd(ClassLoc); + } else { + ObjCInterfaceDecl *SuperClassDecl = + dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + + // Diagnose classes that inherit from deprecated classes. + if (SuperClassDecl) + (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); + + if (PrevDecl && SuperClassDecl == 0) { + // The previous declaration was not a class decl. Check if we have a + // 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()) + SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + } + } + + // This handles the following case: + // + // typedef int SuperClass; + // @interface MyClass : SuperClass {} @end + // + if (!SuperClassDecl) { + Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); } } - - // This handles the following case: - // - // typedef int SuperClass; - // @interface MyClass : SuperClass {} @end - // - if (!SuperClassDecl) { - Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); + + if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) { + if (!SuperClassDecl) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + else if (SuperClassDecl->isForwardDecl()) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperClassDecl->getDeclName() << ClassName + << SourceRange(AtInterfaceLoc, ClassLoc); } + IDecl->setSuperClass(SuperClassDecl); + IDecl->setSuperClassLoc(SuperLoc); + IDecl->setLocEnd(SuperLoc); } - - if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) { - if (!SuperClassDecl) - Diag(SuperLoc, diag::err_undef_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - else if (SuperClassDecl->isForwardDecl()) - Diag(SuperLoc, diag::err_undef_superclass) - << SuperClassDecl->getDeclName() << ClassName - << SourceRange(AtInterfaceLoc, ClassLoc); - } - IDecl->setSuperClass(SuperClassDecl); - IDecl->setSuperClassLoc(SuperLoc); - IDecl->setLocEnd(SuperLoc); } else { // we have a root class. IDecl->setLocEnd(ClassLoc); } - + /// Check then save referenced protocols. if (NumProtoRefs) { IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, Context); IDecl->setLocEnd(EndProtoLoc); } - + CheckObjCDeclScope(IDecl); return DeclPtrTy::make(IDecl); } @@ -184,12 +190,12 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, /// ActOnCompatiblityAlias - this action is called after complete parsing of /// @compatibility_alias declaration. It sets up the alias relationships. Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, - IdentifierInfo *AliasName, + IdentifierInfo *AliasName, SourceLocation AliasLocation, IdentifierInfo *ClassName, SourceLocation ClassLocation) { // Look for previous declaration of alias name - NamedDecl *ADecl = LookupName(TUScope, AliasName, LookupOrdinaryName); + NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName); if (ADecl) { if (isa<ObjCCompatibleAliasDecl>(ADecl)) Diag(AliasLocation, diag::warn_previous_alias_decl); @@ -199,13 +205,13 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, return DeclPtrTy(); } // Check for class declaration - NamedDecl *CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName); + NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCInterfaceType()) { - if (NamedDecl *IDecl = T->getAsObjCInterfaceType()->getDecl()) { + if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) { ClassName = IDecl->getIdentifier(); - CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName); + CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); } } } @@ -216,11 +222,11 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, Diag(CDeclU->getLocation(), diag::note_previous_declaration); return DeclPtrTy(); } - + // Everything checked out, instantiate a new alias declaration AST. - ObjCCompatibleAliasDecl *AliasDecl = + ObjCCompatibleAliasDecl *AliasDecl = ObjCCompatibleAliasDecl::Create(Context, CurContext, AtLoc, AliasName, CDecl); - + if (!CheckObjCDeclScope(AliasDecl)) PushOnScopeChains(AliasDecl, TUScope); @@ -230,17 +236,16 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, void Sema::CheckForwardProtocolDeclarationForCircularDependency( IdentifierInfo *PName, SourceLocation &Ploc, SourceLocation PrevLoc, - const ObjCList<ObjCProtocolDecl> &PList) -{ + const ObjCList<ObjCProtocolDecl> &PList) { for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(), E = PList.end(); I != E; ++I) { - + if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) { if (PDecl->getIdentifier() == PName) { Diag(Ploc, diag::err_protocol_has_circular_dependency); Diag(PrevLoc, diag::note_previous_definition); } - CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc, + CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc, PDecl->getLocation(), PDecl->getReferencedProtocols()); } } @@ -267,16 +272,16 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, return DeclPtrTy::make(PDecl); } ObjCList<ObjCProtocolDecl> PList; - PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); + PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); CheckForwardProtocolDeclarationForCircularDependency( ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); PList.Destroy(Context); - + // Make sure the cached decl gets a valid start location. PDecl->setLocation(AtProtoInterfaceLoc); PDecl->setForwardDecl(false); } else { - PDecl = ObjCProtocolDecl::Create(Context, CurContext, + PDecl = ObjCProtocolDecl::Create(Context, CurContext, AtProtoInterfaceLoc,ProtocolName); PushOnScopeChains(PDecl, TUScope); PDecl->setForwardDecl(false); @@ -288,8 +293,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); PDecl->setLocEnd(EndProtoLoc); } - - CheckObjCDeclScope(PDecl); + + CheckObjCDeclScope(PDecl); return DeclPtrTy::make(PDecl); } @@ -308,7 +313,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, << ProtocolId[i].first; continue; } - + (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second); // If this is a forward declaration and we are supposed to warn in this @@ -324,12 +329,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, /// attributes and types and warns on a variety of inconsistencies. /// void -Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, +Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *inheritedName) { - ObjCPropertyDecl::PropertyAttributeKind CAttr = + ObjCPropertyDecl::PropertyAttributeKind CAttr = Property->getPropertyAttributes(); - ObjCPropertyDecl::PropertyAttributeKind SAttr = + ObjCPropertyDecl::PropertyAttributeKind SAttr = SuperProperty->getPropertyAttributes(); if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) @@ -343,27 +348,27 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "retain" << inheritedName; - + if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "atomic" << inheritedName; if (Property->getSetterName() != SuperProperty->getSetterName()) Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "setter" << inheritedName; + << Property->getDeclName() << "setter" << inheritedName; if (Property->getGetterName() != SuperProperty->getGetterName()) Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "getter" << inheritedName; - QualType LHSType = + QualType LHSType = Context.getCanonicalType(SuperProperty->getType()); - QualType RHSType = + QualType RHSType = Context.getCanonicalType(Property->getType()); - + if (!Context.typesAreCompatible(LHSType, RHSType)) { // FIXME: Incorporate this test with typesAreCompatible. if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType()) - if (ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) + if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) return; Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) << Property->getType() << SuperProperty->getType() << inheritedName; @@ -387,7 +392,7 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { E = IDecl->prop_end(); I != E; ++I) { ObjCPropertyDecl *PDecl = (*I); if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) - DiagnosePropertyMismatch(PDecl, SuperPDecl, + DiagnosePropertyMismatch(PDecl, SuperPDecl, SDecl->getIdentifier()); } } @@ -450,7 +455,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, E = MDecl->protocol_end(); P != E; ++P) // Merge properties of category (*P) into IDECL's MergeOneProtocolPropertiesIntoClass(CatDecl, *P); - + // Go thru the list of protocols for this category and recursively merge // their properties into this class as well. for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), @@ -470,7 +475,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, E = MDecl->protocol_end(); P != E; ++P) // Merge properties of class (*P) into IDECL's MergeOneProtocolPropertiesIntoClass(IDecl, *P); - + // Go thru the list of protocols for this class and recursively merge // their properties into this class as well. for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), @@ -487,7 +492,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of /// a class method in its extension. /// -void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, +void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID) { if (!ID) return; // Possibly due to previous error @@ -520,12 +525,12 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, unsigned NumElts, AttributeList *attrList) { llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols; - + for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; ObjCProtocolDecl *PDecl = LookupProtocol(Ident); if (PDecl == 0) { // Not already seen? - PDecl = ObjCProtocolDecl::Create(Context, CurContext, + PDecl = ObjCProtocolDecl::Create(Context, CurContext, IdentList[i].second, Ident); PushOnScopeChains(PDecl, TUScope); } @@ -533,8 +538,8 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, ProcessDeclAttributeList(TUScope, PDecl, attrList); Protocols.push_back(PDecl); } - - ObjCForwardProtocolDecl *PDecl = + + ObjCForwardProtocolDecl *PDecl = ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc, &Protocols[0], Protocols.size()); CurContext->addDecl(PDecl); @@ -550,7 +555,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, SourceLocation EndProtoLoc) { - ObjCCategoryDecl *CDecl = + ObjCCategoryDecl *CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -564,7 +569,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, } CDecl->setClassInterface(IDecl); - + // If the interface is deprecated, warn about it. (void)DiagnoseUseOfDecl(IDecl, ClassLoc); @@ -583,10 +588,15 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, CDecl->insertNextClassCategory(); if (NumProtoRefs) { - CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); + CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + Context); CDecl->setLocEnd(EndProtoLoc); + // Protocols in the class extension belong to the class. + if (!CDecl->getIdentifier()) + IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, + NumProtoRefs,Context); } - + CheckObjCDeclScope(CDecl); return DeclPtrTy::make(CDecl); } @@ -599,7 +609,20 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); - ObjCCategoryImplDecl *CDecl = + ObjCCategoryDecl *CatIDecl = 0; + if (IDecl) { + CatIDecl = IDecl->FindCategoryDeclaration(CatName); + if (!CatIDecl) { + // Category @implementation with no corresponding @interface. + // Create and install one. + CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(), + CatName); + CatIDecl->setClassInterface(IDecl); + CatIDecl->insertNextClassCategory(); + } + } + + ObjCCategoryImplDecl *CDecl = ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName, IDecl); /// Check that class of this category is already completely declared. @@ -609,10 +632,17 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); - /// TODO: Check that CatName, category name, is not used in another - // implementation. - ObjCCategoryImpls.push_back(CDecl); - + /// Check that CatName, category name, is not used in another implementation. + if (CatIDecl) { + if (CatIDecl->getImplementation()) { + Diag(ClassLoc, diag::err_dup_implementation_category) << ClassName + << CatName; + Diag(CatIDecl->getImplementation()->getLocation(), + diag::note_previous_definition); + } else + CatIDecl->setImplementation(CDecl); + } + CheckObjCDeclScope(CDecl); return DeclPtrTy::make(CDecl); } @@ -620,34 +650,35 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( Sema::DeclPtrTy Sema::ActOnStartClassImplementation( SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, + IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc) { ObjCInterfaceDecl* IDecl = 0; // Check for another declaration kind with the same name. - NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName); + NamedDecl *PrevDecl + = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); } else { // Is there an interface declaration of this class; if not, warn! - IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); if (!IDecl || IDecl->isForwardDecl()) { Diag(ClassLoc, diag::warn_undef_interface) << ClassName; IDecl = 0; } } - + // Check that super class name is valid class name ObjCInterfaceDecl* SDecl = 0; if (SuperClassname) { // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupName(TUScope, SuperClassname, LookupOrdinaryName); + PrevDecl = LookupSingleName(TUScope, SuperClassname, LookupOrdinaryName); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(SuperClassLoc, diag::err_redefinition_different_kind) << SuperClassname; Diag(PrevDecl->getLocation(), diag::note_previous_definition); } else { - SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); if (!SDecl) Diag(SuperClassLoc, diag::err_undef_superclass) << SuperClassname << ClassName; @@ -660,14 +691,14 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( } } } - + if (!IDecl) { // Legacy case of @implementation with no corresponding @interface. // Build, chain & install the interface decl into the identifier. // FIXME: Do we support attributes on the @implementation? If so we should // copy them over. - IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc, + IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc, ClassName, ClassLoc, false, true); IDecl->setSuperClass(SDecl); IDecl->setLocEnd(ClassLoc); @@ -679,20 +710,24 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( // declaration; the user cannot reopen it. IDecl->setForwardDecl(false); } - - ObjCImplementationDecl* IMPDecl = - ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc, + + ObjCImplementationDecl* IMPDecl = + ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc, IDecl, SDecl); - + if (CheckObjCDeclScope(IMPDecl)) return DeclPtrTy::make(IMPDecl); - + // Check that there is no duplicate implementation of this class. - if (LookupObjCImplementation(ClassName)) + if (IDecl->getImplementation()) { // FIXME: Don't leak everything! Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName; - else // add it to the list. + Diag(IDecl->getImplementation()->getLocation(), + diag::note_previous_definition); + } else { // add it to the list. + IDecl->setImplementation(IMPDecl); PushOnScopeChains(IMPDecl, TUScope); + } return DeclPtrTy::make(IMPDecl); } @@ -714,21 +749,21 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, // If implementation has empty ivar list, just return. if (numIvars == 0) return; - + assert(ivars && "missing @implementation ivars"); - + // Check interface's Ivar list against those in the implementation. // names and types must match. // unsigned j = 0; - ObjCInterfaceDecl::ivar_iterator + ObjCInterfaceDecl::ivar_iterator IVI = IDecl->ivar_begin(), IVE = IDecl->ivar_end(); for (; numIvars > 0 && IVI != IVE; ++IVI) { ObjCIvarDecl* ImplIvar = ivars[j++]; ObjCIvarDecl* ClsIvar = *IVI; assert (ImplIvar && "missing implementation ivar"); assert (ClsIvar && "missing class ivar"); - + // First, make sure the types match. if (Context.getCanonicalType(ImplIvar->getType()) != Context.getCanonicalType(ClsIvar->getType())) { @@ -745,7 +780,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, << ImplIvar->getIdentifier(); Diag(ClsBitWidth->getLocStart(), diag::note_previous_definition); } - } + } // Make sure the names are identical. if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) { Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name) @@ -754,7 +789,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, } --numIvars; } - + if (numIvars > 0) Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count); else if (IVI != IVE) @@ -774,22 +809,23 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, ObjCMethodDecl *IntfMethodDecl) { if (!Context.typesAreCompatible(IntfMethodDecl->getResultType(), ImpMethodDecl->getResultType()) && - !QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(), - ImpMethodDecl->getResultType())) { - Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types) + !Context.QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(), + ImpMethodDecl->getResultType())) { + Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types) << ImpMethodDecl->getDeclName() << IntfMethodDecl->getResultType() << ImpMethodDecl->getResultType(); Diag(IntfMethodDecl->getLocation(), diag::note_previous_definition); } - + for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); IM != EM; ++IM, ++IF) { if (Context.typesAreCompatible((*IF)->getType(), (*IM)->getType()) || - QualifiedIdConformsQualifiedId((*IF)->getType(), (*IM)->getType())) + Context.QualifiedIdConformsQualifiedId((*IF)->getType(), + (*IM)->getType())) continue; - - Diag((*IM)->getLocation(), diag::warn_conflicting_param_types) + + Diag((*IM)->getLocation(), diag::warn_conflicting_param_types) << ImpMethodDecl->getDeclName() << (*IF)->getType() << (*IM)->getType(); Diag((*IF)->getLocation(), diag::note_previous_definition); @@ -804,43 +840,41 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, // by far the most common case. if (!PDecl->isReadOnly()) return false; - // Even if property is ready only, if interface has a user defined setter, + // Even if property is ready only, if interface has a user defined setter, // it is not considered read only. if (IDecl->getInstanceMethod(PDecl->getSetterName())) return false; - + // Main class has the property as 'readonly'. Must search - // through the category list to see if the property's + // through the category list to see if the property's // attribute has been over-ridden to 'readwrite'. for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); Category; Category = Category->getNextClassCategory()) { - // Even if property is ready only, if a category has a user defined setter, - // it is not considered read only. + // Even if property is ready only, if a category has a user defined setter, + // it is not considered read only. if (Category->getInstanceMethod(PDecl->getSetterName())) return false; - ObjCPropertyDecl *P = + ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PDecl->getIdentifier()); if (P && !P->isReadOnly()) return false; } - + // Also, check for definition of a setter method in the implementation if // all else failed. if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) { - if (ObjCImplementationDecl *IMD = + if (ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) { if (IMD->getInstanceMethod(PDecl->getSetterName())) return false; - } - else if (ObjCCategoryImplDecl *CIMD = - dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { + } else if (ObjCCategoryImplDecl *CIMD = + dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { if (CIMD->getInstanceMethod(PDecl->getSetterName())) return false; } } // Lastly, look through the implementation (if one is in scope). - if (ObjCImplementationDecl *ImpDecl - = LookupObjCImplementation(IDecl->getIdentifier())) + if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation()) if (ImpDecl->getInstanceMethod(PDecl->getSetterName())) return false; // If all fails, look at the super class. @@ -866,11 +900,11 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, ObjCInterfaceDecl *Super = IDecl->getSuperClass(); ObjCInterfaceDecl *NSIDecl = 0; if (getLangOptions().NeXTRuntime) { - // check to see if class implements forwardInvocation method and objects - // of this class are derived from 'NSProxy' so that to forward requests + // check to see if class implements forwardInvocation method and objects + // of this class are derived from 'NSProxy' so that to forward requests // from one object to another. - // Under such conditions, which means that every method possible is - // implemented in the class, we should not issue "Method definition not + // Under such conditions, which means that every method possible is + // implemented in the class, we should not issue "Method definition not // found" warnings. // FIXME: Use a general GetUnarySelector method for this. IdentifierInfo* II = &Context.Idents.get("forwardInvocation"); @@ -880,7 +914,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, // need be implemented in the implementation. NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy")); } - + // If a method lookup fails locally we still need to look and see if // the method was implemented by a base class or an inherited // protocol. This lookup is slow, but occurs rarely in correct code @@ -888,24 +922,24 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, // check unimplemented instance methods. if (!NSIDecl) - for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), + for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); I != E; ++I) { ObjCMethodDecl *method = *I; - if (method->getImplementationControl() != ObjCMethodDecl::Optional && + if (method->getImplementationControl() != ObjCMethodDecl::Optional && !method->isSynthesized() && !InsMap.count(method->getSelector()) && - (!Super || + (!Super || !Super->lookupInstanceMethod(method->getSelector()))) { // Ugly, but necessary. Method declared in protcol might have // have been synthesized due to a property declared in the class which // uses the protocol. - ObjCMethodDecl *MethodInClass = + ObjCMethodDecl *MethodInClass = IDecl->lookupInstanceMethod(method->getSelector()); if (!MethodInClass || !MethodInClass->isSynthesized()) WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); } } // check unimplemented class methods - for (ObjCProtocolDecl::classmeth_iterator + for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); I != E; ++I) { ObjCMethodDecl *method = *I; @@ -930,8 +964,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool &IncompleteImpl, - bool ImmediateClass) -{ + bool ImmediateClass) { // Check and see if instance methods in class interface have been // implemented in the implementation class. If so, their types match. for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(), @@ -939,28 +972,27 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, if (InsMapSeen.count((*I)->getSelector())) continue; InsMapSeen.insert((*I)->getSelector()); - if (!(*I)->isSynthesized() && + if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) { if (ImmediateClass) WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); continue; - } - else { - ObjCMethodDecl *ImpMethodDecl = + } else { + ObjCMethodDecl *ImpMethodDecl = IMPDecl->getInstanceMethod((*I)->getSelector()); - ObjCMethodDecl *IntfMethodDecl = + ObjCMethodDecl *IntfMethodDecl = CDecl->getInstanceMethod((*I)->getSelector()); - assert(IntfMethodDecl && + assert(IntfMethodDecl && "IntfMethodDecl is null in ImplMethodsVsClassMethods"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); } } - + // Check and see if class methods in class interface have been // implemented in the implementation class. If so, their types match. - for (ObjCInterfaceDecl::classmeth_iterator + for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(), E = CDecl->classmeth_end(); I != E; ++I) { if (ClsMapSeen.count((*I)->getSelector())) continue; @@ -968,11 +1000,10 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, if (!ClsMap.count((*I)->getSelector())) { if (ImmediateClass) WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); - } - else { + } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod((*I)->getSelector()); - ObjCMethodDecl *IntfMethodDecl = + ObjCMethodDecl *IntfMethodDecl = CDecl->getClassMethod((*I)->getSelector()); WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); } @@ -981,26 +1012,26 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, // Check for any implementation of a methods declared in protocol. for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), E = I->protocol_end(); PI != E; ++PI) - MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, (*PI), IncompleteImpl, false); if (I->getSuperClass()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, + IMPDecl, I->getSuperClass(), IncompleteImpl, false); } } -void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, - ObjCContainerDecl* CDecl, +void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* CDecl, bool IncompleteImpl) { llvm::DenseSet<Selector> InsMap; // Check and see if instance methods in class interface have been // implemented in the implementation class. - for (ObjCImplementationDecl::instmeth_iterator + for (ObjCImplementationDecl::instmeth_iterator I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I) InsMap.insert((*I)->getSelector()); - + // 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. @@ -1012,7 +1043,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, continue; ObjCPropertyImplDecl *PI = 0; // Is there a matching propery synthesize/dynamic? - for (ObjCImplDecl::propimpl_iterator + for (ObjCImplDecl::propimpl_iterator I = IMPDecl->propimpl_begin(), EI = IMPDecl->propimpl_end(); I != EI; ++I) if ((*I)->getPropertyDecl() == Prop) { @@ -1022,44 +1053,44 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, if (PI) continue; if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), - diag::warn_setter_getter_impl_required) + Diag(Prop->getLocation(), + diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getGetterName(); Diag(IMPDecl->getLocation(), diag::note_property_impl_required); } - + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { - Diag(Prop->getLocation(), - diag::warn_setter_getter_impl_required) + Diag(Prop->getLocation(), + diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getSetterName(); Diag(IMPDecl->getLocation(), diag::note_property_impl_required); } } - + llvm::DenseSet<Selector> ClsMap; - for (ObjCImplementationDecl::classmeth_iterator + for (ObjCImplementationDecl::classmeth_iterator I = IMPDecl->classmeth_begin(), E = IMPDecl->classmeth_end(); I != E; ++I) ClsMap.insert((*I)->getSelector()); - + // Check for type conflict of methods declared in a class/protocol and // its implementation; if any. llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen; - MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, CDecl, + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, CDecl, IncompleteImpl, true); - + // Check the protocol list for unimplemented methods in the @implementation // class. // Check and see if class methods in class interface have been // implemented in the implementation class. - + if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) { for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), E = I->protocol_end(); PI != E; ++PI) - CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, + CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, I); // Check class extensions (unnamed categories) for (ObjCCategoryDecl *Categories = I->getCategoryList(); @@ -1070,24 +1101,29 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, } } } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { - for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), - E = C->protocol_end(); PI != E; ++PI) - CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, - InsMap, ClsMap, C->getClassInterface()); + // For extended class, unimplemented methods in its protocols will + // be reported in the primary class. + if (C->getIdentifier()) { + for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), + E = C->protocol_end(); PI != E; ++PI) + CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, + InsMap, ClsMap, C->getClassInterface()); + } } else assert(false && "invalid ObjCContainerDecl type."); } -/// ActOnForwardClassDeclaration - +/// ActOnForwardClassDeclaration - Action::DeclPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, unsigned NumElts) { llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces; - + for (unsigned i = 0; i != NumElts; ++i) { // Check for another declaration kind with the same name. - NamedDecl *PrevDecl = LookupName(TUScope, IdentList[i], LookupOrdinaryName); + NamedDecl *PrevDecl + = LookupSingleName(TUScope, IdentList[i], LookupOrdinaryName); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl); @@ -1101,30 +1137,32 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, // typedef NSObject < XCElementTogglerP > XCElementToggler; // @class XCElementToggler; // - // FIXME: Make an extension? + // FIXME: Make an extension? TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl); if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) { Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i]; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } - else if (TDD) { - // a forward class declaration matching a typedef name of a class - // refers to the underlying class. - if (ObjCInterfaceType * OI = + } else if (TDD) { + // 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(); } } - ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); if (!IDecl) { // Not already seen? Make a forward decl. - IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc, - IdentList[i], SourceLocation(), true); + IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc, + IdentList[i], + // FIXME: need to get the 'real' + // identifier loc from the parser. + AtClassLoc, true); PushOnScopeChains(IDecl, TUScope); } Interfaces.push_back(IDecl); } - + ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, &Interfaces[0], Interfaces.size()); @@ -1137,12 +1175,12 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, /// MatchTwoMethodDeclarations - Checks that two methods have matching type and /// returns true, or false, accordingly. /// TODO: Handle protocol list; such as id<p1,p2> in type comparisons -bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, +bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, bool matchBasedOnSizeAndAlignment) { QualType T1 = Context.getCanonicalType(Method->getResultType()); QualType T2 = Context.getCanonicalType(PrevMethod->getResultType()); - + if (T1 != T2) { // The result types are different. if (!matchBasedOnSizeAndAlignment) @@ -1154,11 +1192,11 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2)) return false; } - + ObjCMethodDecl::param_iterator ParamI = Method->param_begin(), E = Method->param_end(); ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin(); - + for (; ParamI != E; ++ParamI, ++PrevI) { assert(PrevI != PrevMethod->param_end() && "Param mismatch"); T1 = Context.getCanonicalType((*ParamI)->getType()); @@ -1183,7 +1221,7 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, /// /// This routine should only be called once, when neither the instance /// nor the factory method pool has an entry for this selector. -Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, +Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, bool isInstance) { assert(ExternalSource && "We need an external AST source"); assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() && @@ -1194,12 +1232,12 @@ Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, // Read the method list from the external source. std::pair<ObjCMethodList, ObjCMethodList> Methods = ExternalSource->ReadMethodPool(Sel); - + if (isInstance) { if (Methods.second.Method) FactoryMethodPool[Sel] = Methods.second; return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first; - } + } if (Methods.first.Method) InstanceMethodPool[Sel] = Methods.first; @@ -1225,21 +1263,22 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { Entry.Next = 0; return; } - + // We've seen a method with this name, see if we have already seen this type // signature. for (ObjCMethodList *List = &Entry; List; List = List->Next) if (MatchTwoMethodDeclarations(Method, List->Method)) return; - + // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". Entry.Next = new ObjCMethodList(Method, Entry.Next); } // FIXME: Finish implementing -Wno-strict-selector-match. -ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, - SourceRange R) { +ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, + SourceRange R, + bool warn) { llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos = InstanceMethodPool.find(Sel); if (Pos == InstanceMethodPool.end()) { @@ -1251,12 +1290,12 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, ObjCMethodList &MethList = Pos->second; bool issueWarning = false; - + if (MethList.Method && MethList.Next) { for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) // This checks if the methods differ by size & alignment. if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) - issueWarning = true; + issueWarning = warn; } if (issueWarning && (MethList.Method && MethList.Next)) { Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; @@ -1288,11 +1327,11 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { } else { // We've seen a method with this name, now check the type signature(s). bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); - - for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; + + for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; Next = Next->Next) match = MatchTwoMethodDeclarations(Method, Next->Method); - + if (!match) { // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". @@ -1302,12 +1341,12 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { } } -ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, +ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R) { llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos = FactoryMethodPool.find(Sel); if (Pos == FactoryMethodPool.end()) { - if (ExternalSource && !InstanceMethodPool.count(Sel)) + if (ExternalSource && !InstanceMethodPool.count(Sel)) Pos = ReadMethodPool(Sel, /*isInstance=*/false); else return 0; @@ -1315,7 +1354,7 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, ObjCMethodList &MethList = Pos->second; bool issueWarning = false; - + if (MethList.Method && MethList.Next) { for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) // This checks if the methods differ by size & alignment. @@ -1333,28 +1372,28 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, return MethList.Method; } -/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods +/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods /// have the property type and issue diagnostics if they don't. /// Also synthesize a getter/setter method if none exist (and update the /// appropriate lookup tables. FIXME: Should reconsider if adding synthesized /// methods is the "right" thing to do. -void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, +void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *CD) { ObjCMethodDecl *GetterMethod, *SetterMethod; - - GetterMethod = CD->getInstanceMethod(property->getGetterName()); + + GetterMethod = CD->getInstanceMethod(property->getGetterName()); SetterMethod = CD->getInstanceMethod(property->getSetterName()); - DiagnosePropertyAccessorMismatch(property, GetterMethod, + DiagnosePropertyAccessorMismatch(property, GetterMethod, property->getLocation()); - + if (SetterMethod) { - if (Context.getCanonicalType(SetterMethod->getResultType()) + if (Context.getCanonicalType(SetterMethod->getResultType()) != Context.VoidTy) Diag(SetterMethod->getLocation(), diag::err_setter_type_void); if (SetterMethod->param_size() != 1 || ((*SetterMethod->param_begin())->getType() != property->getType())) { - Diag(property->getLocation(), - diag::warn_accessor_property_type_mismatch) + Diag(property->getLocation(), + diag::warn_accessor_property_type_mismatch) << property->getDeclName() << SetterMethod->getSelector(); Diag(SetterMethod->getLocation(), diag::note_declared_at); @@ -1369,14 +1408,14 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // declarations jive in that situation (which it is not currently). if (!GetterMethod) { // No instance method of same name as property getter name was found. - // Declare a getter method and add it to the list of methods + // Declare a getter method and add it to the list of methods // for this class. - GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), - property->getLocation(), property->getGetterName(), - property->getType(), CD, true, false, true, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : + GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), property->getGetterName(), + property->getType(), CD, true, false, true, + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : ObjCMethodDecl::Required); CD->addDecl(GetterMethod); } else @@ -1390,22 +1429,23 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // Find the default setter and if one not found, add one. if (!SetterMethod) { // No instance method of same name as property setter name was found. - // Declare a setter method and add it to the list of methods + // Declare a setter method and add it to the list of methods // for this class. - SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), - property->getLocation(), - property->getSetterName(), + SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), + property->getSetterName(), Context.VoidTy, CD, true, false, true, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : ObjCMethodDecl::Required); // Invent the arguments for the setter. We don't bother making a // nice name for the argument. ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, - property->getLocation(), + property->getLocation(), property->getIdentifier(), property->getType(), + /*DInfo=*/0, VarDecl::None, 0); SetterMethod->setMethodParams(Context, &Argument, 1); @@ -1416,7 +1456,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, SetterMethod->setSynthesized(true); property->setSetterMethodDecl(SetterMethod); } - // Add any synthesized methods to the global pool. This allows us to + // Add any synthesized methods to the global pool. This allows us to // handle the following, which is supported by GCC (and part of the design). // // @interface Foo @@ -1429,9 +1469,46 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // } // if (GetterMethod) - AddInstanceMethodToGlobalPool(GetterMethod); + AddInstanceMethodToGlobalPool(GetterMethod); if (SetterMethod) - AddInstanceMethodToGlobalPool(SetterMethod); + AddInstanceMethodToGlobalPool(SetterMethod); +} + +/// CompareMethodParamsInBaseAndSuper - This routine compares methods with +/// identical selector names in current and its super classes and issues +/// a warning if any of their argument types are incompatible. +void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl, + ObjCMethodDecl *Method, + bool IsInstance) { + ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ClassDecl); + if (ID == 0) return; + + while (ObjCInterfaceDecl *SD = ID->getSuperClass()) { + ObjCMethodDecl *SuperMethodDecl = + SD->lookupMethod(Method->getSelector(), IsInstance); + if (SuperMethodDecl == 0) { + ID = SD; + continue; + } + ObjCMethodDecl::param_iterator ParamI = Method->param_begin(), + E = Method->param_end(); + ObjCMethodDecl::param_iterator PrevI = SuperMethodDecl->param_begin(); + for (; ParamI != E; ++ParamI, ++PrevI) { + // Number of parameters are the same and is guaranteed by selector match. + assert(PrevI != SuperMethodDecl->param_end() && "Param mismatch"); + QualType T1 = Context.getCanonicalType((*ParamI)->getType()); + QualType T2 = Context.getCanonicalType((*PrevI)->getType()); + // If type of arguement of method in this class does not match its + // respective argument type in the super class method, issue warning; + if (!Context.typesAreCompatible(T1, T2)) { + Diag((*ParamI)->getLocation(), diag::ext_typecheck_base_super) + << T1 << T2; + Diag(SuperMethodDecl->getLocation(), diag::note_previous_declaration); + return; + } + } + ID = SD; + } } // Note: For class/category implemenations, allMethods/allProperties is @@ -1447,8 +1524,8 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, // should be true. if (!ClassDecl) return; - - bool isInterfaceDeclKind = + + bool isInterfaceDeclKind = isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl) || isa<ObjCProtocolDecl>(ClassDecl); bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); @@ -1467,9 +1544,9 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, if (Method->isInstanceMethod()) { /// Check for instance method of the same name with incompatible types const ObjCMethodDecl *&PrevMethod = InsMap[Method->getSelector()]; - bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) : false; - if ((isInterfaceDeclKind && PrevMethod && !match) + if ((isInterfaceDeclKind && PrevMethod && !match) || (checkIdenticalMethods && match)) { Diag(Method->getLocation(), diag::err_duplicate_method_decl) << Method->getDeclName(); @@ -1479,14 +1556,16 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, InsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "id". AddInstanceMethodToGlobalPool(Method); + // verify that the instance method conforms to the same definition of + // parent methods if it shadows one. + CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true); } - } - else { + } else { /// Check for class method of the same name with incompatible types const ObjCMethodDecl *&PrevMethod = ClsMap[Method->getSelector()]; - bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) : false; - if ((isInterfaceDeclKind && PrevMethod && !match) + if ((isInterfaceDeclKind && PrevMethod && !match) || (checkIdenticalMethods && match)) { Diag(Method->getLocation(), diag::err_duplicate_method_decl) << Method->getDeclName(); @@ -1496,17 +1575,20 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, ClsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "Class". AddFactoryMethodToGlobalPool(Method); + // verify that the class method conforms to the same definition of + // parent methods if it shadows one. + CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false); } } } if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { - // Compares properties declared in this class to those of its + // Compares properties declared in this class to those of its // super class. ComparePropertiesInBaseAndSuper(I); MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I)); } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { // Categories are used to extend the class by declaring new methods. - // By the same token, they are also used to add new properties. No + // By the same token, they are also used to add new properties. No // need to compare the added property to those in the class. // Merge protocol properties into category @@ -1525,13 +1607,13 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, CDecl->setAtEndLoc(AtEndLoc); } if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { - IC->setLocEnd(AtEndLoc); + IC->setAtEndLoc(AtEndLoc); if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) ImplMethodsVsClassMethods(IC, IDecl); - } else if (ObjCCategoryImplDecl* CatImplClass = + } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { - CatImplClass->setLocEnd(AtEndLoc); - + CatImplClass->setAtEndLoc(AtEndLoc); + // Find category interface decl and then check that all methods declared // in this interface are implemented in the category @implementation. if (ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface()) { @@ -1560,7 +1642,7 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, /// CvtQTToAstBitMask - utility routine to produce an AST bitmask for /// objective-c's type qualifier from the parser version of the same info. -static Decl::ObjCDeclQualifier +static Decl::ObjCDeclQualifier CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None; if (PQTVal & ObjCDeclSpec::DQ_In) @@ -1595,13 +1677,14 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( // Make sure we can establish a context for the method. if (!ClassDecl) { Diag(MethodLoc, diag::error_missing_method_context); + FunctionLabelMap.clear(); return DeclPtrTy(); } QualType resultDeclType; - + if (ReturnType) { - resultDeclType = QualType::getFromOpaquePtr(ReturnType); - + resultDeclType = GetTypeFromParser(ReturnType); + // Methods cannot return interface types. All ObjC objects are // passed by reference. if (resultDeclType->isObjCInterfaceType()) { @@ -1611,54 +1694,56 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( } } else // get the type for "id". resultDeclType = Context.getObjCIdType(); - - ObjCMethodDecl* ObjCMethod = + + ObjCMethodDecl* ObjCMethod = ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType, - cast<DeclContext>(ClassDecl), + cast<DeclContext>(ClassDecl), MethodType == tok::minus, isVariadic, false, - MethodDeclKind == tok::objc_optional ? - ObjCMethodDecl::Optional : + MethodDeclKind == tok::objc_optional ? + ObjCMethodDecl::Optional : ObjCMethodDecl::Required); - + llvm::SmallVector<ParmVarDecl*, 16> Params; - + for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { QualType ArgType, UnpromotedArgType; - + if (ArgInfo[i].Type == 0) { UnpromotedArgType = ArgType = Context.getObjCIdType(); } else { - UnpromotedArgType = ArgType = QualType::getFromOpaquePtr(ArgInfo[i].Type); + UnpromotedArgType = ArgType = GetTypeFromParser(ArgInfo[i].Type); // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). ArgType = adjustParameterType(ArgType); } - + ParmVarDecl* Param; if (ArgType == UnpromotedArgType) Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, ArgInfo[i].Name, ArgType, + /*DInfo=*/0, //FIXME: Pass info here. VarDecl::None, 0); else Param = OriginalParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, ArgInfo[i].Name, ArgType, + /*DInfo=*/0, //FIXME: Pass info here. UnpromotedArgType, VarDecl::None, 0); - + if (ArgType->isObjCInterfaceType()) { Diag(ArgInfo[i].NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << ArgType; Param->setInvalidDecl(); } - + Param->setObjCDeclQualifier( CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier())); - + // Apply the attributes to the parameter. ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs); - + Params.push_back(Param); } @@ -1669,12 +1754,12 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( if (AttrList) ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); - - // For implementations (which can be very "coarse grain"), we add the - // method now. This allows the AST to implement lookup methods that work - // incrementally (without waiting until we parse the @end). It also allows + + // For implementations (which can be very "coarse grain"), we add the + // method now. This allows the AST to implement lookup methods that work + // incrementally (without waiting until we parse the @end). It also allows // us to flag multiple declaration errors as they occur. - if (ObjCImplementationDecl *ImpDecl = + if (ObjCImplementationDecl *ImpDecl = dyn_cast<ObjCImplementationDecl>(ClassDecl)) { if (MethodType == tok::minus) { PrevMethod = ImpDecl->getInstanceMethod(Sel); @@ -1685,9 +1770,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( } if (AttrList) Diag(EndLoc, diag::warn_attribute_method_def); - } - else if (ObjCCategoryImplDecl *CatImpDecl = - dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { + } else if (ObjCCategoryImplDecl *CatImpDecl = + dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { if (MethodType == tok::minus) { PrevMethod = CatImpDecl->getInstanceMethod(Sel); CatImpDecl->addInstanceMethod(ObjCMethod); @@ -1703,11 +1787,11 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl) << ObjCMethod->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); - } + } return DeclPtrTy::make(ObjCMethod); } -void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, +void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, SourceLocation Loc, unsigned &Attributes) { // FIXME: Improve the reported location. @@ -1724,8 +1808,8 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, "assign" : (Attributes & ObjCDeclSpec::DQ_PR_copy) ? "copy" : "retain"; - - Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ? + + Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ? diag::err_objc_property_attr_mutually_exclusive : diag::warn_objc_property_attr_mutually_exclusive) << "readonly" << which; @@ -1733,7 +1817,9 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, // Check for copy or retain on non-object types. if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && - !Context.isObjCObjectPointerType(PropertyTy)) { + !PropertyTy->isObjCObjectPointerType() && + !PropertyTy->isBlockPointerType() && + !Context.isObjCNSObjectType(PropertyTy)) { Diag(Loc, diag::err_objc_property_requires_object) << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); @@ -1745,7 +1831,7 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "assign" << "copy"; Attributes &= ~ObjCDeclSpec::DQ_PR_copy; - } + } if (Attributes & ObjCDeclSpec::DQ_PR_retain) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "assign" << "retain"; @@ -1764,15 +1850,15 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && - Context.isObjCObjectPointerType(PropertyTy)) { + PropertyTy->isObjCObjectPointerType()) { // Skip this warning in gc-only mode. - if (getLangOptions().getGCMode() != LangOptions::GCOnly) + if (getLangOptions().getGCMode() != LangOptions::GCOnly) Diag(Loc, diag::warn_objc_property_no_assignment_attribute); // If non-gc code warn that this is likely inappropriate. if (getLangOptions().getGCMode() == LangOptions::NonGC) Diag(Loc, diag::warn_objc_property_default_assign_on_object); - + // FIXME: Implement warning dependent on NSCopying being // implemented. See also: // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496> @@ -1785,7 +1871,7 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, Diag(Loc, diag::warn_objc_property_copy_missing_on_block); } -Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, +Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, @@ -1797,11 +1883,11 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); - // property is defaulted to 'assign' if it is readwrite and is + // property is defaulted to 'assign' if it is readwrite and is // not retain or copy bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || - (isReadWrite && - !(Attributes & ObjCDeclSpec::DQ_PR_retain) && + (isReadWrite && + !(Attributes & ObjCDeclSpec::DQ_PR_retain) && !(Attributes & ObjCDeclSpec::DQ_PR_copy))); QualType T = GetTypeForDeclarator(FD.D, S); Decl *ClassDecl = ClassCategory.getAs<Decl>(); @@ -1810,20 +1896,20 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, CheckObjCPropertyAttributes(T, AtLoc, Attributes); if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) if (!CDecl->getIdentifier()) { - // This is a continuation class. property requires special + // This is a continuation class. property requires special // handling. if ((CCPrimary = CDecl->getClassInterface())) { // Find the property in continuation class's primary class only. ObjCPropertyDecl *PIDecl = 0; IdentifierInfo *PropertyId = FD.D.getIdentifier(); - for (ObjCInterfaceDecl::prop_iterator + for (ObjCInterfaceDecl::prop_iterator I = CCPrimary->prop_begin(), E = CCPrimary->prop_end(); I != E; ++I) if ((*I)->getIdentifier() == PropertyId) { PIDecl = *I; break; } - + if (PIDecl) { // property 'PIDecl's readonly attribute will be over-ridden // with continuation class's readwrite property attribute! @@ -1838,12 +1924,11 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (Attributes & ObjCDeclSpec::DQ_PR_copy) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); PIDecl->setSetterName(SetterSel); - } - else - Diag(AtLoc, diag::err_use_continuation_class) + } else + Diag(AtLoc, diag::err_use_continuation_class) << CCPrimary->getDeclName(); *isOverridingProperty = true; - // Make sure setter decl is synthesized, and added to primary + // Make sure setter decl is synthesized, and added to primary // class's list. ProcessPropertyDecl(PIDecl, CCPrimary); return DeclPtrTy(); @@ -1855,52 +1940,72 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Diag(CDecl->getLocation(), diag::err_continuation_class); *isOverridingProperty = true; return DeclPtrTy(); - } + } } + // Issue a warning if property is 'assign' as default and its object, which is + // 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"))) + if (IDecl->ClassImplementsProtocol(PNSCopying, true)) + Diag(AtLoc, diag::warn_implements_nscopying) + << FD.D.getIdentifier(); + } + } + if (T->isObjCInterfaceType()) + Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); + DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); assert(DC && "ClassDecl is not a DeclContext"); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, - FD.D.getIdentifierLoc(), + FD.D.getIdentifierLoc(), FD.D.getIdentifier(), T); DC->addDecl(PDecl); - + if (T->isArrayType() || T->isFunctionType()) { Diag(AtLoc, diag::err_property_type) << T; PDecl->setInvalidDecl(); } - + ProcessDeclAttributes(S, PDecl, FD.D); // Regardless of setter/getter attribute, we save the default getter/setter // selector names in anticipation of declaration of setter/getter methods. PDecl->setGetterName(GetterSel); PDecl->setSetterName(SetterSel); - + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); - + if (Attributes & ObjCDeclSpec::DQ_PR_getter) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); - + if (Attributes & ObjCDeclSpec::DQ_PR_setter) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); - + if (isReadWrite) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); - + if (Attributes & ObjCDeclSpec::DQ_PR_retain) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); - + if (Attributes & ObjCDeclSpec::DQ_PR_copy) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); - + if (isAssign) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); - + if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); - + if (MethodImplKind == tok::objc_required) PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); else if (MethodImplKind == tok::objc_optional) @@ -1910,7 +2015,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // Make sure setter/getters are declared here. if (CCPrimary) ProcessPropertyDecl(PDecl, CCPrimary); - + return DeclPtrTy::make(PDecl); } @@ -1918,9 +2023,9 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, /// builds the AST node for a property implementation declaration; declared /// as @synthesize or @dynamic. /// -Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, +Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, SourceLocation PropertyLoc, - bool Synthesize, + bool Synthesize, DeclPtrTy ClassCatImpDecl, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar) { @@ -1940,29 +2045,28 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, IDecl = IC->getClassInterface(); // We always synthesize an interface for an implementation // without an interface decl. So, IDecl is always non-zero. - assert(IDecl && + assert(IDecl && "ActOnPropertyImplDecl - @implementation without @interface"); - + // Look for this property declaration in the @implementation's @interface property = IDecl->FindPropertyDeclaration(PropertyId); if (!property) { Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); return DeclPtrTy(); } - } - else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { + } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { if (Synthesize) { Diag(AtLoc, diag::error_synthesize_category_decl); return DeclPtrTy(); - } + } IDecl = CatImplClass->getClassInterface(); if (!IDecl) { Diag(AtLoc, diag::error_missing_property_interface); return DeclPtrTy(); } - ObjCCategoryDecl *Category = + ObjCCategoryDecl *Category = IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier()); - + // If category for this implementation not found, it is an error which // has already been reported eralier. if (!Category) @@ -1990,10 +2094,10 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); if (!Ivar) { DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); - assert(EnclosingContext && + assert(EnclosingContext && "null DeclContext for synthesized ivar - ActOnPropertyImplDecl"); - Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc, - PropertyIvar, PropType, + Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc, + PropertyIvar, PropType, /*Dinfo=*/0, ObjCIvarDecl::Public, (Expr *)0); Ivar->setLexicalDeclContext(IDecl); @@ -2001,35 +2105,34 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, property->setPropertyIvarDecl(Ivar); if (!getLangOptions().ObjCNonFragileABI) Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; - // Note! I deliberately want it to fall thru so, we have a + // Note! I deliberately want it to fall thru so, we have a // a property implementation and to avoid future warnings. - } - else if (getLangOptions().ObjCNonFragileABI && - ClassDeclared != IDecl) { + } else if (getLangOptions().ObjCNonFragileABI && + ClassDeclared != IDecl) { Diag(PropertyLoc, diag::error_ivar_in_superclass_use) - << property->getDeclName() << Ivar->getDeclName() + << property->getDeclName() << Ivar->getDeclName() << ClassDeclared->getDeclName(); Diag(Ivar->getLocation(), diag::note_previous_access_declaration) << Ivar << Ivar->getNameAsCString(); // Note! I deliberately want it to fall thru so more errors are caught. } QualType IvarType = Context.getCanonicalType(Ivar->getType()); - + // Check that type of property and its ivar are type compatible. if (PropType != IvarType) { if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { Diag(PropertyLoc, diag::error_property_ivar_type) << property->getDeclName() << Ivar->getDeclName(); - // Note! I deliberately want it to fall thru so, we have a + // Note! I deliberately want it to fall thru so, we have a // a property implementation and to avoid future warnings. } - + // FIXME! Rules for properties are somewhat different that those // for assignments. Use a new routine to consolidate all cases; // specifically for property redeclarations as well as for ivars. QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); - if (lhsType != rhsType && + if (lhsType != rhsType && lhsType->isArithmeticType()) { Diag(PropertyLoc, diag::error_property_ivar_type) << property->getDeclName() << Ivar->getDeclName(); @@ -2042,78 +2145,77 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, << property->getDeclName() << Ivar->getDeclName(); // Fall thru - see previous comment } - if ((Context.isObjCObjectPointerType(property->getType()) || + if ((property->getType()->isObjCObjectPointerType() || PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && getLangOptions().getGCMode() != LangOptions::NonGC) { Diag(PropertyLoc, diag::error_strong_property) << property->getDeclName() << Ivar->getDeclName(); - // Fall thru - see previous comment + // Fall thru - see previous comment } } } else if (PropertyIvar) // @dynamic Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl); assert (property && "ActOnPropertyImplDecl - property declaration missing"); - ObjCPropertyImplDecl *PIDecl = - ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, - property, - (Synthesize ? - ObjCPropertyImplDecl::Synthesize + ObjCPropertyImplDecl *PIDecl = + ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, + property, + (Synthesize ? + ObjCPropertyImplDecl::Synthesize : ObjCPropertyImplDecl::Dynamic), Ivar); if (IC) { if (Synthesize) - if (ObjCPropertyImplDecl *PPIDecl = + if (ObjCPropertyImplDecl *PPIDecl = IC->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyLoc, diag::error_duplicate_ivar_use) - << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() << PropertyIvar; Diag(PPIDecl->getLocation(), diag::note_previous_use); } - - if (ObjCPropertyImplDecl *PPIDecl + + if (ObjCPropertyImplDecl *PPIDecl = IC->FindPropertyImplDecl(PropertyId)) { Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); return DeclPtrTy(); } IC->addPropertyImplementation(PIDecl); - } - else { + } else { if (Synthesize) - if (ObjCPropertyImplDecl *PPIDecl = + if (ObjCPropertyImplDecl *PPIDecl = CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyLoc, diag::error_duplicate_ivar_use) - << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() << PropertyIvar; Diag(PPIDecl->getLocation(), diag::note_previous_use); } - - if (ObjCPropertyImplDecl *PPIDecl = + + if (ObjCPropertyImplDecl *PPIDecl = CatImplClass->FindPropertyImplDecl(PropertyId)) { Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); return DeclPtrTy(); - } + } CatImplClass->addPropertyImplementation(PIDecl); } - + return DeclPtrTy::make(PIDecl); } bool Sema::CheckObjCDeclScope(Decl *D) { if (isa<TranslationUnitDecl>(CurContext->getLookupContext())) return false; - + Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope); D->setInvalidDecl(); - + return true; } /// Called whenever @defs(ClassName) is encountered in the source. Inserts the /// instance variables of ClassName into Decls. -void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, +void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl<DeclPtrTy> &Decls) { // Check that ClassName is a valid class @@ -2126,7 +2228,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, Diag(DeclStart, diag::err_atdef_nonfragile_interface); return; } - + // Collect the instance variables llvm::SmallVector<FieldDecl*, 32> RecFields; Context.CollectObjCIvars(Class, RecFields); @@ -2139,7 +2241,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, ID->getBitWidth()); Decls.push_back(Sema::DeclPtrTy::make(FD)); } - + // Introduce all of these fields into the appropriate scope. for (llvm::SmallVectorImpl<DeclPtrTy>::iterator D = Decls.begin(); D != Decls.end(); ++D) { diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp new file mode 100644 index 0000000000000..bdd00b84049d3 --- /dev/null +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -0,0 +1,320 @@ +//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Sema routines for C++ exception specification testing. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "llvm/ADT/SmallPtrSet.h" + +namespace clang { + +static const FunctionProtoType *GetUnderlyingFunction(QualType T) +{ + if (const PointerType *PtrTy = T->getAs<PointerType>()) + T = PtrTy->getPointeeType(); + else if (const ReferenceType *RefTy = T->getAs<ReferenceType>()) + T = RefTy->getPointeeType(); + else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) + T = MPTy->getPointeeType(); + return T->getAs<FunctionProtoType>(); +} + +/// CheckSpecifiedExceptionType - Check if the given type is valid in an +/// exception specification. Incomplete types, or pointers to incomplete types +/// other than void are not allowed. +bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { + // FIXME: This may not correctly work with the fix for core issue 437, + // where a class's own type is considered complete within its body. But + // perhaps RequireCompleteType itself should contain this logic? + + // C++ 15.4p2: A type denoted in an exception-specification shall not denote + // an incomplete type. + if (RequireCompleteType(Range.getBegin(), T, + PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range)) + return true; + + // C++ 15.4p2: A type denoted in an exception-specification shall not denote + // an incomplete type a pointer or reference to an incomplete type, other + // than (cv) void*. + int kind; + if (const PointerType* IT = T->getAs<PointerType>()) { + T = IT->getPointeeType(); + kind = 1; + } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) { + T = IT->getPointeeType(); + kind = 2; + } else + return false; + + if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T, + PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/kind << Range)) + return true; + + return false; +} + +/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer +/// to member to a function with an exception specification. This means that +/// it is invalid to add another level of indirection. +bool Sema::CheckDistantExceptionSpec(QualType T) { + if (const PointerType *PT = T->getAs<PointerType>()) + T = PT->getPointeeType(); + else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) + T = PT->getPointeeType(); + else + return false; + + const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); + if (!FnT) + return false; + + return FnT->hasExceptionSpec(); +} + +/// CheckEquivalentExceptionSpec - Check if the two types have equivalent +/// exception specifications. Exception specifications are equivalent if +/// they allow exactly the same set of exception types. It does not matter how +/// that is achieved. See C++ [except.spec]p2. +bool Sema::CheckEquivalentExceptionSpec( + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc) { + return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, + diag::note_previous_declaration, + Old, OldLoc, New, NewLoc); +} + +/// CheckEquivalentExceptionSpec - Check if the two types have equivalent +/// exception specifications. Exception specifications are equivalent if +/// they allow exactly the same set of exception types. It does not matter how +/// that is achieved. See C++ [except.spec]p2. +bool Sema::CheckEquivalentExceptionSpec( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc) { + bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec(); + bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec(); + if (OldAny && NewAny) + return false; + if (OldAny || NewAny) { + Diag(NewLoc, DiagID); + if (NoteID.getDiagID() != 0) + Diag(OldLoc, NoteID); + return true; + } + + bool Success = true; + // Both have a definite exception spec. Collect the first set, then compare + // to the second. + llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; + for (FunctionProtoType::exception_iterator I = Old->exception_begin(), + E = Old->exception_end(); I != E; ++I) + OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType()); + + for (FunctionProtoType::exception_iterator I = New->exception_begin(), + E = New->exception_end(); I != E && Success; ++I) { + CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType(); + if(OldTypes.count(TypePtr)) + NewTypes.insert(TypePtr); + else + Success = false; + } + + Success = Success && OldTypes.size() == NewTypes.size(); + + if (Success) { + return false; + } + Diag(NewLoc, DiagID); + if (NoteID.getDiagID() != 0) + Diag(OldLoc, NoteID); + return true; +} + +/// CheckExceptionSpecSubset - Check whether the second function type's +/// exception specification is a subset (or equivalent) of the first function +/// type. This is used by override and pointer assignment checks. +bool Sema::CheckExceptionSpecSubset( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Superset, SourceLocation SuperLoc, + const FunctionProtoType *Subset, SourceLocation SubLoc) { + // FIXME: As usual, we could be more specific in our error messages, but + // that better waits until we've got types with source locations. + + if (!SubLoc.isValid()) + SubLoc = SuperLoc; + + // If superset contains everything, we're done. + if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec()) + return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + + // It does not. If the subset contains everything, we've failed. + if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) { + Diag(SubLoc, DiagID); + if (NoteID.getDiagID() != 0) + Diag(SuperLoc, NoteID); + return true; + } + + // Neither contains everything. Do a proper comparison. + for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), + SubE = Subset->exception_end(); SubI != SubE; ++SubI) { + // Take one type from the subset. + QualType CanonicalSubT = Context.getCanonicalType(*SubI); + // Unwrap pointers and references so that we can do checks within a class + // hierarchy. Don't unwrap member pointers; they don't have hierarchy + // conversions on the pointee. + bool SubIsPointer = false; + if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) + CanonicalSubT = RefTy->getPointeeType(); + if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { + CanonicalSubT = PtrTy->getPointeeType(); + SubIsPointer = true; + } + bool SubIsClass = CanonicalSubT->isRecordType(); + CanonicalSubT = CanonicalSubT.getUnqualifiedType(); + + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + + bool Contained = false; + // Make sure it's in the superset. + for (FunctionProtoType::exception_iterator SuperI = + Superset->exception_begin(), SuperE = Superset->exception_end(); + SuperI != SuperE; ++SuperI) { + QualType CanonicalSuperT = Context.getCanonicalType(*SuperI); + // SubT must be SuperT or derived from it, or pointer or reference to + // such types. + if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) + CanonicalSuperT = RefTy->getPointeeType(); + if (SubIsPointer) { + if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) + CanonicalSuperT = PtrTy->getPointeeType(); + else { + continue; + } + } + CanonicalSuperT = CanonicalSuperT.getUnqualifiedType(); + // If the types are the same, move on to the next type in the subset. + if (CanonicalSubT == CanonicalSuperT) { + Contained = true; + break; + } + + // Otherwise we need to check the inheritance. + if (!SubIsClass || !CanonicalSuperT->isRecordType()) + continue; + + Paths.clear(); + if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) + continue; + + if (Paths.isAmbiguous(CanonicalSuperT)) + continue; + + if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true)) + continue; + + Contained = true; + break; + } + if (!Contained) { + Diag(SubLoc, DiagID); + if (NoteID.getDiagID() != 0) + Diag(SuperLoc, NoteID); + return true; + } + } + // We've run half the gauntlet. + return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); +} + +static bool CheckSpecForTypesEquivalent(Sema &S, + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + QualType Target, SourceLocation TargetLoc, + QualType Source, SourceLocation SourceLoc) +{ + const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); + if (!TFunc) + return false; + const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); + if (!SFunc) + return false; + + return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, + SFunc, SourceLoc); +} + +/// CheckParamExceptionSpec - Check if the parameter and return types of the +/// two functions have equivalent exception specs. This is part of the +/// assignment and override compatibility check. We do not check the parameters +/// of parameter function pointers recursively, as no sane programmer would +/// even be able to write such a function type. +bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, + const FunctionProtoType *Target, SourceLocation TargetLoc, + const FunctionProtoType *Source, SourceLocation SourceLoc) +{ + if (CheckSpecForTypesEquivalent(*this, + PDiag(diag::err_deep_exception_specs_differ) << 0, 0, + Target->getResultType(), TargetLoc, + Source->getResultType(), SourceLoc)) + return true; + + // We shouldn't even be testing this unless the arguments are otherwise + // compatible. + assert(Target->getNumArgs() == Source->getNumArgs() && + "Functions have different argument counts."); + for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) { + if (CheckSpecForTypesEquivalent(*this, + PDiag(diag::err_deep_exception_specs_differ) << 1, 0, + Target->getArgType(i), TargetLoc, + Source->getArgType(i), SourceLoc)) + return true; + } + return false; +} + +bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) +{ + // First we check for applicability. + // Target type must be a function, function pointer or function reference. + const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); + if (!ToFunc) + return false; + + // SourceType must be a function or function pointer. + const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); + if (!FromFunc) + return false; + + // Now we've got the correct types on both sides, check their compatibility. + // This means that the source of the conversion can only throw a subset of + // the exceptions of the target, and any exception specs on arguments or + // return types must be equivalent. + return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs, + 0, ToFunc, From->getSourceRange().getBegin(), + FromFunc, SourceLocation()); +} + +bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, + const CXXMethodDecl *Old) { + return CheckExceptionSpecSubset(diag::err_override_exception_spec, + diag::note_overridden_virtual_function, + Old->getType()->getAs<FunctionProtoType>(), + Old->getLocation(), + New->getType()->getAs<FunctionProtoType>(), + New->getLocation()); +} + +} // end namespace clang diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a5e5083964222..d8e49c7d69410 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14,18 +14,20 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/LiteralSupport.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Designator.h" #include "clang/Parse/Scope.h" using namespace clang; + /// \brief Determine whether the use of this declaration is valid, and /// emit any corresponding diagnostics. /// @@ -44,12 +46,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { // stuff. Don't warn if we are implementing a deprecated // construct. bool isSilenced = false; - + if (NamedDecl *ND = getCurFunctionOrMethodDecl()) { // If this reference happens *in* a deprecated function or method, don't // warn. isSilenced = ND->getAttr<DeprecatedAttr>(); - + // If this is an Objective-C method implementation, check to see if the // method was deprecated on the declaration, not the definition. if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) { @@ -57,14 +59,14 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { // ObjCImplementationDecl. if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(MD->getParent())) { - + MD = Impl->getClassInterface()->getMethod(MD->getSelector(), MD->isInstanceMethod()); isSilenced |= MD && MD->getAttr<DeprecatedAttr>(); } } } - + if (!isSilenced) Diag(Loc, diag::warn_deprecated) << D->getDeclName(); } @@ -88,18 +90,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { } /// DiagnoseSentinelCalls - This routine checks on method dispatch calls -/// (and other functions in future), which have been declared with sentinel +/// (and other functions in future), which have been declared with sentinel /// attribute. It warns if call does not have the sentinel argument. /// void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, - Expr **Args, unsigned NumArgs) -{ + Expr **Args, unsigned NumArgs) { const SentinelAttr *attr = D->getAttr<SentinelAttr>(); - if (!attr) + if (!attr) return; int sentinelPos = attr->getSentinel(); int nullPos = attr->getNullPos(); - + // FIXME. ObjCMethodDecl and FunctionDecl need be derived from the same common // base class. Then we won't be needing two versions of the same code. unsigned int i = 0; @@ -116,8 +117,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, } warnNotEnoughArgs = (P != E || i >= NumArgs); isMethod = 1; - } - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // skip over named parameters. ObjCMethodDecl::param_iterator P, E = FD->param_end(); for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) { @@ -127,14 +127,13 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ++i; } warnNotEnoughArgs = (P != E || i >= NumArgs); - } - else if (VarDecl *V = dyn_cast<VarDecl>(D)) { + } else if (VarDecl *V = dyn_cast<VarDecl>(D)) { // block or function pointer call. QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { - const FunctionType *FT = Ty->isFunctionPointerType() - ? Ty->getAsPointerType()->getPointeeType()->getAsFunctionType() - : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType(); + const FunctionType *FT = Ty->isFunctionPointerType() + ? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>() + : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) { unsigned NumArgsInProto = Proto->getNumArgs(); unsigned k; @@ -148,11 +147,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, } if (Ty->isBlockPointerType()) isMethod = 2; - } - else + } else return; - } - else + } else return; if (warnNotEnoughArgs) { @@ -176,7 +173,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, } Expr *sentinelExpr = Args[sentinel]; if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() || - !sentinelExpr->isNullPointerConstant(Context))) { + !sentinelExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull))) { Diag(Loc, diag::warn_missing_sentinel) << isMethod; Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; } @@ -198,7 +196,8 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); if (Ty->isFunctionType()) - ImpCastExprToType(E, Context.getPointerType(Ty)); + ImpCastExprToType(E, Context.getPointerType(Ty), + CastExpr::CK_FunctionToPointerDecay); else if (Ty->isArrayType()) { // In C90 mode, arrays only promote to pointers if the array expression is // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has @@ -213,54 +212,20 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { // if (getLangOptions().C99 || getLangOptions().CPlusPlus || E->isLvalue(Context) == Expr::LV_Valid) - ImpCastExprToType(E, Context.getArrayDecayedType(Ty)); + ImpCastExprToType(E, Context.getArrayDecayedType(Ty), + CastExpr::CK_ArrayToPointerDecay); } } -/// \brief Whether this is a promotable bitfield reference according -/// to C99 6.3.1.1p2, bullet 2. -/// -/// \returns the type this bit-field will promote to, or NULL if no -/// promotion occurs. -static QualType isPromotableBitField(Expr *E, ASTContext &Context) { - FieldDecl *Field = E->getBitField(); - if (!Field) - return QualType(); - - const BuiltinType *BT = Field->getType()->getAsBuiltinType(); - if (!BT) - return QualType(); - - if (BT->getKind() != BuiltinType::Bool && - BT->getKind() != BuiltinType::Int && - BT->getKind() != BuiltinType::UInt) - return QualType(); - - llvm::APSInt BitWidthAP; - if (!Field->getBitWidth()->isIntegerConstantExpr(BitWidthAP, Context)) - return QualType(); - - uint64_t BitWidth = BitWidthAP.getZExtValue(); - uint64_t IntSize = Context.getTypeSize(Context.IntTy); - if (BitWidth < IntSize || - (Field->getType()->isSignedIntegerType() && BitWidth == IntSize)) - return Context.IntTy; - - if (BitWidth == IntSize && Field->getType()->isUnsignedIntegerType()) - return Context.UnsignedIntTy; - - return QualType(); -} - /// UsualUnaryConversions - Performs various conversions that are common to most -/// operators (C99 6.3). The conversions of array and function types are +/// operators (C99 6.3). The conversions of array and function types are /// sometimes surpressed. For example, the array->pointer conversion doesn't /// apply if the array is an argument to the sizeof or address (&) operators. /// In these instances, this routine should *not* be called. Expr *Sema::UsualUnaryConversions(Expr *&Expr) { QualType Ty = Expr->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); - + // C99 6.3.1.1p2: // // The following may be used in an expression wherever an int or @@ -274,33 +239,33 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) { // value is converted to an int; otherwise, it is converted to an // unsigned int. These are called the integer promotions. All // other types are unchanged by the integer promotions. + QualType PTy = Context.isPromotableBitField(Expr); + if (!PTy.isNull()) { + ImpCastExprToType(Expr, PTy); + return Expr; + } if (Ty->isPromotableIntegerType()) { - ImpCastExprToType(Expr, Context.IntTy); + QualType PT = Context.getPromotedIntegerType(Ty); + ImpCastExprToType(Expr, PT); return Expr; - } else { - QualType T = isPromotableBitField(Expr, Context); - if (!T.isNull()) { - ImpCastExprToType(Expr, T); - return Expr; - } - } - + } + DefaultFunctionArrayConversion(Expr); return Expr; } /// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that -/// do not have a prototype. Arguments that have type float are promoted to +/// do not have a prototype. Arguments that have type float are promoted to /// double. All other argument types are converted by UsualUnaryConversions(). void Sema::DefaultArgumentPromotion(Expr *&Expr) { QualType Ty = Expr->getType(); assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); - + // If this is a 'float' (CVR qualified or typedef) promote to double. - if (const BuiltinType *BT = Ty->getAsBuiltinType()) + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) if (BT->getKind() == BuiltinType::Float) return ImpCastExprToType(Expr, Context.DoubleTy); - + UsualUnaryConversions(Expr); } @@ -310,14 +275,14 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { /// completely illegal. bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { DefaultArgumentPromotion(Expr); - + if (Expr->getType()->isObjCInterfaceType()) { Diag(Expr->getLocStart(), diag::err_cannot_pass_objc_interface_to_vararg) << Expr->getType() << CT; return true; } - + if (!Expr->getType()->isPODType()) Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg) << Expr->getType() << CT; @@ -328,7 +293,7 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { /// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this -/// routine returns the first non-arithmetic type found. The client is +/// routine returns the first non-arithmetic type found. The client is /// responsible for emitting appropriate error diagnostics. /// FIXME: verify the conversion rules for "complex int" are consistent with /// GCC. @@ -339,11 +304,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, UsualUnaryConversions(rhsExpr); - // For conversion purposes, we ignore any qualifiers. + // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhs = Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType(); - QualType rhs = + QualType rhs = Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType(); // If both types are identical, no conversion is needed. @@ -356,159 +321,20 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, return lhs; // Perform bitfield promotions. - QualType LHSBitfieldPromoteTy = isPromotableBitField(lhsExpr, Context); + QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr); if (!LHSBitfieldPromoteTy.isNull()) lhs = LHSBitfieldPromoteTy; - QualType RHSBitfieldPromoteTy = isPromotableBitField(rhsExpr, Context); + QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr); if (!RHSBitfieldPromoteTy.isNull()) rhs = RHSBitfieldPromoteTy; - QualType destType = UsualArithmeticConversionsType(lhs, rhs); + QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs); if (!isCompAssign) ImpCastExprToType(lhsExpr, destType); ImpCastExprToType(rhsExpr, destType); return destType; } -QualType Sema::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { - // Perform the usual unary conversions. We do this early so that - // integral promotions to "int" can allow us to exit early, in the - // lhs == rhs check. Also, for conversion purposes, we ignore any - // qualifiers. For example, "const float" and "float" are - // equivalent. - if (lhs->isPromotableIntegerType()) - lhs = Context.IntTy; - else - lhs = lhs.getUnqualifiedType(); - if (rhs->isPromotableIntegerType()) - rhs = Context.IntTy; - else - rhs = rhs.getUnqualifiedType(); - - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; - - // If either side is a non-arithmetic type (e.g. a pointer), we are done. - // The caller can deal with this (e.g. pointer + int). - if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) - return lhs; - - // At this point, we have two different arithmetic types. - - // Handle complex types first (C99 6.3.1.8p1). - if (lhs->isComplexType() || rhs->isComplexType()) { - // if we have an integer operand, the result is the complex type. - if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { - // convert the rhs to the lhs complex type. - return lhs; - } - if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { - // convert the lhs to the rhs complex type. - return rhs; - } - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - int result = Context.getFloatingTypeOrder(lhs, rhs); - - if (result > 0) { // The left side is bigger, convert rhs. - rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs); - } else if (result < 0) { // The right side is bigger, convert lhs. - lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs); - } - // At this point, lhs and rhs have the same rank/size. Now, make sure the - // domains match. This is a requirement for our implementation, C99 - // does not require this promotion. - if (lhs != rhs) { // Domains don't match, we have complex/float mix. - if (lhs->isRealFloatingType()) { // handle "double, _Complex double". - return rhs; - } else { // handle "_Complex double, double". - return lhs; - } - } - return lhs; // The domain/size match exactly. - } - // Now handle "real" floating types (i.e. float, double, long double). - if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { - // if we have an integer operand, the result is the real floating type. - if (rhs->isIntegerType()) { - // convert rhs to the lhs floating point type. - return lhs; - } - if (rhs->isComplexIntegerType()) { - // convert rhs to the complex floating point type. - return Context.getComplexType(lhs); - } - if (lhs->isIntegerType()) { - // convert lhs to the rhs floating point type. - return rhs; - } - if (lhs->isComplexIntegerType()) { - // convert lhs to the complex floating point type. - return Context.getComplexType(rhs); - } - // We have two real floating types, float/complex combos were handled above. - // Convert the smaller operand to the bigger result. - int result = Context.getFloatingTypeOrder(lhs, rhs); - if (result > 0) // convert the rhs - return lhs; - assert(result < 0 && "illegal float comparison"); - return rhs; // convert the lhs - } - if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) { - // Handle GCC complex int extension. - const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); - const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); - - if (lhsComplexInt && rhsComplexInt) { - if (Context.getIntegerTypeOrder(lhsComplexInt->getElementType(), - rhsComplexInt->getElementType()) >= 0) - return lhs; // convert the rhs - return rhs; - } else if (lhsComplexInt && rhs->isIntegerType()) { - // convert the rhs to the lhs complex type. - return lhs; - } else if (rhsComplexInt && lhs->isIntegerType()) { - // convert the lhs to the rhs complex type. - return rhs; - } - } - // Finally, we have two differing integer types. - // The rules for this case are in C99 6.3.1.8 - int compare = Context.getIntegerTypeOrder(lhs, rhs); - bool lhsSigned = lhs->isSignedIntegerType(), - rhsSigned = rhs->isSignedIntegerType(); - QualType destType; - if (lhsSigned == rhsSigned) { - // Same signedness; use the higher-ranked type - destType = compare >= 0 ? lhs : rhs; - } else if (compare != (lhsSigned ? 1 : -1)) { - // The unsigned type has greater than or equal rank to the - // signed type, so use the unsigned type - destType = lhsSigned ? rhs : lhs; - } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) { - // The two types are different widths; if we are here, that - // means the signed type is larger than the unsigned type, so - // use the signed type. - destType = lhsSigned ? lhs : rhs; - } else { - // The signed type is higher-ranked than the unsigned type, - // but isn't actually any bigger (like unsigned int and long - // on most 32-bit systems). Use the unsigned type corresponding - // to the signed type. - destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); - } - return destType; -} - //===----------------------------------------------------------------------===// // Semantic Analysis for various Expression Types //===----------------------------------------------------------------------===// @@ -546,9 +372,9 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Literal.GetNumStringChars()+1), ArrayType::Normal, 0); - + // Pass &StringTokLocs[0], StringTokLocs.size() to factory! - return Owned(StringLiteral::Create(Context, Literal.GetString(), + return Owned(StringLiteral::Create(Context, Literal.GetString(), Literal.GetStringLength(), Literal.AnyWide, StrTy, &StringTokLocs[0], @@ -569,7 +395,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, // we wanted to. if (CurBlock->TheDecl == VD->getDeclContext()) return false; - + // If this is an enum constant or function, it is constant, don't snapshot. if (isa<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD)) return false; @@ -580,7 +406,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, if (const VarDecl *Var = dyn_cast<VarDecl>(VD)) if (!Var->hasLocalStorage()) return false; - + // Blocks that have these can't be constant. CurBlock->hasBlockDeclRefExprs = true; @@ -594,15 +420,15 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, // having a reference outside it. if (NextBlock->TheDecl == VD->getDeclContext()) break; - + // Otherwise, the DeclRef from the inner block causes the outer one to need // a snapshot as well. NextBlock->hasBlockDeclRefExprs = true; } - + return true; -} - +} + /// ActOnIdentifierExpr - The parser read an identifier in expression context, @@ -628,35 +454,35 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, const CXXScopeSpec *SS) { if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) { Diag(Loc, - diag::err_auto_variable_cannot_appear_in_own_initializer) + diag::err_auto_variable_cannot_appear_in_own_initializer) << D->getDeclName(); return ExprError(); } - + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) { if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) { - Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function) + Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function) << D->getIdentifier() << FD->getDeclName(); - Diag(D->getLocation(), diag::note_local_variable_declared_here) + Diag(D->getLocation(), diag::note_local_variable_declared_here) << D->getIdentifier(); return ExprError(); } } } } - + MarkDeclarationReferenced(Loc, D); - + Expr *E; if (SS && !SS->isEmpty()) { - E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, + E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent, SS->getRange(), static_cast<NestedNameSpecifier *>(SS->getScopeRep())); } else E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent); - + return Owned(E); } @@ -665,14 +491,14 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, /// is Record. static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context, RecordDecl *Record) { - assert(Record->isAnonymousStructOrUnion() && + 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(), + for (DeclContext::decl_iterator D = Ctx->decls_begin(), DEnd = Ctx->decls_end(); D != DEnd; ++D) { if (*D == Record) { @@ -721,7 +547,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field, break; } Ctx = Ctx->getParent(); - } while (Ctx->isRecord() && + } while (Ctx->isRecord() && cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion()); return BaseObject; @@ -733,7 +559,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, Expr *BaseObjectExpr, SourceLocation OpLoc) { llvm::SmallVector<FieldDecl *, 4> AnonFields; - VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field, + VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field, AnonFields); // Build the expression that refers to the base object, from @@ -741,7 +567,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, // of the anonymous union objects and, eventually, the field we // found via name lookup. bool BaseObjectIsPointer = false; - unsigned ExtraQuals = 0; + Qualifiers BaseQuals; if (BaseObject) { // BaseObject is an anonymous struct/union variable (and is, // therefore, not part of another non-anonymous record). @@ -749,29 +575,30 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, MarkDeclarationReferenced(Loc, BaseObject); BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(), SourceLocation()); - ExtraQuals - = Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers(); + BaseQuals + = Context.getCanonicalType(BaseObject->getType()).getQualifiers(); } else if (BaseObjectExpr) { // The caller provided the base object expression. Determine // whether its a pointer and whether it adds any qualifiers to the // anonymous struct/union fields we're looking into. QualType ObjectType = BaseObjectExpr->getType(); - if (const PointerType *ObjectPtr = ObjectType->getAsPointerType()) { + if (const PointerType *ObjectPtr = ObjectType->getAs<PointerType>()) { BaseObjectIsPointer = true; ObjectType = ObjectPtr->getPointeeType(); } - ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers(); + BaseQuals + = Context.getCanonicalType(ObjectType).getQualifiers(); } else { // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed // program our base object expression is "this". if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { if (!MD->isStatic()) { - QualType AnonFieldType + QualType AnonFieldType = Context.getTagDeclType( cast<RecordDecl>(AnonFields.back()->getDeclContext())); QualType ThisType = Context.getTagDeclType(MD->getParent()); - if ((Context.getCanonicalType(AnonFieldType) + if ((Context.getCanonicalType(AnonFieldType) == Context.getCanonicalType(ThisType)) || IsDerivedFrom(ThisType, AnonFieldType)) { // Our base object expression is "this". @@ -783,10 +610,10 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) << Field->getDeclName()); } - ExtraQuals = MD->getTypeQualifiers(); + BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); } - if (!BaseObjectExpr) + if (!BaseObjectExpr) return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) << Field->getDeclName()); } @@ -794,20 +621,35 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, // Build the implicit member references to the field of the // anonymous struct/union. Expr *Result = BaseObjectExpr; + Qualifiers ResultQuals = BaseQuals; for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator FI = AnonFields.rbegin(), FIEnd = AnonFields.rend(); FI != FIEnd; ++FI) { QualType MemberType = (*FI)->getType(); - if (!(*FI)->isMutable()) { - unsigned combinedQualifiers - = MemberType.getCVRQualifiers() | ExtraQuals; - MemberType = MemberType.getQualifiedType(combinedQualifiers); - } + Qualifiers MemberTypeQuals = + Context.getCanonicalType(MemberType).getQualifiers(); + + // CVR attributes from the base are picked up by members, + // except that 'mutable' members don't pick up 'const'. + if ((*FI)->isMutable()) + ResultQuals.removeConst(); + + // GC attributes are never picked up by members. + ResultQuals.removeObjCGCAttr(); + + // TR 18037 does not allow fields to be declared with address spaces. + assert(!MemberTypeQuals.hasAddressSpace()); + + Qualifiers NewQuals = ResultQuals + MemberTypeQuals; + if (NewQuals != MemberTypeQuals) + MemberType = Context.getQualifiedType(MemberType, NewQuals); + MarkDeclarationReferenced(Loc, *FI); + // FIXME: Might this end up being a qualified name? Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, OpLoc, MemberType); BaseObjectIsPointer = false; - ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers(); + ResultQuals = NewQuals; } return Owned(Result); @@ -835,7 +677,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, Sema::OwningExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, DeclarationName Name, bool HasTrailingLParen, - const CXXScopeSpec *SS, + const CXXScopeSpec *SS, bool isAddressOfOperand) { // Could be enum-constant, value decl, instance variable, etc. if (SS && SS->isInvalid()) @@ -848,12 +690,13 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // FIXME: Member of the current instantiation. if (SS && isDependentScopeSpecifier(*SS)) { return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy, - Loc, SS->getRange(), - static_cast<NestedNameSpecifier *>(SS->getScopeRep()))); + Loc, SS->getRange(), + static_cast<NestedNameSpecifier *>(SS->getScopeRep()), + isAddressOfOperand)); } - LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName, - false, true, Loc); + LookupResult Lookup; + LookupParsedName(Lookup, S, SS, Name, LookupOrdinaryName, false, true, Loc); if (Lookup.isAmbiguous()) { DiagnoseAmbiguousLookup(Lookup, Name, Loc, @@ -861,8 +704,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, : SourceRange()); return ExprError(); } - - NamedDecl *D = Lookup.getAsDecl(); + + NamedDecl *D = Lookup.getAsSingleDecl(Context); // If this reference is in an Objective-C method, then ivar lookup happens as // well. @@ -870,8 +713,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, if (II && getCurMethodDecl()) { // There are two cases to handle here. 1) scoped lookup could have failed, // in which case we should look for an ivar. 2) scoped lookup could have - // found a decl, but that decl is outside the current instance method (i.e. - // a global variable). In these two cases, we do a lookup for an ivar with + // found a decl, but that decl is outside the current instance method (i.e. + // a global variable). In these two cases, we do a lookup for an ivar with // this name, if the lookup sucedes, we replace it our current decl. if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) { ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); @@ -880,12 +723,12 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // Check if referencing a field with __attribute__((deprecated)). if (DiagnoseUseOfDecl(IV, Loc)) return ExprError(); - + // If we're referencing an invalid decl, just return this as a silent // error node. The error diagnostic was already emitted on the decl. if (IV->isInvalidDecl()) return ExprError(); - + bool IsClsMethod = getCurMethodDecl()->isClassMethod(); // If a class method attemps to use a free standing ivar, this is // an error. @@ -901,15 +744,15 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // FIXME: This should use a new expr for a direct reference, don't // turn this into Self->ivar, just return a BareIVarExpr or something. IdentifierInfo &II = Context.Idents.get("self"); - OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false); + OwningExprResult SelfExpr = ActOnIdentifierExpr(S, SourceLocation(), + II, false); MarkDeclarationReferenced(Loc, IV); - return Owned(new (Context) - ObjCIvarRefExpr(IV, IV->getType(), Loc, + return Owned(new (Context) + ObjCIvarRefExpr(IV, IV->getType(), Loc, SelfExpr.takeAs<Expr>(), true, true)); } } - } - else if (getCurMethodDecl()->isInstanceMethod()) { + } else if (getCurMethodDecl()->isInstanceMethod()) { // We should warn if a local variable hides an ivar. ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); ObjCInterfaceDecl *ClassDeclared; @@ -922,10 +765,10 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // Needed to implement property "super.method" notation. if (D == 0 && II->isStr("super")) { QualType T; - + if (getCurMethodDecl()->isInstanceMethod()) - T = Context.getPointerType(Context.getObjCInterfaceType( - getCurMethodDecl()->getClassInterface())); + T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( + getCurMethodDecl()->getClassInterface())); else T = Context.getObjCClassType(); return Owned(new (Context) ObjCSuperExpr(Loc, T)); @@ -934,7 +777,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // Determine whether this name might be a candidate for // argument-dependent lookup. - bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && + bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && HasTrailingLParen; if (ADL && D == 0) { @@ -960,8 +803,9 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // If this name wasn't predeclared and if this is not a function call, // diagnose the problem. if (SS && !SS->isEmpty()) - return ExprError(Diag(Loc, diag::err_typecheck_no_member) - << Name << SS->getRange()); + return ExprError(Diag(Loc, diag::err_no_member) + << Name << computeDeclContext(*SS, false) + << SS->getRange()); else if (Name.getNameKind() == DeclarationName::CXXOperatorName || Name.getNameKind() == DeclarationName::CXXConversionFunctionName) return ExprError(Diag(Loc, diag::err_undeclared_use) @@ -970,18 +814,18 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name); } } - + if (VarDecl *Var = dyn_cast<VarDecl>(D)) { // Warn about constructs like: // if (void *X = foo()) { ... } else { X }. // In the else block, the pointer is always false. - + // FIXME: In a template instantiation, we don't have scope // information to check this property. if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { Scope *CheckS = S; while (CheckS) { - if (CheckS->isWithinElse() && + if (CheckS->isWithinElse() && CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { if (Var->getType()->isBooleanType()) ExprError(Diag(Loc, diag::warn_value_always_false) @@ -991,7 +835,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, << Var->getDeclName()); break; } - + // Move up one more control parent to check again. CheckS = CheckS->getControlParent(); if (CheckS) @@ -1010,24 +854,66 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, QualType T = Func->getType(); QualType NoProtoType = T; - if (const FunctionProtoType *Proto = T->getAsFunctionProtoType()) + if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>()) NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType()); return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS); } } - + return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand); } +/// \brief Cast member's object to its own class if necessary. +bool +Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) { + if (FieldDecl *FD = dyn_cast<FieldDecl>(Member)) + if (CXXRecordDecl *RD = + dyn_cast<CXXRecordDecl>(FD->getDeclContext())) { + QualType DestType = + Context.getCanonicalType(Context.getTypeDeclType(RD)); + if (DestType->isDependentType() || From->getType()->isDependentType()) + return false; + QualType FromRecordType = From->getType(); + QualType DestRecordType = DestType; + if (FromRecordType->getAs<PointerType>()) { + DestType = Context.getPointerType(DestType); + FromRecordType = FromRecordType->getPointeeType(); + } + if (!Context.hasSameUnqualifiedType(FromRecordType, DestRecordType) && + CheckDerivedToBaseConversion(FromRecordType, + DestRecordType, + From->getSourceRange().getBegin(), + From->getSourceRange())) + return true; + ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, + /*isLvalue=*/true); + } + return false; +} + +/// \brief Build a MemberExpr AST node. +static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, + const CXXScopeSpec *SS, NamedDecl *Member, + SourceLocation Loc, QualType Ty) { + if (SS && SS->isSet()) + return MemberExpr::Create(C, Base, isArrow, + (NestedNameSpecifier *)SS->getScopeRep(), + SS->getRange(), Member, Loc, + // FIXME: Explicit template argument lists + false, SourceLocation(), 0, 0, SourceLocation(), + Ty); + + return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty); +} /// \brief Complete semantic analysis for a reference to the given declaration. Sema::OwningExprResult Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, bool HasTrailingLParen, - const CXXScopeSpec *SS, + const CXXScopeSpec *SS, bool isAddressOfOperand) { assert(D && "Cannot refer to a NULL declaration"); DeclarationName Name = D->getDeclName(); - + // If this is an expression of the form &Class::member, don't build an // implicit member ref, because we want a pointer to the member in general, // not any specific instance's member. @@ -1060,7 +946,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { if (!MD->isStatic()) { - // C++ [class.mfct.nonstatic]p2: + // C++ [class.mfct.nonstatic]p2: // [...] if name lookup (3.4.1) resolves the name in the // id-expression to a nonstatic nontype member of class X or of // a base class of X, the id-expression is transformed into a @@ -1072,45 +958,74 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, Ctx = FD->getDeclContext(); MemberType = FD->getType(); - if (const ReferenceType *RefType = MemberType->getAsReferenceType()) + if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>()) MemberType = RefType->getPointeeType(); - else if (!FD->isMutable()) { - unsigned combinedQualifiers - = MemberType.getCVRQualifiers() | MD->getTypeQualifiers(); - MemberType = MemberType.getQualifiedType(combinedQualifiers); - } + else if (!FD->isMutable()) + MemberType + = Context.getQualifiedType(MemberType, + Qualifiers::fromCVRMask(MD->getTypeQualifiers())); } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { if (!Method->isStatic()) { Ctx = Method->getParent(); MemberType = Method->getType(); } - } else if (OverloadedFunctionDecl *Ovl + } else if (FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>(D)) { + if (CXXMethodDecl *Method + = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) { + if (!Method->isStatic()) { + Ctx = Method->getParent(); + MemberType = Context.OverloadTy; + } + } + } else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) { - for (OverloadedFunctionDecl::function_iterator + // FIXME: We need an abstraction for iterating over one or more function + // templates or functions. This code is far too repetitive! + for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), FuncEnd = Ovl->function_end(); Func != FuncEnd; ++Func) { - if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func)) - if (!DMethod->isStatic()) { - Ctx = Ovl->getDeclContext(); - MemberType = Context.OverloadTy; - break; - } + CXXMethodDecl *DMethod = 0; + if (FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>(*Func)) + DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + else + DMethod = dyn_cast<CXXMethodDecl>(*Func); + + if (DMethod && !DMethod->isStatic()) { + Ctx = DMethod->getDeclContext(); + MemberType = Context.OverloadTy; + break; + } } } if (Ctx && Ctx->isRecord()) { QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx)); QualType ThisType = Context.getTagDeclType(MD->getParent()); - if ((Context.getCanonicalType(CtxType) + if ((Context.getCanonicalType(CtxType) == Context.getCanonicalType(ThisType)) || IsDerivedFrom(ThisType, CtxType)) { // Build the implicit member access expression. Expr *This = new (Context) CXXThisExpr(SourceLocation(), MD->getThisType(Context)); MarkDeclarationReferenced(Loc, D); - return Owned(new (Context) MemberExpr(This, true, D, - Loc, MemberType)); + if (PerformObjectMemberConversion(This, D)) + return ExprError(); + + bool ShouldCheckUse = true; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + // Don't diagnose the use of a virtual member function unless it's + // explicitly qualified. + if (MD->isVirtual() && (!SS || !SS->isSet())) + ShouldCheckUse = false; + } + + if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc)) + return ExprError(); + return Owned(BuildMemberExpr(Context, This, true, SS, D, + Loc, MemberType)); } } } @@ -1145,13 +1060,18 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) return BuildDeclRefExpr(Template, Context.OverloadTy, Loc, false, false, SS); + else if (UnresolvedUsingDecl *UD = dyn_cast<UnresolvedUsingDecl>(D)) + return BuildDeclRefExpr(UD, Context.DependentTy, Loc, + /*TypeDependent=*/true, + /*ValueDependent=*/true, SS); + ValueDecl *VD = cast<ValueDecl>(D); // Check whether this declaration can be used. Note that we suppress // this check when we're going to perform argument-dependent lookup // on this function name, because this might not be the function // that overload resolution actually selects. - bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && + bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && HasTrailingLParen; if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc)) return ExprError(); @@ -1177,9 +1097,9 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // This is to record that a 'const' was actually synthesize and added. bool constAdded = !ExprTy.isConstQualified(); // Variable will be bound by-copy, make it const within the closure. - + ExprTy.addConst(); - return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false, + return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false, constAdded)); } // If this reference is not in a block or if the referenced variable is @@ -1189,7 +1109,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, bool ValueDependent = false; if (getLangOptions().CPlusPlus) { // C++ [temp.dep.expr]p3: - // An id-expression is type-dependent if it contains: + // An id-expression is type-dependent if it contains: // - an identifier that was declared with a dependent type, if (VD->getType()->isDependentType()) TypeDependent = true; @@ -1226,7 +1146,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // - a constant with integral or enumeration type and is // initialized with an expression that is value-dependent else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) { - if (Dcl->getType().getCVRQualifiers() == QualType::Const && + if (Dcl->getType().getCVRQualifiers() == Qualifiers::Const && Dcl->getInit()) { ValueDependent = Dcl->getInit()->isValueDependent(); } @@ -1250,21 +1170,24 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, // Pre-defined identifiers are of type char[x], where x is the length of the // string. - unsigned Length; - if (FunctionDecl *FD = getCurFunctionDecl()) - Length = FD->getIdentifier()->getLength(); - else if (ObjCMethodDecl *MD = getCurMethodDecl()) - Length = MD->getSynthesizedMethodSize(); - else { + + Decl *currentDecl = getCurFunctionOrMethodDecl(); + if (!currentDecl) { Diag(Loc, diag::ext_predef_outside_function); - // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string. - Length = IT == PredefinedExpr::PrettyFunction ? strlen("top level") : 0; + currentDecl = Context.getTranslationUnitDecl(); } + QualType ResTy; + if (cast<DeclContext>(currentDecl)->isDependentContext()) { + ResTy = Context.DependentTy; + } else { + unsigned Length = + PredefinedExpr::ComputeName(Context, IT, currentDecl).length(); - llvm::APInt LengthI(32, Length + 1); - QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const); - ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); + llvm::APInt LengthI(32, Length + 1); + ResTy = Context.CharTy.withConst(); + ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); + } return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT)); } @@ -1304,7 +1227,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Get the spelling of the token, which eliminates trigraphs, etc. unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); - NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, Tok.getLocation(), PP); if (Literal.hadError) return ExprError(); @@ -1417,7 +1340,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { // If this is an imaginary literal, create the ImaginaryLiteral wrapper. if (Literal.isImaginary) - Res = new (Context) ImaginaryLiteral(Res, + Res = new (Context) ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); return Owned(Res); @@ -1446,27 +1369,27 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange; return false; } - + // Allow sizeof(void)/alignof(void) as an extension. if (exprType->isVoidType()) { Diag(OpLoc, diag::ext_sizeof_void_type) << (isSizeof ? "sizeof" : "__alignof") << ExprRange; return false; } - + if (RequireCompleteType(OpLoc, exprType, - isSizeof ? diag::err_sizeof_incomplete_type : - diag::err_alignof_incomplete_type, - ExprRange)) + isSizeof ? diag::err_sizeof_incomplete_type : + PDiag(diag::err_alignof_incomplete_type) + << ExprRange)) return true; - + // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) { Diag(OpLoc, diag::err_sizeof_nonfragile_interface) << exprType << isSizeof << ExprRange; return true; } - + return false; } @@ -1474,7 +1397,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &ExprRange) { E = E->IgnoreParens(); - // alignof decl is always ok. + // alignof decl is always ok. if (isa<DeclRefExpr>(E)) return false; @@ -1490,15 +1413,15 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, // Alignment of a field access is always okay, so long as it isn't a // bit-field. if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) - if (dyn_cast<FieldDecl>(ME->getMemberDecl())) + if (isa<FieldDecl>(ME->getMemberDecl())) return false; return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); } /// \brief Build a sizeof or alignof expression given a type operand. -Action::OwningExprResult -Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, +Action::OwningExprResult +Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { if (T.isNull()) return ExprError(); @@ -1515,8 +1438,8 @@ Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, /// \brief Build a sizeof or alignof expression given an expression /// operand. -Action::OwningExprResult -Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, +Action::OwningExprResult +Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { // Verify that the operand is valid. bool isInvalid = false; @@ -1550,9 +1473,10 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, if (TyOrEx == 0) return ExprError(); if (isType) { - QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx); + // FIXME: Preserve type source info. + QualType ArgTy = GetTypeFromParser(TyOrEx); return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange); - } + } // Get the end location. Expr *ArgEx = (Expr *)TyOrEx; @@ -1568,15 +1492,15 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { if (V->isTypeDependent()) return Context.DependentTy; - + // These operators return the element type of a complex type. - if (const ComplexType *CT = V->getType()->getAsComplexType()) + if (const ComplexType *CT = V->getType()->getAs<ComplexType>()) return CT->getElementType(); - + // Otherwise they pass through real integer and floating point types here. if (V->getType()->isArithmeticType()) return V->getType(); - + // Reject anything else. Diag(Loc, diag::err_realimag_invalid_type) << V->getType() << (isReal ? "__real" : "__imag"); @@ -1588,6 +1512,8 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { Action::OwningExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, ExprArg Input) { + // Since this might be a postfix expression, get rid of ParenListExprs. + Input = MaybeConvertParenListExprToParenExpr(S, move(Input)); Expr *Arg = (Expr *)Input.get(); UnaryOperator::Opcode Opc; @@ -1612,9 +1538,9 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, // for objects of that type. When the postfix increment is // called as a result of using the ++ operator, the int // argument will have value zero. - Expr *Args[2] = { - Arg, - new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0, + Expr *Args[2] = { + Arg, + new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0, /*isSigned=*/true), Context.IntTy, SourceLocation()) }; @@ -1646,9 +1572,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, } // Determine the result type - QualType ResultTy - = FnDecl->getType()->getAsFunctionType()->getResultType(); - ResultTy = ResultTy.getNonReferenceType(); + QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); // Build the actual expression node. Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), @@ -1657,9 +1581,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, Input.release(); Args[0] = Arg; - return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr, - Args, 2, ResultTy, - OpLoc)); + + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, OverOp, + FnExpr, Args, 2, + ResultTy, OpLoc)); + + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), + FnDecl)) + return ExprError(); + return Owned(TheCall.release()); + } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -1672,11 +1604,19 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, } } - case OR_No_Viable_Function: - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. - break; - + case OR_No_Viable_Function: { + // No viable function; try checking this as a built-in operator, which + // will fail and provide a diagnostic. Then, print the overload + // candidates. + OwningExprResult Result = CreateBuiltinUnaryOp(OpLoc, Opc, move(Input)); + assert(Result.isInvalid() && + "C++ postfix-unary operator overloading is missing candidates!"); + if (Result.isInvalid()) + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + + return move(Result); + } + case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) << UnaryOperator::getOpcodeStr(Opc) @@ -1698,17 +1638,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, // build a built-in operation. } - QualType result = CheckIncrementDecrementOperand(Arg, OpLoc, - Opc == UnaryOperator::PostInc); - if (result.isNull()) - return ExprError(); Input.release(); - return Owned(new (Context) UnaryOperator(Arg, Opc, result, OpLoc)); + Input = Arg; + return CreateBuiltinUnaryOp(OpLoc, Opc, move(Input)); } Action::OwningExprResult Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, ExprArg Idx, SourceLocation RLoc) { + // Since this might be a postfix expression, get rid of ParenListExprs. + Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + Expr *LHSExp = static_cast<Expr*>(Base.get()), *RHSExp = static_cast<Expr*>(Idx.get()); @@ -1720,12 +1660,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, Context.DependentTy, RLoc)); } - if (getLangOptions().CPlusPlus && + if (getLangOptions().CPlusPlus && (LHSExp->getType()->isRecordType() || LHSExp->getType()->isEnumeralType() || RHSExp->getType()->isRecordType() || RHSExp->getType()->isEnumeralType())) { - // Add the appropriate overloaded operators (C++ [over.match.oper]) + // Add the appropriate overloaded operators (C++ [over.match.oper]) // to the candidate set. OverloadCandidateSet CandidateSet; Expr *Args[2] = { LHSExp, RHSExp }; @@ -1746,7 +1686,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { if (PerformObjectArgumentInitialization(LHSExp, Method) || - PerformCopyInitialization(RHSExp, + PerformCopyInitialization(RHSExp, FnDecl->getParamDecl(0)->getType(), "passing")) return ExprError(); @@ -1762,9 +1702,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, } // Determine the result type - QualType ResultTy - = FnDecl->getType()->getAsFunctionType()->getResultType(); - ResultTy = ResultTy.getNonReferenceType(); + QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); // Build the actual expression node. Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), @@ -1775,9 +1713,16 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, Idx.release(); Args[0] = LHSExp; Args[1] = RHSExp; - return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, - FnExpr, Args, 2, - ResultTy, LLoc)); + + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript, + FnExpr, Args, 2, + ResultTy, RLoc)); + if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(), + FnDecl)) + return ExprError(); + + return Owned(TheCall.release()); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -1834,16 +1779,27 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, BaseExpr = LHSExp; IndexExpr = RHSExp; ResultType = Context.DependentTy; - } else if (const PointerType *PTy = LHSTy->getAsPointerType()) { + } else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) { + BaseExpr = LHSExp; + IndexExpr = RHSExp; + ResultType = PTy->getPointeeType(); + } else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) { + // Handle the uncommon case of "123[Ptr]". + BaseExpr = RHSExp; + IndexExpr = LHSExp; + ResultType = PTy->getPointeeType(); + } else if (const ObjCObjectPointerType *PTy = + LHSTy->getAs<ObjCObjectPointerType>()) { BaseExpr = LHSExp; IndexExpr = RHSExp; ResultType = PTy->getPointeeType(); - } else if (const PointerType *PTy = RHSTy->getAsPointerType()) { + } else if (const ObjCObjectPointerType *PTy = + RHSTy->getAs<ObjCObjectPointerType>()) { // Handle the uncommon case of "123[Ptr]". BaseExpr = RHSExp; IndexExpr = LHSExp; ResultType = PTy->getPointeeType(); - } else if (const VectorType *VTy = LHSTy->getAsVectorType()) { + } else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) { BaseExpr = LHSExp; // vectors: V[123] IndexExpr = RHSExp; @@ -1862,7 +1818,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, BaseExpr = LHSExp; IndexExpr = RHSExp; - ResultType = LHSTy->getAsPointerType()->getPointeeType(); + ResultType = LHSTy->getAs<PointerType>()->getPointeeType(); } else if (RHSTy->isArrayType()) { // Same as previous, except for 123[f().a] case Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << @@ -1872,38 +1828,45 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, BaseExpr = RHSExp; IndexExpr = LHSExp; - ResultType = RHSTy->getAsPointerType()->getPointeeType(); + ResultType = RHSTy->getAs<PointerType>()->getPointeeType(); } else { return ExprError(Diag(LLoc, diag::err_typecheck_subscript_value) << LHSExp->getSourceRange() << RHSExp->getSourceRange()); } // C99 6.5.2.1p1 - if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent()) + if (!(IndexExpr->getType()->isIntegerType() && + IndexExpr->getType()->isScalarType()) && !IndexExpr->isTypeDependent()) return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer) << IndexExpr->getSourceRange()); + if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || + IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) + && !IndexExpr->isTypeDependent()) + Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange(); + // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly, - // C++ [expr.sub]p1: The type "T" shall be a completely-defined object - // type. Note that Functions are not objects, and that (in C99 parlance) + // C++ [expr.sub]p1: The type "T" shall be a completely-defined object + // type. Note that Functions are not objects, and that (in C99 parlance) // incomplete types are not object types. if (ResultType->isFunctionType()) { Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type) << ResultType << BaseExpr->getSourceRange(); return ExprError(); } - + if (!ResultType->isDependentType() && - RequireCompleteType(LLoc, ResultType, diag::err_subscript_incomplete_type, - BaseExpr->getSourceRange())) + RequireCompleteType(LLoc, ResultType, + PDiag(diag::err_subscript_incomplete_type) + << BaseExpr->getSourceRange())) return ExprError(); - + // Diagnose bad cases where we step over interface counts. if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { Diag(LLoc, diag::err_subscript_nonfragile_interface) << ResultType << BaseExpr->getSourceRange(); return ExprError(); } - + Base.release(); Idx.release(); return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, @@ -1912,11 +1875,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, QualType Sema:: CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, - IdentifierInfo &CompName, SourceLocation CompLoc) { - const ExtVectorType *vecType = baseType->getAsExtVectorType(); + const IdentifierInfo *CompName, + SourceLocation CompLoc) { + const ExtVectorType *vecType = baseType->getAs<ExtVectorType>(); // The vector accessor can't exceed the number of elements. - const char *compStr = CompName.getName(); + const char *compStr = CompName->getName(); // This flag determines whether or not the component is one of the four // special names that indicate a subset of exactly half the elements are @@ -1953,7 +1917,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, // Ensure no component accessor exceeds the width of the vector type it // operates on. if (!HalvingSwizzle) { - compStr = CompName.getName(); + compStr = CompName->getName(); if (HexSwizzle) compStr++; @@ -1981,7 +1945,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, // vec4.s0 is a float, vec4.s23 is a vec3, etc. // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2 - : CompName.getLength(); + : CompName->getLength(); if (HexSwizzle) CompSize--; @@ -1999,18 +1963,18 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, } static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, - IdentifierInfo &Member, + IdentifierInfo *Member, const Selector &Sel, ASTContext &Context) { - - if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(&Member)) + + if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) return PD; if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) return OMD; - + for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), E = PDecl->protocol_end(); I != E; ++I) { - if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel, + if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel, Context)) return D; } @@ -2018,14 +1982,14 @@ static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, } static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, - IdentifierInfo &Member, + IdentifierInfo *Member, const Selector &Sel, ASTContext &Context) { // Check protocols on qualified interfaces. Decl *GDecl = 0; for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), E = QIdTy->qual_end(); I != E; ++I) { - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) { + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { GDecl = PD; break; } @@ -2047,101 +2011,213 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, return GDecl; } -/// FindMethodInNestedImplementations - Look up a method in current and -/// all base class implementations. -/// -ObjCMethodDecl *Sema::FindMethodInNestedImplementations( - const ObjCInterfaceDecl *IFace, - const Selector &Sel) { - ObjCMethodDecl *Method = 0; - if (ObjCImplementationDecl *ImpDecl - = LookupObjCImplementation(IFace->getIdentifier())) - Method = ImpDecl->getInstanceMethod(Sel); - - if (!Method && IFace->getSuperClass()) - return FindMethodInNestedImplementations(IFace->getSuperClass(), Sel); - return Method; -} - Action::OwningExprResult -Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, +Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation MemberLoc, - IdentifierInfo &Member, - DeclPtrTy ObjCImpDecl) { + DeclarationName MemberName, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS, + NamedDecl *FirstQualifierInScope) { + if (SS && SS->isInvalid()) + return ExprError(); + + // Since this might be a postfix expression, get rid of ParenListExprs. + Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + Expr *BaseExpr = Base.takeAs<Expr>(); - assert(BaseExpr && "no record expression"); + assert(BaseExpr && "no base expression"); // Perform default conversions. DefaultFunctionArrayConversion(BaseExpr); QualType BaseType = BaseExpr->getType(); + // If this is an Objective-C pseudo-builtin and a definition is provided then + // use that. + if (BaseType->isObjCIdType()) { + // We have an 'id' type. Rather than fall through, we check if this + // is a reference to 'isa'. + if (BaseType != Context.ObjCIdRedefinitionType) { + BaseType = Context.ObjCIdRedefinitionType; + ImpCastExprToType(BaseExpr, BaseType); + } + } assert(!BaseType.isNull() && "no type for member expression"); + // Handle properties on ObjC 'Class' types. + if (OpKind == tok::period && BaseType->isObjCClassType()) { + // Also must look for a getter name which uses property syntax. + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + if (ObjCMethodDecl *MD = getCurMethodDecl()) { + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + ObjCMethodDecl *Getter; + // FIXME: need to also look locally in the implementation. + if ((Getter = IFace->lookupClassMethod(Sel))) { + // Check the use of this method. + if (DiagnoseUseOfDecl(Getter, MemberLoc)) + return ExprError(); + } + // If we found a getter then this may be a valid dot-reference, we + // will look for the matching setter, in case it is needed. + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); + ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + Setter = IFace->lookupPrivateInstanceMethod(SetterSel); + } + // Look through local category implementations associated with the class. + if (!Setter) + Setter = IFace->getCategoryClassMethod(SetterSel); + + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) + return ExprError(); + + if (Getter || Setter) { + QualType PType; + + if (Getter) + PType = Getter->getResultType(); + else + // Get the expression type from Setter's incoming parameter. + PType = (*(Setter->param_end() -1))->getType(); + // FIXME: we must check that the setter has property type. + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, + PType, + Setter, MemberLoc, BaseExpr)); + } + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << MemberName << BaseType); + } + } + + if (BaseType->isObjCClassType() && + BaseType != Context.ObjCClassRedefinitionType) { + BaseType = Context.ObjCClassRedefinitionType; + ImpCastExprToType(BaseExpr, BaseType); + } + // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. if (OpKind == tok::arrow) { - if (BaseType->isDependentType()) - return Owned(new (Context) CXXUnresolvedMemberExpr(Context, - BaseExpr, true, - OpLoc, - DeclarationName(&Member), - MemberLoc)); - else if (const PointerType *PT = BaseType->getAsPointerType()) + if (BaseType->isDependentType()) { + NestedNameSpecifier *Qualifier = 0; + if (SS) { + Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + if (!FirstQualifierInScope) + FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier); + } + + return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true, + OpLoc, Qualifier, + SS? SS->getRange() : SourceRange(), + FirstQualifierInScope, + MemberName, + MemberLoc, + HasExplicitTemplateArgs, + LAngleLoc, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + RAngleLoc)); + } + else if (const PointerType *PT = BaseType->getAs<PointerType>()) BaseType = PT->getPointeeType(); - else if (getLangOptions().CPlusPlus && BaseType->isRecordType()) - return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc, - MemberLoc, Member)); + else if (BaseType->isObjCObjectPointerType()) + ; else return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) << BaseType << BaseExpr->getSourceRange()); - } else { - if (BaseType->isDependentType()) { - // Require that the base type isn't a pointer type + } else if (BaseType->isDependentType()) { + // Require that the base type isn't a pointer type // (so we'll report an error for) // T* t; // t.f; - // + // // In Obj-C++, however, the above expression is valid, since it could be // accessing the 'f' property if T is an Obj-C interface. The extra check // allows this, while still reporting an error if T is a struct pointer. - const PointerType *PT = BaseType->getAsPointerType(); + const PointerType *PT = BaseType->getAs<PointerType>(); + + if (!PT || (getLangOptions().ObjC1 && + !PT->getPointeeType()->isRecordType())) { + NestedNameSpecifier *Qualifier = 0; + if (SS) { + Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + if (!FirstQualifierInScope) + FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier); + } - if (!PT || (getLangOptions().ObjC1 && - !PT->getPointeeType()->isRecordType())) - return Owned(new (Context) CXXUnresolvedMemberExpr(Context, - BaseExpr, false, - OpLoc, - DeclarationName(&Member), - MemberLoc)); + return Owned(CXXUnresolvedMemberExpr::Create(Context, + BaseExpr, false, + OpLoc, + Qualifier, + SS? SS->getRange() : SourceRange(), + FirstQualifierInScope, + MemberName, + MemberLoc, + HasExplicitTemplateArgs, + LAngleLoc, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + RAngleLoc)); + } } - } // Handle field access to simple records. This also handles access to fields // of the ObjC 'id' struct. - if (const RecordType *RTy = BaseType->getAsRecordType()) { + if (const RecordType *RTy = BaseType->getAs<RecordType>()) { RecordDecl *RDecl = RTy->getDecl(); if (RequireCompleteType(OpLoc, BaseType, - diag::err_typecheck_incomplete_tag, - BaseExpr->getSourceRange())) + PDiag(diag::err_typecheck_incomplete_tag) + << BaseExpr->getSourceRange())) return ExprError(); + DeclContext *DC = RDecl; + if (SS && SS->isSet()) { + // If the member name was a qualified-id, look into the + // nested-name-specifier. + DC = computeDeclContext(*SS, false); + + // FIXME: If DC is not computable, we should build a + // CXXUnresolvedMemberExpr. + assert(DC && "Cannot handle non-computable dependent contexts in lookup"); + } + // The record definition is complete, now make sure the member is valid. - // FIXME: Qualified name lookup for C++ is a bit more complicated than this. - LookupResult Result - = LookupQualifiedName(RDecl, DeclarationName(&Member), - LookupMemberName, false); - - if (!Result) - return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member) - << &Member << BaseExpr->getSourceRange()); + LookupResult Result; + LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false); + + if (Result.empty()) + return ExprError(Diag(MemberLoc, diag::err_no_member) + << MemberName << DC << BaseExpr->getSourceRange()); if (Result.isAmbiguous()) { - DiagnoseAmbiguousLookup(Result, DeclarationName(&Member), - MemberLoc, BaseExpr->getSourceRange()); + DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc, + BaseExpr->getSourceRange()); return ExprError(); } - - NamedDecl *MemberDecl = Result; + + NamedDecl *MemberDecl = Result.getAsSingleDecl(Context); + + if (SS && SS->isSet()) { + TypeDecl* TyD = cast<TypeDecl>(MemberDecl->getDeclContext()); + QualType BaseTypeCanon + = Context.getCanonicalType(BaseType).getUnqualifiedType(); + QualType MemberTypeCanon + = Context.getCanonicalType(Context.getTypeDeclType(TyD)); + + if (BaseTypeCanon != MemberTypeCanon && + !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) + return ExprError(Diag(SS->getBeginLoc(), + diag::err_not_direct_base_or_virtual) + << MemberTypeCanon << BaseTypeCanon); + } // If the decl being referenced had an error, return an error for this // sub-expr without emitting another error, in order to avoid cascading @@ -2149,8 +2225,16 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, if (MemberDecl->isInvalidDecl()) return ExprError(); + bool ShouldCheckUse = true; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) { + // Don't diagnose the use of a virtual member function unless it's + // explicitly qualified. + if (MD->isVirtual() && (!SS || !SS->isSet())) + ShouldCheckUse = false; + } + // Check the use of this field - if (DiagnoseUseOfDecl(MemberDecl, MemberLoc)) + if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) return ExprError(); if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) { @@ -2161,137 +2245,253 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, BaseExpr, OpLoc); // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - // FIXME: Handle address space modifiers QualType MemberType = FD->getType(); - if (const ReferenceType *Ref = MemberType->getAsReferenceType()) + if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) MemberType = Ref->getPointeeType(); else { - unsigned combinedQualifiers = - MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers(); - if (FD->isMutable()) - combinedQualifiers &= ~QualType::Const; - MemberType = MemberType.getQualifiedType(combinedQualifiers); + Qualifiers BaseQuals = BaseType.getQualifiers(); + BaseQuals.removeObjCGCAttr(); + if (FD->isMutable()) BaseQuals.removeConst(); + + Qualifiers MemberQuals + = Context.getCanonicalType(MemberType).getQualifiers(); + + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + MemberType = Context.getQualifiedType(MemberType, Combined); } MarkDeclarationReferenced(MemberLoc, FD); - return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD, - MemberLoc, MemberType)); + if (PerformObjectMemberConversion(BaseExpr, FD)) + return ExprError(); + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, + FD, MemberLoc, MemberType)); } - + if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, - Var, MemberLoc, - Var->getType().getNonReferenceType())); + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, + Var, MemberLoc, + Var->getType().getNonReferenceType())); } if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, - MemberFn, MemberLoc, - MemberFn->getType())); + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, + MemberFn, MemberLoc, + MemberFn->getType())); + } + if (FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + + if (HasExplicitTemplateArgs) + return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), + FunTmpl, MemberLoc, true, + LAngleLoc, ExplicitTemplateArgs, + NumExplicitTemplateArgs, RAngleLoc, + Context.OverloadTy)); + + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, + FunTmpl, MemberLoc, + Context.OverloadTy)); } if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) - return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl, - MemberLoc, Context.OverloadTy)); + = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) { + if (HasExplicitTemplateArgs) + return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), + Ovl, MemberLoc, true, + LAngleLoc, ExplicitTemplateArgs, + NumExplicitTemplateArgs, RAngleLoc, + Context.OverloadTy)); + + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, + Ovl, MemberLoc, Context.OverloadTy)); + } if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, - Enum, MemberLoc, Enum->getType())); + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, + Enum, MemberLoc, Enum->getType())); } if (isa<TypeDecl>(MemberDecl)) return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) - << DeclarationName(&Member) << int(OpKind == tok::arrow)); + << MemberName << int(OpKind == tok::arrow)); // We found a declaration kind that we didn't expect. This is a // generic error message that tells the user that she can't refer // to this member with '.' or '->'. return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_unknown) - << DeclarationName(&Member) << int(OpKind == tok::arrow)); + << MemberName << int(OpKind == tok::arrow)); + } + + // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring + // into a record type was handled above, any destructor we see here is a + // pseudo-destructor. + if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) { + // C++ [expr.pseudo]p2: + // The left hand side of the dot operator shall be of scalar type. The + // left hand side of the arrow operator shall be of pointer to scalar + // type. + if (!BaseType->isScalarType()) + return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) + << BaseType << BaseExpr->getSourceRange()); + + // [...] The type designated by the pseudo-destructor-name shall be the + // same as the object type. + if (!MemberName.getCXXNameType()->isDependentType() && + !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType())) + return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch) + << BaseType << MemberName.getCXXNameType() + << BaseExpr->getSourceRange() << SourceRange(MemberLoc)); + + // [...] Furthermore, the two type-names in a pseudo-destructor-name of + // the form + // + // ::[opt] nested-name-specifier[opt] type-name :: ̃ type-name + // + // shall designate the same scalar type. + // + // FIXME: DPG can't see any way to trigger this particular clause, so it + // isn't checked here. + + // FIXME: We've lost the precise spelling of the type by going through + // DeclarationName. Can we do better? + return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr, + OpKind == tok::arrow, + OpLoc, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), + MemberName.getCXXNameType(), + MemberLoc)); } // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. - if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) { - ObjCInterfaceDecl *ClassDeclared; - if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(&Member, - ClassDeclared)) { - // If the decl being referenced had an error, return an error for this - // sub-expr without emitting another error, in order to avoid cascading - // error cases. - if (IV->isInvalidDecl()) - return ExprError(); + if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) || + (OpKind == tok::period && BaseType->isObjCInterfaceType())) { + const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>(); + const ObjCInterfaceType *IFaceT = + OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>(); + if (IFaceT) { + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + + ObjCInterfaceDecl *IDecl = IFaceT->getDecl(); + ObjCInterfaceDecl *ClassDeclared; + ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); - // Check whether we can reference this field. - if (DiagnoseUseOfDecl(IV, MemberLoc)) - return ExprError(); - if (IV->getAccessControl() != ObjCIvarDecl::Public && - IV->getAccessControl() != ObjCIvarDecl::Package) { - ObjCInterfaceDecl *ClassOfMethodDecl = 0; - if (ObjCMethodDecl *MD = getCurMethodDecl()) - ClassOfMethodDecl = MD->getClassInterface(); - else if (ObjCImpDecl && getCurFunctionDecl()) { - // Case of a c-function declared inside an objc implementation. - // FIXME: For a c-style function nested inside an objc implementation - // class, there is no implementation context available, so we pass - // down the context as argument to this routine. Ideally, this context - // need be passed down in the AST node and somehow calculated from the - // AST for a function decl. - Decl *ImplDecl = ObjCImpDecl.getAs<Decl>(); - if (ObjCImplementationDecl *IMPD = - dyn_cast<ObjCImplementationDecl>(ImplDecl)) - ClassOfMethodDecl = IMPD->getClassInterface(); - else if (ObjCCategoryImplDecl* CatImplClass = - dyn_cast<ObjCCategoryImplDecl>(ImplDecl)) - ClassOfMethodDecl = CatImplClass->getClassInterface(); - } - - if (IV->getAccessControl() == ObjCIvarDecl::Private) { - if (ClassDeclared != IFTy->getDecl() || - ClassOfMethodDecl != ClassDeclared) - Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName(); + if (IV) { + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (IV->isInvalidDecl()) + return ExprError(); + + // Check whether we can reference this field. + if (DiagnoseUseOfDecl(IV, MemberLoc)) + return ExprError(); + if (IV->getAccessControl() != ObjCIvarDecl::Public && + IV->getAccessControl() != ObjCIvarDecl::Package) { + ObjCInterfaceDecl *ClassOfMethodDecl = 0; + if (ObjCMethodDecl *MD = getCurMethodDecl()) + ClassOfMethodDecl = MD->getClassInterface(); + else if (ObjCImpDecl && getCurFunctionDecl()) { + // Case of a c-function declared inside an objc implementation. + // FIXME: For a c-style function nested inside an objc implementation + // class, there is no implementation context available, so we pass + // down the context as argument to this routine. Ideally, this context + // need be passed down in the AST node and somehow calculated from the + // AST for a function decl. + Decl *ImplDecl = ObjCImpDecl.getAs<Decl>(); + if (ObjCImplementationDecl *IMPD = + dyn_cast<ObjCImplementationDecl>(ImplDecl)) + ClassOfMethodDecl = IMPD->getClassInterface(); + else if (ObjCCategoryImplDecl* CatImplClass = + dyn_cast<ObjCCategoryImplDecl>(ImplDecl)) + ClassOfMethodDecl = CatImplClass->getClassInterface(); + } + + if (IV->getAccessControl() == ObjCIvarDecl::Private) { + if (ClassDeclared != IDecl || + ClassOfMethodDecl != ClassDeclared) + Diag(MemberLoc, diag::error_private_ivar_access) + << IV->getDeclName(); + } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) + // @protected + Diag(MemberLoc, diag::error_protected_ivar_access) + << IV->getDeclName(); } - // @protected - else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl)) - Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName(); - } - return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, BaseExpr, - OpKind == tok::arrow)); + return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), + MemberLoc, BaseExpr, + OpKind == tok::arrow)); + } + return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) + << IDecl->getDeclName() << MemberName + << BaseExpr->getSourceRange()); } - return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) - << IFTy->getDecl()->getDeclName() << &Member - << BaseExpr->getSourceRange()); } + // Handle properties on 'id' and qualified "id". + if (OpKind == tok::period && (BaseType->isObjCIdType() || + BaseType->isObjCQualifiedIdType())) { + const ObjCObjectPointerType *QIdTy = BaseType->getAs<ObjCObjectPointerType>(); + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + // Check protocols on qualified interfaces. + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) { + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { + // Check the use of this declaration + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { + // Check the use of this method. + if (DiagnoseUseOfDecl(OMD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel, + OMD->getResultType(), + OMD, OpLoc, MemberLoc, + NULL, 0)); + } + } + + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << MemberName << BaseType); + } // Handle Objective-C property access, which is "Obj.property" where Obj is a // pointer to a (potentially qualified) interface type. - const PointerType *PTy; - const ObjCInterfaceType *IFTy; - if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) && - (IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) { - ObjCInterfaceDecl *IFace = IFTy->getDecl(); + const ObjCObjectPointerType *OPT; + if (OpKind == tok::period && + (OPT = BaseType->getAsObjCInterfacePointerType())) { + const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); + ObjCInterfaceDecl *IFace = IFaceT->getDecl(); + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); // Search for a declared property first. - if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) { + if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); QualType ResTy = PD->getType(); - Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) ResTy = Getter->getResultType(); return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, MemberLoc, BaseExpr)); } - // Check protocols on qualified interfaces. - for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(), - E = IFTy->qual_end(); I != E; ++I) - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) { + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); @@ -2299,27 +2499,32 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), MemberLoc, BaseExpr)); } + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } // If that failed, look for an "implicit" property by seeing if the nullary // selector is implemented. // FIXME: The logic for looking up nullary and unary selectors should be // shared with the code in ActOnInstanceMessage. - Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); // If this reference is in an @implementation, check for 'private' methods. if (!Getter) - Getter = FindMethodInNestedImplementations(IFace, Sel); + Getter = IFace->lookupPrivateInstanceMethod(Sel); // Look through local category implementations associated with the class. - if (!Getter) { - for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Getter; i++) { - if (ObjCCategoryImpls[i]->getClassInterface() == IFace) - Getter = ObjCCategoryImpls[i]->getInstanceMethod(Sel); - } - } + if (!Getter) + Getter = IFace->getCategoryInstanceMethod(Sel); if (Getter) { // Check if we can reference this property. if (DiagnoseUseOfDecl(Getter, MemberLoc)) @@ -2327,22 +2532,18 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } // If we found a getter then this may be a valid dot-reference, we // will look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), &Member); + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); if (!Setter) { // If this reference is in an @implementation, also check for 'private' // methods. - Setter = FindMethodInNestedImplementations(IFace, SetterSel); + Setter = IFace->lookupPrivateInstanceMethod(SetterSel); } // Look through local category implementations associated with the class. - if (!Setter) { - for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { - if (ObjCCategoryImpls[i]->getClassInterface() == IFace) - Setter = ObjCCategoryImpls[i]->getInstanceMethod(SetterSel); - } - } + if (!Setter) + Setter = IFace->getCategoryInstanceMethod(SetterSel); if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); @@ -2352,107 +2553,31 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, if (Getter) PType = Getter->getResultType(); - else { - for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), - E = Setter->param_end(); PI != E; ++PI) - PType = (*PI)->getType(); - } + else + // Get the expression type from Setter's incoming parameter. + PType = (*(Setter->param_end() -1))->getType(); // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << &Member << BaseType); - } - // Handle properties on qualified "id" protocols. - const ObjCObjectPointerType *QIdTy; - if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) { - // Check protocols on qualified interfaces. - Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); - if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) { - if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { - // Check the use of this declaration - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), - MemberLoc, BaseExpr)); - } - if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { - // Check the use of this method. - if (DiagnoseUseOfDecl(OMD, MemberLoc)) - return ExprError(); - - return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel, - OMD->getResultType(), - OMD, OpLoc, MemberLoc, - NULL, 0)); - } - } - - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << &Member << BaseType); + << MemberName << BaseType); } - // Handle properties on ObjC 'Class' types. - if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) { - // Also must look for a getter name which uses property syntax. - Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); - if (ObjCMethodDecl *MD = getCurMethodDecl()) { - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - ObjCMethodDecl *Getter; - // FIXME: need to also look locally in the implementation. - if ((Getter = IFace->lookupClassMethod(Sel))) { - // Check the use of this method. - if (DiagnoseUseOfDecl(Getter, MemberLoc)) - return ExprError(); - } - // If we found a getter then this may be a valid dot-reference, we - // will look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), &Member); - ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = FindMethodInNestedImplementations(IFace, SetterSel); - } - // Look through local category implementations associated with the class. - if (!Setter) { - for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { - if (ObjCCategoryImpls[i]->getClassInterface() == IFace) - Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel); - } - } - if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) - return ExprError(); + // Handle the following exceptional case (*Obj).isa. + if (OpKind == tok::period && + BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) && + MemberName.getAsIdentifierInfo()->isStr("isa")) + return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, + Context.getObjCIdType())); - if (Getter || Setter) { - QualType PType; - - if (Getter) - PType = Getter->getResultType(); - else { - for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), - E = Setter->param_end(); PI != E; ++PI) - PType = (*PI)->getType(); - } - // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, - Setter, MemberLoc, BaseExpr)); - } - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << &Member << BaseType); - } - } - // Handle 'field access' to vectors, such as 'V.xx'. if (BaseType->isExtVectorType()) { + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc); if (ret.isNull()) return ExprError(); - return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, Member, + return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member, MemberLoc)); } @@ -2462,10 +2587,10 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // If the user is trying to apply -> or . to a function or function // pointer, it's probably because they forgot parentheses to call // the function. Suggest the addition of those parentheses. - if (BaseType == Context.OverloadTy || + if (BaseType == Context.OverloadTy || BaseType->isFunctionType() || - (BaseType->isPointerType() && - BaseType->getAsPointerType()->isFunctionType())) { + (BaseType->isPointerType() && + BaseType->getAs<PointerType>()->isFunctionType())) { SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); Diag(Loc, diag::note_member_reference_needs_call) << CodeModificationHint::CreateInsertion(Loc, "()"); @@ -2474,6 +2599,63 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); } +Action::OwningExprResult +Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, SourceLocation MemberLoc, + IdentifierInfo &Member, + DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) { + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc, + DeclarationName(&Member), ObjCImpDecl, SS); +} + +Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, + FunctionDecl *FD, + ParmVarDecl *Param) { + if (Param->hasUnparsedDefaultArg()) { + Diag (CallLoc, + diag::err_use_of_default_argument_to_function_declared_later) << + FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName(); + Diag(UnparsedDefaultArgLocs[Param], + diag::note_default_argument_declared_here); + } else { + if (Param->hasUninstantiatedDefaultArg()) { + Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); + + // Instantiate the expression. + MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD); + + InstantiatingTemplate Inst(*this, CallLoc, Param, + ArgList.getInnermost().getFlatArgumentList(), + ArgList.getInnermost().flat_size()); + + OwningExprResult Result = SubstExpr(UninstExpr, ArgList); + if (Result.isInvalid()) + return ExprError(); + + if (SetParamDefaultArgument(Param, move(Result), + /*FIXME:EqualLoc*/ + UninstExpr->getSourceRange().getBegin())) + return ExprError(); + } + + Expr *DefaultExpr = Param->getDefaultArg(); + + // If the default expression creates temporaries, we need to + // push them to the current stack of expression temporaries so they'll + // be properly destroyed. + if (CXXExprWithTemporaries *E + = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) { + assert(!E->shouldDestroyTemporaries() && + "Can't destroy temporaries in a default argument expr!"); + for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) + ExprTemporaries.push_back(E->getTemporary(I)); + } + } + + // We already type-checked the argument, so we know it works. + return Owned(CXXDefaultArgExpr::Create(Context, Param)); +} + /// ConvertArgumentsForCall - Converts the arguments specified in /// Args/NumArgs to the parameter types of the function FDecl with /// function prototype Proto. Call is the call expression itself, and @@ -2529,40 +2711,24 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, if (RequireCompleteType(Arg->getSourceRange().getBegin(), ProtoArgType, - diag::err_call_incomplete_argument, - Arg->getSourceRange())) + PDiag(diag::err_call_incomplete_argument) + << Arg->getSourceRange())) return true; // Pass the argument. if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) return true; } else { - if (FDecl->getParamDecl(i)->hasUnparsedDefaultArg()) { - Diag (Call->getSourceRange().getBegin(), - diag::err_use_of_default_argument_to_function_declared_later) << - FDecl << cast<CXXRecordDecl>(FDecl->getDeclContext())->getDeclName(); - Diag(UnparsedDefaultArgLocs[FDecl->getParamDecl(i)], - diag::note_default_argument_declared_here); - } else { - Expr *DefaultExpr = FDecl->getParamDecl(i)->getDefaultArg(); - - // If the default expression creates temporaries, we need to - // push them to the current stack of expression temporaries so they'll - // be properly destroyed. - if (CXXExprWithTemporaries *E - = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) { - assert(!E->shouldDestroyTemporaries() && - "Can't destroy temporaries in a default argument expr!"); - for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) - ExprTemporaries.push_back(E->getTemporary(I)); - } - } - - // We already type-checked the argument, so we know it works. - Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i)); + ParmVarDecl *Param = FDecl->getParamDecl(i); + + OwningExprResult ArgExpr = + BuildCXXDefaultArgExpr(Call->getSourceRange().getBegin(), + FDecl, Param); + if (ArgExpr.isInvalid()) + return true; + + Arg = ArgExpr.takeAs<Expr>(); } - - QualType ArgType = Arg->getType(); Call->setArg(i, Arg); } @@ -2586,6 +2752,96 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, return Invalid; } +/// \brief "Deconstruct" the function argument of a call expression to find +/// the underlying declaration (if any), the name of the called function, +/// whether argument-dependent lookup is available, whether it has explicit +/// template arguments, etc. +void Sema::DeconstructCallFunction(Expr *FnExpr, + NamedDecl *&Function, + DeclarationName &Name, + NestedNameSpecifier *&Qualifier, + SourceRange &QualifierRange, + bool &ArgumentDependentLookup, + bool &HasExplicitTemplateArguments, + const TemplateArgument *&ExplicitTemplateArgs, + unsigned &NumExplicitTemplateArgs) { + // Set defaults for all of the output parameters. + Function = 0; + Name = DeclarationName(); + Qualifier = 0; + QualifierRange = SourceRange(); + ArgumentDependentLookup = getLangOptions().CPlusPlus; + HasExplicitTemplateArguments = false; + + // If we're directly calling a function, get the appropriate declaration. + // Also, in C++, keep track of whether we should perform argument-dependent + // lookup and whether there were any explicitly-specified template arguments. + while (true) { + if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr)) + FnExpr = IcExpr->getSubExpr(); + else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) { + // Parentheses around a function disable ADL + // (C++0x [basic.lookup.argdep]p1). + ArgumentDependentLookup = false; + FnExpr = PExpr->getSubExpr(); + } else if (isa<UnaryOperator>(FnExpr) && + cast<UnaryOperator>(FnExpr)->getOpcode() + == UnaryOperator::AddrOf) { + FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr(); + } else if (QualifiedDeclRefExpr *QDRExpr + = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) { + // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). + ArgumentDependentLookup = false; + Qualifier = QDRExpr->getQualifier(); + QualifierRange = QDRExpr->getQualifierRange(); + Function = dyn_cast<NamedDecl>(QDRExpr->getDecl()); + break; + } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) { + Function = dyn_cast<NamedDecl>(DRExpr->getDecl()); + break; + } else if (UnresolvedFunctionNameExpr *DepName + = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) { + Name = DepName->getName(); + break; + } else if (TemplateIdRefExpr *TemplateIdRef + = dyn_cast<TemplateIdRefExpr>(FnExpr)) { + Function = TemplateIdRef->getTemplateName().getAsTemplateDecl(); + if (!Function) + Function = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl(); + HasExplicitTemplateArguments = true; + ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs(); + NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs(); + + // C++ [temp.arg.explicit]p6: + // [Note: For simple function names, argument dependent lookup (3.4.2) + // applies even when the function name is not visible within the + // scope of the call. This is because the call still has the syntactic + // form of a function call (3.4.1). But when a function template with + // explicit template arguments is used, the call does not have the + // correct syntactic form unless there is a function template with + // that name visible at the point of the call. If no such name is + // visible, the call is not syntactically well-formed and + // argument-dependent lookup does not apply. If some such name is + // visible, argument dependent lookup applies and additional function + // templates may be found in other namespaces. + // + // The summary of this paragraph is that, if we get to this point and the + // template-id was not a qualified name, then argument-dependent lookup + // is still possible. + if ((Qualifier = TemplateIdRef->getQualifier())) { + ArgumentDependentLookup = false; + QualifierRange = TemplateIdRef->getQualifierRange(); + } + break; + } else { + // Any kind of name that does not refer to a declaration (or + // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3). + ArgumentDependentLookup = false; + break; + } + } +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -2594,6 +2850,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, MultiExprArg args, SourceLocation *CommaLocs, SourceLocation RParenLoc) { unsigned NumArgs = args.size(); + + // Since this might be a postfix expression, get rid of ParenListExprs. + fn = MaybeConvertParenListExprToParenExpr(S, move(fn)); + Expr *Fn = fn.takeAs<Expr>(); Expr **Args = reinterpret_cast<Expr**>(args.release()); assert(Fn && "no function call expression"); @@ -2602,6 +2862,25 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, DeclarationName UnqualifiedName; if (getLangOptions().CPlusPlus) { + // If this is a pseudo-destructor expression, build the call immediately. + if (isa<CXXPseudoDestructorExpr>(Fn)) { + if (NumArgs > 0) { + // Pseudo-destructor calls should not have any arguments. + Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args) + << CodeModificationHint::CreateRemoval( + SourceRange(Args[0]->getLocStart(), + Args[NumArgs-1]->getLocEnd())); + + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Destroy(Context); + + NumArgs = 0; + } + + return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy, + RParenLoc)); + } + // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. // FIXME: Will need to cache the results of name lookup (including ADL) in @@ -2632,70 +2911,42 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc)); } + + // Determine whether this is a call to a pointer-to-member function. + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Fn->IgnoreParens())) { + if (BO->getOpcode() == BinaryOperator::PtrMemD || + BO->getOpcode() == BinaryOperator::PtrMemI) { + const FunctionProtoType *FPT = cast<FunctionProtoType>(BO->getType()); + QualType ReturnTy = FPT->getResultType(); + + CXXMemberCallExpr *CE = + new (Context) CXXMemberCallExpr(Context, BO, Args, NumArgs, + ReturnTy.getNonReferenceType(), + RParenLoc); + + ExprOwningPtr<CXXMemberCallExpr> TheCall(this, CE); + + if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, + RParenLoc)) + return ExprError(); + + return Owned(MaybeBindToTemporary(TheCall.release()).release()); + } + } } // If we're directly calling a function, get the appropriate declaration. - // Also, in C++, keep track of whether we should perform argument-dependent + // Also, in C++, keep track of whether we should perform argument-dependent // lookup and whether there were any explicitly-specified template arguments. - Expr *FnExpr = Fn; bool ADL = true; bool HasExplicitTemplateArgs = 0; const TemplateArgument *ExplicitTemplateArgs = 0; unsigned NumExplicitTemplateArgs = 0; - while (true) { - if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr)) - FnExpr = IcExpr->getSubExpr(); - else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) { - // Parentheses around a function disable ADL - // (C++0x [basic.lookup.argdep]p1). - ADL = false; - FnExpr = PExpr->getSubExpr(); - } else if (isa<UnaryOperator>(FnExpr) && - cast<UnaryOperator>(FnExpr)->getOpcode() - == UnaryOperator::AddrOf) { - FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr(); - } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) { - // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). - ADL &= !isa<QualifiedDeclRefExpr>(DRExpr); - NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl()); - break; - } else if (UnresolvedFunctionNameExpr *DepName - = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) { - UnqualifiedName = DepName->getName(); - break; - } else if (TemplateIdRefExpr *TemplateIdRef - = dyn_cast<TemplateIdRefExpr>(FnExpr)) { - NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl(); - HasExplicitTemplateArgs = true; - ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs(); - NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs(); - - // C++ [temp.arg.explicit]p6: - // [Note: For simple function names, argument dependent lookup (3.4.2) - // applies even when the function name is not visible within the - // scope of the call. This is because the call still has the syntactic - // form of a function call (3.4.1). But when a function template with - // explicit template arguments is used, the call does not have the - // correct syntactic form unless there is a function template with - // that name visible at the point of the call. If no such name is - // visible, the call is not syntactically well-formed and - // argument-dependent lookup does not apply. If some such name is - // visible, argument dependent lookup applies and additional function - // templates may be found in other namespaces. - // - // The summary of this paragraph is that, if we get to this point and the - // template-id was not a qualified name, then argument-dependent lookup - // is still possible. - if (TemplateIdRef->getQualifier()) - ADL = false; - break; - } else { - // Any kind of name that does not refer to a declaration (or - // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3). - ADL = false; - break; - } - } + NestedNameSpecifier *Qualifier = 0; + SourceRange QualifierRange; + DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange, + ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs, + NumExplicitTemplateArgs); OverloadedFunctionDecl *Ovl = 0; FunctionTemplateDecl *FunctionTemplate = 0; @@ -2708,10 +2959,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, Ovl = dyn_cast<OverloadedFunctionDecl>(NDecl); } - if (Ovl || FunctionTemplate || + if (Ovl || FunctionTemplate || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) { // We don't perform ADL for implicit declarations of builtins. - if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit()) + if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit()) ADL = false; // We don't perform ADL in C. @@ -2719,27 +2970,26 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, ADL = false; if (Ovl || FunctionTemplate || ADL) { - FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName, + FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName, HasExplicitTemplateArgs, ExplicitTemplateArgs, NumExplicitTemplateArgs, - LParenLoc, Args, NumArgs, CommaLocs, + LParenLoc, Args, NumArgs, CommaLocs, RParenLoc, ADL); if (!FDecl) return ExprError(); // Update Fn to refer to the actual function selected. Expr *NewFn = 0; - if (QualifiedDeclRefExpr *QDRExpr - = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) + if (Qualifier) NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(), - QDRExpr->getLocation(), + Fn->getLocStart(), false, false, - QDRExpr->getQualifierRange(), - QDRExpr->getQualifier()); + QualifierRange, + Qualifier); else NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(), - Fn->getSourceRange().getBegin()); + Fn->getLocStart()); Fn->Destroy(Context); Fn = NewFn; } @@ -2759,25 +3009,23 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, if (!Fn->getType()->isBlockPointerType()) { // C99 6.5.2.2p1 - "The expression that denotes the called function shall // have type pointer to function". - const PointerType *PT = Fn->getType()->getAsPointerType(); + const PointerType *PT = Fn->getType()->getAs<PointerType>(); if (PT == 0) return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); - FuncT = PT->getPointeeType()->getAsFunctionType(); + FuncT = PT->getPointeeType()->getAs<FunctionType>(); } else { // This is a block call. - FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()-> - getAsFunctionType(); + FuncT = Fn->getType()->getAs<BlockPointerType>()->getPointeeType()-> + getAs<FunctionType>(); } if (FuncT == 0) return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); // Check for a valid return type - if (!FuncT->getResultType()->isVoidType() && - RequireCompleteType(Fn->getSourceRange().getBegin(), - FuncT->getResultType(), - diag::err_call_incomplete_return, - TheCall->getSourceRange())) + if (CheckCallReturnType(FuncT->getResultType(), + Fn->getSourceRange().getBegin(), TheCall.get(), + FDecl)) return ExprError(); // We know the result type of the call, set it. @@ -2796,7 +3044,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, const FunctionDecl *Def = 0; if (FDecl->getBody(Def) && NumArgs != Def->param_size()) { const FunctionProtoType *Proto = - Def->getType()->getAsFunctionProtoType(); + Def->getType()->getAs<FunctionProtoType>(); if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) { Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments) << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange(); @@ -2810,8 +3058,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, DefaultArgumentPromotion(Arg); if (RequireCompleteType(Arg->getSourceRange().getBegin(), Arg->getType(), - diag::err_call_incomplete_argument, - Arg->getSourceRange())) + PDiag(diag::err_call_incomplete_argument) + << Arg->getSourceRange())) return ExprError(); TheCall->setArg(i, Arg); } @@ -2825,20 +3073,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // Check for sentinels if (NDecl) DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs); + // Do special checking on direct calls to functions. - if (FDecl) - return CheckFunctionCall(FDecl, TheCall.take()); - if (NDecl) - return CheckBlockCall(NDecl, TheCall.take()); + if (FDecl) { + if (CheckFunctionCall(FDecl, TheCall.get())) + return ExprError(); - return Owned(TheCall.take()); + if (unsigned BuiltinID = FDecl->getBuiltinID()) + return CheckBuiltinFunctionCall(BuiltinID, TheCall.take()); + } else if (NDecl) { + if (CheckBlockCall(NDecl, TheCall.get())) + return ExprError(); + } + + return MaybeBindToTemporary(TheCall.take()); } Action::OwningExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg InitExpr) { assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); - QualType literalType = QualType::getFromOpaquePtr(Ty); + //FIXME: Preserve type source info. + QualType literalType = GetTypeFromParser(Ty); // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); Expr *literalExpr = static_cast<Expr*>(InitExpr.get()); @@ -2849,8 +3105,9 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())); } else if (!literalType->isDependentType() && RequireCompleteType(LParenLoc, literalType, - diag::err_typecheck_decl_incomplete_type, - SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()))) + PDiag(diag::err_typecheck_decl_incomplete_type) + << SourceRange(LParenLoc, + literalExpr->getSourceRange().getEnd()))) return ExprError(); if (CheckInitializerTypes(literalExpr, literalType, LParenLoc, @@ -2883,15 +3140,20 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, } /// CheckCastTypes - Check type constraints for casting between types. -bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) { - UsualUnaryConversions(castExpr); +bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, + CastExpr::CastKind& Kind, + CXXMethodDecl *& ConversionDecl, + bool FunctionalStyle) { + if (getLangOptions().CPlusPlus) + return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle, + ConversionDecl); + + DefaultFunctionArrayConversion(castExpr); // C99 6.5.4p2: the cast type needs to be void or scalar and the expression // type needs to be scalar. if (castType->isVoidType()) { // Cast to void allows any expr type. - } else if (castType->isDependentType() || castExpr->isTypeDependent()) { - // We can't check any more until template instantiation time. } else if (!castType->isScalarType() && !castType->isVectorType()) { if (Context.getCanonicalType(castType).getUnqualifiedType() == Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) && @@ -2900,9 +3162,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) { // FIXME: Check that the cast destination type is complete. Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) << castType << castExpr->getSourceRange(); + Kind = CastExpr::CK_NoOp; } else if (castType->isUnionType()) { // GCC cast to union extension - RecordDecl *RD = castType->getAsRecordType()->getDecl(); + RecordDecl *RD = castType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator Field, FieldEnd; for (Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { @@ -2916,6 +3179,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) { if (Field == FieldEnd) return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) << castExpr->getType() << castExpr->getSourceRange(); + Kind = CastExpr::CK_ToUnion; } else { // Reject any other conversions to non-scalar types. return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) @@ -2974,7 +3238,7 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); - + // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. if (SrcTy->isVectorType()) { @@ -2995,20 +3259,104 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) { } Action::OwningExprResult -Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, +Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op) { + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + assert((Ty != 0) && (Op.get() != 0) && "ActOnCastExpr(): missing type or expr"); - Expr *castExpr = Op.takeAs<Expr>(); - QualType castType = QualType::getFromOpaquePtr(Ty); + Expr *castExpr = (Expr *)Op.get(); + //FIXME: Preserve type source info. + QualType castType = GetTypeFromParser(Ty); - if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr)) + // If the Expr being casted is a ParenListExpr, handle it specially. + if (isa<ParenListExpr>(castExpr)) + return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType); + CXXMethodDecl *Method = 0; + if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr, + Kind, Method)) return ExprError(); - return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType, + + if (Method) { + OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind, + Method, move(Op)); + + if (CastArg.isInvalid()) + return ExprError(); + + castExpr = CastArg.takeAs<Expr>(); + } else { + Op.release(); + } + + return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(), + Kind, castExpr, castType, LParenLoc, RParenLoc)); } +/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence +/// of comma binary operators. +Action::OwningExprResult +Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) { + Expr *expr = EA.takeAs<Expr>(); + ParenListExpr *E = dyn_cast<ParenListExpr>(expr); + if (!E) + return Owned(expr); + + OwningExprResult Result(*this, E->getExpr(0)); + + for (unsigned i = 1, e = E->getNumExprs(); i != e && !Result.isInvalid(); ++i) + Result = ActOnBinOp(S, E->getExprLoc(), tok::comma, move(Result), + Owned(E->getExpr(i))); + + return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), move(Result)); +} + +Action::OwningExprResult +Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, + SourceLocation RParenLoc, ExprArg Op, + QualType Ty) { + ParenListExpr *PE = (ParenListExpr *)Op.get(); + + // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')' + // then handle it as such. + if (getLangOptions().AltiVec && Ty->isVectorType()) { + if (PE->getNumExprs() == 0) { + Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer); + return ExprError(); + } + + llvm::SmallVector<Expr *, 8> initExprs; + for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) + initExprs.push_back(PE->getExpr(i)); + + // FIXME: This means that pretty-printing the final AST will produce curly + // braces instead of the original commas. + Op.release(); + InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0], + initExprs.size(), RParenLoc); + E->setType(Ty); + return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc, + Owned(E)); + } else { + // This is not an AltiVec-style cast, so turn the ParenListExpr into a + // sequence of BinOp comma operators. + Op = MaybeConvertParenListExprToParenExpr(S, move(Op)); + return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op)); + } +} + +Action::OwningExprResult Sema::ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val) { + unsigned nexprs = Val.size(); + Expr **exprs = reinterpret_cast<Expr**>(Val.release()); + assert((exprs != 0) && "ActOnParenListExpr() missing expr list"); + Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R); + return Owned(expr); +} + /// Note that lhs is not null here, even if this is the gnu "x ?: y" extension. /// In that case, lhs = cond. /// C99 6.5.15 @@ -3033,6 +3381,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, } // Now check the two expressions. + if (LHSTy->isVectorType() || RHSTy->isVectorType()) + return CheckVectorOperands(QuestionLoc, LHS, RHS); // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. @@ -3043,8 +3393,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // If both operands are the same structure or union type, the result is that // type. - if (const RecordType *LHSRT = LHSTy->getAsRecordType()) { // C99 6.5.15p3 - if (const RecordType *RHSRT = RHSTy->getAsRecordType()) + if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3 + if (const RecordType *RHSRT = RHSTy->getAs<RecordType>()) if (LHSRT->getDecl() == RHSRT->getDecl()) // "If both the operands have structure or union type, the result has // that type." This implies that CV qualifiers are dropped. @@ -3067,24 +3417,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, } // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." - if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() || - Context.isObjCObjectPointerType(LHSTy)) && - RHS->isNullPointerConstant(Context)) { + if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && + RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer. return LHSTy; } - if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() || - Context.isObjCObjectPointerType(RHSTy)) && - LHS->isNullPointerConstant(Context)) { + if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && + LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer. return RHSTy; } + // Handle things like Class and struct objc_class*. Here we case the result + // to the pseudo-builtin, because that will be implicitly cast back to the + // redefinition type if an attempt is made to access its fields. + if (LHSTy->isObjCClassType() && + (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy); + return LHSTy; + } + if (RHSTy->isObjCClassType() && + (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy); + return RHSTy; + } + // And the same for struct objc_object* / id + if (LHSTy->isObjCIdType() && + (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy); + return LHSTy; + } + if (RHSTy->isObjCIdType() && + (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy); + return RHSTy; + } // Handle block pointer types. if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { QualType destType = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, destType); + ImpCastExprToType(LHS, destType); ImpCastExprToType(RHS, destType); return destType; } @@ -3098,8 +3470,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return LHSTy; } // The block pointer types aren't identical, continue checking. - QualType lhptee = LHSTy->getAsBlockPointerType()->getPointeeType(); - QualType rhptee = RHSTy->getAsBlockPointerType()->getPointeeType(); + QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType(); if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) { @@ -3118,48 +3490,17 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, LHSTy); return LHSTy; } - // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type - // evaluates to "struct objc_object *" (and is handled above when comparing - // id with statically typed objects). - if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) { - // GCC allows qualified id and any Objective-C type to devolve to - // id. Currently localizing to here until clear this should be - // part of ObjCQualifiedIdTypesAreCompatible. - if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) || - (LHSTy->isObjCQualifiedIdType() && - Context.isObjCObjectPointerType(RHSTy)) || - (RHSTy->isObjCQualifiedIdType() && - Context.isObjCObjectPointerType(LHSTy))) { - // FIXME: This is not the correct composite type. This only happens to - // work because id can more or less be used anywhere, however this may - // change the type of method sends. - - // FIXME: gcc adds some type-checking of the arguments and emits - // (confusing) incompatible comparison warnings in some - // cases. Investigate. - QualType compositeType = Context.getObjCIdType(); - ImpCastExprToType(LHS, compositeType); - ImpCastExprToType(RHS, compositeType); - return compositeType; - } - } // Check constraints for Objective-C object pointers types. - if (Context.isObjCObjectPointerType(LHSTy) && - Context.isObjCObjectPointerType(RHSTy)) { - + if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { + if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { // Two identical object pointer types are always compatible. return LHSTy; } - // No need to check for block pointer types or qualified id types (they - // were handled above). - assert((LHSTy->isPointerType() && RHSTy->isPointerType()) && - "Sema::CheckConditionalOperands(): Unexpected type"); - QualType lhptee = LHSTy->getAsPointerType()->getPointeeType(); - QualType rhptee = RHSTy->getAsPointerType()->getPointeeType(); - + const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>(); QualType compositeType = LHSTy; - + // If both operands are interfaces and either operand can be // assigned to the other, use that type as the composite // type. This allows @@ -3173,16 +3514,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. // It could return the composite type. - const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType(); - if (LHSIface && RHSIface && - Context.canAssignObjCInterfaces(LHSIface, RHSIface)) { - compositeType = LHSTy; - } else if (LHSIface && RHSIface && - Context.canAssignObjCInterfaces(RHSIface, LHSIface)) { - compositeType = RHSTy; - } else if (Context.isObjCIdStructType(lhptee) || - Context.isObjCIdStructType(rhptee)) { + if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { + compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; + } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { + compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; + } else if ((LHSTy->isObjCQualifiedIdType() || + RHSTy->isObjCQualifiedIdType()) && + Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) { + // Need to handle "id<xx>" explicitly. + // GCC allows qualified id and any Objective-C type to devolve to + // id. Currently localizing to here until clear this should be + // part of ObjCQualifiedIdTypesAreCompatible. + compositeType = Context.getObjCIdType(); + } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); } else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) @@ -3198,23 +3542,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, compositeType); return compositeType; } + // Check Objective-C object pointer types and 'void *' + if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) { + QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType destPointee + = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); + QualType destType = Context.getPointerType(destPointee); + ImpCastExprToType(LHS, destType); // add qualifiers if necessary + ImpCastExprToType(RHS, destType); // promote to void* + return destType; + } + if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { + QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); + QualType destPointee + = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); + QualType destType = Context.getPointerType(destPointee); + ImpCastExprToType(RHS, destType); // add qualifiers if necessary + ImpCastExprToType(LHS, destType); // promote to void* + return destType; + } // Check constraints for C object pointers types (C99 6.5.15p3,6). if (LHSTy->isPointerType() && RHSTy->isPointerType()) { // get the "pointed to" types - QualType lhptee = LHSTy->getAsPointerType()->getPointeeType(); - QualType rhptee = RHSTy->getAsPointerType()->getPointeeType(); + QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); // ignore qualifiers on void (C99 6.5.15p3, clause 6) if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { // Figure out necessary qualifiers (C99 6.5.15p6) - QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers()); + QualType destPointee + = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); ImpCastExprToType(LHS, destType); // add qualifiers if necessary ImpCastExprToType(RHS, destType); // promote to void* return destType; } if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { - QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers()); + QualType destPointee + = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); ImpCastExprToType(LHS, destType); // add qualifiers if necessary ImpCastExprToType(RHS, destType); // promote to void* @@ -3248,7 +3615,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, LHSTy); return LHSTy; } - + // GCC compatibility: soften pointer/integer mismatch. if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) @@ -3292,12 +3659,11 @@ Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, Cond.release(); LHS.release(); RHS.release(); - return Owned(new (Context) ConditionalOperator(CondExpr, + return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc, isLHSNull ? 0 : LHSExpr, - RHSExpr, result)); + ColonLoc, RHSExpr, result)); } - // CheckPointerTypesForAssignment - This is a very tricky routine (despite // being closely modeled after the C99 spec:-). The odd characteristic of this // routine is it effectively iqnores the qualifiers on the top level pointee. @@ -3307,9 +3673,16 @@ Sema::AssignConvertType Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { QualType lhptee, rhptee; + if ((lhsType->isObjCClassType() && + (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) || + (rhsType->isObjCClassType() && + (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) { + return Compatible; + } + // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = lhsType->getAsPointerType()->getPointeeType(); - rhptee = rhsType->getAsPointerType()->getPointeeType(); + lhptee = lhsType->getAs<PointerType>()->getPointeeType(); + rhptee = rhsType->getAs<PointerType>()->getPointeeType(); // make sure we operate on the canonical type lhptee = Context.getCanonicalType(lhptee); @@ -3371,7 +3744,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { return IncompatiblePointerSign; } // General pointer incompatibility takes priority over qualifiers. - return IncompatiblePointer; + return IncompatiblePointer; } return ConvTy; } @@ -3386,8 +3759,8 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, QualType lhptee, rhptee; // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = lhsType->getAsBlockPointerType()->getPointeeType(); - rhptee = rhsType->getAsBlockPointerType()->getPointeeType(); + lhptee = lhsType->getAs<BlockPointerType>()->getPointeeType(); + rhptee = rhsType->getAs<BlockPointerType>()->getPointeeType(); // make sure we operate on the canonical type lhptee = Context.getCanonicalType(lhptee); @@ -3430,6 +3803,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { if (lhsType == rhsType) return Compatible; // Common case: fast path an exact match. + if ((lhsType->isObjCClassType() && + (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) || + (rhsType->isObjCClassType() && + (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) { + return Compatible; + } + // If the left-hand side is a reference type, then we are in a // (rare!) case where we've allowed the use of references in C, // e.g., as a parameter type in a built-in function. In this case, @@ -3437,23 +3817,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { // right-hand side type. The caller is responsible for adjusting // lhsType so that the resulting expression does not have reference // type. - if (const ReferenceType *lhsTypeRef = lhsType->getAsReferenceType()) { + if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) { if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType)) return Compatible; return Incompatible; } - - if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) { - if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false)) - return Compatible; - // Relax integer conversions like we do for pointers below. - if (rhsType->isIntegerType()) - return IntToPointer; - if (lhsType->isIntegerType()) - return PointerToInt; - return IncompatibleObjCQualifiedId; - } - // Allow scalar to ExtVector assignments, and assignments of an ExtVector type // to the same ExtVector type. if (lhsType->isExtVectorType()) { @@ -3462,7 +3830,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { if (!rhsType->isVectorType() && rhsType->isArithmeticType()) return Compatible; } - + if (lhsType->isVectorType() || rhsType->isVectorType()) { // If we are allowing lax vector conversions, and LHS and RHS are both // vectors, the total size only needs to be the same. This is a bitcast; @@ -3485,13 +3853,18 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { if (isa<PointerType>(rhsType)) return CheckPointerTypesForAssignment(lhsType, rhsType); - if (rhsType->getAsBlockPointerType()) { - if (lhsType->getAsPointerType()->getPointeeType()->isVoidType()) + // In general, C pointers are not compatible with ObjC object pointers. + if (isa<ObjCObjectPointerType>(rhsType)) { + if (lhsType->isVoidPointerType()) // an exception to the rule. + return Compatible; + return IncompatiblePointer; + } + if (rhsType->getAs<BlockPointerType>()) { + if (lhsType->getAs<PointerType>()->getPointeeType()->isVoidType()) return Compatible; // Treat block pointers as objects. - if (getLangOptions().ObjC1 && - lhsType == Context.getCanonicalType(Context.getObjCIdType())) + if (getLangOptions().ObjC1 && lhsType->isObjCIdType()) return Compatible; } return Incompatible; @@ -3502,20 +3875,47 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return IntToBlockPointer; // Treat block pointers as objects. - if (getLangOptions().ObjC1 && - rhsType == Context.getCanonicalType(Context.getObjCIdType())) + if (getLangOptions().ObjC1 && rhsType->isObjCIdType()) return Compatible; if (rhsType->isBlockPointerType()) return CheckBlockPointerTypesForAssignment(lhsType, rhsType); - if (const PointerType *RHSPT = rhsType->getAsPointerType()) { + if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) { if (RHSPT->getPointeeType()->isVoidType()) return Compatible; } return Incompatible; } + if (isa<ObjCObjectPointerType>(lhsType)) { + if (rhsType->isIntegerType()) + return IntToPointer; + + // In general, C pointers are not compatible with ObjC object pointers. + if (isa<PointerType>(rhsType)) { + if (rhsType->isVoidPointerType()) // an exception to the rule. + return Compatible; + return IncompatiblePointer; + } + if (rhsType->isObjCObjectPointerType()) { + if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) + return Compatible; + if (Context.typesAreCompatible(lhsType, rhsType)) + return Compatible; + if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) + return IncompatibleObjCQualifiedId; + return IncompatiblePointer; + } + if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) { + if (RHSPT->getPointeeType()->isVoidType()) + return Compatible; + } + // Treat block pointers as objects. + if (rhsType->isBlockPointerType()) + return Compatible; + return Incompatible; + } if (isa<PointerType>(rhsType)) { // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. if (lhsType == Context.BoolTy) @@ -3528,7 +3928,26 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return CheckPointerTypesForAssignment(lhsType, rhsType); if (isa<BlockPointerType>(lhsType) && - rhsType->getAsPointerType()->getPointeeType()->isVoidType()) + rhsType->getAs<PointerType>()->getPointeeType()->isVoidType()) + return Compatible; + return Incompatible; + } + if (isa<ObjCObjectPointerType>(rhsType)) { + // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. + if (lhsType == Context.BoolTy) + return Compatible; + + if (lhsType->isIntegerType()) + return PointerToInt; + + // In general, C pointers are not compatible with ObjC object pointers. + if (isa<PointerType>(lhsType)) { + if (lhsType->isVoidPointerType()) // an exception to the rule. + return Compatible; + return IncompatiblePointer; + } + if (isa<BlockPointerType>(lhsType) && + rhsType->getAs<PointerType>()->getPointeeType()->isVoidType()) return Compatible; return Incompatible; } @@ -3542,7 +3961,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { /// \brief Constructs a transparent union from an expression that is /// used to initialize the transparent union. -static void ConstructTransparentUnion(ASTContext &C, Expr *&E, +static void ConstructTransparentUnion(ASTContext &C, Expr *&E, QualType UnionType, FieldDecl *Field) { // Build an initializer list that designates the appropriate member // of the transparent union. @@ -3562,7 +3981,7 @@ Sema::AssignConvertType Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { QualType FromType = rExpr->getType(); - // If the ArgType is a Union type, we want to handle a potential + // If the ArgType is a Union type, we want to handle a potential // transparent_union GCC extension. const RecordType *UT = ArgType->getAsUnionType(); if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) @@ -3580,13 +3999,14 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { // 1) void pointer // 2) null pointer constant if (FromType->isPointerType()) - if (FromType->getAsPointerType()->getPointeeType()->isVoidType()) { + if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) { ImpCastExprToType(rExpr, it->getType()); InitField = *it; break; } - - if (rExpr->isNullPointerConstant(Context)) { + + if (rExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(rExpr, it->getType()); InitField = *it; break; @@ -3626,10 +4046,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. - if ((lhsType->isPointerType() || - lhsType->isObjCQualifiedIdType() || + if ((lhsType->isPointerType() || + lhsType->isObjCObjectPointerType() || lhsType->isBlockPointerType()) - && rExpr->isNullPointerConstant(Context)) { + && rExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(rExpr, lhsType); return Compatible; } @@ -3681,8 +4102,8 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, // type. It would be nice if we only had one vector type someday. if (getLangOptions().LaxVectorConversions) { // FIXME: Should we warn here? - if (const VectorType *LV = lhsType->getAsVectorType()) { - if (const VectorType *RV = rhsType->getAsVectorType()) + if (const VectorType *LV = lhsType->getAs<VectorType>()) { + if (const VectorType *RV = rhsType->getAs<VectorType>()) if (LV->getElementType() == RV->getElementType() && LV->getNumElements() == RV->getNumElements()) { return lhsType->isExtVectorType() ? lhsType : rhsType; @@ -3698,9 +4119,9 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, std::swap(rex, lex); std::swap(rhsType, lhsType); } - + // Handle the case of an ext vector and scalar. - if (const ExtVectorType *LV = lhsType->getAsExtVectorType()) { + if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) { QualType EltTy = LV->getElementType(); if (EltTy->isIntegralType() && rhsType->isIntegralType()) { if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) { @@ -3718,7 +4139,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, } } } - + // Vectors of different size or scalar and non-ext-vector are errors. Diag(Loc, diag::err_typecheck_vector_not_convertable) << lex->getType() << rex->getType() @@ -3727,8 +4148,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, } inline QualType Sema::CheckMultiplyDivideOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) -{ + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); @@ -3740,8 +4160,7 @@ inline QualType Sema::CheckMultiplyDivideOperands( } inline QualType Sema::CheckRemainderOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) -{ + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) return CheckVectorOperands(Loc, lex, rex); @@ -3756,8 +4175,7 @@ inline QualType Sema::CheckRemainderOperands( } inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) -{ + Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { QualType compType = CheckVectorOperands(Loc, lex, rex); if (CompLHSTy) *CompLHSTy = compType; @@ -3775,12 +4193,14 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 // Put any potential pointer into PExp Expr* PExp = lex, *IExp = rex; - if (IExp->getType()->isPointerType()) + if (IExp->getType()->isAnyPointerType()) std::swap(PExp, IExp); - if (const PointerType *PTy = PExp->getType()->getAsPointerType()) { + if (PExp->getType()->isAnyPointerType()) { + if (IExp->getType()->isIntegerType()) { - QualType PointeeTy = PTy->getPointeeType(); + QualType PointeeTy = PExp->getType()->getPointeeType(); + // Check for arithmetic on pointers to incomplete types. if (PointeeTy->isVoidType()) { if (getLangOptions().CPlusPlus) { @@ -3802,30 +4222,31 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 // GNU extension: arithmetic on pointer to function Diag(Loc, diag::ext_gnu_ptr_func_arith) << lex->getType() << lex->getSourceRange(); - } else if (!PTy->isDependentType() && - RequireCompleteType(Loc, PointeeTy, - diag::err_typecheck_arithmetic_incomplete_type, - PExp->getSourceRange(), SourceRange(), - PExp->getType())) - return QualType(); - + } else { + // Check if we require a complete type. + if (((PExp->getType()->isPointerType() && + !PExp->getType()->isDependentType()) || + PExp->getType()->isObjCObjectPointerType()) && + RequireCompleteType(Loc, PointeeTy, + PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << PExp->getSourceRange() + << PExp->getType())) + return QualType(); + } // Diagnose bad cases where we step over interface counts. if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) << PointeeTy << PExp->getSourceRange(); return QualType(); } - + if (CompLHSTy) { - QualType LHSTy = lex->getType(); - if (LHSTy->isPromotableIntegerType()) - LHSTy = Context.IntTy; - else { - QualType T = isPromotableBitField(lex, Context); - if (!T.isNull()) - LHSTy = T; + QualType LHSTy = Context.isPromotableBitField(lex); + if (LHSTy.isNull()) { + LHSTy = lex->getType(); + if (LHSTy->isPromotableIntegerType()) + LHSTy = Context.getPromotedIntegerType(LHSTy); } - *CompLHSTy = LHSTy; } return PExp->getType(); @@ -3856,8 +4277,8 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, } // Either ptr - int or ptr - ptr. - if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) { - QualType lpointee = LHSPTy->getPointeeType(); + if (lex->getType()->isAnyPointerType()) { + QualType lpointee = lex->getType()->getPointeeType(); // The LHS must be an completely-defined object type. @@ -3882,11 +4303,10 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, // GNU C extension: arithmetic on pointer to function ComplainAboutFunc = lex; } else if (!lpointee->isDependentType() && - RequireCompleteType(Loc, lpointee, - diag::err_typecheck_sub_ptr_object, - lex->getSourceRange(), - SourceRange(), - lex->getType())) + RequireCompleteType(Loc, lpointee, + PDiag(diag::err_typecheck_sub_ptr_object) + << lex->getSourceRange() + << lex->getType())) return QualType(); // Diagnose bad cases where we step over interface counts. @@ -3895,7 +4315,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, << lpointee << lex->getSourceRange(); return QualType(); } - + // The result type of a pointer-int computation is the pointer type. if (rex->getType()->isIntegerType()) { if (ComplainAboutVoid) @@ -3903,7 +4323,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, << lex->getSourceRange() << rex->getSourceRange(); if (ComplainAboutFunc) Diag(Loc, diag::ext_gnu_ptr_func_arith) - << ComplainAboutFunc->getType() + << ComplainAboutFunc->getType() << ComplainAboutFunc->getSourceRange(); if (CompLHSTy) *CompLHSTy = lex->getType(); @@ -3911,7 +4331,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, } // Handle pointer-pointer subtractions. - if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) { + if (const PointerType *RHSPTy = rex->getType()->getAs<PointerType>()) { QualType rpointee = RHSPTy->getPointeeType(); // RHS must be a completely-type object type. @@ -3936,10 +4356,9 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, ComplainAboutFunc = rex; } else if (!rpointee->isDependentType() && RequireCompleteType(Loc, rpointee, - diag::err_typecheck_sub_ptr_object, - rex->getSourceRange(), - SourceRange(), - rex->getType())) + PDiag(diag::err_typecheck_sub_ptr_object) + << rex->getSourceRange() + << rex->getType())) return QualType(); if (getLangOptions().CPlusPlus) { @@ -3967,7 +4386,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, << lex->getSourceRange() << rex->getSourceRange(); if (ComplainAboutFunc) Diag(Loc, diag::ext_gnu_ptr_func_arith) - << ComplainAboutFunc->getType() + << ComplainAboutFunc->getType() << ComplainAboutFunc->getSourceRange(); if (CompLHSTy) *CompLHSTy = lex->getType(); @@ -3987,19 +4406,32 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 - QualType LHSTy; - if (lex->getType()->isPromotableIntegerType()) - LHSTy = Context.IntTy; - else { - LHSTy = isPromotableBitField(lex, Context); - if (LHSTy.isNull()) - LHSTy = lex->getType(); + QualType LHSTy = Context.isPromotableBitField(lex); + if (LHSTy.isNull()) { + LHSTy = lex->getType(); + if (LHSTy->isPromotableIntegerType()) + LHSTy = Context.getPromotedIntegerType(LHSTy); } if (!isCompAssign) ImpCastExprToType(lex, LHSTy); UsualUnaryConversions(rex); + // Sanity-check shift operands + llvm::APSInt Right; + // Check right/shifter operand + if (!rex->isValueDependent() && + rex->isIntegerConstantExpr(Right, Context)) { + if (Right.isNegative()) + Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange(); + else { + llvm::APInt LeftBits(Right.getBitWidth(), + Context.getTypeSize(lex->getType())); + if (Right.uge(LeftBits)) + Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange(); + } + } + // "The type of the result is that of the promoted left operand." return LHSTy; } @@ -4027,7 +4459,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. - // NOTE: Don't warn about comparisons of enum constants. These can arise + // NOTE: Don't warn about comparisons of enum constants. These can arise // from macro expansions, and are usually quite deliberate. Expr *LHSStripped = lex->IgnoreParens(); Expr *RHSStripped = rex->IgnoreParens(); @@ -4036,24 +4468,25 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (DRL->getDecl() == DRR->getDecl() && !isa<EnumConstantDecl>(DRL->getDecl())) Diag(Loc, diag::warn_selfcomparison); - + if (isa<CastExpr>(LHSStripped)) LHSStripped = LHSStripped->IgnoreParenCasts(); if (isa<CastExpr>(RHSStripped)) RHSStripped = RHSStripped->IgnoreParenCasts(); - + // Warn about comparisons against a string constant (unless the other // operand is null), the user probably wants strcmp. Expr *literalString = 0; Expr *literalStringStripped = 0; if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && - !RHSStripped->isNullPointerConstant(Context)) { + !RHSStripped->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { literalString = lex; literalStringStripped = LHSStripped; - } - else if ((isa<StringLiteral>(RHSStripped) || - isa<ObjCEncodeExpr>(RHSStripped)) && - !LHSStripped->isNullPointerConstant(Context)) { + } else if ((isa<StringLiteral>(RHSStripped) || + isa<ObjCEncodeExpr>(RHSStripped)) && + !LHSStripped->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { literalString = rex; literalStringStripped = RHSStripped; } @@ -4098,41 +4531,31 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return ResultTy; } - bool LHSIsNull = lex->isNullPointerConstant(Context); - bool RHSIsNull = rex->isNullPointerConstant(Context); + bool LHSIsNull = lex->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull); + bool RHSIsNull = rex->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull); // All of the following pointer related warnings are GCC extensions, except // when handling null pointer constants. One day, we can consider making them // errors (when -pedantic-errors is enabled). if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2 QualType LCanPointeeTy = - Context.getCanonicalType(lType->getAsPointerType()->getPointeeType()); + Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType()); QualType RCanPointeeTy = - Context.getCanonicalType(rType->getAsPointerType()->getPointeeType()); - - if (rType->isFunctionPointerType() || lType->isFunctionPointerType()) { - if (isRelational) { - Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - } - } - if (((!LHSIsNull || isRelational) && LCanPointeeTy->isVoidType()) != - ((!RHSIsNull || isRelational) && RCanPointeeTy->isVoidType())) { - Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - } - // Simple check: if the pointee types are identical, we're done. - if (LCanPointeeTy == RCanPointeeTy) - return ResultTy; + Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType()); if (getLangOptions().CPlusPlus) { + if (LCanPointeeTy == RCanPointeeTy) + return ResultTy; + // C++ [expr.rel]p2: // [...] Pointer conversions (4.10) and qualification // conversions (4.4) are performed on pointer operands (or on // a pointer operand and a null pointer constant) to bring // them to their composite pointer type. [...] // - // C++ [expr.eq]p2 uses the same notion for (in)equality + // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. QualType T = FindCompositePointerType(lex, rex); if (T.isNull()) { @@ -4145,36 +4568,82 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, ImpCastExprToType(rex, T); return ResultTy; } - - if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2 - !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() && - !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), - RCanPointeeTy.getUnqualifiedType()) && - !Context.areComparableObjCPointerTypes(lType, rType)) { + // C99 6.5.9p2 and C99 6.5.8p2 + if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), + RCanPointeeTy.getUnqualifiedType())) { + // Valid unless a relational comparison of function pointers + if (isRelational && LCanPointeeTy->isFunctionType()) { + Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + } + } else if (!isRelational && + (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { + // Valid unless comparison between non-null pointer and function pointer + if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) + && !LHSIsNull && !RHSIsNull) { + Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + } + } else { + // Invalid Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); // promote the pointer to pointer + if (LCanPointeeTy != RCanPointeeTy) + ImpCastExprToType(rex, lType); // promote the pointer to pointer return ResultTy; } - // C++ allows comparison of pointers with null pointer constants. + if (getLangOptions().CPlusPlus) { - if (lType->isPointerType() && RHSIsNull) { - ImpCastExprToType(rex, lType); + // Comparison of pointers with null pointer constants and equality + // comparisons of member pointers to null pointer constants. + if (RHSIsNull && + (lType->isPointerType() || + (!isRelational && lType->isMemberPointerType()))) { + ImpCastExprToType(rex, lType, CastExpr::CK_NullToMemberPointer); + return ResultTy; + } + if (LHSIsNull && + (rType->isPointerType() || + (!isRelational && rType->isMemberPointerType()))) { + ImpCastExprToType(lex, rType, CastExpr::CK_NullToMemberPointer); return ResultTy; } - if (rType->isPointerType() && LHSIsNull) { - ImpCastExprToType(lex, rType); + + // Comparison of member pointers. + if (!isRelational && + lType->isMemberPointerType() && rType->isMemberPointerType()) { + // C++ [expr.eq]p2: + // In addition, pointers to members can be compared, or a pointer to + // member and a null pointer constant. Pointer to member conversions + // (4.11) and qualification conversions (4.4) are performed to bring + // them to a common type. If one operand is a null pointer constant, + // the common type is the type of the other operand. Otherwise, the + // common type is a pointer to member type similar (4.4) to the type + // of one of the operands, with a cv-qualification signature (4.4) + // that is the union of the cv-qualification signatures of the operand + // types. + QualType T = FindCompositePointerType(lex, rex); + if (T.isNull()) { + Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + ImpCastExprToType(lex, T); + ImpCastExprToType(rex, T); return ResultTy; } - // And comparison of nullptr_t with itself. + + // Comparison of nullptr_t with itself. if (lType->isNullPtrType() && rType->isNullPtrType()) return ResultTy; } + // Handle block pointer types. if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) { - QualType lpointee = lType->getAsBlockPointerType()->getPointeeType(); - QualType rpointee = rType->getAsBlockPointerType()->getPointeeType(); + QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType(); + QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType(); if (!LHSIsNull && !RHSIsNull && !Context.typesAreCompatible(lpointee, rpointee)) { @@ -4189,9 +4658,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, && ((lType->isBlockPointerType() && rType->isPointerType()) || (lType->isPointerType() && rType->isBlockPointerType()))) { if (!LHSIsNull && !RHSIsNull) { - if (!((rType->isPointerType() && rType->getAsPointerType() + if (!((rType->isPointerType() && rType->getAs<PointerType>() ->getPointeeType()->isVoidType()) - || (lType->isPointerType() && lType->getAsPointerType() + || (lType->isPointerType() && lType->getAs<PointerType>() ->getPointeeType()->isVoidType()))) Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); @@ -4200,10 +4669,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return ResultTy; } - if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) { + if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) { if (lType->isPointerType() || rType->isPointerType()) { - const PointerType *LPT = lType->getAsPointerType(); - const PointerType *RPT = rType->getAsPointerType(); + const PointerType *LPT = lType->getAs<PointerType>(); + const PointerType *RPT = rType->getAs<PointerType>(); bool LPtrToVoid = LPT ? Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false; bool RPtrToVoid = RPT ? @@ -4213,43 +4682,49 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, !Context.typesAreCompatible(lType, rType)) { Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - ImpCastExprToType(rex, lType); - return ResultTy; } ImpCastExprToType(rex, lType); return ResultTy; } - if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) { + if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { + if (!Context.areComparableObjCPointerTypes(lType, rType)) + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); ImpCastExprToType(rex, lType); return ResultTy; - } else { - if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) { - Diag(Loc, diag::warn_incompatible_qualified_id_operands) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - ImpCastExprToType(rex, lType); - return ResultTy; - } } } - if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) && - rType->isIntegerType()) { - if (isRelational) - Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - else if (!RHSIsNull) - Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer) + if (lType->isAnyPointerType() && rType->isIntegerType()) { + unsigned DiagID = 0; + if (RHSIsNull) { + if (isRelational) + DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; + } else if (isRelational) + DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; + else + DiagID = diag::ext_typecheck_comparison_of_pointer_integer; + + if (DiagID) { + Diag(Loc, DiagID) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + } ImpCastExprToType(rex, lType); // promote the integer to pointer return ResultTy; } - if (lType->isIntegerType() && - (rType->isPointerType() || rType->isObjCQualifiedIdType())) { - if (isRelational) - Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - else if (!LHSIsNull) - Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer) + if (lType->isIntegerType() && rType->isAnyPointerType()) { + unsigned DiagID = 0; + if (LHSIsNull) { + if (isRelational) + DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; + } else if (isRelational) + DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; + else + DiagID = diag::ext_typecheck_comparison_of_pointer_integer; + + if (DiagID) { + Diag(Loc, DiagID) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + } ImpCastExprToType(lex, rType); // promote the integer to pointer return ResultTy; } @@ -4299,21 +4774,13 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, CheckFloatComparison(Loc,lex,rex); } - // FIXME: Vector compare support in the LLVM backend is not fully reliable, - // just reject all vector comparisons for now. - if (1) { - Diag(Loc, diag::err_typecheck_vector_comparison) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - return QualType(); - } - // Return the type for the comparison, which is the same as vector type for // integer vectors, or an integer type of identical size and number of // elements for floating point vectors. if (lType->isIntegerType()) return lType; - const VectorType *VTy = lType->getAsVectorType(); + const VectorType *VTy = lType->getAs<VectorType>(); unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); @@ -4326,8 +4793,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, } inline QualType Sema::CheckBitwiseOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) -{ + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); @@ -4339,8 +4805,7 @@ inline QualType Sema::CheckBitwiseOperands( } inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] - Expr *&lex, Expr *&rex, SourceLocation Loc) -{ + Expr *&lex, Expr *&rex, SourceLocation Loc) { UsualUnaryConversions(lex); UsualUnaryConversions(rex); @@ -4353,18 +4818,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] /// is a read-only property; return true if so. A readonly property expression /// depends on various declarations and thus must be treated specially. /// -static bool IsReadonlyProperty(Expr *E, Sema &S) -{ +static bool IsReadonlyProperty(Expr *E, Sema &S) { if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) { QualType BaseType = PropExpr->getBase()->getType(); - if (const PointerType *PTy = BaseType->getAsPointerType()) - if (const ObjCInterfaceType *IFTy = - PTy->getPointeeType()->getAsObjCInterfaceType()) - if (ObjCInterfaceDecl *IFace = IFTy->getDecl()) - if (S.isPropertyReadonly(PDecl, IFace)) - return true; + if (const ObjCObjectPointerType *OPT = + BaseType->getAsObjCInterfacePointerType()) + if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl()) + if (S.isPropertyReadonly(PDecl, IFace)) + return true; } } return false; @@ -4374,7 +4837,7 @@ static bool IsReadonlyProperty(Expr *E, Sema &S) /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { SourceLocation OrigLoc = Loc; - Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context, + Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context, &Loc); if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S)) IsLV = Expr::MLV_ReadonlyProperty; @@ -4403,8 +4866,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: return S.RequireCompleteType(Loc, E->getType(), - diag::err_typecheck_incomplete_type_not_modifiable_lvalue, - E->getSourceRange()); + PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue) + << E->getSourceRange()); case Expr::MLV_DuplicateVectorComponents: Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue; break; @@ -4425,7 +4888,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { if (NeedType) S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign; else - S.Diag(Loc, Diag) << E->getSourceRange() << Assign; + S.Diag(Loc, Diag) << E->getSourceRange() << Assign; return true; } @@ -4449,9 +4912,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, // Special case of NSObject attributes on c-style pointer types. if (ConvTy == IncompatiblePointer && ((Context.isObjCNSObjectType(LHSType) && - Context.isObjCObjectPointerType(RHSType)) || + RHSType->isObjCObjectPointerType()) || (Context.isObjCNSObjectType(RHSType) && - Context.isObjCObjectPointerType(LHSType)))) + LHSType->isObjCObjectPointerType()))) ConvTy = Compatible; // If the RHS is a unary plus or minus, check to see if they = and + are @@ -4525,9 +4988,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange(); } else if (ResType->isRealType()) { // OK! - } else if (const PointerType *PT = ResType->getAsPointerType()) { + } else if (ResType->isAnyPointerType()) { + QualType PointeeTy = ResType->getPointeeType(); + // C99 6.5.2.4p2, 6.5.6p2 - if (PT->getPointeeType()->isVoidType()) { + if (PointeeTy->isVoidType()) { if (getLangOptions().CPlusPlus) { Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) << Op->getSourceRange(); @@ -4536,7 +5001,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, // Pointer to void is a GNU extension in C. Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); - } else if (PT->getPointeeType()->isFunctionType()) { + } else if (PointeeTy->isFunctionType()) { if (getLangOptions().CPlusPlus) { Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) << Op->getType() << Op->getSourceRange(); @@ -4545,11 +5010,17 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, Diag(OpLoc, diag::ext_gnu_ptr_func_arith) << ResType << Op->getSourceRange(); - } else if (RequireCompleteType(OpLoc, PT->getPointeeType(), - diag::err_typecheck_arithmetic_incomplete_type, - Op->getSourceRange(), SourceRange(), - ResType)) + } else if (RequireCompleteType(OpLoc, PointeeTy, + PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << Op->getSourceRange() + << ResType)) return QualType(); + // Diagnose bad cases where we step over interface counts. + else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) + << PointeeTy << Op->getSourceRange(); + return QualType(); + } } else if (ResType->isComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. Diag(OpLoc, diag::ext_integer_increment_complex) @@ -4672,6 +5143,15 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { Diag(OpLoc, diag::err_typecheck_address_of) << "vector element" << op->getSourceRange(); return QualType(); + } else if (isa<ObjCPropertyRefExpr>(op)) { + // cannot take address of a property expression. + Diag(OpLoc, diag::err_typecheck_address_of) + << "property expression" << op->getSourceRange(); + return QualType(); + } else if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(op)) { + // FIXME: Can LHS ever be null here? + if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull()) + return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc); } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. @@ -4681,17 +5161,26 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { << "register variable" << op->getSourceRange(); return QualType(); } - } else if (isa<OverloadedFunctionDecl>(dcl)) { + } else if (isa<OverloadedFunctionDecl>(dcl) || + isa<FunctionTemplateDecl>(dcl)) { return Context.OverloadTy; - } else if (isa<FieldDecl>(dcl)) { + } else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) { // Okay: we can take the address of a field. // Could be a pointer to member, though, if there is an explicit // scope qualifier for the class. if (isa<QualifiedDeclRefExpr>(op)) { DeclContext *Ctx = dcl->getDeclContext(); - if (Ctx && Ctx->isRecord()) + if (Ctx && Ctx->isRecord()) { + if (FD->getType()->isReferenceType()) { + Diag(OpLoc, + diag::err_cannot_form_pointer_to_member_of_reference_type) + << FD->getDeclName() << FD->getType(); + return QualType(); + } + return Context.getMemberPointerType(op->getType(), Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr()); + } } } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) { // Okay: we can take the address of a function. @@ -4725,9 +5214,12 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { // incomplete type or void. It would be possible to warn about dereferencing // a void pointer, but it's completely well-defined, and such a warning is // unlikely to catch any mistakes. - if (const PointerType *PT = Ty->getAsPointerType()) + if (const PointerType *PT = Ty->getAs<PointerType>()) return PT->getPointeeType(); + if (const ObjCObjectPointerType *OPT = Ty->getAs<ObjCObjectPointerType>()) + return OPT->getPointeeType(); + Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) << Ty << Op->getSourceRange(); return QualType(); @@ -4914,7 +5406,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, assert((rhs != 0) && "ActOnBinOp(): missing right expression"); if (getLangOptions().CPlusPlus && - (lhs->getType()->isOverloadableType() || + (lhs->getType()->isOverloadableType() || rhs->getType()->isOverloadableType())) { // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local @@ -4926,7 +5418,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), Functions); Expr *Args[2] = { lhs, rhs }; - DeclarationName OpName + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); ArgumentDependentLookup(OpName, Args, 2, Functions); } @@ -4941,7 +5433,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, } Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, - unsigned OpcIn, + unsigned OpcIn, ExprArg InputArg) { UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn); @@ -4949,16 +5441,17 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, Expr *Input = (Expr *)InputArg.get(); QualType resultType; switch (Opc) { - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: case UnaryOperator::OffsetOf: assert(false && "Invalid unary operator"); break; case UnaryOperator::PreInc: case UnaryOperator::PreDec: + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: resultType = CheckIncrementDecrementOperand(Input, OpLoc, - Opc == UnaryOperator::PreInc); + Opc == UnaryOperator::PreInc || + Opc == UnaryOperator::PostInc); break; case UnaryOperator::AddrOf: resultType = CheckAddressOfOperand(Input, OpLoc); @@ -5043,7 +5536,7 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, if (OverOp != OO_None) { LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), Functions); - DeclarationName OpName + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); ArgumentDependentLookup(OpName, &Input, 1, Functions); } @@ -5116,7 +5609,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, SourceLocation RPLoc) { // FIXME: This function leaks all expressions in the offset components on // error. - QualType ArgTy = QualType::getFromOpaquePtr(argty); + // FIXME: Preserve type source info. + QualType ArgTy = GetTypeFromParser(argty); assert(!ArgTy.isNull() && "Missing type argument!"); bool Dependent = ArgTy->isDependentType(); @@ -5147,7 +5641,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, if (!Dependent) { bool DidWarnAboutNonPOD = false; - + // FIXME: Dependent case loses a lot of information here. And probably // leaks like a sieve. for (unsigned i = 0; i != NumComponents; ++i) { @@ -5180,7 +5674,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, continue; } - const RecordType *RC = Res->getType()->getAsRecordType(); + const RecordType *RC = Res->getType()->getAs<RecordType>(); if (!RC) { Res->Destroy(Context); return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) @@ -5197,15 +5691,16 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, DidWarnAboutNonPOD = true; } } - + + LookupResult R; + LookupQualifiedName(R, RD, OC.U.IdentInfo, LookupMemberName); + FieldDecl *MemberDecl - = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo, - LookupMemberName) - .getAsDecl()); + = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context)); // FIXME: Leaks Res if (!MemberDecl) - return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member) - << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd)); + return ExprError(Diag(BuiltinLoc, diag::err_no_member) + << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); // FIXME: C++: Verify that MemberDecl isn't a static field. // FIXME: Verify that MemberDecl isn't a bitfield. @@ -5229,8 +5724,9 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, TypeTy *arg1,TypeTy *arg2, SourceLocation RPLoc) { - QualType argT1 = QualType::getFromOpaquePtr(arg1); - QualType argT2 = QualType::getFromOpaquePtr(arg2); + // FIXME: Preserve type source info. + QualType argT1 = GetTypeFromParser(arg1); + QualType argT2 = GetTypeFromParser(arg2); assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)"); @@ -5255,8 +5751,10 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)"); QualType resType; + bool ValueDependent = false; if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) { resType = Context.DependentTy; + ValueDependent = true; } else { // The conditional expression is required to be a constant expression. llvm::APSInt condEval(32); @@ -5268,11 +5766,15 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, // If the condition is > zero, then the AST type is the same as the LSHExpr. resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType(); + ValueDependent = condEval.getZExtValue() ? LHSExpr->isValueDependent() + : RHSExpr->isValueDependent(); } cond.release(); expr1.release(); expr2.release(); return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, - resType, RPLoc)); + resType, RPLoc, + resType->isDependentType(), + ValueDependent)); } //===----------------------------------------------------------------------===// @@ -5291,6 +5793,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { BSI->ReturnType = QualType(); BSI->TheScope = BlockScope; BSI->hasBlockDeclRefExprs = false; + BSI->hasPrototype = false; BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking; CurFunctionNeedsScopeChecking = false; @@ -5320,12 +5823,12 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->isVariadic = false; // Check for a valid sentinel attribute on this block. if (CurBlock->TheDecl->getAttr<SentinelAttr>()) { - Diag(ParamInfo.getAttributes()->getLoc(), + Diag(ParamInfo.getAttributes()->getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; // FIXME: remove the attribute. } - QualType RetTy = T.getTypePtr()->getAsFunctionType()->getResultType(); - + QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType(); + // Do not allow returning a objc interface by-value. if (RetTy->isObjCInterfaceType()) { Diag(ParamInfo.getSourceRange().getBegin(), @@ -5367,17 +5870,17 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { PushOnScopeChains(*AI, CurBlock->TheScope); // Check for a valid sentinel attribute on this block. - if (!CurBlock->isVariadic && + if (!CurBlock->isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) { - Diag(ParamInfo.getAttributes()->getLoc(), + Diag(ParamInfo.getAttributes()->getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; // FIXME: remove the attribute. } - + // Analyze the return type. QualType T = GetTypeForDeclarator(ParamInfo, CurScope); - QualType RetTy = T->getAsFunctionType()->getResultType(); - + QualType RetTy = T->getAs<FunctionType>()->getResultType(); + // Do not allow returning a objc interface by-value. if (RetTy->isObjCInterfaceType()) { Diag(ParamInfo.getSourceRange().getBegin(), @@ -5407,7 +5910,7 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(CaretLoc, diag::err_blocks_disable); - + // Ensure that CurBlock is deleted. llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock); @@ -5424,12 +5927,15 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i) ArgTypes.push_back(BSI->Params[i]->getType()); + bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>(); QualType BlockTy; if (!BSI->hasPrototype) - BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0); + BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0, + NoReturn); else BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(), - BSI->isVariadic, 0); + BSI->isVariadic, 0, false, false, 0, 0, + NoReturn); // FIXME: Check that return/parameter types are complete/non-abstract DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end()); @@ -5439,8 +5945,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (CurFunctionNeedsScopeChecking) DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get())); CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; - + BSI->TheDecl->setBody(body.takeAs<CompoundStmt>()); + CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody()); return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs)); } @@ -5448,10 +5955,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, ExprArg expr, TypeTy *type, SourceLocation RPLoc) { - QualType T = QualType::getFromOpaquePtr(type); + QualType T = GetTypeFromParser(type); Expr *E = static_cast<Expr*>(expr.get()); Expr *OrigExpr = E; - + InitBuiltinVaListType(); // Get the va_list type @@ -5466,7 +5973,7 @@ Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, } else { // Otherwise, the va_list argument must be an l-value because // it is modified by va_arg. - if (!E->isTypeDependent() && + if (!E->isTypeDependent() && CheckForModifiableLvalue(E, BuiltinLoc, *this)) return ExprError(); } @@ -5600,17 +6107,17 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ return false; } -Sema::ExpressionEvaluationContext -Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { +Sema::ExpressionEvaluationContext +Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { // Introduce a new set of potentially referenced declarations to the stack. if (NewContext == PotentiallyPotentiallyEvaluated) PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls()); - + std::swap(ExprEvalContext, NewContext); return NewContext; } -void +void Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, ExpressionEvaluationContext NewContext) { ExprEvalContext = NewContext; @@ -5622,7 +6129,7 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, PotentiallyReferencedDecls RemainingDecls; RemainingDecls.swap(PotentiallyReferencedDeclStack.back()); PotentiallyReferencedDeclStack.pop_back(); - + for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(), IEnd = RemainingDecls.end(); I != IEnd; ++I) @@ -5642,30 +6149,33 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, /// \param D the declaration that has been referenced by the source code. void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { assert(D && "No declaration?"); - + if (D->isUsed()) return; - - // Mark a parameter declaration "used", regardless of whether we're in a - // template or not. - if (isa<ParmVarDecl>(D)) + + // Mark a parameter or variable declaration "used", regardless of whether we're in a + // template or not. The reason for this is that unevaluated expressions + // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and + // -Wunused-parameters) + if (isa<ParmVarDecl>(D) || + (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) D->setUsed(true); - + // Do not mark anything as "used" within a dependent context; wait for // an instantiation. if (CurContext->isDependentContext()) return; - + switch (ExprEvalContext) { case Unevaluated: // We are in an expression that is not potentially evaluated; do nothing. return; - + case PotentiallyEvaluated: // We are in a potentially-evaluated expression, so this declaration is // "used"; handle this below. break; - + case PotentiallyPotentiallyEvaluated: // We are in an expression that may be potentially evaluated; queue this // declaration reference until we know whether the expression is @@ -5673,23 +6183,22 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D)); return; } - + // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { unsigned TypeQuals; if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) { if (!Constructor->isUsed()) DefineImplicitDefaultConstructor(Loc, Constructor); - } - else if (Constructor->isImplicit() && - Constructor->isCopyConstructor(Context, TypeQuals)) { + } else if (Constructor->isImplicit() && + Constructor->isCopyConstructor(Context, TypeQuals)) { if (!Constructor->isUsed()) DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { if (Destructor->isImplicit() && !Destructor->isUsed()) DefineImplicitDestructor(Loc, Destructor); - + } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { @@ -5698,28 +6207,125 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } } if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { - // Implicit instantiation of function templates and member functions of + // Implicit instantiation of function templates and member functions of // class templates. - if (!Function->getBody()) { - // FIXME: distinguish between implicit instantiations of function - // templates and explicit specializations (the latter don't get - // instantiated, naturally). - if (Function->getInstantiatedFromMemberFunction() || - Function->getPrimaryTemplate()) + if (!Function->getBody() && + Function->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) { + bool AlreadyInstantiated = false; + if (FunctionTemplateSpecializationInfo *SpecInfo + = Function->getTemplateSpecializationInfo()) { + if (SpecInfo->getPointOfInstantiation().isInvalid()) + SpecInfo->setPointOfInstantiation(Loc); + else + AlreadyInstantiated = true; + } else if (MemberSpecializationInfo *MSInfo + = Function->getMemberSpecializationInfo()) { + if (MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->setPointOfInstantiation(Loc); + else + AlreadyInstantiated = true; + } + + if (!AlreadyInstantiated) PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); } - // FIXME: keep track of references to static functions Function->setUsed(true); return; } - + if (VarDecl *Var = dyn_cast<VarDecl>(D)) { - (void)Var; - // FIXME: implicit template instantiation + // Implicit instantiation of static data members of class templates. + if (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember()) { + MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); + if (MSInfo->getPointOfInstantiation().isInvalid() && + MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) { + MSInfo->setPointOfInstantiation(Loc); + PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc)); + } + } + // FIXME: keep track of references to static data? + D->setUsed(true); + return; + } +} + +bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, + CallExpr *CE, FunctionDecl *FD) { + if (ReturnType->isVoidType() || !ReturnType->isIncompleteType()) + return false; + + PartialDiagnostic Note = + FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here) + << FD->getDeclName() : PDiag(); + SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation(); + + if (RequireCompleteType(Loc, ReturnType, + FD ? + PDiag(diag::err_call_function_incomplete_return) + << CE->getSourceRange() << FD->getDeclName() : + PDiag(diag::err_call_incomplete_return) + << CE->getSourceRange(), + std::make_pair(NoteLoc, Note))) + return true; + + return false; +} + +// Diagnose the common s/=/==/ typo. Note that adding parentheses +// will prevent this condition from triggering, which is what we want. +void Sema::DiagnoseAssignmentAsCondition(Expr *E) { + SourceLocation Loc; + + if (isa<BinaryOperator>(E)) { + BinaryOperator *Op = cast<BinaryOperator>(E); + if (Op->getOpcode() != BinaryOperator::Assign) + return; + + Loc = Op->getOperatorLoc(); + } else if (isa<CXXOperatorCallExpr>(E)) { + CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E); + if (Op->getOperator() != OO_Equal) + return; + + Loc = Op->getOperatorLoc(); + } else { + // Not an assignment. + return; } + + SourceLocation Open = E->getSourceRange().getBegin(); + SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); + + Diag(Loc, diag::warn_condition_is_assignment) + << E->getSourceRange() + << CodeModificationHint::CreateInsertion(Open, "(") + << CodeModificationHint::CreateInsertion(Close, ")"); } +bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { + DiagnoseAssignmentAsCondition(E); + + if (!E->isTypeDependent()) { + DefaultFunctionArrayConversion(E); + + QualType T = E->getType(); + + if (getLangOptions().CPlusPlus) { + if (CheckCXXBooleanCondition(E)) // C++ 6.4p4 + return true; + } else if (!T->isScalarType()) { // C99 6.8.4.1p1 + Diag(Loc, diag::err_typecheck_statement_requires_scalar) + << T << E->getSourceRange(); + return true; + } + } + + return false; +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7afa5941dad90..5f111c8a60e7a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -11,13 +11,14 @@ // //===----------------------------------------------------------------------===// -#include "SemaInherit.h" #include "Sema.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Lex/Preprocessor.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" using namespace clang; @@ -31,9 +32,10 @@ Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc, TypeTy *Ty, bool HasTrailingLParen, const CXXScopeSpec &SS, bool isAddressOfOperand) { - QualType ConvType = QualType::getFromOpaquePtr(Ty); - QualType ConvTypeCanon = Context.getCanonicalType(ConvType); - DeclarationName ConvName + //FIXME: Preserve type source info. + QualType ConvType = GetTypeFromParser(Ty); + CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); + DeclarationName ConvName = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen, &SS, isAddressOfOperand); @@ -59,12 +61,17 @@ Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { - NamespaceDecl *StdNs = GetStdNamespace(); - if (!StdNs) + if (!StdNamespace) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - + + if (isType) + // FIXME: Preserve type source info. + TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr(); + IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); - Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName); + LookupResult R; + LookupQualifiedName(R, StdNamespace, TypeInfoII, LookupTagName); + Decl *TypeInfoDecl = R.getAsSingleDecl(Context); RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); @@ -73,29 +80,29 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, if (!isType) { // C++0x [expr.typeid]p3: - // When typeid is applied to an expression other than an lvalue of a - // polymorphic class type [...] [the] expression is an unevaluated + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] [the] expression is an unevaluated // operand. - + // FIXME: if the type of the expression is a class type, the class // shall be completely defined. bool isUnevaluatedOperand = true; Expr *E = static_cast<Expr *>(TyOrExpr); if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) { QualType T = E->getType(); - if (const RecordType *RecordT = T->getAsRecordType()) { + if (const RecordType *RecordT = T->getAs<RecordType>()) { CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); if (RecordD->isPolymorphic()) isUnevaluatedOperand = false; } } - + // If this is an unevaluated operand, clear out the set of declaration // references we have been computing. if (isUnevaluatedOperand) PotentiallyReferencedDeclStack.back().clear(); } - + return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr, TypeInfoType.withConst(), SourceRange(OpLoc, RParenLoc))); @@ -136,15 +143,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = E->getType(); int isPointer = 0; - if (const PointerType* Ptr = Ty->getAsPointerType()) { + if (const PointerType* Ptr = Ty->getAs<PointerType>()) { Ty = Ptr->getPointeeType(); isPointer = 1; } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, - isPointer ? diag::err_throw_incomplete_ptr - : diag::err_throw_incomplete, - E->getSourceRange(), SourceRange(), QualType())) + PDiag(isPointer ? diag::err_throw_incomplete_ptr + : diag::err_throw_incomplete) + << E->getSourceRange())) return true; } @@ -179,7 +186,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceLocation *CommaLocs, SourceLocation RParenLoc) { assert(TypeRep && "Missing type!"); - QualType Ty = QualType::getFromOpaquePtr(TypeRep); + // FIXME: Preserve type source info. + QualType Ty = GetTypeFromParser(TypeRep); unsigned NumExprs = exprs.size(); Expr **Exprs = (Expr**)exprs.get(); SourceLocation TyBeginLoc = TypeRange.getBegin(); @@ -188,14 +196,27 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) { exprs.release(); - - return Owned(CXXUnresolvedConstructExpr::Create(Context, - TypeRange.getBegin(), Ty, + + return Owned(CXXUnresolvedConstructExpr::Create(Context, + TypeRange.getBegin(), Ty, LParenLoc, Exprs, NumExprs, RParenLoc)); } + if (Ty->isArrayType()) + return ExprError(Diag(TyBeginLoc, + diag::err_value_init_for_array_type) << FullRange); + if (!Ty->isVoidType() && + RequireCompleteType(TyBeginLoc, Ty, + PDiag(diag::err_invalid_incomplete_type_use) + << FullRange)) + return ExprError(); + + if (RequireNonAbstractType(TyBeginLoc, Ty, + diag::err_allocation_of_abstract_type)) + return ExprError(); + // C++ [expr.type.conv]p1: // If the expression list is a single expression, the type conversion @@ -203,36 +224,54 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // corresponding cast expression. // if (NumExprs == 1) { - if (CheckCastTypes(TypeRange, Ty, Exprs[0])) + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CXXMethodDecl *Method = 0; + if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method, + /*FunctionalStyle=*/true)) return ExprError(); + exprs.release(); + if (Method) { + OwningExprResult CastArg + = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(), + Kind, Method, Owned(Exprs[0])); + if (CastArg.isInvalid()) + return ExprError(); + + Exprs[0] = CastArg.takeAs<Expr>(); + } + return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), - Ty, TyBeginLoc, Exprs[0], - RParenLoc)); + Ty, TyBeginLoc, Kind, + Exprs[0], RParenLoc)); } - if (const RecordType *RT = Ty->getAsRecordType()) { + if (const RecordType *RT = Ty->getAs<RecordType>()) { CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl()); - // FIXME: We should always create a CXXTemporaryObjectExpr here unless - // both the ctor and dtor are trivial. - if (NumExprs > 1 || Record->hasUserDeclaredConstructor()) { + if (NumExprs > 1 || !Record->hasTrivialConstructor() || + !Record->hasTrivialDestructor()) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(Ty, Exprs, NumExprs, + = PerformInitializationByConstructor(Ty, move(exprs), TypeRange.getBegin(), SourceRange(TypeRange.getBegin(), RParenLoc), DeclarationName(), - IK_Direct); + IK_Direct, + ConstructorArgs); if (!Constructor) return ExprError(); - exprs.release(); - Expr *E = new (Context) CXXTemporaryObjectExpr(Context, Constructor, - Ty, TyBeginLoc, Exprs, - NumExprs, RParenLoc); - return MaybeBindToTemporary(E); + OwningExprResult Result = + BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc, + move_arg(ConstructorArgs), RParenLoc); + if (Result.isInvalid()) + return ExprError(); + + return MaybeBindToTemporary(Result.takeAs<Expr>()); } // Fall through to value-initialize an object of class type that @@ -255,18 +294,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // complete object type or the (possibly cv-qualified) void type, creates an // rvalue of the specified type, which is value-initialized. // - if (Ty->isArrayType()) - return ExprError(Diag(TyBeginLoc, - diag::err_value_init_for_array_type) << FullRange); - if (!Ty->isDependentType() && !Ty->isVoidType() && - RequireCompleteType(TyBeginLoc, Ty, - diag::err_invalid_incomplete_type_use, FullRange)) - return ExprError(); - - if (RequireNonAbstractType(TyBeginLoc, Ty, - diag::err_allocation_of_abstract_type)) - return ExprError(); - exprs.release(); return Owned(new (Context) CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc)); } @@ -283,8 +310,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementRParen, bool ParenTypeId, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen) -{ + SourceLocation ConstructorRParen) { Expr *ArraySize = 0; unsigned Skip = 0; // If the specified type is an array, unwrap it and save the expression. @@ -301,29 +327,37 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, Skip = 1; } - QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); - if (D.isInvalidType()) - return ExprError(); - // Every dimension shall be of constant size. - unsigned i = 1; - QualType ElementType = AllocType; - while (const ArrayType *Array = Context.getAsArrayType(ElementType)) { - if (!Array->isConstantArrayType()) { - Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst) - << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange(); - return ExprError(); + if (D.getNumTypeObjects() > 0 && + D.getTypeObject(0).Kind == DeclaratorChunk::Array) { + for (unsigned I = 1, N = D.getNumTypeObjects(); I < N; ++I) { + if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) + break; + + DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr; + if (Expr *NumElts = (Expr *)Array.NumElts) { + if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() && + !NumElts->isIntegerConstantExpr(Context)) { + Diag(D.getTypeObject(I).Loc, diag::err_new_array_nonconst) + << NumElts->getSourceRange(); + return ExprError(); + } + } } - ElementType = Array->getElementType(); - ++i; } + + //FIXME: Store DeclaratorInfo in CXXNew expression. + DeclaratorInfo *DInfo = 0; + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo, Skip); + if (D.isInvalidType()) + return ExprError(); - return BuildCXXNew(StartLoc, UseGlobal, + return BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, - move(PlacementArgs), + move(PlacementArgs), PlacementRParen, ParenTypeId, - AllocType, + AllocType, D.getSourceRange().getBegin(), D.getSourceRange(), Owned(ArraySize), @@ -332,12 +366,12 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, ConstructorRParen); } -Sema::OwningExprResult +Sema::OwningExprResult Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, - bool ParenTypeId, + bool ParenTypeId, QualType AllocType, SourceLocation TypeLoc, SourceRange TypeRange, @@ -369,12 +403,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, llvm::APSInt Value; if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { if (Value < llvm::APSInt( - llvm::APInt::getNullValue(Value.getBitWidth()), false)) + llvm::APInt::getNullValue(Value.getBitWidth()), + Value.isUnsigned())) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); } } + + ImpCastExprToType(ArraySize, Context.getSizeType()); } FunctionDecl *OperatorNew = 0; @@ -413,17 +450,24 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, unsigned NumConsArgs = ConstructorArgs.size(); if (AllocType->isDependentType()) { // Skip all the checks. - } - else if ((RT = AllocType->getAsRecordType()) && - !AllocType->isAggregateType()) { + } else if ((RT = AllocType->getAs<RecordType>()) && + !AllocType->isAggregateType()) { + ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); + Constructor = PerformInitializationByConstructor( - AllocType, ConsArgs, NumConsArgs, + AllocType, move(ConstructorArgs), TypeLoc, SourceRange(TypeLoc, ConstructorRParen), RT->getDecl()->getDeclName(), - NumConsArgs != 0 ? IK_Direct : IK_Default); + NumConsArgs != 0 ? IK_Direct : IK_Default, + ConvertedConstructorArgs); if (!Constructor) return ExprError(); + + // Take the converted constructor arguments and use them for the new + // expression. + NumConsArgs = ConvertedConstructorArgs.size(); + ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } else { if (!Init) { // FIXME: Check that no subpart is const. @@ -454,15 +498,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, ResultType, - StartLoc, Init ? ConstructorRParen : SourceLocation())); + StartLoc, Init ? ConstructorRParen : SourceLocation())); } /// CheckAllocatedType - Checks that a type is suitable as the allocated type /// in a new-expression. /// dimension off and stores the size expression in ArraySize. bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, - SourceRange R) -{ + SourceRange R) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) @@ -473,8 +516,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, << AllocType << 1 << R; else if (!AllocType->isDependentType() && RequireCompleteType(Loc, AllocType, - diag::err_new_incomplete_type, - R)) + PDiag(diag::err_new_incomplete_type) + << R)) return true; else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) @@ -490,8 +533,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool IsArray, Expr **PlaceArgs, unsigned NumPlaceArgs, FunctionDecl *&OperatorNew, - FunctionDecl *&OperatorDelete) -{ + FunctionDecl *&OperatorDelete) { // --- Choosing an allocation function --- // C++ 5.3.4p8 - 14 & 18 // 1) If UseGlobal is true, only look in the global scope. Else, also look @@ -506,17 +548,18 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // We don't care about the actual value of this argument. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? - AllocArgs[0] = new (Context) IntegerLiteral(llvm::APInt::getNullValue( - Context.Target.getPointerWidth(0)), - Context.getSizeType(), - SourceLocation()); + IntegerLiteral Size(llvm::APInt::getNullValue( + Context.Target.getPointerWidth(0)), + Context.getSizeType(), + SourceLocation()); + AllocArgs[0] = &Size; std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1); DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); if (AllocType->isRecordType() && !UseGlobal) { - CXXRecordDecl *Record - = cast<CXXRecordDecl>(AllocType->getAsRecordType()->getDecl()); + CXXRecordDecl *Record + = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl()); // FIXME: We fail to find inherited overloads. if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0], AllocArgs.size(), Record, /*AllowMissing=*/true, @@ -537,10 +580,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // copy them back. if (NumPlaceArgs > 0) std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs); - - // FIXME: This is leaked on error. But so much is currently in Sema that it's - // easier to clean it in one go. - AllocArgs[0]->Destroy(Context); + return false; } @@ -549,24 +589,30 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, Expr** Args, unsigned NumArgs, DeclContext *Ctx, - bool AllowMissing, FunctionDecl *&Operator) -{ - DeclContext::lookup_iterator Alloc, AllocEnd; - llvm::tie(Alloc, AllocEnd) = Ctx->lookup(Name); - if (Alloc == AllocEnd) { + bool AllowMissing, FunctionDecl *&Operator) { + LookupResult R; + LookupQualifiedName(R, Ctx, Name, LookupOrdinaryName); + if (R.empty()) { if (AllowMissing) return false; return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; } + // FIXME: handle ambiguity + OverloadCandidateSet Candidates; - for (; Alloc != AllocEnd; ++Alloc) { + for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); + Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. - if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) + if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) { AddOverloadCandidate(Fn, Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); + continue; + } + + // FIXME: Handle function templates } // Do the resolution. @@ -578,7 +624,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // The first argument is size_t, and the first parameter must be size_t, // too. This is checked on declaration and can be assumed. (It can't be // asserted on, though, since invalid decls are left in there.) - for (unsigned i = 1; i < NumArgs; ++i) { + for (unsigned i = 0; i < NumArgs; ++i) { // FIXME: Passing word to diagnostic. if (PerformCopyInitialization(Args[i], FnDecl->getParamDecl(i)->getType(), @@ -623,16 +669,52 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, /// @endcode /// Note that the placement and nothrow forms of new are *not* implicitly /// declared. Their use requires including \<new\>. -void Sema::DeclareGlobalNewDelete() -{ +void Sema::DeclareGlobalNewDelete() { if (GlobalNewDeleteDeclared) return; + + // C++ [basic.std.dynamic]p2: + // [...] The following allocation and deallocation functions (18.4) are + // implicitly declared in global scope in each translation unit of a + // program + // + // void* operator new(std::size_t) throw(std::bad_alloc); + // void* operator new[](std::size_t) throw(std::bad_alloc); + // void operator delete(void*) throw(); + // void operator delete[](void*) throw(); + // + // These implicit declarations introduce only the function names operator + // new, operator new[], operator delete, operator delete[]. + // + // Here, we need to refer to std::bad_alloc, so we will implicitly declare + // "std" or "bad_alloc" as necessary to form the exception specification. + // However, we do not make these implicit declarations visible to name + // lookup. + if (!StdNamespace) { + // The "std" namespace has not yet been defined, so build one implicitly. + StdNamespace = NamespaceDecl::Create(Context, + Context.getTranslationUnitDecl(), + SourceLocation(), + &PP.getIdentifierTable().get("std")); + StdNamespace->setImplicit(true); + } + + if (!StdBadAlloc) { + // The "std::bad_alloc" class has not yet been declared, so build it + // implicitly. + StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class, + StdNamespace, + SourceLocation(), + &PP.getIdentifierTable().get("bad_alloc"), + SourceLocation(), 0); + StdBadAlloc->setImplicit(true); + } + GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); - // FIXME: Exception specifications are not added. DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_New), VoidPtr, SizeT); @@ -650,8 +732,7 @@ void Sema::DeclareGlobalNewDelete() /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, - QualType Return, QualType Argument) -{ + QualType Return, QualType Argument) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); // Check if this function is already declared. @@ -667,14 +748,26 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, } } - QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0); + QualType BadAllocType; + bool HasBadAllocExceptionSpec + = (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New); + if (HasBadAllocExceptionSpec) { + assert(StdBadAlloc && "Must have std::bad_alloc declared"); + BadAllocType = Context.getTypeDeclType(StdBadAlloc); + } + + QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, + true, false, + HasBadAllocExceptionSpec? 1 : 0, + &BadAllocType); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, - FnType, FunctionDecl::None, false, true, - SourceLocation()); + FnType, /*DInfo=*/0, FunctionDecl::None, false, true); Alloc->setImplicit(); ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), - 0, Argument, VarDecl::None, 0); + 0, Argument, /*DInfo=*/0, + VarDecl::None, 0); Alloc->setParams(Context, &Param, 1); // FIXME: Also add this declaration to the IdentifierResolver, but @@ -689,43 +782,131 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, /// @code delete [] ptr; @endcode Action::OwningExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, - bool ArrayForm, ExprArg Operand) -{ - // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type - // having a single conversion function to a pointer type. The result has - // type void." + bool ArrayForm, ExprArg Operand) { + // C++ [expr.delete]p1: + // The operand shall have a pointer type, or a class type having a single + // conversion function to a pointer type. The result has type void. + // // DR599 amends "pointer type" to "pointer to object type" in both cases. + FunctionDecl *OperatorDelete = 0; + Expr *Ex = (Expr *)Operand.get(); if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); - if (Type->isRecordType()) { - // FIXME: Find that one conversion function and amend the type. + if (const RecordType *Record = Type->getAs<RecordType>()) { + llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; + CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + OverloadedFunctionDecl *Conversions = + RD->getVisibleConversionFunctions(); + + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + // Skip over templated conversion functions; they aren't considered. + if (isa<FunctionTemplateDecl>(*Func)) + continue; + + CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + if (ConvPtrType->getPointeeType()->isObjectType()) + ObjectPtrConversions.push_back(Conv); + } + if (ObjectPtrConversions.size() == 1) { + // We have a single conversion to a pointer-to-object type. Perform + // that conversion. + Operand.release(); + if (!PerformImplicitConversion(Ex, + ObjectPtrConversions.front()->getConversionType(), + "converting")) { + Operand = Owned(Ex); + Type = Ex->getType(); + } + } + else if (ObjectPtrConversions.size() > 1) { + Diag(StartLoc, diag::err_ambiguous_delete_operand) + << Type << Ex->getSourceRange(); + for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) { + CXXConversionDecl *Conv = ObjectPtrConversions[i]; + Diag(Conv->getLocation(), diag::err_ovl_candidate); + } + return ExprError(); + } } if (!Type->isPointerType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); - QualType Pointee = Type->getAsPointerType()->getPointeeType(); + QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && - RequireCompleteType(StartLoc, Pointee, - diag::warn_delete_incomplete, - Ex->getSourceRange())) + RequireCompleteType(StartLoc, Pointee, + PDiag(diag::warn_delete_incomplete) + << Ex->getSourceRange())) return ExprError(); - // FIXME: Look up the correct operator delete overload and pass a pointer - // along. + // C++ [expr.delete]p2: + // [Note: a pointer to a const type can be the operand of a + // delete-expression; it is not necessary to cast away the constness + // (5.2.11) of the pointer expression before it is used as the operand + // of the delete-expression. ] + ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), + CastExpr::CK_NoOp); + + // Update the operand. + Operand.take(); + Operand = ExprArg(*this, Ex); + + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( + ArrayForm ? OO_Array_Delete : OO_Delete); + + if (Pointee->isRecordType() && !UseGlobal) { + CXXRecordDecl *Record + = cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl()); + + // Try to find operator delete/operator delete[] in class scope. + LookupResult Found; + LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName); + // FIXME: Diagnose ambiguity properly + assert(!Found.isAmbiguous() && "Ambiguous delete/delete[] not handled"); + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); + F != FEnd; ++F) { + if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F)) + if (Delete->isUsualDeallocationFunction()) { + OperatorDelete = Delete; + break; + } + } + + if (!Record->hasTrivialDestructor()) + if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context)) + MarkDeclarationReferenced(StartLoc, + const_cast<CXXDestructorDecl*>(Dtor)); + } + + if (!OperatorDelete) { + // Didn't find a member overload. Look for a global one. + DeclareGlobalNewDelete(); + DeclContext *TUDecl = Context.getTranslationUnitDecl(); + if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName, + &Ex, 1, TUDecl, /*AllowMissing=*/false, + OperatorDelete)) + return ExprError(); + } + // FIXME: Check access and ambiguity of operator delete and destructor. } Operand.release(); return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, - 0, Ex, StartLoc)); + OperatorDelete, Ex, StartLoc)); } @@ -747,8 +928,11 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); - QualType Ty = GetTypeForDeclarator(D, S); - + // FIXME: Store DeclaratorInfo in the expression. + DeclaratorInfo *DInfo = 0; + TagDecl *OwnedTag = 0; + QualType Ty = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag); + if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl // would be created and CXXConditionDeclExpr wants a VarDecl. @@ -757,18 +941,9 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, } else if (Ty->isArrayType()) { // ...or an array. Diag(StartLoc, diag::err_invalid_use_of_array_type) << SourceRange(StartLoc, EqualLoc); - } else if (const RecordType *RT = Ty->getAsRecordType()) { - RecordDecl *RD = RT->getDecl(); - // The type-specifier-seq shall not declare a new class... - if (RD->isDefinition() && - (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD)))) - Diag(RD->getLocation(), diag::err_type_defined_in_condition); - } else if (const EnumType *ET = Ty->getAsEnumType()) { - EnumDecl *ED = ET->getDecl(); - // ...or enumeration. - if (ED->isDefinition() && - (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED)))) - Diag(ED->getLocation(), diag::err_type_defined_in_condition); + } else if (OwnedTag && OwnedTag->isDefinition()) { + // The type-specifier-seq shall not declare a new class or enumeration. + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition); } DeclPtrTy Dcl = ActOnDeclarator(S, D); @@ -801,7 +976,7 @@ bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) { /// conversion from a string literal to a pointer to non-const char or /// non-const wchar_t (for narrow and wide string literals, /// respectively). -bool +bool Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // Look inside the implicit cast, if it exists. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From)) @@ -812,12 +987,12 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // string literal can be converted to an rvalue of type "pointer // to wchar_t" (C++ 4.2p2). if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From)) - if (const PointerType *ToPtrType = ToType->getAsPointerType()) - if (const BuiltinType *ToPointeeType - = ToPtrType->getPointeeType()->getAsBuiltinType()) { + if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) + if (const BuiltinType *ToPointeeType + = ToPtrType->getPointeeType()->getAs<BuiltinType>()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). - if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 && + if (!ToPtrType->getPointeeType().hasQualifiers() && ((StrLit->isWide() && ToPointeeType->isWideCharType()) || (!StrLit->isWide() && (ToPointeeType->getKind() == BuiltinType::Char_U || @@ -839,16 +1014,31 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const char *Flavor, bool AllowExplicit, - bool Elidable) -{ + bool Elidable) { ImplicitConversionSequence ICS; + return PerformImplicitConversion(From, ToType, Flavor, AllowExplicit, + Elidable, ICS); +} + +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + const char *Flavor, bool AllowExplicit, + bool Elidable, + ImplicitConversionSequence& ICS) { ICS.ConversionKind = ImplicitConversionSequence::BadConversion; if (Elidable && getLangOptions().CPlusPlus0x) { - ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions*/false, - AllowExplicit, /*ForceRValue*/true); + ICS = TryImplicitConversion(From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*ForceRValue=*/true, + /*InOverloadResolution=*/false); } if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { - ICS = TryImplicitConversion(From, ToType, false, AllowExplicit); + ICS = TryImplicitConversion(From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } return PerformImplicitConversion(From, ToType, ICS, Flavor); } @@ -869,13 +1059,48 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return true; break; - case ImplicitConversionSequence::UserDefinedConversion: - // FIXME: This is, of course, wrong. We'll need to actually call the - // constructor or conversion operator, and then cope with the standard - // conversions. - ImpCastExprToType(From, ToType.getNonReferenceType(), - ToType->isLValueReferenceType()); - return false; + case ImplicitConversionSequence::UserDefinedConversion: { + + FunctionDecl *FD = ICS.UserDefined.ConversionFunction; + CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + QualType BeforeToType; + if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) { + CastKind = CastExpr::CK_UserDefinedConversion; + + // If the user-defined conversion is specified by a conversion function, + // the initial standard conversion sequence converts the source type to + // the implicit object parameter of the conversion function. + BeforeToType = Context.getTagDeclType(Conv->getParent()); + } else if (const CXXConstructorDecl *Ctor = + dyn_cast<CXXConstructorDecl>(FD)) { + CastKind = CastExpr::CK_ConstructorConversion; + + // If the user-defined conversion is specified by a constructor, the + // initial standard conversion sequence converts the source type to the + // type required by the argument of the constructor + BeforeToType = Ctor->getParamDecl(0)->getType(); + } + else + assert(0 && "Unknown conversion function kind!"); + + if (PerformImplicitConversion(From, BeforeToType, + ICS.UserDefined.Before, "converting")) + return true; + + OwningExprResult CastArg + = BuildCXXCastArgument(From->getLocStart(), + ToType.getNonReferenceType(), + CastKind, cast<CXXMethodDecl>(FD), + Owned(From)); + + if (CastArg.isInvalid()) + return true; + + From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), + CastKind, CastArg.takeAs<Expr>(), + ToType->isLValueReferenceType()); + return false; + } case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); @@ -895,7 +1120,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, /// otherwise. The expression From is replaced with the converted /// expression. Flavor is the context in which we're performing this /// conversion, for use in error messages. -bool +bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, const char *Flavor) { @@ -908,10 +1133,31 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); - - // FIXME: Keep track of whether the copy constructor is elidable or not. - From = CXXConstructExpr::Create(Context, ToType, - SCS.CopyConstructor, false, &From, 1); + if (SCS.Second == ICK_Derived_To_Base) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor), + MultiExprArg(*this, (void **)&From, 1), + /*FIXME:ConstructLoc*/SourceLocation(), + ConstructorArgs)) + return true; + OwningExprResult FromResult = + BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), + ToType, SCS.CopyConstructor, + move_arg(ConstructorArgs)); + if (FromResult.isInvalid()) + return true; + From = FromResult.takeAs<Expr>(); + return false; + } + OwningExprResult FromResult = + BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), + ToType, SCS.CopyConstructor, + MultiExprArg(*this, (void**)&From, 1)); + + if (FromResult.isInvalid()) + return true; + + From = FromResult.takeAs<Expr>(); return false; } @@ -924,7 +1170,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, FromType, CastExpr::CK_ArrayToPointerDecay); break; case ICK_Function_To_Pointer: @@ -940,7 +1186,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, FromType = From->getType(); } FromType = Context.getPointerType(FromType); - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay); break; default: @@ -951,7 +1197,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Perform the second implicit conversion switch (SCS.Second) { case ICK_Identity: - // Nothing to do. + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + // Nothing else to do. break; case ICK_Integral_Promotion: @@ -968,26 +1218,32 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ImpCastExprToType(From, FromType); break; - case ICK_Pointer_Conversion: + case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC) { // Diagnose incompatible Objective-C conversions - Diag(From->getSourceRange().getBegin(), + Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Flavor << From->getSourceRange(); } - if (CheckPointerConversion(From, ToType)) + + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (CheckPointerConversion(From, ToType, Kind)) return true; - ImpCastExprToType(From, ToType); + ImpCastExprToType(From, ToType, Kind); break; - - case ICK_Pointer_Member: - if (CheckMemberPointerConversion(From, ToType)) + } + + case ICK_Pointer_Member: { + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (CheckMemberPointerConversion(From, ToType, Kind)) return true; - ImpCastExprToType(From, ToType); + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + ImpCastExprToType(From, ToType, Kind); break; - + } case ICK_Boolean_Conversion: FromType = Context.BoolTy; ImpCastExprToType(From, FromType); @@ -1006,7 +1262,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Qualification: // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue // references. - ImpCastExprToType(From, ToType.getNonReferenceType(), + ImpCastExprToType(From, ToType.getNonReferenceType(), + CastExpr::CK_Unknown, ToType->isLValueReferenceType()); break; @@ -1023,34 +1280,38 @@ Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, SourceLocation LParen, TypeTy *Ty, SourceLocation RParen) { - // FIXME: Some of the type traits have requirements. Interestingly, only the - // __is_base_of requirement is explicitly stated to be diagnosed. Indeed, G++ - // accepts __is_pod(Incomplete) without complaints, and claims that the type - // is indeed a POD. + QualType T = GetTypeFromParser(Ty); + + // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html + // all traits except __is_class, __is_enum and __is_union require a the type + // to be complete. + if (OTT != UTT_IsClass && OTT != UTT_IsEnum && OTT != UTT_IsUnion) { + if (RequireCompleteType(KWLoc, T, + diag::err_incomplete_type_used_in_type_trait_expr)) + return ExprError(); + } // There is no point in eagerly computing the value. The traits are designed // to be used from type trait templates, so Ty will be a template parameter // 99% of the time. - return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, - QualType::getFromOpaquePtr(Ty), - RParen, Context.BoolTy)); + return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, T, + RParen, Context.BoolTy)); } QualType Sema::CheckPointerToMemberOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) -{ + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) { const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] QualType RType = rex->getType(); - const MemberPointerType *MemPtr = RType->getAsMemberPointerType(); + const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RType << rex->getSourceRange(); return QualType(); - } + } QualType Class(MemPtr->getClass(), 0); @@ -1060,7 +1321,7 @@ QualType Sema::CheckPointerToMemberOperands( // such a class] QualType LType = lex->getType(); if (isIndirect) { - if (const PointerType *Ptr = LType->getAsPointerType()) + if (const PointerType *Ptr = LType->getAs<PointerType>()) LType = Ptr->getPointeeType().getNonReferenceType(); else { Diag(Loc, diag::err_bad_memptr_lhs) @@ -1071,8 +1332,8 @@ QualType Sema::CheckPointerToMemberOperands( if (Context.getCanonicalType(Class).getUnqualifiedType() != Context.getCanonicalType(LType).getUnqualifiedType()) { - BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, - /*DetectVirtual=*/false); + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, or is that // overkill? if (!IsDerivedFrom(LType, Class, Paths) || @@ -1096,10 +1357,7 @@ QualType Sema::CheckPointerToMemberOperands( // argument. // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); - if (LType.isConstQualified()) - Result.addConst(); - if (LType.isVolatileQualified()) - Result.addVolatile(); + Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); return Result; } @@ -1124,8 +1382,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) { /// conversion. static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, SourceLocation QuestionLoc, - ImplicitConversionSequence &ICS) -{ + ImplicitConversionSequence &ICS) { // C++0x 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined @@ -1137,7 +1394,11 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // conversion the reference must bind directly to E1. if (!Self.CheckReferenceInit(From, Self.Context.getLValueReferenceType(To->getType()), - &ICS)) + To->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + &ICS)) { assert((ICS.ConversionKind == ImplicitConversionSequence::StandardConversion || @@ -1157,8 +1418,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // the same or one is a base class of the other: QualType FTy = From->getType(); QualType TTy = To->getType(); - const RecordType *FRec = FTy->getAsRecordType(); - const RecordType *TRec = TTy->getAsRecordType(); + const RecordType *FRec = FTy->getAs<RecordType>(); + const RecordType *TRec = TTy->getAs<RecordType>(); bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy); if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { @@ -1169,7 +1430,10 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // Could still fail if there's no copy constructor. // FIXME: Is this a hard error then, or just a conversion failure? The // standard doesn't say. - ICS = Self.TryCopyInitialization(From, TTy); + ICS = Self.TryCopyInitialization(From, TTy, + /*SuppressUserConversions=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } } else { // -- Otherwise: E1 can be converted to match E2 if E1 can be @@ -1178,12 +1442,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // First find the decayed type. if (TTy->isFunctionType()) TTy = Self.Context.getPointerType(TTy); - else if(TTy->isArrayType()) + else if (TTy->isArrayType()) TTy = Self.Context.getArrayDecayedType(TTy); // Now try the implicit conversion. // FIXME: This doesn't detect ambiguities. - ICS = Self.TryImplicitConversion(From, TTy); + ICS = Self.TryImplicitConversion(From, TTy, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } return false; } @@ -1239,8 +1507,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// second part of a standard conversion is ICK_DerivedToBase. This function /// handles the reference binding specially. static bool ConvertForConditional(Sema &Self, Expr *&E, - const ImplicitConversionSequence &ICS) -{ + const ImplicitConversionSequence &ICS) { if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion && ICS.Standard.ReferenceBinding) { assert(ICS.Standard.DirectBinding && @@ -1248,14 +1515,22 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, // FIXME: CheckReferenceInit should be able to reuse the ICS instead of // redoing all the work. return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS))); + TargetType(ICS)), + /*FIXME:*/E->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false); } if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion && ICS.UserDefined.After.ReferenceBinding) { assert(ICS.UserDefined.After.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS))); + TargetType(ICS)), + /*FIXME:*/E->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false); } if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting")) return true; @@ -1412,27 +1687,48 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // containing class, and second-level cv-ness. // cv-ness is not a union, but must match one of the two operands. (Which, // frankly, is stupid.) - const MemberPointerType *LMemPtr = LTy->getAsMemberPointerType(); - const MemberPointerType *RMemPtr = RTy->getAsMemberPointerType(); - if (LMemPtr && RHS->isNullPointerConstant(Context)) { + const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>(); + const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>(); + if (LMemPtr && + RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(RHS, LTy); return LTy; } - if (RMemPtr && LHS->isNullPointerConstant(Context)) { + if (RMemPtr && + LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(LHS, RTy); return RTy; } if (LMemPtr && RMemPtr) { QualType LPointee = LMemPtr->getPointeeType(); QualType RPointee = RMemPtr->getPointeeType(); + + QualifierCollector LPQuals, RPQuals; + const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee)); + const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee)); + // First, we check that the unqualified pointee type is the same. If it's // not, there's no conversion that will unify the two pointers. - if (Context.getCanonicalType(LPointee).getUnqualifiedType() == - Context.getCanonicalType(RPointee).getUnqualifiedType()) { - // Second, we take the greater of the two cv qualifications. If neither + if (LPCan == RPCan) { + + // Second, we take the greater of the two qualifications. If neither // is greater than the other, the conversion is not possible. - unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers(); - if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){ + + Qualifiers MergedQuals = LPQuals + RPQuals; + + bool CompatibleQuals = true; + if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() && + MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers()) + CompatibleQuals = false; + else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace()) + // FIXME: + // C99 6.5.15 as modified by TR 18037: + // If the second and third operands are pointers into different + // address spaces, the address spaces must overlap. + CompatibleQuals = false; + // FIXME: GC qualifiers? + + if (CompatibleQuals) { // Third, we check if either of the container classes is derived from // the other. QualType LContainer(LMemPtr->getClass(), 0); @@ -1450,8 +1746,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The type 'Q Pointee (MoreDerived::*)' is the common type. // We don't use ImpCastExprToType here because this could still fail // for ambiguous or inaccessible conversions. - QualType Common = Context.getMemberPointerType( - LPointee.getQualifiedType(Q), MoreDerived.getTypePtr()); + LPointee = Context.getQualifiedType(LPointee, MergedQuals); + QualType Common + = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr()); if (PerformImplicitConversion(LHS, Common, "converting")) return QualType(); if (PerformImplicitConversion(RHS, Common, "converting")) @@ -1470,30 +1767,37 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// \brief Find a merged pointer type and convert the two expressions to it. /// -/// This finds the composite pointer type for @p E1 and @p E2 according to -/// C++0x 5.9p2. It converts both expressions to this type and returns it. +/// This finds the composite pointer type (or member pointer type) for @p E1 +/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this +/// type and returns it. /// It does not emit diagnostics. QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); - if(!T1->isPointerType() && !T2->isPointerType()) - return QualType(); + + if (!T1->isPointerType() && !T1->isMemberPointerType() && + !T2->isPointerType() && !T2->isMemberPointerType()) + return QualType(); + + // FIXME: Do we need to work on the canonical types? // C++0x 5.9p2 // Pointer conversions and qualification conversions are performed on // pointer operands to bring them to their composite pointer type. If // one operand is a null pointer constant, the composite pointer type is // the type of the other operand. - if (E1->isNullPointerConstant(Context)) { + if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(E1, T2); return T2; } - if (E2->isNullPointerConstant(Context)) { + if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(E2, T1); return T1; } - // Now both have to be pointers. - if(!T1->isPointerType() || !T2->isPointerType()) + + // Now both have to be pointers or member pointers. + if (!T1->isPointerType() && !T1->isMemberPointerType() && + !T2->isPointerType() && !T2->isMemberPointerType()) return QualType(); // Otherwise, of one of the operands has type "pointer to cv1 void," then @@ -1506,32 +1810,93 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { // What we do here is, we build the two possible composite types, and try the // conversions in both directions. If only one works, or if the two composite // types are the same, we have succeeded. + // FIXME: extended qualifiers? llvm::SmallVector<unsigned, 4> QualifierUnion; + llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass; QualType Composite1 = T1, Composite2 = T2; - const PointerType *Ptr1, *Ptr2; - while ((Ptr1 = Composite1->getAsPointerType()) && - (Ptr2 = Composite2->getAsPointerType())) { - Composite1 = Ptr1->getPointeeType(); - Composite2 = Ptr2->getPointeeType(); - QualifierUnion.push_back( - Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); - } - // Rewrap the composites as pointers with the union CVRs. - for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(), - E = QualifierUnion.end(); I != E; ++I) { - Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I)); - Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I)); + do { + const PointerType *Ptr1, *Ptr2; + if ((Ptr1 = Composite1->getAs<PointerType>()) && + (Ptr2 = Composite2->getAs<PointerType>())) { + Composite1 = Ptr1->getPointeeType(); + Composite2 = Ptr2->getPointeeType(); + QualifierUnion.push_back( + Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); + MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); + continue; + } + + const MemberPointerType *MemPtr1, *MemPtr2; + if ((MemPtr1 = Composite1->getAs<MemberPointerType>()) && + (MemPtr2 = Composite2->getAs<MemberPointerType>())) { + Composite1 = MemPtr1->getPointeeType(); + Composite2 = MemPtr2->getPointeeType(); + QualifierUnion.push_back( + Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); + MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), + MemPtr2->getClass())); + continue; + } + + // FIXME: block pointer types? + + // Cannot unwrap any more types. + break; + } while (true); + + // Rewrap the composites as pointers or member pointers with the union CVRs. + llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC + = MemberOfClass.begin(); + for (llvm::SmallVector<unsigned, 4>::iterator + I = QualifierUnion.begin(), + E = QualifierUnion.end(); + I != E; (void)++I, ++MOC) { + Qualifiers Quals = Qualifiers::fromCVRMask(*I); + if (MOC->first && MOC->second) { + // Rebuild member pointer type + Composite1 = Context.getMemberPointerType( + Context.getQualifiedType(Composite1, Quals), + MOC->first); + Composite2 = Context.getMemberPointerType( + Context.getQualifiedType(Composite2, Quals), + MOC->second); + } else { + // Rebuild pointer type + Composite1 + = Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); + Composite2 + = Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); + } } - ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1); - ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1); + ImplicitConversionSequence E1ToC1 = + TryImplicitConversion(E1, Composite1, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + ImplicitConversionSequence E2ToC1 = + TryImplicitConversion(E2, Composite1, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + ImplicitConversionSequence E1ToC2, E2ToC2; E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { - E1ToC2 = TryImplicitConversion(E1, Composite2); - E2ToC2 = TryImplicitConversion(E2, Composite2); + E1ToC2 = TryImplicitConversion(E1, Composite2, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + E2ToC2 = TryImplicitConversion(E2, Composite2, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } bool ToC1Viable = E1ToC1.ConversionKind != @@ -1556,84 +1921,264 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { } Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { - const RecordType *RT = E->getType()->getAsRecordType(); + if (!Context.getLangOptions().CPlusPlus) + return Owned(E); + + const RecordType *RT = E->getType()->getAs<RecordType>(); if (!RT) return Owned(E); - + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (RD->hasTrivialDestructor()) return Owned(E); - - CXXTemporary *Temp = CXXTemporary::Create(Context, + + if (CallExpr *CE = dyn_cast<CallExpr>(E)) { + QualType Ty = CE->getCallee()->getType(); + if (const PointerType *PT = Ty->getAs<PointerType>()) + Ty = PT->getPointeeType(); + + const FunctionType *FTy = Ty->getAs<FunctionType>(); + if (FTy->getResultType()->isReferenceType()) + return Owned(E); + } + CXXTemporary *Temp = CXXTemporary::Create(Context, RD->getDestructor(Context)); ExprTemporaries.push_back(Temp); - MarkDestructorReferenced(E->getExprLoc(), E->getType()); + if (CXXDestructorDecl *Destructor = + const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) + MarkDeclarationReferenced(E->getExprLoc(), Destructor); // FIXME: Add the temporary to the temporaries vector. return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } -// FIXME: This doesn't handle casts yet. -Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) { - const RecordType *RT = E->getType()->getAsRecordType(); - if (!RT) - return E; - - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialDestructor()) - return E; - - /// The expr passed in must be a CXXExprWithTemporaries. - CXXExprWithTemporaries *TempExpr = dyn_cast<CXXExprWithTemporaries>(E); - if (!TempExpr) - return E; - - Expr *SubExpr = TempExpr->getSubExpr(); - if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) { - assert(BE->getTemporary() == - TempExpr->getTemporary(TempExpr->getNumTemporaries() - 1) && - "Found temporary is not last in list!"); - - Expr *BindSubExpr = BE->getSubExpr(); - BE->setSubExpr(0); - - if (TempExpr->getNumTemporaries() == 1) { - // There's just one temporary left, so we don't need the TempExpr node. - TempExpr->Destroy(Context); - return BindSubExpr; - } else { - TempExpr->removeLastTemporary(); - TempExpr->setSubExpr(BindSubExpr); - BE->Destroy(Context); - } - - return E; - } - - // FIXME: We might need to handle other expressions here. - return E; -} - -Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, +Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, bool ShouldDestroyTemps) { assert(SubExpr && "sub expression can't be null!"); - + if (ExprTemporaries.empty()) return SubExpr; - + Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, - &ExprTemporaries[0], + &ExprTemporaries[0], ExprTemporaries.size(), ShouldDestroyTemps); ExprTemporaries.clear(); - + return E; } +Sema::OwningExprResult +Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, TypeTy *&ObjectType) { + // Since this might be a postfix expression, get rid of ParenListExprs. + Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + + Expr *BaseExpr = (Expr*)Base.get(); + assert(BaseExpr && "no record expansion"); + + QualType BaseType = BaseExpr->getType(); + if (BaseType->isDependentType()) { + // FIXME: member of the current instantiation + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); + } + + // C++ [over.match.oper]p8: + // [...] When operator->returns, the operator-> is applied to the value + // returned, with the original second operand. + if (OpKind == tok::arrow) { + // The set of types we've considered so far. + llvm::SmallPtrSet<CanQualType,8> CTypes; + llvm::SmallVector<SourceLocation, 8> Locations; + CTypes.insert(Context.getCanonicalType(BaseType)); + + while (BaseType->isRecordType()) { + Base = BuildOverloadedArrowExpr(S, move(Base), OpLoc); + BaseExpr = (Expr*)Base.get(); + if (BaseExpr == NULL) + return ExprError(); + if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(BaseExpr)) + Locations.push_back(OpCall->getDirectCallee()->getLocation()); + BaseType = BaseExpr->getType(); + CanQualType CBaseType = Context.getCanonicalType(BaseType); + if (!CTypes.insert(CBaseType)) { + Diag(OpLoc, diag::err_operator_arrow_circular); + for (unsigned i = 0; i < Locations.size(); i++) + Diag(Locations[i], diag::note_declared_at); + return ExprError(); + } + } + } + + if (BaseType->isPointerType()) + BaseType = BaseType->getPointeeType(); + + // We could end up with various non-record types here, such as extended + // vector types or Objective-C interfaces. Just return early and let + // ActOnMemberReferenceExpr do the work. + if (!BaseType->isRecordType()) { + // C++ [basic.lookup.classref]p2: + // [...] If the type of the object expression is of pointer to scalar + // type, the unqualified-id is looked up in the context of the complete + // postfix-expression. + ObjectType = 0; + return move(Base); + } + + // C++ [basic.lookup.classref]p2: + // If the id-expression in a class member access (5.2.5) is an + // unqualified-id, and the type of the object expres- sion is of a class + // type C (or of pointer to a class type C), the unqualified-id is looked + // up in the scope of class C. [...] + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); +} + +Sema::OwningExprResult +Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + IdentifierInfo *ClassName, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + if (SS.isInvalid()) + return ExprError(); + + QualType BaseType; + if (isUnknownSpecialization(SS)) + BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(), + ClassName); + else { + TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS); + if (!BaseTy) { + Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << ClassName; + return ExprError(); + } + + BaseType = GetTypeFromParser(BaseTy); + } + + CanQualType CanBaseType = Context.getCanonicalType(BaseType); + DeclarationName DtorName = + Context.DeclarationNames.getCXXDestructorName(CanBaseType); + + OwningExprResult Result + = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, + DtorName, DeclPtrTy(), &SS); + if (Result.isInvalid() || HasTrailingLParen) + return move(Result); + + // The only way a reference to a destructor can be used is to + // immediately call them. Since the next token is not a '(', produce a + // diagnostic and build the call now. + Expr *E = (Expr *)Result.get(); + SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd()); + Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa<CXXPseudoDestructorExpr>(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, + MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); +} + +Sema::OwningExprResult +Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + OverloadedOperatorKind OverOpKind, + const CXXScopeSpec *SS) { + if (SS && SS->isInvalid()) + return ExprError(); + + DeclarationName Name = + Context.DeclarationNames.getCXXOperatorName(OverOpKind); + + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, + Name, DeclPtrTy(), SS); +} + +Sema::OwningExprResult +Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + TypeTy *Ty, + const CXXScopeSpec *SS) { + if (SS && SS->isInvalid()) + return ExprError(); + + //FIXME: Preserve type source info. + QualType ConvType = GetTypeFromParser(Ty); + CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); + DeclarationName ConvName = + Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); + + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, + ConvName, DeclPtrTy(), SS); +} + +CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, + CXXMethodDecl *Method) { + MemberExpr *ME = + new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, + SourceLocation(), Method->getType()); + QualType ResultType; + if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Method)) + ResultType = Conv->getConversionType().getNonReferenceType(); + else + ResultType = Method->getResultType().getNonReferenceType(); + + CXXMemberCallExpr *CE = + new (Context) CXXMemberCallExpr(Context, ME, 0, 0, + ResultType, + SourceLocation()); + return CE; +} + +Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, + QualType Ty, + CastExpr::CastKind Kind, + CXXMethodDecl *Method, + ExprArg Arg) { + Expr *From = Arg.takeAs<Expr>(); + + switch (Kind) { + default: assert(0 && "Unhandled cast kind!"); + case CastExpr::CK_ConstructorConversion: { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + + if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method), + MultiExprArg(*this, (void **)&From, 1), + CastLoc, ConstructorArgs)) + return ExprError(); + + return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs)); + } + + case CastExpr::CK_UserDefinedConversion: { + assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); + + // Cast to base if needed. + if (PerformObjectArgumentInitialization(From, Method)) + return ExprError(); + + // Create an implicit call expr that calls it. + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); + return Owned(CE); + } + } +} + Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) - FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr, + FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr, /*ShouldDestroyTemps=*/true); + return Owned(FullExpr); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 7bb6b44c39cf9..d7e4e4a67fe96 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -20,7 +20,7 @@ using namespace clang; -Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, +Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, ExprTy **strings, unsigned NumStrings) { StringLiteral **Strings = reinterpret_cast<StringLiteral**>(strings); @@ -30,40 +30,40 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, // each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one // StringLiteral for ObjCStringLiteral to hold onto. StringLiteral *S = Strings[0]; - + // If we have a multi-part string, merge it all together. if (NumStrings != 1) { // Concatenate objc strings. llvm::SmallString<128> StrBuf; llvm::SmallVector<SourceLocation, 8> StrLocs; - + for (unsigned i = 0; i != NumStrings; ++i) { S = Strings[i]; - + // ObjC strings can't be wide. if (S->isWide()) { Diag(S->getLocStart(), diag::err_cfstring_literal_not_string_constant) << S->getSourceRange(); return true; } - + // Get the string data. StrBuf.append(S->getStrData(), S->getStrData()+S->getByteLength()); - + // Get the locations of the string tokens. StrLocs.append(S->tokloc_begin(), S->tokloc_end()); - + // Free the temporary string. S->Destroy(Context); } - + // Create the aggregate string with the appropriate content and location // information. S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), false, Context.getPointerType(Context.CharTy), &StrLocs[0], StrLocs.size()); } - + // Verify that this composite string is acceptable for ObjC strings. if (CheckObjCString(S)) return true; @@ -74,29 +74,29 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, // interface private (even though it appears in the header files). QualType Ty = Context.getObjCConstantStringInterface(); if (!Ty.isNull()) { - Ty = Context.getPointerType(Ty); + Ty = Context.getObjCObjectPointerType(Ty); } else { IdentifierInfo *NSIdent = &Context.Idents.get("NSString"); - NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName); + NamedDecl *IF = LookupSingleName(TUScope, NSIdent, LookupOrdinaryName); if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { Context.setObjCConstantStringInterface(StrIF); Ty = Context.getObjCConstantStringInterface(); - Ty = Context.getPointerType(Ty); + Ty = Context.getObjCObjectPointerType(Ty); } else { // If there is no NSString interface defined then treat constant // strings as untyped objects and let the runtime figure it out later. Ty = Context.getObjCIdType(); } } - + return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]); } -Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, +Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, QualType EncodedType, SourceLocation RParenLoc) { QualType StrTy; - if (EncodedType->isDependentType()) + if (EncodedType->isDependentType()) StrTy = Context.DependentTy; else { std::string Str; @@ -111,7 +111,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1), ArrayType::Normal, 0); } - + return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc); } @@ -120,7 +120,8 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation LParenLoc, TypeTy *ty, SourceLocation RParenLoc) { - QualType EncodedType = QualType::getFromOpaquePtr(ty); + // FIXME: Preserve type source info ? + QualType EncodedType = GetTypeFromParser(ty); return BuildObjCEncodeExpression(AtLoc, EncodedType, RParenLoc); } @@ -130,8 +131,8 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, SourceLocation SelLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { - ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LParenLoc, RParenLoc)); + ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LParenLoc, RParenLoc), false); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LParenLoc, RParenLoc)); @@ -152,19 +153,19 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; } - + QualType Ty = Context.getObjCProtoType(); if (Ty.isNull()) return true; - Ty = Context.getPointerType(Ty); + Ty = Context.getObjCObjectPointerType(Ty); return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc); } -bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, - Selector Sel, ObjCMethodDecl *Method, +bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, + Selector Sel, ObjCMethodDecl *Method, bool isClassMessage, SourceLocation lbrac, SourceLocation rbrac, - QualType &ReturnType) { + QualType &ReturnType) { if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). for (unsigned i = 0; i != NumArgs; i++) @@ -177,9 +178,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, ReturnType = Context.getObjCIdType(); return false; } - + ReturnType = Method->getResultType(); - + unsigned NumNamedArgs = Sel.getNumArgs(); assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!"); @@ -187,22 +188,22 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, for (unsigned i = 0; i < NumNamedArgs; i++) { Expr *argExpr = Args[i]; assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); - + QualType lhsType = Method->param_begin()[i]->getType(); QualType rhsType = argExpr->getType(); - // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. + // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. if (lhsType->isArrayType()) lhsType = Context.getArrayDecayedType(lhsType); else if (lhsType->isFunctionType()) lhsType = Context.getPointerType(lhsType); - AssignConvertType Result = + AssignConvertType Result = CheckSingleAssignmentConstraints(lhsType, argExpr); if (Args[i] != argExpr) // The expression was converted. Args[i] = argExpr; // Make sure we store the converted expression. - - IsError |= + + IsError |= DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, argExpr, "sending"); } @@ -214,7 +215,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, } else { // Check for extra arguments to non-variadic methods. if (NumArgs != NumNamedArgs) { - Diag(Args[NumNamedArgs]->getLocStart(), + Diag(Args[NumNamedArgs]->getLocStart(), diag::err_typecheck_call_too_many_args) << 2 /*method*/ << Method->getSourceRange() << SourceRange(Args[NumNamedArgs]->getLocStart(), @@ -241,29 +242,24 @@ ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel, ObjCMethodDecl *Method = 0; // lookup in class and all superclasses while (ClassDecl && !Method) { - if (ObjCImplementationDecl *ImpDecl - = LookupObjCImplementation(ClassDecl->getIdentifier())) + if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) Method = ImpDecl->getClassMethod(Sel); - + // Look through local category implementations associated with the class. - if (!Method) { - for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) { - if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl) - Method = ObjCCategoryImpls[i]->getClassMethod(Sel); - } - } - + if (!Method) + Method = ClassDecl->getCategoryClassMethod(Sel); + // Before we give up, check if the selector is an instance method. // But only in the root. This matches gcc's behaviour and what the // runtime expects. if (!Method && !ClassDecl->getSuperClass()) { Method = ClassDecl->lookupInstanceMethod(Sel); - // Look through local category implementations associated + // Look through local category implementations associated // with the root class. - if (!Method) + if (!Method) Method = LookupPrivateInstanceMethod(Sel, ClassDecl); } - + ClassDecl = ClassDecl->getSuperClass(); } return Method; @@ -274,17 +270,12 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, ObjCMethodDecl *Method = 0; while (ClassDecl && !Method) { // If we have implementations in scope, check "private" methods. - if (ObjCImplementationDecl *ImpDecl - = LookupObjCImplementation(ClassDecl->getIdentifier())) + if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) Method = ImpDecl->getInstanceMethod(Sel); - + // Look through local category implementations associated with the class. - if (!Method) { - for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) { - if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl) - Method = ObjCCategoryImpls[i]->getInstanceMethod(Sel); - } - } + if (!Method) + Method = ClassDecl->getCategoryInstanceMethod(Sel); ClassDecl = ClassDecl->getSuperClass(); } return Method; @@ -295,11 +286,11 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( IdentifierInfo &propertyName, SourceLocation &receiverNameLoc, SourceLocation &propertyNameLoc) { - + ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName); - + // Search for a declared property first. - + Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel); @@ -307,8 +298,7 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( if (!Getter) if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) - if (ObjCImplementationDecl *ImpDecl - = LookupObjCImplementation(ClassDecl->getIdentifier())) + if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) Getter = ImpDecl->getClassMethod(Sel); if (Getter) { @@ -317,29 +307,24 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( if (DiagnoseUseOfDecl(Getter, propertyNameLoc)) return ExprError(); } - + // Look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), PP.getSelectorTable(), &propertyName); - + ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); if (!Setter) { // If this reference is in an @implementation, also check for 'private' // methods. if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) - if (ObjCImplementationDecl *ImpDecl - = LookupObjCImplementation(ClassDecl->getIdentifier())) + if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) Setter = ImpDecl->getClassMethod(SetterSel); } // Look through local category implementations associated with the class. - if (!Setter) { - for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { - if (ObjCCategoryImpls[i]->getClassInterface() == IFace) - Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel); - } - } + if (!Setter) + Setter = IFace->getCategoryClassMethod(SetterSel); if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc)) return ExprError(); @@ -354,7 +339,8 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( E = Setter->param_end(); PI != E; ++PI) PType = (*PI)->getType(); } - return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, Setter, + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr( + Getter, PType, Setter, propertyNameLoc, IFace, receiverNameLoc)); } return ExprError(Diag(propertyNameLoc, diag::err_property_not_found) @@ -369,32 +355,31 @@ Sema::ExprResult Sema::ActOnClassMessage( Scope *S, IdentifierInfo *receiverName, Selector Sel, SourceLocation lbrac, SourceLocation receiverLoc, - SourceLocation selectorLoc, SourceLocation rbrac, - ExprTy **Args, unsigned NumArgs) -{ + SourceLocation selectorLoc, SourceLocation rbrac, + ExprTy **Args, unsigned NumArgs) { assert(receiverName && "missing receiver class name"); Expr **ArgExprs = reinterpret_cast<Expr **>(Args); ObjCInterfaceDecl* ClassDecl = 0; bool isSuper = false; - + if (receiverName->isStr("super")) { if (getCurMethodDecl()) { isSuper = true; ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface(); if (!OID) - return Diag(lbrac, diag::error_no_super_class_message) + return Diag(lbrac, diag::error_no_super_class_message) << getCurMethodDecl()->getDeclName(); ClassDecl = OID->getSuperClass(); if (!ClassDecl) return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName(); if (getCurMethodDecl()->isInstanceMethod()) { QualType superTy = Context.getObjCInterfaceType(ClassDecl); - superTy = Context.getPointerType(superTy); + superTy = Context.getObjCObjectPointerType(superTy); ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(), superTy); // We are really in an instance method, redirect. - return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, + return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, selectorLoc, rbrac, Args, NumArgs); } // We are sending a message to 'super' within a class method. Do nothing, @@ -402,20 +387,21 @@ Sema::ExprResult Sema::ActOnClassMessage( } else { // 'super' has been used outside a method context. If a variable named // 'super' has been declared, redirect. If not, produce a diagnostic. - NamedDecl *SuperDecl = LookupName(S, receiverName, LookupOrdinaryName); + NamedDecl *SuperDecl + = LookupSingleName(S, receiverName, LookupOrdinaryName); ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl); if (VD) { - ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(), + ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(), receiverLoc); // We are really in an instance method, redirect. - return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, + return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, selectorLoc, rbrac, Args, NumArgs); } return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; - } + } } else ClassDecl = getObjCInterfaceDecl(receiverName); - + // The following code allows for the following GCC-ism: // // typedef XCElementDisplayRect XCElementGraphicsRect; @@ -427,10 +413,11 @@ Sema::ExprResult Sema::ActOnClassMessage( // // If necessary, the following lookup could move to getObjCInterfaceDecl(). if (!ClassDecl) { - NamedDecl *IDecl = LookupName(TUScope, receiverName, LookupOrdinaryName); + NamedDecl *IDecl + = LookupSingleName(TUScope, receiverName, LookupOrdinaryName); if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) { const ObjCInterfaceType *OCIT; - OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType(); + OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>(); if (!OCIT) { Diag(receiverLoc, diag::err_invalid_receiver_to_message); return true; @@ -446,25 +433,25 @@ Sema::ExprResult Sema::ActOnClassMessage( Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName(); Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); if (Method) - Diag(Method->getLocation(), diag::note_method_sent_forward_class) + Diag(Method->getLocation(), diag::note_method_sent_forward_class) << Method->getDeclName(); } if (!Method) Method = ClassDecl->lookupClassMethod(Sel); - + // If we have an implementation in scope, check "private" methods. if (!Method) Method = LookupPrivateClassMethod(Sel, ClassDecl); if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) return true; - - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true, + + if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true, lbrac, rbrac, returnType)) return true; returnType = returnType.getNonReferenceType(); - + // If we have the ObjCInterfaceDecl* for the class that is receiving the // message, use that to construct the ObjCMessageExpr. Otherwise pass on the // IdentifierInfo* for the class. @@ -483,19 +470,19 @@ Sema::ExprResult Sema::ActOnClassMessage( // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, - SourceLocation lbrac, + SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs) { assert(receiver && "missing receiver expression"); - + Expr **ArgExprs = reinterpret_cast<Expr **>(Args); Expr *RExpr = static_cast<Expr *>(receiver); - + // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. DefaultFunctionArrayConversion(RExpr); - + QualType returnType; QualType ReceiverCType = Context.getCanonicalType(RExpr->getType()).getUnqualifiedType(); @@ -508,8 +495,8 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) { Method = SuperDecl->lookupInstanceMethod(Sel); - - if (!Method) + + if (!Method) // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, SuperDecl); } @@ -521,39 +508,42 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, lbrac, rbrac, returnType)) return true; - + returnType = returnType.getNonReferenceType(); return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, ArgExprs, NumArgs); } // Handle messages to id. - if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) || - ReceiverCType->isBlockPointerType() || + if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() || Context.isObjCNSObjectType(RExpr->getType())) { ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool( Sel, SourceRange(lbrac,rbrac)); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac)); - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, + if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, lbrac, rbrac, returnType)) return true; returnType = returnType.getNonReferenceType(); return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, ArgExprs, NumArgs); } - + // Handle messages to Class. - if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) { + if (ReceiverCType->isObjCClassType() || + ReceiverCType->isObjCQualifiedClassType()) { ObjCMethodDecl *Method = 0; - + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { // First check the public methods in the class interface. Method = ClassDecl->lookupClassMethod(Sel); - + if (!Method) Method = LookupPrivateClassMethod(Sel, ClassDecl); + + // FIXME: if we still haven't found a method, we need to look in + // protocols (if we have qualifiers). } if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) return true; @@ -584,13 +574,13 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, ArgExprs, NumArgs); } - + ObjCMethodDecl *Method = 0; ObjCInterfaceDecl* ClassDecl = 0; - - // We allow sending a message to a qualified ID ("id<foo>"), which is ok as + + // We allow sending a message to a qualified ID ("id<foo>"), which is ok as // long as one of the protocols implements the selector (if not, warn). - if (const ObjCObjectPointerType *QIdTy = + if (const ObjCObjectPointerType *QIdTy = ReceiverCType->getAsObjCQualifiedIdType()) { // Search protocols for instance methods. for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), @@ -602,19 +592,19 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) break; } - } else if (const ObjCInterfaceType *OCIType = - ReceiverCType->getAsPointerToObjCInterfaceType()) { + } else if (const ObjCObjectPointerType *OCIType = + ReceiverCType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). - - ClassDecl = OCIType->getDecl(); + + ClassDecl = OCIType->getInterfaceDecl(); // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be // faster than the following method (which can do *many* linear searches). // The idea is to add class info to InstanceMethodPool. Method = ClassDecl->lookupInstanceMethod(Sel); - + if (!Method) { // Search protocol qualifiers. - for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(), + for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), E = OCIType->qual_end(); QI != E; ++QI) { if ((Method = (*QI)->lookupInstanceMethod(Sel))) break; @@ -623,7 +613,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (!Method) { // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); - + if (!Method && !isSelfExpr(RExpr)) { // If we still haven't found a method, look in the global pool. This // behavior isn't very desirable, however we need it for GCC @@ -631,9 +621,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool( Sel, SourceRange(lbrac,rbrac)); - if (Method && !OCIType->getDecl()->isForwardDecl()) - Diag(lbrac, diag::warn_maynot_respond) - << OCIType->getDecl()->getIdentifier()->getName() << Sel; + if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) + Diag(lbrac, diag::warn_maynot_respond) + << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel; } } } @@ -641,7 +631,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, return true; } else if (!Context.getObjCIdType().isNull() && (ReceiverCType->isPointerType() || - (ReceiverCType->isIntegerType() && + (ReceiverCType->isIntegerType() && ReceiverCType->isScalarType()))) { // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(lbrac, diag::warn_bad_receiver_type) @@ -653,7 +643,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, << RExpr->getType() << RExpr->getSourceRange(); return true; } - + if (Method) DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs); if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, @@ -664,217 +654,3 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, rbrac, ArgExprs, NumArgs); } -//===----------------------------------------------------------------------===// -// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. -//===----------------------------------------------------------------------===// - -/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the -/// inheritance hierarchy of 'rProto'. -static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, - ObjCProtocolDecl *rProto) { - if (lProto == rProto) - return true; - for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), - E = rProto->protocol_end(); PI != E; ++PI) - if (ProtocolCompatibleWithProtocol(lProto, *PI)) - return true; - return false; -} - -/// ClassImplementsProtocol - Checks that 'lProto' protocol -/// has been implemented in IDecl class, its super class or categories (if -/// lookupCategory is true). -static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, - ObjCInterfaceDecl *IDecl, - bool lookupCategory, - bool RHSIsQualifiedID = false) { - - // 1st, look up the class. - const ObjCList<ObjCProtocolDecl> &Protocols = - IDecl->getReferencedProtocols(); - - for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), - E = Protocols.end(); PI != E; ++PI) { - if (ProtocolCompatibleWithProtocol(lProto, *PI)) - return true; - // This is dubious and is added to be compatible with gcc. In gcc, it is - // also allowed assigning a protocol-qualified 'id' type to a LHS object - // when protocol in qualified LHS is in list of protocols in the rhs 'id' - // object. This IMO, should be a bug. - // FIXME: Treat this as an extension, and flag this as an error when GCC - // extensions are not enabled. - if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto)) - return true; - } - - // 2nd, look up the category. - if (lookupCategory) - for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) { - for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), - E = CDecl->protocol_end(); PI != E; ++PI) - if (ProtocolCompatibleWithProtocol(lProto, *PI)) - return true; - } - - // 3rd, look up the super class(s) - if (IDecl->getSuperClass()) - return - ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory, - RHSIsQualifiedID); - - return false; -} - -/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...> -/// return true if lhs's protocols conform to rhs's protocol; false -/// otherwise. -bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { - if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType()) - return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false); - return false; -} - -/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an -/// ObjCQualifiedIDType. -/// FIXME: Move to ASTContext::typesAreCompatible() and friends. -bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, - bool compare) { - // Allow id<P..> and an 'id' or void* type in all cases. - if (const PointerType *PT = lhs->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - if (PointeeTy->isVoidType() || - Context.isObjCIdStructType(PointeeTy) || - Context.isObjCClassStructType(PointeeTy)) - return true; - } else if (const PointerType *PT = rhs->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - if (PointeeTy->isVoidType() || - Context.isObjCIdStructType(PointeeTy) || - Context.isObjCClassStructType(PointeeTy)) - return true; - } - - if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) { - const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType(); - const ObjCQualifiedInterfaceType *rhsQI = 0; - QualType rtype; - - if (!rhsQID) { - // Not comparing two ObjCQualifiedIdType's? - if (!rhs->isPointerType()) return false; - - rtype = rhs->getAsPointerType()->getPointeeType(); - rhsQI = rtype->getAsObjCQualifiedInterfaceType(); - if (rhsQI == 0) { - // If the RHS is a unqualified interface pointer "NSString*", - // make sure we check the class hierarchy. - if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { - ObjCInterfaceDecl *rhsID = IT->getDecl(); - for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), - E = lhsQID->qual_end(); I != E; ++I) { - // when comparing an id<P> on lhs with a static type on rhs, - // see if static class implements all of id's protocols, directly or - // through its super class and categories. - if (!ClassImplementsProtocol(*I, rhsID, true)) - return false; - } - return true; - } - } - } - - ObjCObjectPointerType::qual_iterator RHSProtoI, RHSProtoE; - if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *"). - RHSProtoI = rhsQI->qual_begin(); - RHSProtoE = rhsQI->qual_end(); - } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *"). - RHSProtoI = rhsQID->qual_begin(); - RHSProtoE = rhsQID->qual_end(); - } else { - return false; - } - - for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), - E = lhsQID->qual_end(); I != E; ++I) { - ObjCProtocolDecl *lhsProto = *I; - bool match = false; - - // when comparing an id<P> on lhs with a static type on rhs, - // see if static class implements all of id's protocols, directly or - // through its super class and categories. - for (; RHSProtoI != RHSProtoE; ++RHSProtoI) { - ObjCProtocolDecl *rhsProto = *RHSProtoI; - if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || - (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { - match = true; - break; - } - } - if (rhsQI) { - // If the RHS is a qualified interface pointer "NSString<P>*", - // make sure we check the class hierarchy. - if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { - ObjCInterfaceDecl *rhsID = IT->getDecl(); - for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), - E = lhsQID->qual_end(); I != E; ++I) { - // when comparing an id<P> on lhs with a static type on rhs, - // see if static class implements all of id's protocols, directly or - // through its super class and categories. - if (ClassImplementsProtocol(*I, rhsID, true)) { - match = true; - break; - } - } - } - } - if (!match) - return false; - } - - return true; - } - - const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType(); - assert(rhsQID && "One of the LHS/RHS should be id<x>"); - - if (!lhs->isPointerType()) - return false; - - QualType ltype = lhs->getAsPointerType()->getPointeeType(); - if (const ObjCQualifiedInterfaceType *lhsQI = - ltype->getAsObjCQualifiedInterfaceType()) { - ObjCObjectPointerType::qual_iterator LHSProtoI = lhsQI->qual_begin(); - ObjCObjectPointerType::qual_iterator LHSProtoE = lhsQI->qual_end(); - for (; LHSProtoI != LHSProtoE; ++LHSProtoI) { - bool match = false; - ObjCProtocolDecl *lhsProto = *LHSProtoI; - for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(), - E = rhsQID->qual_end(); I != E; ++I) { - ObjCProtocolDecl *rhsProto = *I; - if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || - (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { - match = true; - break; - } - } - if (!match) - return false; - } - return true; - } - - if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) { - // for static type vs. qualified 'id' type, check that class implements - // all of 'id's protocols. - ObjCInterfaceDecl *lhsID = IT->getDecl(); - for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(), - E = rhsQID->qual_end(); I != E; ++I) { - if (!ClassImplementsProtocol(*I, lhsID, compare, true)) - return false; - } - return true; - } - return false; -} - diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index ecfdfd7ba0b64..27f0896807633 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -36,7 +36,7 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) { // See if this is a string literal or @encode. Init = Init->IgnoreParens(); - + // Handle @encode, which is a narrow string. if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType()) return Init; @@ -58,26 +58,38 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) { if (Context.typesAreCompatible(Context.getWCharType(), ElemTy.getUnqualifiedType())) return Init; - + return 0; } -static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, +static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, bool DirectInit, Sema &S) { // Get the type before calling CheckSingleAssignmentConstraints(), since // it can promote the expression. - QualType InitType = Init->getType(); - + QualType InitType = Init->getType(); + if (S.getLangOptions().CPlusPlus) { // FIXME: I dislike this error message. A lot. - if (S.PerformImplicitConversion(Init, DeclType, "initializing", DirectInit)) - return S.Diag(Init->getSourceRange().getBegin(), - diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << "initializing" - << Init->getSourceRange(); + if (S.PerformImplicitConversion(Init, DeclType, + "initializing", DirectInit)) { + ImplicitConversionSequence ICS; + OverloadCandidateSet CandidateSet; + if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined, + CandidateSet, + true, false, false) != S.OR_Ambiguous) + return S.Diag(Init->getSourceRange().getBegin(), + diag::err_typecheck_convert_incompatible) + << DeclType << Init->getType() << "initializing" + << Init->getSourceRange(); + S.Diag(Init->getSourceRange().getBegin(), + diag::err_typecheck_convert_ambiguous) + << DeclType << Init->getType() << Init->getSourceRange(); + S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + return true; + } return false; } - + Sema::AssignConvertType ConvTy = S.CheckSingleAssignmentConstraints(DeclType, Init); return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, @@ -89,21 +101,22 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { uint64_t StrLength = cast<ConstantArrayType>(Str->getType())->getSize().getZExtValue(); - + const ArrayType *AT = S.Context.getAsArrayType(DeclT); if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) { - // C99 6.7.8p14. We have an array of character type with unknown size + // C99 6.7.8p14. We have an array of character type with unknown size // being initialized to a string literal. llvm::APSInt ConstVal(32); ConstVal = StrLength; // Return a new array type (C99 6.7.8p22). - DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal, - ArrayType::Normal, 0); + DeclT = S.Context.getConstantArrayWithoutExprType(IAT->getElementType(), + ConstVal, + ArrayType::Normal, 0); return; } - + const ConstantArrayType *CAT = cast<ConstantArrayType>(AT); - + // C99 6.7.8p14. We have an array of character type with known size. However, // the size may be smaller or larger than the string we are initializing. // FIXME: Avoid truncation for 64-bit length strings. @@ -111,7 +124,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { S.Diag(Str->getSourceRange().getBegin(), diag::warn_initializer_string_for_char_array_too_long) << Str->getSourceRange(); - + // Set the type to the actual size that we are initializing. If we have // something like: // char x[1] = "foo"; @@ -122,23 +135,26 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, SourceLocation InitLoc, DeclarationName InitEntity, bool DirectInit) { - if (DeclType->isDependentType() || + if (DeclType->isDependentType() || Init->isTypeDependent() || Init->isValueDependent()) return false; - + // C++ [dcl.init.ref]p1: // A variable declared to be a T& or T&&, that is "reference to type T" // (8.3.2), shall be initialized by an object, or function, of // type T or by an object that can be converted into a T. if (DeclType->isReferenceType()) - return CheckReferenceInit(Init, DeclType, 0, false, DirectInit); - + return CheckReferenceInit(Init, DeclType, InitLoc, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/DirectInit, + /*ForceRValue=*/false); + // C99 6.7.8p3: The type of the entity to be initialized shall be an array // of unknown size ("[]") or an object type that is not a variable array type. if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType)) return Diag(InitLoc, diag::err_variable_object_no_init) << VAT->getSizeExpr()->getSourceRange(); - + InitListExpr *InitList = dyn_cast<InitListExpr>(Init); if (!InitList) { // FIXME: Handle wide strings @@ -146,41 +162,52 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, CheckStringInit(Str, DeclType, *this); return false; } - + // C++ [dcl.init]p14: // -- If the destination type is a (possibly cv-qualified) class // type: if (getLangOptions().CPlusPlus && DeclType->isRecordType()) { QualType DeclTypeC = Context.getCanonicalType(DeclType); QualType InitTypeC = Context.getCanonicalType(Init->getType()); - + // -- If the initialization is direct-initialization, or if it is // copy-initialization where the cv-unqualified version of the // source type is the same class as, or a derived class of, the // class of the destination, constructors are considered. if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) || IsDerivedFrom(InitTypeC, DeclTypeC)) { - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(DeclType->getAsRecordType()->getDecl()); - + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->getDecl()); + // No need to make a CXXConstructExpr if both the ctor and dtor are // trivial. if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor()) return false; - - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(DeclType, &Init, 1, - InitLoc, Init->getSourceRange(), - InitEntity, - DirectInit? IK_Direct : IK_Copy); + + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(DeclType, + MultiExprArg(*this, + (void **)&Init, 1), + InitLoc, Init->getSourceRange(), + InitEntity, + DirectInit? IK_Direct : IK_Copy, + ConstructorArgs); if (!Constructor) return true; - - Init = CXXConstructExpr::Create(Context, DeclType, Constructor, false, - &Init, 1); + + OwningExprResult InitResult = + BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), + DeclType, Constructor, + move_arg(ConstructorArgs)); + if (InitResult.isInvalid()) + return true; + + Init = InitResult.takeAs<Expr>(); return false; } - + // -- Otherwise (i.e., for the remaining copy-initialization // cases), user-defined conversion sequences that can // convert from the source type to the destination type or @@ -197,7 +224,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, // have ASTs for such things. if (!PerformImplicitConversion(Init, DeclType, "initializing")) return false; - + if (InitEntity) return Diag(InitLoc, diag::err_cannot_initialize_decl) << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid) @@ -206,15 +233,15 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid) << Init->getType() << Init->getSourceRange(); } - + // C99 6.7.8p16. if (DeclType->isArrayType()) return Diag(Init->getLocStart(), diag::err_array_init_list_required) << Init->getSourceRange(); - + return CheckSingleInitializer(Init, DeclType, DirectInit, *this); - } - + } + bool hadError = CheckInitList(InitList, DeclType); Init = InitList; return hadError; @@ -257,8 +284,8 @@ class InitListChecker { bool hadError; std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic; InitListExpr *FullyStructuredList; - - void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, + + void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); @@ -266,41 +293,41 @@ class InitListChecker { unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); - void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, - bool SubobjectIsDesignatorContext, + void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, + bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); - void CheckSubElementType(InitListExpr *IList, QualType ElemType, + void CheckSubElementType(InitListExpr *IList, QualType ElemType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - void CheckScalarType(InitListExpr *IList, QualType DeclType, + void CheckScalarType(InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - void CheckReferenceType(InitListExpr *IList, QualType DeclType, + void CheckReferenceType(InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, - RecordDecl::field_iterator Field, + void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, + RecordDecl::field_iterator Field, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); - void CheckArrayType(InitListExpr *IList, QualType &DeclType, - llvm::APSInt elementIndex, + void CheckArrayType(InitListExpr *IList, QualType &DeclType, + llvm::APSInt elementIndex, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, + bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, unsigned DesigIdx, - QualType &CurrentObjectType, + QualType &CurrentObjectType, RecordDecl::field_iterator *NextField, llvm::APSInt *NextElementIndex, unsigned &Index, @@ -334,15 +361,15 @@ public: /// with expressions that perform value-initialization of the /// appropriate type. void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { - assert((ILE->getType() != SemaRef.Context.VoidTy) && + assert((ILE->getType() != SemaRef.Context.VoidTy) && "Should not have void type"); SourceLocation Loc = ILE->getSourceRange().getBegin(); if (ILE->getSyntacticForm()) Loc = ILE->getSyntacticForm()->getSourceRange().getBegin(); - - if (const RecordType *RType = ILE->getType()->getAsRecordType()) { + + if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { unsigned Init = 0, NumInits = ILE->getNumInits(); - for (RecordDecl::field_iterator + for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(), FieldEnd = RType->getDecl()->field_end(); Field != FieldEnd; ++Field) { @@ -354,11 +381,11 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { // C++ [dcl.init.aggr]p9: // If an incomplete or empty initializer-list leaves a // member of reference type uninitialized, the program is - // ill-formed. + // ill-formed. SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) << Field->getType() << ILE->getSyntacticForm()->getSourceRange(); - SemaRef.Diag(Field->getLocation(), + SemaRef.Diag(Field->getLocation(), diag::note_uninit_reference_member); hadError = true; return; @@ -371,9 +398,9 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { // we make that call explicit in the representation (even when it means // extending the initializer list)? if (Init < NumInits && !hadError) - ILE->setInit(Init, + ILE->setInit(Init, new (SemaRef.Context) ImplicitValueInitExpr(Field->getType())); - } else if (InitListExpr *InnerILE + } else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init))) FillInValueInitializations(InnerILE); ++Init; @@ -384,22 +411,22 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { } return; - } + } QualType ElementType; - + unsigned NumInits = ILE->getNumInits(); unsigned NumElements = NumInits; if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) { ElementType = AType->getElementType(); if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) NumElements = CAType->getSize().getZExtValue(); - } else if (const VectorType *VType = ILE->getType()->getAsVectorType()) { + } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) { ElementType = VType->getElementType(); NumElements = VType->getNumElements(); - } else + } else ElementType = ILE->getType(); - + for (unsigned Init = 0; Init != NumElements; ++Init) { if (Init >= NumInits || !ILE->getInit(Init)) { if (SemaRef.CheckValueInitialization(ElementType, Loc)) { @@ -411,10 +438,10 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { // we make that call explicit in the representation (even when it means // extending the initializer list)? if (Init < NumInits && !hadError) - ILE->setInit(Init, + ILE->setInit(Init, new (SemaRef.Context) ImplicitValueInitExpr(ElementType)); - } - else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init))) + } else if (InitListExpr *InnerILE + = dyn_cast<InitListExpr>(ILE->getInit(Init))) FillInValueInitializations(InnerILE); } } @@ -426,7 +453,7 @@ InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T) unsigned newIndex = 0; unsigned newStructuredIndex = 0; - FullyStructuredList + FullyStructuredList = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange()); CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex, /*TopLevelObject=*/true); @@ -446,9 +473,9 @@ int InitListChecker::numArrayElements(QualType DeclType) { } int InitListChecker::numStructUnionElements(QualType DeclType) { - RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl(); + RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl(); int InitializableMembers = 0; - for (RecordDecl::field_iterator + for (RecordDecl::field_iterator Field = structDecl->field_begin(), FieldEnd = structDecl->field_end(); Field != FieldEnd; ++Field) { @@ -460,19 +487,19 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { return InitializableMembers - structDecl->hasFlexibleArrayMember(); } -void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, +void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject) { int maxElements = 0; - + if (T->isArrayType()) maxElements = numArrayElements(T); else if (T->isStructureType() || T->isUnionType()) maxElements = numStructUnionElements(T); else if (T->isVectorType()) - maxElements = T->getAsVectorType()->getNumElements(); + maxElements = T->getAs<VectorType>()->getNumElements(); else assert(0 && "CheckImplicitInitList(): Illegal type"); @@ -486,8 +513,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, // Build a structured initializer list corresponding to this subobject. InitListExpr *StructuredSubobjectInitList - = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList, - StructuredIndex, + = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList, + StructuredIndex, SourceRange(ParentIList->getInit(Index)->getSourceRange().getBegin(), ParentIList->getSourceRange().getEnd())); unsigned StructuredSubobjectInitIndex = 0; @@ -495,7 +522,7 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, // Check the element types and build the structural subobject. unsigned StartIndex = Index; CheckListElementTypes(ParentIList, T, false, Index, - StructuredSubobjectInitList, + StructuredSubobjectInitList, StructuredSubobjectInitIndex, TopLevelObject); unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1); @@ -504,7 +531,7 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, // Update the structured sub-object initializer so that it's ending // range corresponds with the end of the last initializer it used. if (EndIndex < ParentIList->getNumInits()) { - SourceLocation EndLoc + SourceLocation EndLoc = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); StructuredSubobjectInitList->setRBraceLoc(EndLoc); } @@ -518,7 +545,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); SyntacticToSemantic[IList] = StructuredList; StructuredList->setSyntacticForm(IList); - CheckListElementTypes(IList, T, true, Index, StructuredList, + CheckListElementTypes(IList, T, true, Index, StructuredList, StructuredIndex, TopLevelObject); IList->setType(T); StructuredList->setType(T); @@ -541,7 +568,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, // Don't complain for incomplete types, since we'll get an error // elsewhere QualType CurrentObjectType = StructuredList->getType(); - int initKind = + int initKind = CurrentObjectType->isArrayType()? 0 : CurrentObjectType->isVectorType()? 1 : CurrentObjectType->isScalarType()? 2 : @@ -553,6 +580,10 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, DK = diag::err_excess_initializers; hadError = true; } + if (SemaRef.getLangOptions().OpenCL && initKind == 1) { + DK = diag::err_excess_initializers; + hadError = true; + } SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK) << initKind << IList->getInit(Index)->getSourceRange(); @@ -567,7 +598,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, } void InitListChecker::CheckListElementTypes(InitListExpr *IList, - QualType &DeclType, + QualType &DeclType, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, @@ -579,8 +610,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isAggregateType()) { if (DeclType->isRecordType()) { - RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); - CheckStructUnionTypes(IList, DeclType, RD->field_begin(), + RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + CheckStructUnionTypes(IList, DeclType, RD->field_begin(), SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex, TopLevelObject); @@ -590,8 +621,7 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, false); CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex); - } - else + } else assert(0 && "Aggregate that isn't a structure or array?!"); } else if (DeclType->isVoidType() || DeclType->isFunctionType()) { // This type is invalid, issue a diagnostic. @@ -615,13 +645,13 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex); } else { // In C, all types are either scalars or aggregates, but - // additional handling is needed here for C++ (and possibly others?). + // additional handling is needed here for C++ (and possibly others?). assert(0 && "Unsupported initializer type"); } } void InitListChecker::CheckSubElementType(InitListExpr *IList, - QualType ElemType, + QualType ElemType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { @@ -629,11 +659,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) { unsigned newIndex = 0; unsigned newStructuredIndex = 0; - InitListExpr *newStructuredList + InitListExpr *newStructuredList = getStructuredSubobjectInit(IList, Index, ElemType, StructuredList, StructuredIndex, SubInitList->getSourceRange()); - CheckExplicitInitList(SubInitList, ElemType, newIndex, + CheckExplicitInitList(SubInitList, ElemType, newIndex, newStructuredList, newStructuredIndex); ++StructuredIndex; ++Index; @@ -652,10 +682,14 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, // initializing the aggregate member with an ini- tializer from // an initializer-list. If the initializer can initialize a // member, the member is initialized. [...] - ImplicitConversionSequence ICS - = SemaRef.TryCopyInitialization(expr, ElemType); + ImplicitConversionSequence ICS + = SemaRef.TryCopyInitialization(expr, ElemType, + /*SuppressUserConversions=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) { - if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, + if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, "initializing")) hadError = true; UpdateStructuredListElement(StructuredList, StructuredIndex, expr); @@ -665,7 +699,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, // Fall through for subaggregate initialization } else { - // C99 6.7.8p13: + // C99 6.7.8p13: // // The initializer for a structure or union object that has // automatic storage duration shall be either an initializer @@ -684,13 +718,13 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, } // C++ [dcl.init.aggr]p12: - // + // // [...] Otherwise, if the member is itself a non-empty // subaggregate, brace elision is assumed and the initializer is // considered for the initialization of the first member of // the subaggregate. if (ElemType->isAggregateType() || ElemType->isVectorType()) { - CheckImplicitInitList(IList, ElemType, Index, StructuredList, + CheckImplicitInitList(IList, ElemType, Index, StructuredList, StructuredIndex); ++StructuredIndex; } else { @@ -719,7 +753,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType, ++StructuredIndex; return; } else if (isa<DesignatedInitExpr>(expr)) { - SemaRef.Diag(expr->getSourceRange().getBegin(), + SemaRef.Diag(expr->getSourceRange().getBegin(), diag::err_designator_for_scalar_init) << DeclType << expr->getSourceRange(); hadError = true; @@ -763,10 +797,14 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType, ++Index; ++StructuredIndex; return; - } + } Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. - if (SemaRef.CheckReferenceInit(expr, DeclType)) + if (SemaRef.CheckReferenceInit(expr, DeclType, + /*FIXME:*/expr->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false)) hadError = true; else if (savExpr != expr) { // The type was promoted, update initializer list. @@ -782,7 +820,7 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType, // general, it would be useful to pass location information down the stack, // so that we know the location (or decl) of the "current object" being // initialized. - SemaRef.Diag(IList->getLocStart(), + SemaRef.Diag(IList->getLocStart(), diag::err_init_reference_member_uninitialized) << DeclType << IList->getSourceRange(); @@ -793,28 +831,59 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType, } } -void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, +void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { if (Index < IList->getNumInits()) { - const VectorType *VT = DeclType->getAsVectorType(); - int maxElements = VT->getNumElements(); + const VectorType *VT = DeclType->getAs<VectorType>(); + unsigned maxElements = VT->getNumElements(); + unsigned numEltsInit = 0; QualType elementType = VT->getElementType(); - - for (int i = 0; i < maxElements; ++i) { - // Don't attempt to go past the end of the init list - if (Index >= IList->getNumInits()) - break; - CheckSubElementType(IList, elementType, Index, - StructuredList, StructuredIndex); + + if (!SemaRef.getLangOptions().OpenCL) { + for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) { + // Don't attempt to go past the end of the init list + if (Index >= IList->getNumInits()) + break; + CheckSubElementType(IList, elementType, Index, + StructuredList, StructuredIndex); + } + } else { + // OpenCL initializers allows vectors to be constructed from vectors. + for (unsigned i = 0; i < maxElements; ++i) { + // Don't attempt to go past the end of the init list + if (Index >= IList->getNumInits()) + break; + QualType IType = IList->getInit(Index)->getType(); + if (!IType->isVectorType()) { + CheckSubElementType(IList, elementType, Index, + StructuredList, StructuredIndex); + ++numEltsInit; + } else { + const VectorType *IVT = IType->getAs<VectorType>(); + unsigned numIElts = IVT->getNumElements(); + QualType VecType = SemaRef.Context.getExtVectorType(elementType, + numIElts); + CheckSubElementType(IList, VecType, Index, + StructuredList, StructuredIndex); + numEltsInit += numIElts; + } + } } + + // OpenCL & AltiVec require all elements to be initialized. + if (numEltsInit != maxElements) + if (SemaRef.getLangOptions().OpenCL || SemaRef.getLangOptions().AltiVec) + SemaRef.Diag(IList->getSourceRange().getBegin(), + diag::err_vector_incorrect_num_initializers) + << (numEltsInit < maxElements) << maxElements << numEltsInit; } } -void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, +void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, llvm::APSInt elementIndex, - bool SubobjectIsDesignatorContext, + bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { @@ -873,7 +942,7 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, // Handle this designated initializer. elementIndex will be // updated to be the next array element we'll initialize. - if (CheckDesignatedInitializer(IList, DIE, 0, + if (CheckDesignatedInitializer(IList, DIE, 0, DeclType, 0, &elementIndex, Index, StructuredList, StructuredIndex, true, false)) { @@ -921,31 +990,31 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, diag::ext_typecheck_zero_array_size); } - DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements, + DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements, ArrayType::Normal, 0); } } -void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, - QualType DeclType, +void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, + QualType DeclType, RecordDecl::field_iterator Field, - bool SubobjectIsDesignatorContext, + bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject) { - RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl(); - + RecordDecl* structDecl = DeclType->getAs<RecordType>()->getDecl(); + // If the record is invalid, some of it's members are invalid. To avoid // confusion, we forgo checking the intializer for the entire record. if (structDecl->isInvalidDecl()) { hadError = true; return; - } + } if (DeclType->isUnionType() && IList->getNumInits() == 0) { // Value-initialize the first named member of the union. - RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { if (Field->getDeclName()) { @@ -960,7 +1029,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, // anything except look at designated initializers; That's okay, // because an error should get printed out elsewhere. It might be // worthwhile to skip over the rest of the initializer, though. - RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator FieldEnd = RD->field_end(); bool InitializedSomething = false; while (Index < IList->getNumInits()) { @@ -975,7 +1044,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, // Handle this designated initializer. Field will be updated to // the next field that we'll be initializing. - if (CheckDesignatedInitializer(IList, DIE, 0, + if (CheckDesignatedInitializer(IList, DIE, 0, DeclType, &Field, 0, Index, StructuredList, StructuredIndex, true, TopLevelObject)) @@ -1016,15 +1085,15 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, ++Field; } - if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() || + if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() || Index >= IList->getNumInits()) return; // Handle GNU flexible array initializers. - if (!TopLevelObject && + if (!TopLevelObject && (!isa<InitListExpr>(IList->getInit(Index)) || cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) { - SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), + SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), diag::err_flexible_array_init_nonempty) << IList->getInit(Index)->getSourceRange().getBegin(); SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) @@ -1033,7 +1102,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, ++Index; return; } else { - SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), + SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), diag::ext_flexible_array_init) << IList->getInit(Index)->getSourceRange().getBegin(); SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) @@ -1055,8 +1124,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, /// Field/FieldIndex will be updated to point to the (new) /// currently-designated field. static void ExpandAnonymousFieldDesignator(Sema &SemaRef, - DesignatedInitExpr *DIE, - unsigned DesigIdx, + DesignatedInitExpr *DIE, + unsigned DesigIdx, FieldDecl *Field, RecordDecl::field_iterator &FieldIter, unsigned &FieldIndex) { @@ -1066,14 +1135,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, // anonymous struct/union (backwards). llvm::SmallVector<FieldDecl *, 4> Path; SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path); - + // Build the replacement designators. llvm::SmallVector<Designator, 4> Replacements; for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator FI = Path.rbegin(), FIEnd = Path.rend(); FI != FIEnd; ++FI) { if (FI + 1 == FIEnd) - Replacements.push_back(Designator((IdentifierInfo *)0, + Replacements.push_back(Designator((IdentifierInfo *)0, DIE->getDesignator(DesigIdx)->getDotLoc(), DIE->getDesignator(DesigIdx)->getFieldLoc())); else @@ -1085,9 +1154,9 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, // Expand the current designator into the set of replacement // designators, so we have a full subobject path down to where the // member of the anonymous struct/union is actually stored. - DIE->ExpandDesignator(DesigIdx, &Replacements[0], + DIE->ExpandDesignator(DesigIdx, &Replacements[0], &Replacements[0] + Replacements.size()); - + // Update FieldIter/FieldIndex; RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext()); FieldIter = Record->field_begin(); @@ -1112,7 +1181,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, /// resides at the given @p Index within the initializer list @p /// IList, is well-formed for a current object of type @p DeclType /// (C99 6.7.8). The actual subobject that this designator refers to -/// within the current subobject is returned in either +/// within the current subobject is returned in either /// @p NextField or @p NextElementIndex (whichever is appropriate). /// /// @param IList The initializer list in which this designated @@ -1141,9 +1210,9 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, /// actually be initialized. /// /// @returns true if there was an error, false otherwise. -bool +bool InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, - DesignatedInitExpr *DIE, + DesignatedInitExpr *DIE, unsigned DesigIdx, QualType &CurrentObjectType, RecordDecl::field_iterator *NextField, @@ -1176,14 +1245,14 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, } bool IsFirstDesignator = (DesigIdx == 0); - assert((IsFirstDesignator || StructuredList) && + assert((IsFirstDesignator || StructuredList) && "Need a non-designated initializer list to start from"); DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx); // Determine the structural initializer list that corresponds to the // current subobject. StructuredList = IsFirstDesignator? SyntacticToSemantic[IList] - : getStructuredSubobjectInit(IList, Index, CurrentObjectType, + : getStructuredSubobjectInit(IList, Index, CurrentObjectType, StructuredList, StructuredIndex, SourceRange(D->getStartLocation(), DIE->getSourceRange().getEnd())); @@ -1198,8 +1267,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // // then the current object (defined below) shall have // structure or union type and the identifier shall be the - // name of a member of that type. - const RecordType *RT = CurrentObjectType->getAsRecordType(); + // name of a member of that type. + const RecordType *RT = CurrentObjectType->getAs<RecordType>(); if (!RT) { SourceLocation Loc = D->getDotLoc(); if (Loc.isInvalid()) @@ -1216,7 +1285,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, FieldDecl *KnownField = D->getField(); IdentifierInfo *FieldName = D->getFieldName(); unsigned FieldIndex = 0; - RecordDecl::field_iterator + RecordDecl::field_iterator Field = RT->getDecl()->field_begin(), FieldEnd = RT->getDecl()->field_end(); for (; Field != FieldEnd; ++Field) { @@ -1234,7 +1303,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // name. Perform another lookup for this name, which may find // something that we can't designate (e.g., a member function), // may find nothing, or may find a member of an anonymous - // struct/union. + // struct/union. DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); if (Lookup.first == Lookup.second) { // Name lookup didn't find anything. @@ -1247,7 +1316,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, ->isAnonymousStructOrUnion()) { // Handle an field designator that refers to a member of an // anonymous struct or union. - ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, + ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, cast<FieldDecl>(*Lookup.first), Field, FieldIndex); D = DIE->getDesignator(DesigIdx); @@ -1255,7 +1324,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // Name lookup found something, but it wasn't a field. SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) << FieldName; - SemaRef.Diag((*Lookup.first)->getLocation(), + SemaRef.Diag((*Lookup.first)->getLocation(), diag::note_field_designator_found); ++Index; return true; @@ -1277,7 +1346,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // Update the designator with the field declaration. D->setField(*Field); - + // Make sure that our non-designated initializer list has space // for a subobject corresponding to this field. if (FieldIndex >= StructuredList->getNumInits()) @@ -1289,11 +1358,11 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, if ((DesigIdx + 1) != DIE->size()) { // We can't designate an object within the flexible array // member (because GCC doesn't allow it). - DesignatedInitExpr::Designator *NextD + DesignatedInitExpr::Designator *NextD = DIE->getDesignator(DesigIdx + 1); - SemaRef.Diag(NextD->getStartLocation(), + SemaRef.Diag(NextD->getStartLocation(), diag::err_designator_into_flexible_array_member) - << SourceRange(NextD->getStartLocation(), + << SourceRange(NextD->getStartLocation(), DIE->getSourceRange().getEnd()); SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) << *Field; @@ -1311,9 +1380,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, } // Handle GNU flexible array initializers. - if (!Invalid && !TopLevelObject && + if (!Invalid && !TopLevelObject && cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) { - SemaRef.Diag(DIE->getSourceRange().getBegin(), + SemaRef.Diag(DIE->getSourceRange().getBegin(), diag::err_flexible_array_init_nonempty) << DIE->getSourceRange().getBegin(); SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) @@ -1331,7 +1400,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, unsigned newStructuredIndex = FieldIndex; unsigned OldIndex = Index; IList->setInit(Index, DIE->getInit()); - CheckSubElementType(IList, Field->getType(), Index, + CheckSubElementType(IList, Field->getType(), Index, StructuredList, newStructuredIndex); IList->setInit(OldIndex, DIE); if (hadError && !prevHadError) { @@ -1412,10 +1481,10 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, } else { assert(D->isArrayRangeDesignator() && "Need array-range designator"); - - DesignatedStartIndex = + + DesignatedStartIndex = DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context); - DesignatedEndIndex = + DesignatedEndIndex = DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context); IndexExpr = DIE->getArrayRangeEnd(*D); @@ -1447,11 +1516,11 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, DesignatedStartIndex.setIsUnsigned(true); DesignatedEndIndex.setIsUnsigned(true); } - + // Make sure that our non-designated initializer list has space // for a subobject corresponding to this array element. if (DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) - StructuredList->resizeInits(SemaRef.Context, + StructuredList->resizeInits(SemaRef.Context, DesignatedEndIndex.getZExtValue() + 1); // Repeatedly perform subobject initializations in the range @@ -1483,7 +1552,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, StructuredIndex = ElementIndex; return false; } - + if (!FinishSubobjectInit) return false; @@ -1491,7 +1560,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, bool prevHadError = hadError; CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index, StructuredList, ElementIndex); - return hadError && !prevHadError; + return hadError && !prevHadError; } // Get the structured initializer list for a subobject of type @@ -1507,7 +1576,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, ExistingInit = SyntacticToSemantic[IList]; else if (StructuredIndex < StructuredList->getNumInits()) ExistingInit = StructuredList->getInit(StructuredIndex); - + if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit)) return Result; @@ -1516,24 +1585,24 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, // subobjects of the current object, but there was already an // initialization that completely initialized the current // subobject, e.g., by a compound literal: - // + // // struct X { int a, b; }; // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 }; - // + // // Here, xs[0].a == 0 and xs[0].b == 3, since the second, // designated initializer re-initializes the whole // subobject [0], overwriting previous initializers. - SemaRef.Diag(InitRange.getBegin(), + SemaRef.Diag(InitRange.getBegin(), diag::warn_subobject_initializer_overrides) << InitRange; - SemaRef.Diag(ExistingInit->getSourceRange().getBegin(), + SemaRef.Diag(ExistingInit->getSourceRange().getBegin(), diag::note_previous_initializer) << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange(); } - InitListExpr *Result - = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0, + InitListExpr *Result + = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0, InitRange.getEnd()); Result->setType(CurrentObjectType); @@ -1548,7 +1617,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, NumInits = SubList->getNumInits(); } - if (const ArrayType *AType + if (const ArrayType *AType = SemaRef.Context.getAsArrayType(CurrentObjectType)) { if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) { NumElements = CAType->getSize().getZExtValue(); @@ -1557,14 +1626,14 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, if (NumInits && NumElements > NumInits) NumElements = 0; } - } else if (const VectorType *VType = CurrentObjectType->getAsVectorType()) + } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) NumElements = VType->getNumElements(); - else if (const RecordType *RType = CurrentObjectType->getAsRecordType()) { + else if (const RecordType *RType = CurrentObjectType->getAs<RecordType>()) { RecordDecl *RDecl = RType->getDecl(); if (RDecl->isUnion()) NumElements = 1; else - NumElements = std::distance(RDecl->field_begin(), + NumElements = std::distance(RDecl->field_begin(), RDecl->field_end()); } @@ -1596,15 +1665,15 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) { // This initializer overwrites a previous initializer. Warn. - SemaRef.Diag(expr->getSourceRange().getBegin(), + SemaRef.Diag(expr->getSourceRange().getBegin(), diag::warn_initializer_overrides) << expr->getSourceRange(); - SemaRef.Diag(PrevInit->getSourceRange().getBegin(), + SemaRef.Diag(PrevInit->getSourceRange().getBegin(), diag::note_previous_initializer) << /*FIXME:has side effects=*/0 << PrevInit->getSourceRange(); } - + ++StructuredIndex; } @@ -1615,7 +1684,7 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, /// failure. Returns true if there was an error, false otherwise. If /// everything went okay, Value will receive the value of the constant /// expression. -static bool +static bool CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) { SourceLocation Loc = Index->getSourceRange().getBegin(); @@ -1646,7 +1715,7 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, const Designator &D = Desig.getDesignator(Idx); switch (D.getKind()) { case Designator::FieldDesignator: - Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(), + Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(), D.getFieldLoc())); break; @@ -1659,7 +1728,7 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, Invalid = true; else { Designators.push_back(ASTDesignator(InitExpressions.size(), - D.getLBracketLoc(), + D.getLBracketLoc(), D.getRBracketLoc())); InitExpressions.push_back(Index); } @@ -1691,12 +1760,12 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, if (!StartDependent && !EndDependent && EndValue < StartValue) { Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range) - << StartValue.toString(10) << EndValue.toString(10) + << StartValue.toString(10) << EndValue.toString(10) << StartIndex->getSourceRange() << EndIndex->getSourceRange(); Invalid = true; } else { Designators.push_back(ASTDesignator(InitExpressions.size(), - D.getLBracketLoc(), + D.getLBracketLoc(), D.getEllipsisLoc(), D.getRBracketLoc())); InitExpressions.push_back(StartIndex); @@ -1741,7 +1810,7 @@ bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) { /// accessible, non-deleted default constructor. In C, everything can /// be value-initialized, which corresponds to C's notion of /// initializing objects with static storage duration when no -/// initializer is provided for that object. +/// initializer is provided for that object. /// /// \returns true if there was an error, false otherwise. bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { @@ -1753,19 +1822,34 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { if (const ArrayType *AT = Context.getAsArrayType(Type)) return CheckValueInitialization(AT->getElementType(), Loc); - if (const RecordType *RT = Type->getAsRecordType()) { + if (const RecordType *RT = Type->getAs<RecordType>()) { if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { // -- if T is a class type (clause 9) with a user-declared // constructor (12.1), then the default constructor for T is // called (and the initialization is ill-formed if T has no // accessible default constructor); - if (ClassDecl->hasUserDeclaredConstructor()) - // FIXME: Eventually, we'll need to put the constructor decl into the - // AST. - return PerformInitializationByConstructor(Type, 0, 0, Loc, - SourceRange(Loc), - DeclarationName(), - IK_Direct); + if (ClassDecl->hasUserDeclaredConstructor()) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(Type, + MultiExprArg(*this, 0, 0), + Loc, SourceRange(Loc), + DeclarationName(), + IK_Direct, + ConstructorArgs); + if (!Constructor) + return true; + + OwningExprResult Init + = BuildCXXConstructExpr(Loc, Type, Constructor, + move_arg(ConstructorArgs)); + if (Init.isInvalid()) + return true; + + // FIXME: Actually perform the value-initialization! + return false; + } } } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 6f2fc5e0c434b..dd877c16fba79 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -12,18 +12,20 @@ // //===----------------------------------------------------------------------===// #include "Sema.h" -#include "SemaInherit.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/Parse/DeclSpec.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/ErrorHandling.h" #include <set> #include <vector> #include <iterator> @@ -34,7 +36,6 @@ using namespace clang; typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy; typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet; -typedef llvm::SmallVector<Sema::LookupResult, 3> LookupResultsTy; /// UsingDirAncestorCompare - Implements strict weak ordering of /// UsingDirectives. It orders them by address of its common ancestor. @@ -59,7 +60,7 @@ struct UsingDirAncestorCompare { /// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs /// (ordered by common ancestors), found in namespace NS, /// including all found (recursively) in their nominated namespaces. -void AddNamespaceUsingDirectives(ASTContext &Context, +void AddNamespaceUsingDirectives(ASTContext &Context, DeclContext *NS, UsingDirectivesTy &UDirs, NamespaceSet &Visited) { @@ -76,7 +77,7 @@ void AddNamespaceUsingDirectives(ASTContext &Context, /// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S, /// including all found in the namespaces they nominate. -static void AddScopeUsingDirectives(ASTContext &Context, Scope *S, +static void AddScopeUsingDirectives(ASTContext &Context, Scope *S, UsingDirectivesTy &UDirs) { NamespaceSet VisitedNS; @@ -99,189 +100,17 @@ static void AddScopeUsingDirectives(ASTContext &Context, Scope *S, NamespaceDecl *Nominated = UD->getNominatedNamespace(); if (!VisitedNS.count(Nominated)) { VisitedNS.insert(Nominated); - AddNamespaceUsingDirectives(Context, Nominated, UDirs, + AddNamespaceUsingDirectives(Context, Nominated, UDirs, /*ref*/ VisitedNS); } } } } -/// MaybeConstructOverloadSet - Name lookup has determined that the -/// elements in [I, IEnd) have the name that we are looking for, and -/// *I is a match for the namespace. This routine returns an -/// appropriate Decl for name lookup, which may either be *I or an -/// OverloadedFunctionDecl that represents the overloaded functions in -/// [I, IEnd). -/// -/// The existance of this routine is temporary; users of LookupResult -/// should be able to handle multiple results, to deal with cases of -/// ambiguity and overloaded functions without needing to create a -/// Decl node. -template<typename DeclIterator> -static NamedDecl * -MaybeConstructOverloadSet(ASTContext &Context, - DeclIterator I, DeclIterator IEnd) { - assert(I != IEnd && "Iterator range cannot be empty"); - assert(!isa<OverloadedFunctionDecl>(*I) && - "Cannot have an overloaded function"); - - if ((*I)->isFunctionOrFunctionTemplate()) { - // If we found a function, there might be more functions. If - // so, collect them into an overload set. - DeclIterator Last = I; - OverloadedFunctionDecl *Ovl = 0; - for (++Last; - Last != IEnd && (*Last)->isFunctionOrFunctionTemplate(); - ++Last) { - if (!Ovl) { - // FIXME: We leak this overload set. Eventually, we want to stop - // building the declarations for these overload sets, so there will be - // nothing to leak. - Ovl = OverloadedFunctionDecl::Create(Context, (*I)->getDeclContext(), - (*I)->getDeclName()); - NamedDecl *ND = (*I)->getUnderlyingDecl(); - if (isa<FunctionDecl>(ND)) - Ovl->addOverload(cast<FunctionDecl>(ND)); - else - Ovl->addOverload(cast<FunctionTemplateDecl>(ND)); - } - - NamedDecl *ND = (*Last)->getUnderlyingDecl(); - if (isa<FunctionDecl>(ND)) - Ovl->addOverload(cast<FunctionDecl>(ND)); - else - Ovl->addOverload(cast<FunctionTemplateDecl>(ND)); - } - - // If we had more than one function, we built an overload - // set. Return it. - if (Ovl) - return Ovl; - } - - return *I; -} - -/// Merges together multiple LookupResults dealing with duplicated Decl's. -static Sema::LookupResult -MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) { - typedef Sema::LookupResult LResult; - typedef llvm::SmallPtrSet<NamedDecl*, 4> DeclsSetTy; - - // Remove duplicated Decl pointing at same Decl, by storing them in - // associative collection. This might be case for code like: - // - // namespace A { int i; } - // namespace B { using namespace A; } - // namespace C { using namespace A; } - // - // void foo() { - // using namespace B; - // using namespace C; - // ++i; // finds A::i, from both namespace B and C at global scope - // } - // - // C++ [namespace.qual].p3: - // The same declaration found more than once is not an ambiguity - // (because it is still a unique declaration). - DeclsSetTy FoundDecls; - - // Counter of tag names, and functions for resolving ambiguity - // and name hiding. - std::size_t TagNames = 0, Functions = 0, OrdinaryNonFunc = 0; - - LookupResultsTy::iterator I = Results.begin(), End = Results.end(); - - // No name lookup results, return early. - if (I == End) return LResult::CreateLookupResult(Context, 0); - - // Keep track of the tag declaration we found. We only use this if - // we find a single tag declaration. - TagDecl *TagFound = 0; - - for (; I != End; ++I) { - switch (I->getKind()) { - case LResult::NotFound: - assert(false && - "Should be always successful name lookup result here."); - break; - - case LResult::AmbiguousReference: - case LResult::AmbiguousBaseSubobjectTypes: - case LResult::AmbiguousBaseSubobjects: - assert(false && "Shouldn't get ambiguous lookup here."); - break; - - case LResult::Found: { - NamedDecl *ND = I->getAsDecl()->getUnderlyingDecl(); - - if (TagDecl *TD = dyn_cast<TagDecl>(ND)) { - TagFound = Context.getCanonicalDecl(TD); - TagNames += FoundDecls.insert(TagFound)? 1 : 0; - } else if (ND->isFunctionOrFunctionTemplate()) - Functions += FoundDecls.insert(ND)? 1 : 0; - else - FoundDecls.insert(ND); - break; - } - - case LResult::FoundOverloaded: - for (LResult::iterator FI = I->begin(), FEnd = I->end(); FI != FEnd; ++FI) - Functions += FoundDecls.insert(*FI)? 1 : 0; - break; - } - } - OrdinaryNonFunc = FoundDecls.size() - TagNames - Functions; - bool Ambiguous = false, NameHidesTags = false; - - if (FoundDecls.size() == 1) { - // 1) Exactly one result. - } else if (TagNames > 1) { - // 2) Multiple tag names (even though they may be hidden by an - // object name). - Ambiguous = true; - } else if (FoundDecls.size() - TagNames == 1) { - // 3) Ordinary name hides (optional) tag. - NameHidesTags = TagFound; - } else if (Functions) { - // C++ [basic.lookup].p1: - // ... Name lookup may associate more than one declaration with - // a name if it finds the name to be a function name; the declarations - // are said to form a set of overloaded functions (13.1). - // Overload resolution (13.3) takes place after name lookup has succeeded. - // - if (!OrdinaryNonFunc) { - // 4) Functions hide tag names. - NameHidesTags = TagFound; - } else { - // 5) Functions + ordinary names. - Ambiguous = true; - } - } else { - // 6) Multiple non-tag names - Ambiguous = true; - } - - if (Ambiguous) - return LResult::CreateLookupResult(Context, - FoundDecls.begin(), FoundDecls.size()); - if (NameHidesTags) { - // There's only one tag, TagFound. Remove it. - assert(TagFound && FoundDecls.count(TagFound) && "No tag name found?"); - FoundDecls.erase(TagFound); - } - - // Return successful name lookup result. - return LResult::CreateLookupResult(Context, - MaybeConstructOverloadSet(Context, - FoundDecls.begin(), - FoundDecls.end())); -} - // Retrieve the set of identifier namespaces that correspond to a // specific kind of name lookup. -inline unsigned -getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, +inline unsigned +getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, bool CPlusPlus) { unsigned IDNS = 0; switch (NameKind) { @@ -300,7 +129,7 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, case Sema::LookupMemberName: IDNS = Decl::IDNS_Member; if (CPlusPlus) - IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary; + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary; break; case Sema::LookupNestedNameSpecifierName: @@ -323,97 +152,81 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, return IDNS; } -Sema::LookupResult -Sema::LookupResult::CreateLookupResult(ASTContext &Context, NamedDecl *D) { - if (D) - D = D->getUnderlyingDecl(); - - LookupResult Result; - Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))? - OverloadedDeclSingleDecl : SingleDecl; - Result.First = reinterpret_cast<uintptr_t>(D); - Result.Last = 0; - Result.Context = &Context; - return Result; +// Necessary because CXXBasePaths is not complete in Sema.h +void Sema::LookupResult::deletePaths(CXXBasePaths *Paths) { + delete Paths; } -/// @brief Moves the name-lookup results from Other to this LookupResult. -Sema::LookupResult -Sema::LookupResult::CreateLookupResult(ASTContext &Context, - IdentifierResolver::iterator F, - IdentifierResolver::iterator L) { - LookupResult Result; - Result.Context = &Context; - - if (F != L && (*F)->isFunctionOrFunctionTemplate()) { - IdentifierResolver::iterator Next = F; - ++Next; - if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) { - Result.StoredKind = OverloadedDeclFromIdResolver; - Result.First = F.getAsOpaqueValue(); - Result.Last = L.getAsOpaqueValue(); - return Result; - } - } - - NamedDecl *D = *F; - if (D) - D = D->getUnderlyingDecl(); - - Result.StoredKind = SingleDecl; - Result.First = reinterpret_cast<uintptr_t>(D); - Result.Last = 0; - return Result; -} - -Sema::LookupResult -Sema::LookupResult::CreateLookupResult(ASTContext &Context, - DeclContext::lookup_iterator F, - DeclContext::lookup_iterator L) { - LookupResult Result; - Result.Context = &Context; - - if (F != L && (*F)->isFunctionOrFunctionTemplate()) { - DeclContext::lookup_iterator Next = F; - ++Next; - if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) { - Result.StoredKind = OverloadedDeclFromDeclContext; - Result.First = reinterpret_cast<uintptr_t>(F); - Result.Last = reinterpret_cast<uintptr_t>(L); - return Result; - } - } +void Sema::LookupResult::resolveKind() { + unsigned N = Decls.size(); - NamedDecl *D = *F; - if (D) - D = D->getUnderlyingDecl(); - - Result.StoredKind = SingleDecl; - Result.First = reinterpret_cast<uintptr_t>(D); - Result.Last = 0; - return Result; -} + // Fast case: no possible ambiguity. + if (N <= 1) return; -/// @brief Determine the result of name lookup. -Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const { - switch (StoredKind) { - case SingleDecl: - return (reinterpret_cast<Decl *>(First) != 0)? Found : NotFound; + // Don't do any extra resolution if we've already resolved as ambiguous. + if (Kind == Ambiguous) return; - case OverloadedDeclSingleDecl: - case OverloadedDeclFromIdResolver: - case OverloadedDeclFromDeclContext: - return FoundOverloaded; + llvm::SmallPtrSet<NamedDecl*, 16> Unique; - case AmbiguousLookupStoresBasePaths: - return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects; + bool Ambiguous = false; + bool HasTag = false, HasFunction = false, HasNonFunction = false; - case AmbiguousLookupStoresDecls: - return AmbiguousReference; + unsigned UniqueTagIndex = 0; + + unsigned I = 0; + while (I < N) { + NamedDecl *D = Decls[I]; + assert(D == D->getUnderlyingDecl()); + + NamedDecl *CanonD = cast<NamedDecl>(D->getCanonicalDecl()); + if (!Unique.insert(CanonD)) { + // If it's not unique, pull something off the back (and + // continue at this index). + Decls[I] = Decls[--N]; + } else if (isa<UnresolvedUsingDecl>(D)) { + // FIXME: proper support for UnresolvedUsingDecls. + Decls[I] = Decls[--N]; + } else { + // Otherwise, do some decl type analysis and then continue. + if (isa<TagDecl>(D)) { + if (HasTag) + Ambiguous = true; + UniqueTagIndex = I; + HasTag = true; + } else if (D->isFunctionOrFunctionTemplate()) { + HasFunction = true; + } else { + if (HasNonFunction) + Ambiguous = true; + HasNonFunction = true; + } + I++; + } } - // We can't ever get here. - return NotFound; + // C++ [basic.scope.hiding]p2: + // A class name or enumeration name can be hidden by the name of + // an object, function, or enumerator declared in the same + // scope. If a class or enumeration name and an object, function, + // or enumerator are declared in the same scope (in any order) + // with the same name, the class or enumeration name is hidden + // wherever the object, function, or enumerator name is visible. + // But it's still an error if there are distinct tag types found, + // even if they're not visible. (ref?) + if (HasTag && !Ambiguous && (HasFunction || HasNonFunction)) + Decls[UniqueTagIndex] = Decls[--N]; + + Decls.set_size(N); + + if (HasFunction && HasNonFunction) + Ambiguous = true; + + if (Ambiguous) + setAmbiguous(LookupResult::AmbiguousReference); + else if (N > 1) + Kind = LookupResult::FoundOverloaded; + else + Kind = LookupResult::Found; } /// @brief Converts the result of name lookup into a single (possible @@ -423,197 +236,99 @@ Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const { /// (if only a single declaration was found), an /// OverloadedFunctionDecl (if an overloaded function was found), or /// NULL (if no declaration was found). This conversion must not be -/// used anywhere where name lookup could result in an ambiguity. +/// used anywhere where name lookup could result in an ambiguity. /// /// The OverloadedFunctionDecl conversion is meant as a stop-gap /// solution, since it causes the OverloadedFunctionDecl to be /// leaked. FIXME: Eventually, there will be a better way to iterate /// over the set of overloaded functions returned by name lookup. -NamedDecl *Sema::LookupResult::getAsDecl() const { - switch (StoredKind) { - case SingleDecl: - return reinterpret_cast<NamedDecl *>(First); - - case OverloadedDeclFromIdResolver: - return MaybeConstructOverloadSet(*Context, - IdentifierResolver::iterator::getFromOpaqueValue(First), - IdentifierResolver::iterator::getFromOpaqueValue(Last)); - - case OverloadedDeclFromDeclContext: - return MaybeConstructOverloadSet(*Context, - reinterpret_cast<DeclContext::lookup_iterator>(First), - reinterpret_cast<DeclContext::lookup_iterator>(Last)); - - case OverloadedDeclSingleDecl: - return reinterpret_cast<OverloadedFunctionDecl*>(First); - - case AmbiguousLookupStoresDecls: - case AmbiguousLookupStoresBasePaths: - assert(false && - "Name lookup returned an ambiguity that could not be handled"); - break; +NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const { + size_t size = Decls.size(); + if (size == 0) return 0; + if (size == 1) return *begin(); + + if (isAmbiguous()) return 0; + + iterator I = begin(), E = end(); + + OverloadedFunctionDecl *Ovl + = OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(), + (*I)->getDeclName()); + for (; I != E; ++I) { + NamedDecl *ND = *I; + assert(ND->getUnderlyingDecl() == ND + && "decls in lookup result should have redirections stripped"); + assert(ND->isFunctionOrFunctionTemplate()); + if (isa<FunctionDecl>(ND)) + Ovl->addOverload(cast<FunctionDecl>(ND)); + else + Ovl->addOverload(cast<FunctionTemplateDecl>(ND)); + // FIXME: UnresolvedUsingDecls. } - - return 0; + + return Ovl; } -/// @brief Retrieves the BasePaths structure describing an ambiguous -/// name lookup, or null. -BasePaths *Sema::LookupResult::getBasePaths() const { - if (StoredKind == AmbiguousLookupStoresBasePaths) - return reinterpret_cast<BasePaths *>(First); - return 0; +void Sema::LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { + CXXBasePaths::paths_iterator I, E; + DeclContext::lookup_iterator DI, DE; + for (I = P.begin(), E = P.end(); I != E; ++I) + for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI) + addDecl(*DI); } -Sema::LookupResult::iterator::reference -Sema::LookupResult::iterator::operator*() const { - switch (Result->StoredKind) { - case SingleDecl: - return reinterpret_cast<NamedDecl*>(Current); - - case OverloadedDeclSingleDecl: - return *reinterpret_cast<NamedDecl**>(Current); - - case OverloadedDeclFromIdResolver: - return *IdentifierResolver::iterator::getFromOpaqueValue(Current); - - case AmbiguousLookupStoresBasePaths: - if (Result->Last) - return *reinterpret_cast<NamedDecl**>(Current); - - // Fall through to handle the DeclContext::lookup_iterator we're - // storing. - - case OverloadedDeclFromDeclContext: - case AmbiguousLookupStoresDecls: - return *reinterpret_cast<DeclContext::lookup_iterator>(Current); - } - - return 0; +void Sema::LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) { + Paths = new CXXBasePaths; + Paths->swap(P); + addDeclsFromBasePaths(*Paths); + resolveKind(); + setAmbiguous(AmbiguousBaseSubobjects); } -Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() { - switch (Result->StoredKind) { - case SingleDecl: - Current = reinterpret_cast<uintptr_t>((NamedDecl*)0); - break; - - case OverloadedDeclSingleDecl: { - NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current); - ++I; - Current = reinterpret_cast<uintptr_t>(I); - break; - } - - case OverloadedDeclFromIdResolver: { - IdentifierResolver::iterator I - = IdentifierResolver::iterator::getFromOpaqueValue(Current); - ++I; - Current = I.getAsOpaqueValue(); - break; - } - - case AmbiguousLookupStoresBasePaths: - if (Result->Last) { - NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current); - ++I; - Current = reinterpret_cast<uintptr_t>(I); - break; - } - // Fall through to handle the DeclContext::lookup_iterator we're - // storing. - - case OverloadedDeclFromDeclContext: - case AmbiguousLookupStoresDecls: { - DeclContext::lookup_iterator I - = reinterpret_cast<DeclContext::lookup_iterator>(Current); - ++I; - Current = reinterpret_cast<uintptr_t>(I); - break; - } - } - - return *this; +void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { + Paths = new CXXBasePaths; + Paths->swap(P); + addDeclsFromBasePaths(*Paths); + resolveKind(); + setAmbiguous(AmbiguousBaseSubobjectTypes); } -Sema::LookupResult::iterator Sema::LookupResult::begin() { - switch (StoredKind) { - case SingleDecl: - case OverloadedDeclFromIdResolver: - case OverloadedDeclFromDeclContext: - case AmbiguousLookupStoresDecls: - return iterator(this, First); - - case OverloadedDeclSingleDecl: { - OverloadedFunctionDecl * Ovl = - reinterpret_cast<OverloadedFunctionDecl*>(First); - return iterator(this, - reinterpret_cast<uintptr_t>(&(*Ovl->function_begin()))); - } - - case AmbiguousLookupStoresBasePaths: - if (Last) - return iterator(this, - reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_begin())); - else - return iterator(this, - reinterpret_cast<uintptr_t>(getBasePaths()->front().Decls.first)); +void Sema::LookupResult::print(llvm::raw_ostream &Out) { + Out << Decls.size() << " result(s)"; + if (isAmbiguous()) Out << ", ambiguous"; + if (Paths) Out << ", base paths present"; + + for (iterator I = begin(), E = end(); I != E; ++I) { + Out << "\n"; + (*I)->print(Out, 2); } - - // Required to suppress GCC warning. - return iterator(); } -Sema::LookupResult::iterator Sema::LookupResult::end() { - switch (StoredKind) { - case SingleDecl: - case OverloadedDeclFromIdResolver: - case OverloadedDeclFromDeclContext: - case AmbiguousLookupStoresDecls: - return iterator(this, Last); - - case OverloadedDeclSingleDecl: { - OverloadedFunctionDecl * Ovl = - reinterpret_cast<OverloadedFunctionDecl*>(First); - return iterator(this, - reinterpret_cast<uintptr_t>(&(*Ovl->function_end()))); - } - - case AmbiguousLookupStoresBasePaths: - if (Last) - return iterator(this, - reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_end())); - else - return iterator(this, reinterpret_cast<uintptr_t>( - getBasePaths()->front().Decls.second)); - } +// Adds all qualifying matches for a name within a decl context to the +// given lookup result. Returns true if any matches were found. +static bool LookupDirect(Sema::LookupResult &R, DeclContext *DC, + DeclarationName Name, + Sema::LookupNameKind NameKind, + unsigned IDNS) { + bool Found = false; - // Required to suppress GCC warning. - return iterator(); -} + DeclContext::lookup_iterator I, E; + for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I) + if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS)) + R.addDecl(*I), Found = true; -void Sema::LookupResult::Destroy() { - if (BasePaths *Paths = getBasePaths()) - delete Paths; - else if (getKind() == AmbiguousReference) - delete[] reinterpret_cast<NamedDecl **>(First); + return Found; } -static void -CppNamespaceLookup(ASTContext &Context, DeclContext *NS, +static bool +CppNamespaceLookup(Sema::LookupResult &R, ASTContext &Context, DeclContext *NS, DeclarationName Name, Sema::LookupNameKind NameKind, - unsigned IDNS, LookupResultsTy &Results, - UsingDirectivesTy *UDirs = 0) { + unsigned IDNS, UsingDirectivesTy *UDirs = 0) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); // Perform qualified name lookup into the LookupCtx. - DeclContext::lookup_iterator I, E; - for (llvm::tie(I, E) = NS->lookup(Name); I != E; ++I) - if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS)) { - Results.push_back(Sema::LookupResult::CreateLookupResult(Context, I, E)); - break; - } + bool Found = LookupDirect(R, NS, Name, NameKind, IDNS); if (UDirs) { // For each UsingDirectiveDecl, which common ancestor is equal @@ -622,11 +337,15 @@ CppNamespaceLookup(ASTContext &Context, DeclContext *NS, llvm::tie(UI, UEnd) = std::equal_range(UDirs->begin(), UDirs->end(), NS, UsingDirAncestorCompare()); - + for (; UI != UEnd; ++UI) - CppNamespaceLookup(Context, (*UI)->getNominatedNamespace(), - Name, NameKind, IDNS, Results); + if (LookupDirect(R, (*UI)->getNominatedNamespace(), Name, NameKind, IDNS)) + Found = true; } + + R.resolveKind(); + + return Found; } static bool isNamespaceOrTranslationUnitScope(Scope *S) { @@ -635,16 +354,31 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { return false; } -std::pair<bool, Sema::LookupResult> -Sema::CppLookupName(Scope *S, DeclarationName Name, +// Find the next outer declaration context corresponding to this scope. +static DeclContext *findOuterContext(Scope *S) { + for (S = S->getParent(); S; S = S->getParent()) + if (S->getEntity()) + return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext(); + + return 0; +} + +bool +Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, LookupNameKind NameKind, bool RedeclarationOnly) { assert(getLangOptions().CPlusPlus && "Can perform only C++ lookup"); - unsigned IDNS + unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true); + + // If we're testing for redeclarations, also look in the friend namespaces. + if (RedeclarationOnly) { + if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend; + if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend; + } + Scope *Initial = S; - DeclContext *OutOfLineCtx = 0; - IdentifierResolver::iterator + IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); @@ -653,8 +387,8 @@ Sema::CppLookupName(Scope *S, DeclarationName Name, // ...During unqualified name lookup (3.4.1), the names appear as if // they were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. - // [Note: in this context, “contains” means “contains directly or - // indirectly”. + // [Note: in this context, "contains" means "contains directly or + // indirectly". // // For example: // namespace A { int i; } @@ -668,47 +402,33 @@ Sema::CppLookupName(Scope *S, DeclarationName Name, // for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { // Check whether the IdResolver has anything in this scope. + bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { if (isAcceptableLookupResult(*I, NameKind, IDNS)) { - // We found something. Look for anything else in our scope - // with this same name and in an acceptable identifier - // namespace, so that we can construct an overload set if we - // need to. - IdentifierResolver::iterator LastI = I; - for (++LastI; LastI != IEnd; ++LastI) { - if (!S->isDeclScope(DeclPtrTy::make(*LastI))) - break; - } - LookupResult Result = - LookupResult::CreateLookupResult(Context, I, LastI); - return std::make_pair(true, Result); + Found = true; + R.addDecl(*I); } } + if (Found) { + R.resolveKind(); + return true; + } + if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { - LookupResult R; - // Perform member lookup into struct. - // FIXME: In some cases, we know that every name that could be found by - // this qualified name lookup will also be on the identifier chain. For - // example, inside a class without any base classes, we never need to - // perform qualified lookup because all of the members are on top of the - // identifier chain. - if (isa<RecordDecl>(Ctx)) { - R = LookupQualifiedName(Ctx, Name, NameKind, RedeclarationOnly); - if (R) - return std::make_pair(true, R); - } - if (Ctx->getParent() != Ctx->getLexicalParent() - || isa<CXXMethodDecl>(Ctx)) { - // It is out of line defined C++ method or struct, we continue - // doing name lookup in parent context. Once we will find namespace - // or translation-unit we save it for possible checking - // using-directives later. - for (OutOfLineCtx = Ctx; OutOfLineCtx && !OutOfLineCtx->isFileContext(); - OutOfLineCtx = OutOfLineCtx->getParent()) { - R = LookupQualifiedName(OutOfLineCtx, Name, NameKind, RedeclarationOnly); - if (R) - return std::make_pair(true, R); - } + DeclContext *OuterCtx = findOuterContext(S); + for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; + Ctx = Ctx->getLookupParent()) { + if (Ctx->isFunctionOrMethod()) + continue; + + // Perform qualified name lookup into this context. + // FIXME: In some cases, we know that every name that could be found by + // this qualified name lookup will also be on the identifier chain. For + // example, inside a class without any base classes, we never need to + // perform qualified lookup because all of the members are on top of the + // identifier chain. + if (LookupQualifiedName(R, Ctx, Name, NameKind, RedeclarationOnly)) + return true; } } } @@ -731,71 +451,41 @@ Sema::CppLookupName(Scope *S, DeclarationName Name, // that aren't strictly lexical, and therefore we walk through the // context as well as walking through the scopes. - LookupResultsTy LookupResults; - assert((!OutOfLineCtx || OutOfLineCtx->isFileContext()) && - "We should have been looking only at file context here already."); - bool LookedInCtx = false; - LookupResult Result; - while (OutOfLineCtx && - OutOfLineCtx != S->getEntity() && - OutOfLineCtx->isNamespace()) { - LookedInCtx = true; - - // Look into context considering using-directives. - CppNamespaceLookup(Context, OutOfLineCtx, Name, NameKind, IDNS, - LookupResults, &UDirs); - - if ((Result = MergeLookupResults(Context, LookupResults)) || - (RedeclarationOnly && !OutOfLineCtx->isTransparentContext())) - return std::make_pair(true, Result); - - OutOfLineCtx = OutOfLineCtx->getParent(); - } - for (; S; S = S->getParent()) { DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); + if (Ctx->isTransparentContext()) + continue; + assert(Ctx && Ctx->isFileContext() && "We should have been looking only at file context here already."); // Check whether the IdResolver has anything in this scope. + bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { if (isAcceptableLookupResult(*I, NameKind, IDNS)) { // We found something. Look for anything else in our scope // with this same name and in an acceptable identifier // namespace, so that we can construct an overload set if we // need to. - IdentifierResolver::iterator LastI = I; - for (++LastI; LastI != IEnd; ++LastI) { - if (!S->isDeclScope(DeclPtrTy::make(*LastI))) - break; - } - - // We store name lookup result, and continue trying to look into - // associated context, and maybe namespaces nominated by - // using-directives. - LookupResults.push_back( - LookupResult::CreateLookupResult(Context, I, LastI)); - break; + Found = true; + R.addDecl(*I); } } - LookedInCtx = true; // Look into context considering using-directives. - CppNamespaceLookup(Context, Ctx, Name, NameKind, IDNS, - LookupResults, &UDirs); + if (CppNamespaceLookup(R, Context, Ctx, Name, NameKind, IDNS, &UDirs)) + Found = true; - if ((Result = MergeLookupResults(Context, LookupResults)) || - (RedeclarationOnly && !Ctx->isTransparentContext())) - return std::make_pair(true, Result); - } + if (Found) { + R.resolveKind(); + return true; + } - if (!(LookedInCtx || LookupResults.empty())) { - // We didn't Performed lookup in Scope entity, so we return - // result form IdentifierResolver. - assert((LookupResults.size() == 1) && "Wrong size!"); - return std::make_pair(true, LookupResults.front()); + if (RedeclarationOnly && !Ctx->isTransparentContext()) + return false; } - return std::make_pair(false, LookupResult()); + + return !R.empty(); } /// @brief Perform unqualified name lookup starting from a given @@ -823,17 +513,16 @@ Sema::CppLookupName(Scope *S, DeclarationName Name, /// @param Name The name of the entity that we are searching for. /// /// @param Loc If provided, the source location where we're performing -/// name lookup. At present, this is only used to produce diagnostics when +/// name lookup. At present, this is only used to produce diagnostics when /// C library functions (like "malloc") are implicitly declared. /// /// @returns The result of name lookup, which includes zero or more /// declarations and possibly additional information used to diagnose /// ambiguities. -Sema::LookupResult -Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, - bool RedeclarationOnly, bool AllowBuiltinCreation, - SourceLocation Loc) { - if (!Name) return LookupResult::CreateLookupResult(Context, 0); +bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name, + LookupNameKind NameKind, bool RedeclarationOnly, + bool AllowBuiltinCreation, SourceLocation Loc) { + if (!Name) return false; if (!getLangOptions().CPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so @@ -861,7 +550,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, case Sema::LookupRedeclarationWithLinkage: // Find the nearest non-transparent declaration scope. while (!(S->getFlags() & Scope::DeclScope) || - (S->getEntity() && + (S->getEntity() && static_cast<DeclContext *>(S->getEntity()) ->isTransparentContext())) S = S->getParent(); @@ -875,7 +564,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, case Sema::LookupObjCImplementationName: IDNS = Decl::IDNS_ObjCImplementation; break; - + case Sema::LookupObjCCategoryImplName: IDNS = Decl::IDNS_ObjCCategoryImpl; break; @@ -888,7 +577,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, bool LeftStartingScope = false; for (IdentifierResolver::iterator I = IdResolver.begin(Name), - IEnd = IdResolver.end(); + IEnd = IdResolver.end(); I != IEnd; ++I) if ((*I)->isInIdentifierNamespace(IDNS)) { if (NameKind == LookupRedeclarationWithLinkage) { @@ -903,6 +592,8 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, continue; } + R.addDecl(*I); + if ((*I)->getAttr<OverloadableAttr>()) { // If this declaration has the "overloadable" attribute, we // might have a set of overloaded functions. @@ -918,26 +609,24 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, for (++LastI; LastI != IEnd; ++LastI) { if (!S->isDeclScope(DeclPtrTy::make(*LastI))) break; + R.addDecl(*LastI); } - - return LookupResult::CreateLookupResult(Context, I, LastI); } - // We have a single lookup result. - return LookupResult::CreateLookupResult(Context, *I); + R.resolveKind(); + + return true; } } else { // Perform C++ unqualified name lookup. - std::pair<bool, LookupResult> MaybeResult = - CppLookupName(S, Name, NameKind, RedeclarationOnly); - if (MaybeResult.first) - return MaybeResult.second; + if (CppLookupName(R, S, Name, NameKind, RedeclarationOnly)) + return true; } // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. - if (NameKind == LookupOrdinaryName || + if (NameKind == LookupOrdinaryName || NameKind == LookupRedeclarationWithLinkage) { IdentifierInfo *II = Name.getAsIdentifierInfo(); if (II && AllowBuiltinCreation) { @@ -945,17 +634,132 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, if (unsigned BuiltinID = II->getBuiltinID()) { // In C++, we don't have any predefined library functions like // 'malloc'. Instead, we'll just error. - if (getLangOptions().CPlusPlus && + if (getLangOptions().CPlusPlus && Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - return LookupResult::CreateLookupResult(Context, 0); + return false; + + NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, + S, RedeclarationOnly, Loc); + if (D) R.addDecl(D); + return (D != NULL); + } + } + } + return false; +} + +/// @brief Perform qualified name lookup in the namespaces nominated by +/// using directives by the given context. +/// +/// C++98 [namespace.qual]p2: +/// Given X::m (where X is a user-declared namespace), or given ::m +/// (where X is the global namespace), let S be the set of all +/// declarations of m in X and in the transitive closure of all +/// namespaces nominated by using-directives in X and its used +/// namespaces, except that using-directives are ignored in any +/// namespace, including X, directly containing one or more +/// declarations of m. No namespace is searched more than once in +/// the lookup of a name. If S is the empty set, the program is +/// ill-formed. Otherwise, if S has exactly one member, or if the +/// context of the reference is a using-declaration +/// (namespace.udecl), S is the required set of declarations of +/// m. Otherwise if the use of m is not one that allows a unique +/// declaration to be chosen from S, the program is ill-formed. +/// C++98 [namespace.qual]p5: +/// During the lookup of a qualified namespace member name, if the +/// lookup finds more than one declaration of the member, and if one +/// declaration introduces a class name or enumeration name and the +/// other declarations either introduce the same object, the same +/// enumerator or a set of functions, the non-type name hides the +/// class or enumeration name if and only if the declarations are +/// from the same namespace; otherwise (the declarations are from +/// different namespaces), the program is ill-formed. +static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R, + DeclContext *StartDC, + DeclarationName Name, + Sema::LookupNameKind NameKind, + unsigned IDNS) { + assert(StartDC->isFileContext() && "start context is not a file context"); + + DeclContext::udir_iterator I = StartDC->using_directives_begin(); + DeclContext::udir_iterator E = StartDC->using_directives_end(); + + if (I == E) return false; + + // We have at least added all these contexts to the queue. + llvm::DenseSet<DeclContext*> Visited; + Visited.insert(StartDC); + + // We have not yet looked into these namespaces, much less added + // their "using-children" to the queue. + llvm::SmallVector<NamespaceDecl*, 8> Queue; + + // We have already looked into the initial namespace; seed the queue + // with its using-children. + for (; I != E; ++I) { + NamespaceDecl *ND = (*I)->getNominatedNamespace(); + if (Visited.insert(ND).second) + Queue.push_back(ND); + } + + // The easiest way to implement the restriction in [namespace.qual]p5 + // is to check whether any of the individual results found a tag + // and, if so, to declare an ambiguity if the final result is not + // a tag. + bool FoundTag = false; + bool FoundNonTag = false; + + Sema::LookupResult LocalR; + + bool Found = false; + while (!Queue.empty()) { + NamespaceDecl *ND = Queue.back(); + Queue.pop_back(); + + // We go through some convolutions here to avoid copying results + // between LookupResults. + bool UseLocal = !R.empty(); + Sema::LookupResult &DirectR = UseLocal ? LocalR : R; + bool FoundDirect = LookupDirect(DirectR, ND, Name, NameKind, IDNS); + + if (FoundDirect) { + // First do any local hiding. + DirectR.resolveKind(); + + // If the local result is a tag, remember that. + if (DirectR.isSingleTagDecl()) + FoundTag = true; + else + FoundNonTag = true; - return LookupResult::CreateLookupResult(Context, - LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, - S, RedeclarationOnly, Loc)); + // Append the local results to the total results if necessary. + if (UseLocal) { + R.addAllDecls(LocalR); + LocalR.clear(); } } + + // If we find names in this namespace, ignore its using directives. + if (FoundDirect) { + Found = true; + continue; + } + + for (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) { + NamespaceDecl *Nom = (*I)->getNominatedNamespace(); + if (Visited.insert(Nom).second) + Queue.push_back(Nom); + } } - return LookupResult::CreateLookupResult(Context, 0); + + if (Found) { + if (FoundTag && FoundNonTag) + R.setAmbiguousQualifiedTagHiding(); + else + R.resolveKind(); + } + + return Found; } /// @brief Perform qualified name lookup into a given context. @@ -988,40 +792,91 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, /// @returns The result of name lookup, which includes zero or more /// declarations and possibly additional information used to diagnose /// ambiguities. -Sema::LookupResult -Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, - LookupNameKind NameKind, bool RedeclarationOnly) { +bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + DeclarationName Name, LookupNameKind NameKind, + bool RedeclarationOnly) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); - - if (!Name) return LookupResult::CreateLookupResult(Context, 0); + + if (!Name) + return false; // If we're performing qualified name lookup (e.g., lookup into a // struct), find fields as part of ordinary name lookup. unsigned IDNS - = getIdentifierNamespacesFromLookupNameKind(NameKind, + = getIdentifierNamespacesFromLookupNameKind(NameKind, getLangOptions().CPlusPlus); if (NameKind == LookupOrdinaryName) IDNS |= Decl::IDNS_Member; + // Make sure that the declaration context is complete. + assert((!isa<TagDecl>(LookupCtx) || + LookupCtx->isDependentContext() || + cast<TagDecl>(LookupCtx)->isDefinition() || + Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>() + ->isBeingDefined()) && + "Declaration context must already be complete!"); + // Perform qualified name lookup into the LookupCtx. - DeclContext::lookup_iterator I, E; - for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I) - if (isAcceptableLookupResult(*I, NameKind, IDNS)) - return LookupResult::CreateLookupResult(Context, I, E); + if (LookupDirect(R, LookupCtx, Name, NameKind, IDNS)) { + R.resolveKind(); + return true; + } + + // Don't descend into implied contexts for redeclarations. + // C++98 [namespace.qual]p6: + // In a declaration for a namespace member in which the + // declarator-id is a qualified-id, given that the qualified-id + // for the namespace member has the form + // nested-name-specifier unqualified-id + // the unqualified-id shall name a member of the namespace + // designated by the nested-name-specifier. + // See also [class.mfct]p5 and [class.static.data]p2. + if (RedeclarationOnly) + return false; - // If this isn't a C++ class or we aren't allowed to look into base + // If this is a namespace, look it up in + if (LookupCtx->isFileContext()) + return LookupQualifiedNameInUsingDirectives(R, LookupCtx, Name, NameKind, + IDNS); + + // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. - if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx)) - return LookupResult::CreateLookupResult(Context, 0); + if (!isa<CXXRecordDecl>(LookupCtx)) + return false; // Perform lookup into our base classes. - BasePaths Paths; - Paths.setOrigin(Context.getTypeDeclType(cast<RecordDecl>(LookupCtx))); + CXXRecordDecl *LookupRec = cast<CXXRecordDecl>(LookupCtx); + CXXBasePaths Paths; + Paths.setOrigin(LookupRec); // Look for this member in our base classes - if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx), - MemberLookupCriteria(Name, NameKind, IDNS), Paths)) - return LookupResult::CreateLookupResult(Context, 0); + CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0; + switch (NameKind) { + case LookupOrdinaryName: + case LookupMemberName: + case LookupRedeclarationWithLinkage: + BaseCallback = &CXXRecordDecl::FindOrdinaryMember; + break; + + case LookupTagName: + BaseCallback = &CXXRecordDecl::FindTagMember; + break; + + case LookupOperatorName: + case LookupNamespaceName: + case LookupObjCProtocolName: + case LookupObjCImplementationName: + case LookupObjCCategoryImplName: + // These lookups will never find a member in a C++ class (or base class). + return false; + + case LookupNestedNameSpecifierName: + BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember; + break; + } + + if (!LookupRec->lookupInBases(BaseCallback, Name.getAsOpaquePtr(), Paths)) + return false; // C++ [class.member.lookup]p2: // [...] If the resulting set of declarations are not all from @@ -1032,29 +887,28 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; - for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); + for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { - const BasePathElement &PathElement = Path->back(); + const CXXBasePathElement &PathElement = Path->back(); // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { - // This is the first subobject we've looked at. Record it's type. + // This is the first subobject we've looked at. Record its type. SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); SubobjectNumber = PathElement.SubobjectNumber; - } else if (SubobjectType + } else if (SubobjectType != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of // different types. This lookup is ambiguous. - BasePaths *PathsOnHeap = new BasePaths; - PathsOnHeap->swap(Paths); - return LookupResult::CreateLookupResult(Context, PathsOnHeap, true); + R.setAmbiguousBaseSubobjectTypes(Paths); + return true; } else if (SubobjectNumber != PathElement.SubobjectNumber) { // We have a different subobject of the same type. // C++ [class.member.lookup]p5: // A static member, a nested type or an enumerator defined in // a base class T can unambiguously be found even if an object - // has more than one base class subobject of type T. + // has more than one base class subobject of type T. Decl *FirstDecl = *Path->Decls.first; if (isa<VarDecl>(FirstDecl) || isa<TypeDecl>(FirstDecl) || @@ -1083,21 +937,18 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, // We have found a nonstatic member name in multiple, distinct // subobjects. Name lookup is ambiguous. - BasePaths *PathsOnHeap = new BasePaths; - PathsOnHeap->swap(Paths); - return LookupResult::CreateLookupResult(Context, PathsOnHeap, false); + R.setAmbiguousBaseSubobjects(Paths); + return true; } } // Lookup in a base class succeeded; return these results. - // If we found a function declaration, return an overload set. - if ((*Paths.front().Decls.first)->isFunctionOrFunctionTemplate()) - return LookupResult::CreateLookupResult(Context, - Paths.front().Decls.first, Paths.front().Decls.second); - - // We found a non-function declaration; return a single declaration. - return LookupResult::CreateLookupResult(Context, *Paths.front().Decls.first); + DeclContext::lookup_iterator I, E; + for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) + R.addDecl(*I); + R.resolveKind(); + return true; } /// @brief Performs name lookup for a name that was parsed in the @@ -1111,59 +962,50 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, /// /// @param S The scope from which unqualified name lookup will /// begin. -/// -/// @param SS An optional C++ scope-specified, e.g., "::N::M". +/// +/// @param SS An optional C++ scope-specifier, e.g., "::N::M". /// /// @param Name The name of the entity that name lookup will /// search for. /// /// @param Loc If provided, the source location where we're performing -/// name lookup. At present, this is only used to produce diagnostics when +/// name lookup. At present, this is only used to produce diagnostics when /// C library functions (like "malloc") are implicitly declared. /// -/// @returns The result of qualified or unqualified name lookup. -Sema::LookupResult -Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, - DeclarationName Name, LookupNameKind NameKind, - bool RedeclarationOnly, bool AllowBuiltinCreation, - SourceLocation Loc) { - if (SS && (SS->isSet() || SS->isInvalid())) { - // If the scope specifier is invalid, don't even look for +/// @param EnteringContext Indicates whether we are going to enter the +/// context of the scope-specifier SS (if present). +/// +/// @returns True if any decls were found (but possibly ambiguous) +bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, + DeclarationName Name, LookupNameKind NameKind, + bool RedeclarationOnly, bool AllowBuiltinCreation, + SourceLocation Loc, + bool EnteringContext) { + if (SS && SS->isInvalid()) { + // When the scope specifier is invalid, don't even look for // anything. - if (SS->isInvalid()) - return LookupResult::CreateLookupResult(Context, 0); - - assert(!isUnknownSpecialization(*SS) && "Can't lookup dependent types"); - - if (isDependentScopeSpecifier(*SS)) { - // Determine whether we are looking into the current - // instantiation. - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); - CXXRecordDecl *Current = getCurrentInstantiationOf(NNS); - assert(Current && "Bad dependent scope specifier"); - - // We nested name specifier refers to the current instantiation, - // so now we will look for a member of the current instantiation - // (C++0x [temp.dep.type]). - unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, true); - DeclContext::lookup_iterator I, E; - for (llvm::tie(I, E) = Current->lookup(Name); I != E; ++I) - if (isAcceptableLookupResult(*I, NameKind, IDNS)) - return LookupResult::CreateLookupResult(Context, I, E); - } + return false; + } - if (RequireCompleteDeclContext(*SS)) - return LookupResult::CreateLookupResult(Context, 0); + if (SS && SS->isSet()) { + if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { + // We have resolved the scope specifier to a particular declaration + // contex, and will perform name lookup in that context. + if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS)) + return false; - return LookupQualifiedName(computeDeclContext(*SS), - Name, NameKind, RedeclarationOnly); + return LookupQualifiedName(R, DC, Name, NameKind, RedeclarationOnly); + } + + // We could not resolve the scope specified to a specific declaration + // context, which means that SS refers to an unknown specialization. + // Name lookup can't find anything in this case. + return false; } - LookupResult result(LookupName(S, Name, NameKind, RedeclarationOnly, - AllowBuiltinCreation, Loc)); - - return(result); + // Perform unqualified name lookup starting in the given scope. + return LookupName(R, S, Name, NameKind, RedeclarationOnly, + AllowBuiltinCreation, Loc); } @@ -1171,7 +1013,7 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, /// from name lookup. /// /// @param Result The ambiguous name lookup result. -/// +/// /// @param Name The name of the entity that name lookup was /// searching for. /// @@ -1184,79 +1026,164 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, /// /// @returns true bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, - SourceLocation NameLoc, + SourceLocation NameLoc, SourceRange LookupRange) { assert(Result.isAmbiguous() && "Lookup result must be ambiguous"); - if (BasePaths *Paths = Result.getBasePaths()) { - if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) { - QualType SubobjectType = Paths->front().back().Base->getType(); - Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) - << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) - << LookupRange; - - DeclContext::lookup_iterator Found = Paths->front().Decls.first; - while (isa<CXXMethodDecl>(*Found) && - cast<CXXMethodDecl>(*Found)->isStatic()) - ++Found; - - Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); - - Result.Destroy(); - return true; - } - - assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes && - "Unhandled form of name lookup ambiguity"); + switch (Result.getAmbiguityKind()) { + case LookupResult::AmbiguousBaseSubobjects: { + CXXBasePaths *Paths = Result.getBasePaths(); + QualType SubobjectType = Paths->front().back().Base->getType(); + Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) + << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) + << LookupRange; + + DeclContext::lookup_iterator Found = Paths->front().Decls.first; + while (isa<CXXMethodDecl>(*Found) && + cast<CXXMethodDecl>(*Found)->isStatic()) + ++Found; + + Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); + + return true; + } + case LookupResult::AmbiguousBaseSubobjectTypes: { Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) << Name << LookupRange; - + + CXXBasePaths *Paths = Result.getBasePaths(); std::set<Decl *> DeclsPrinted; - for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end(); + for (CXXBasePaths::paths_iterator Path = Paths->begin(), + PathEnd = Paths->end(); Path != PathEnd; ++Path) { Decl *D = *Path->Decls.first; if (DeclsPrinted.insert(D).second) Diag(D->getLocation(), diag::note_ambiguous_member_found); } - Result.Destroy(); return true; - } else if (Result.getKind() == LookupResult::AmbiguousReference) { - Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; + } - NamedDecl **DI = reinterpret_cast<NamedDecl **>(Result.First), - **DEnd = reinterpret_cast<NamedDecl **>(Result.Last); + case LookupResult::AmbiguousTagHiding: { + Diag(NameLoc, diag::err_ambiguous_tag_hiding) << Name << LookupRange; - for (; DI != DEnd; ++DI) - Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI; + llvm::SmallPtrSet<NamedDecl*,8> TagDecls; + + LookupResult::iterator DI, DE = Result.end(); + for (DI = Result.begin(); DI != DE; ++DI) + if (TagDecl *TD = dyn_cast<TagDecl>(*DI)) { + TagDecls.insert(TD); + Diag(TD->getLocation(), diag::note_hidden_tag); + } + + for (DI = Result.begin(); DI != DE; ++DI) + if (!isa<TagDecl>(*DI)) + Diag((*DI)->getLocation(), diag::note_hiding_object); + + // For recovery purposes, go ahead and implement the hiding. + Result.hideDecls(TagDecls); - Result.Destroy(); return true; } - assert(false && "Unhandled form of name lookup ambiguity"); + case LookupResult::AmbiguousReference: { + Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; + + LookupResult::iterator DI = Result.begin(), DE = Result.end(); + for (; DI != DE; ++DI) + Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI; + + return true; + } + } - // We can't reach here. + llvm::llvm_unreachable("unknown ambiguity kind"); return true; } +static void +addAssociatedClassesAndNamespaces(QualType T, + ASTContext &Context, + Sema::AssociatedNamespaceSet &AssociatedNamespaces, + Sema::AssociatedClassSet &AssociatedClasses); + +static void CollectNamespace(Sema::AssociatedNamespaceSet &Namespaces, + DeclContext *Ctx) { + if (Ctx->isFileContext()) + Namespaces.insert(Ctx); +} + +// \brief Add the associated classes and namespaces for argument-dependent +// lookup that involves a template argument (C++ [basic.lookup.koenig]p2). +static void +addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, + ASTContext &Context, + Sema::AssociatedNamespaceSet &AssociatedNamespaces, + Sema::AssociatedClassSet &AssociatedClasses) { + // C++ [basic.lookup.koenig]p2, last bullet: + // -- [...] ; + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Type: + // [...] the namespaces and classes associated with the types of the + // template arguments provided for template type parameters (excluding + // template template parameters) + addAssociatedClassesAndNamespaces(Arg.getAsType(), Context, + AssociatedNamespaces, + AssociatedClasses); + break; + + case TemplateArgument::Declaration: + // [...] the namespaces in which any template template arguments are + // defined; and the classes in which any member templates used as + // template template arguments are defined. + if (ClassTemplateDecl *ClassTemplate + = dyn_cast<ClassTemplateDecl>(Arg.getAsDecl())) { + DeclContext *Ctx = ClassTemplate->getDeclContext(); + if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) + AssociatedClasses.insert(EnclosingClass); + // Add the associated namespace for this class. + while (Ctx->isRecord()) + Ctx = Ctx->getParent(); + CollectNamespace(AssociatedNamespaces, Ctx); + } + break; + + case TemplateArgument::Integral: + case TemplateArgument::Expression: + // [Note: non-type template arguments do not contribute to the set of + // associated namespaces. ] + break; + + case TemplateArgument::Pack: + for (TemplateArgument::pack_iterator P = Arg.pack_begin(), + PEnd = Arg.pack_end(); + P != PEnd; ++P) + addAssociatedClassesAndNamespaces(*P, Context, + AssociatedNamespaces, + AssociatedClasses); + break; + } +} + // \brief Add the associated classes and namespaces for -// argument-dependent lookup with an argument of class type -// (C++ [basic.lookup.koenig]p2). -static void -addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, +// argument-dependent lookup with an argument of class type +// (C++ [basic.lookup.koenig]p2). +static void +addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, ASTContext &Context, Sema::AssociatedNamespaceSet &AssociatedNamespaces, - Sema::AssociatedClassSet &AssociatedClasses, - bool &GlobalScope) { + Sema::AssociatedClassSet &AssociatedClasses) { // C++ [basic.lookup.koenig]p2: // [...] // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a // member, if any; and its direct and indirect base // classes. Its associated namespaces are the namespaces in - // which its associated classes are defined. + // which its associated classes are defined. // Add the class of which it is a member, if any. DeclContext *Ctx = Class->getDeclContext(); @@ -1265,17 +1192,38 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, // Add the associated namespace for this class. while (Ctx->isRecord()) Ctx = Ctx->getParent(); - if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx)) - AssociatedNamespaces.insert(EnclosingNamespace); - else if (Ctx->isTranslationUnit()) - GlobalScope = true; - + CollectNamespace(AssociatedNamespaces, Ctx); + // Add the class itself. If we've already seen this class, we don't // need to visit base classes. if (!AssociatedClasses.insert(Class)) return; - // FIXME: Handle class template specializations + // -- If T is a template-id, its associated namespaces and classes are + // the namespace in which the template is defined; for member + // templates, the member template’s class; the namespaces and classes + // associated with the types of the template arguments provided for + // template type parameters (excluding template template parameters); the + // namespaces in which any template template arguments are defined; and + // the classes in which any member templates used as template template + // arguments are defined. [Note: non-type template arguments do not + // contribute to the set of associated namespaces. ] + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Class)) { + DeclContext *Ctx = Spec->getSpecializedTemplate()->getDeclContext(); + if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) + AssociatedClasses.insert(EnclosingClass); + // Add the associated namespace for this class. + while (Ctx->isRecord()) + Ctx = Ctx->getParent(); + CollectNamespace(AssociatedNamespaces, Ctx); + + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + addAssociatedClassesAndNamespaces(TemplateArgs[I], Context, + AssociatedNamespaces, + AssociatedClasses); + } // Add direct and indirect base classes along with their associated // namespaces. @@ -1290,17 +1238,14 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(), BaseEnd = Class->bases_end(); Base != BaseEnd; ++Base) { - const RecordType *BaseType = Base->getType()->getAsRecordType(); + const RecordType *BaseType = Base->getType()->getAs<RecordType>(); CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); if (AssociatedClasses.insert(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); while (BaseCtx->isRecord()) BaseCtx = BaseCtx->getParent(); - if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx)) - AssociatedNamespaces.insert(EnclosingNamespace); - else if (BaseCtx->isTranslationUnit()) - GlobalScope = true; + CollectNamespace(AssociatedNamespaces, BaseCtx); // Make sure we visit the bases of this base class. if (BaseDecl->bases_begin() != BaseDecl->bases_end()) @@ -1312,13 +1257,12 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, // \brief Add the associated classes and namespaces for // argument-dependent lookup with an argument of type T -// (C++ [basic.lookup.koenig]p2). -static void -addAssociatedClassesAndNamespaces(QualType T, +// (C++ [basic.lookup.koenig]p2). +static void +addAssociatedClassesAndNamespaces(QualType T, ASTContext &Context, Sema::AssociatedNamespaceSet &AssociatedNamespaces, - Sema::AssociatedClassSet &AssociatedClasses, - bool &GlobalScope) { + Sema::AssociatedClassSet &AssociatedClasses) { // C++ [basic.lookup.koenig]p2: // // For each argument type T in the function call, there is a set @@ -1332,44 +1276,43 @@ addAssociatedClassesAndNamespaces(QualType T, T = Context.getCanonicalType(T).getUnqualifiedType(); // -- If T is a pointer to U or an array of U, its associated - // namespaces and classes are those associated with U. + // namespaces and classes are those associated with U. // // We handle this by unwrapping pointer and array types immediately, // to avoid unnecessary recursion. while (true) { - if (const PointerType *Ptr = T->getAsPointerType()) + if (const PointerType *Ptr = T->getAs<PointerType>()) T = Ptr->getPointeeType(); else if (const ArrayType *Ptr = Context.getAsArrayType(T)) T = Ptr->getElementType(); - else + else break; } // -- If T is a fundamental type, its associated sets of // namespaces and classes are both empty. - if (T->getAsBuiltinType()) + if (T->getAs<BuiltinType>()) return; // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a // member, if any; and its direct and indirect base // classes. Its associated namespaces are the namespaces in - // which its associated classes are defined. - if (const RecordType *ClassType = T->getAsRecordType()) - if (CXXRecordDecl *ClassDecl + // which its associated classes are defined. + if (const RecordType *ClassType = T->getAs<RecordType>()) + if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(ClassType->getDecl())) { - addAssociatedClassesAndNamespaces(ClassDecl, Context, - AssociatedNamespaces, - AssociatedClasses, - GlobalScope); + addAssociatedClassesAndNamespaces(ClassDecl, Context, + AssociatedNamespaces, + AssociatedClasses); return; } // -- If T is an enumeration type, its associated namespace is // the namespace in which it is defined. If it is class // member, its associated class is the member’s class; else - // it has no associated class. - if (const EnumType *EnumT = T->getAsEnumType()) { + // it has no associated class. + if (const EnumType *EnumT = T->getAs<EnumType>()) { EnumDecl *Enum = EnumT->getDecl(); DeclContext *Ctx = Enum->getDeclContext(); @@ -1379,10 +1322,7 @@ addAssociatedClassesAndNamespaces(QualType T, // Add the associated namespace for this class. while (Ctx->isRecord()) Ctx = Ctx->getParent(); - if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx)) - AssociatedNamespaces.insert(EnclosingNamespace); - else if (Ctx->isTranslationUnit()) - GlobalScope = true; + CollectNamespace(AssociatedNamespaces, Ctx); return; } @@ -1390,50 +1330,48 @@ addAssociatedClassesAndNamespaces(QualType T, // -- If T is a function type, its associated namespaces and // classes are those associated with the function parameter // types and those associated with the return type. - if (const FunctionType *FunctionType = T->getAsFunctionType()) { + if (const FunctionType *FnType = T->getAs<FunctionType>()) { // Return type - addAssociatedClassesAndNamespaces(FunctionType->getResultType(), + addAssociatedClassesAndNamespaces(FnType->getResultType(), Context, - AssociatedNamespaces, AssociatedClasses, - GlobalScope); + AssociatedNamespaces, AssociatedClasses); - const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FunctionType); + const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType); if (!Proto) return; // Argument types for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), - ArgEnd = Proto->arg_type_end(); + ArgEnd = Proto->arg_type_end(); Arg != ArgEnd; ++Arg) addAssociatedClassesAndNamespaces(*Arg, Context, - AssociatedNamespaces, AssociatedClasses, - GlobalScope); - + AssociatedNamespaces, AssociatedClasses); + return; } // -- If T is a pointer to a member function of a class X, its // associated namespaces and classes are those associated // with the function parameter types and return type, - // together with those associated with X. + // together with those associated with X. // // -- If T is a pointer to a data member of class X, its // associated namespaces and classes are those associated // with the member type together with those associated with - // X. - if (const MemberPointerType *MemberPtr = T->getAsMemberPointerType()) { + // X. + if (const MemberPointerType *MemberPtr = T->getAs<MemberPointerType>()) { // Handle the type that the pointer to member points to. addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(), Context, - AssociatedNamespaces, AssociatedClasses, - GlobalScope); + AssociatedNamespaces, + AssociatedClasses); // Handle the class type into which this points. - if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType()) + if (const RecordType *Class = MemberPtr->getClass()->getAs<RecordType>()) addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()), Context, - AssociatedNamespaces, AssociatedClasses, - GlobalScope); + AssociatedNamespaces, + AssociatedClasses); return; } @@ -1447,13 +1385,12 @@ addAssociatedClassesAndNamespaces(QualType T, /// arguments. /// /// This routine computes the sets of associated classes and associated -/// namespaces searched by argument-dependent lookup +/// namespaces searched by argument-dependent lookup /// (C++ [basic.lookup.argdep]) for a given set of arguments. -void +void Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, - AssociatedClassSet &AssociatedClasses, - bool &GlobalScope) { + AssociatedClassSet &AssociatedClasses) { AssociatedNamespaces.clear(); AssociatedClasses.clear(); @@ -1463,14 +1400,14 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, // associated classes to be considered. The sets of namespaces and // classes is determined entirely by the types of the function // arguments (and the namespace of any template template - // argument). + // argument). for (unsigned ArgIdx = 0; ArgIdx != NumArgs; ++ArgIdx) { Expr *Arg = Args[ArgIdx]; if (Arg->getType() != Context.OverloadTy) { addAssociatedClassesAndNamespaces(Arg->getType(), Context, - AssociatedNamespaces, AssociatedClasses, - GlobalScope); + AssociatedNamespaces, + AssociatedClasses); continue; } @@ -1482,16 +1419,23 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, // classes and namespaces associated with its (non-dependent) // parameter types and return type. DeclRefExpr *DRE = 0; + TemplateIdRefExpr *TIRE = 0; + Arg = Arg->IgnoreParens(); if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) { - if (unaryOp->getOpcode() == UnaryOperator::AddrOf) + if (unaryOp->getOpcode() == UnaryOperator::AddrOf) { DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr()); - } else + TIRE = dyn_cast<TemplateIdRefExpr>(unaryOp->getSubExpr()); + } + } else { DRE = dyn_cast<DeclRefExpr>(Arg); - if (!DRE) - continue; + TIRE = dyn_cast<TemplateIdRefExpr>(Arg); + } - OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl()); + OverloadedFunctionDecl *Ovl = 0; + if (DRE) + Ovl = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl()); + else if (TIRE) + Ovl = TIRE->getTemplateName().getAsOverloadedFunctionDecl(); if (!Ovl) continue; @@ -1506,16 +1450,13 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, // that, if this is a member function, we do *not* consider the // enclosing namespace of its class. DeclContext *Ctx = FDecl->getDeclContext(); - if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx)) - AssociatedNamespaces.insert(EnclosingNamespace); - else if (Ctx->isTranslationUnit()) - GlobalScope = true; + CollectNamespace(AssociatedNamespaces, Ctx); // Add the classes and namespaces associated with the parameter // types and return type of this function. addAssociatedClassesAndNamespaces(FDecl->getType(), Context, - AssociatedNamespaces, AssociatedClasses, - GlobalScope); + AssociatedNamespaces, + AssociatedClasses); } } } @@ -1525,7 +1466,7 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, /// arguments have types T1 (and, if non-empty, T2). This routine /// implements the check in C++ [over.match.oper]p3b2 concerning /// enumeration types. -static bool +static bool IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, QualType T1, QualType T2, ASTContext &Context) { @@ -1535,7 +1476,7 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType())) return true; - const FunctionProtoType *Proto = Fn->getType()->getAsFunctionProtoType(); + const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>(); if (Proto->getNumArgs() < 1) return false; @@ -1561,26 +1502,19 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, /// \brief Find the protocol with the given name, if any. ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { - Decl *D = LookupName(TUScope, II, LookupObjCProtocolName).getAsDecl(); + Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName); return cast_or_null<ObjCProtocolDecl>(D); } -/// \brief Find the Objective-C implementation with the given name, if -/// any. -ObjCImplementationDecl *Sema::LookupObjCImplementation(IdentifierInfo *II) { - Decl *D = LookupName(TUScope, II, LookupObjCImplementationName).getAsDecl(); - return cast_or_null<ObjCImplementationDecl>(D); -} - /// \brief Find the Objective-C category implementation with the given /// name, if any. ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) { - Decl *D = LookupName(TUScope, II, LookupObjCCategoryImplName).getAsDecl(); + Decl *D = LookupSingleName(TUScope, II, LookupObjCCategoryImplName); return cast_or_null<ObjCCategoryImplDecl>(D); } void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, - QualType T1, QualType T2, + QualType T1, QualType T2, FunctionSet &Functions) { // C++ [over.match.oper]p3: // -- The set of non-member candidates is the result of the @@ -1589,17 +1523,18 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, // unqualified function calls (3.4.2) except that all member // functions are ignored. However, if no operand has a class // type, only those non-member functions in the lookup set - // that have a first parameter of type T1 or “reference to - // (possibly cv-qualified) T1”, when T1 is an enumeration + // that have a first parameter of type T1 or "reference to + // (possibly cv-qualified) T1", when T1 is an enumeration // type, or (if there is a right operand) a second parameter - // of type T2 or “reference to (possibly cv-qualified) T2”, + // of type T2 or "reference to (possibly cv-qualified) T2", // when T2 is an enumeration type, are candidate functions. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); - LookupResult Operators = LookupName(S, OpName, LookupOperatorName); - + LookupResult Operators; + LookupName(Operators, S, OpName, LookupOperatorName); + assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous"); - if (!Operators) + if (Operators.empty()) return; for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end(); @@ -1607,10 +1542,10 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) { if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) Functions.insert(FD); // FIXME: canonical FD - } else if (FunctionTemplateDecl *FunTmpl + } else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*Op)) { // FIXME: friend operators? - // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, + // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, // later? if (!FunTmpl->getDeclContext()->isRecord()) Functions.insert(FunTmpl); @@ -1618,6 +1553,14 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, } } +static void CollectFunctionDecl(Sema::FunctionSet &Functions, + Decl *D) { + if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) + Functions.insert(Func); + else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) + Functions.insert(FunTmpl); +} + void Sema::ArgumentDependentLookup(DeclarationName Name, Expr **Args, unsigned NumArgs, FunctionSet &Functions) { @@ -1625,10 +1568,9 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; AssociatedClassSet AssociatedClasses; - bool GlobalScope = false; - FindAssociatedClassesAndNamespaces(Args, NumArgs, - AssociatedNamespaces, AssociatedClasses, - GlobalScope); + FindAssociatedClassesAndNamespaces(Args, NumArgs, + AssociatedNamespaces, + AssociatedClasses); // C++ [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) @@ -1642,8 +1584,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, // Here, we compute Y and add its members to the overloaded // candidate set. for (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(), - NSEnd = AssociatedNamespaces.end(); - NS != NSEnd; ++NS) { + NSEnd = AssociatedNamespaces.end(); + NS != NSEnd; ++NS) { // When considering an associated namespace, the lookup is the // same as the lookup performed when the associated namespace is // used as a qualifier (3.4.3.2) except that: @@ -1651,28 +1593,22 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, // -- Any using-directives in the associated namespace are // ignored. // - // -- FIXME: Any namespace-scope friend functions declared in + // -- Any namespace-scope friend functions declared in // associated classes are visible within their respective // namespaces even if they are not visible during an ordinary // lookup (11.4). DeclContext::lookup_iterator I, E; for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) { - if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*I)) - Functions.insert(Func); - else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*I)) - Functions.insert(FunTmpl); - } - } - - if (GlobalScope) { - DeclContext::lookup_iterator I, E; - for (llvm::tie(I, E) - = Context.getTranslationUnitDecl()->lookup(Name); - I != E; ++I) { - if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*I)) - Functions.insert(Func); - else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*I)) - Functions.insert(FunTmpl); + Decl *D = *I; + // If the only declaration here is an ordinary friend, consider + // it only if it was declared in an associated classes. + if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) { + DeclContext *LexDC = D->getLexicalDeclContext(); + if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) + continue; + } + + CollectFunctionDecl(Functions, D); } } } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 03ac2d9bb73a4..99e7b0811c91f 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -12,23 +12,25 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "SemaInherit.h" #include "clang/Basic/Diagnostic.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/PartialDiagnostic.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include <algorithm> +#include <cstdio> namespace clang { /// GetConversionCategory - Retrieve the implicit conversion /// category corresponding to the given implicit conversion kind. -ImplicitConversionCategory +ImplicitConversionCategory GetConversionCategory(ImplicitConversionKind Kind) { static const ImplicitConversionCategory Category[(int)ICK_Num_Conversion_Kinds] = { @@ -136,10 +138,9 @@ ImplicitConversionRank StandardConversionSequence::getRank() const { /// isPointerConversionToBool - Determines whether this conversion is /// a conversion of a pointer or pointer-to-member to bool. This is -/// used as part of the ranking of standard conversion sequences +/// used as part of the ranking of standard conversion sequences /// (C++ 13.3.3.2p4). -bool StandardConversionSequence::isPointerConversionToBool() const -{ +bool StandardConversionSequence::isPointerConversionToBool() const { QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); @@ -159,10 +160,9 @@ bool StandardConversionSequence::isPointerConversionToBool() const /// conversion is a conversion of a pointer to a void pointer. This is /// used as part of the ranking of standard conversion sequences (C++ /// 13.3.3.2p4). -bool +bool StandardConversionSequence:: -isPointerConversionToVoidPointer(ASTContext& Context) const -{ +isPointerConversionToVoidPointer(ASTContext& Context) const { QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); @@ -173,7 +173,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const FromType = Context.getArrayDecayedType(FromType); if (Second == ICK_Pointer_Conversion) - if (const PointerType* ToPtrType = ToType->getAsPointerType()) + if (const PointerType* ToPtrType = ToType->getAs<PointerType>()) return ToPtrType->getPointeeType()->isVoidType(); return false; @@ -260,7 +260,7 @@ void ImplicitConversionSequence::DebugPrint() const { // same signature (C++ 1.3.10) or if the Old declaration isn't a // function (or overload set). When it does return false and Old is an // OverloadedFunctionDecl, MatchedDecl will be set to point to the -// FunctionDecl that New cannot be overloaded with. +// FunctionDecl that New cannot be overloaded with. // // Example: Given the following input: // @@ -269,7 +269,7 @@ void ImplicitConversionSequence::DebugPrint() const { // int f(int, int); // #3 // // When we process #1, there is no previous declaration of "f", -// so IsOverload will not be used. +// so IsOverload will not be used. // // When we process #2, Old is a FunctionDecl for #1. By comparing the // parameter types, we see that #1 and #2 are overloaded (since they @@ -283,9 +283,8 @@ void ImplicitConversionSequence::DebugPrint() const { // signature), IsOverload returns false and MatchedDecl will be set to // point to the FunctionDecl for #2. bool -Sema::IsOverload(FunctionDecl *New, Decl* OldD, - OverloadedFunctionDecl::function_iterator& MatchedDecl) -{ +Sema::IsOverload(FunctionDecl *New, Decl* OldD, + OverloadedFunctionDecl::function_iterator& MatchedDecl) { if (OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(OldD)) { // Is this new function an overload of every function in the // overload set? @@ -304,8 +303,8 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, return IsOverload(New, Old->getTemplatedDecl(), MatchedDecl); else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) { FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); - FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); - + FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); + // C++ [temp.fct]p2: // A function template can be overloaded with other function templates // and with normal (non-template) functions. @@ -340,21 +339,21 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, return true; // C++ [temp.over.link]p4: - // The signature of a function template consists of its function + // The signature of a function template consists of its function // signature, its return type and its template parameter list. The names // of the template parameters are significant only for establishing the - // relationship between the template parameters and the rest of the + // relationship between the template parameters and the rest of the // signature. // // We check the return type and template parameter lists for function // templates first; the remaining checks follow. if (NewTemplate && - (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), - OldTemplate->getTemplateParameters(), + (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), + OldTemplate->getTemplateParameters(), false, false, SourceLocation()) || OldType->getResultType() != NewType->getResultType())) return true; - + // If the function is a class member, its signature includes the // cv-qualifiers (if any) on the function itself. // @@ -365,7 +364,7 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, // can be overloaded. CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); - if (OldMethod && NewMethod && + if (OldMethod && NewMethod && !OldMethod->isStatic() && !NewMethod->isStatic() && OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers()) return true; @@ -405,18 +404,25 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, /// permitted. /// If @p ForceRValue, then overloading is performed as if From was an rvalue, /// no matter its actual lvalueness. +/// If @p UserCast, the implicit conversion is being done for a user-specified +/// cast. ImplicitConversionSequence Sema::TryImplicitConversion(Expr* From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, bool ForceRValue) -{ + bool AllowExplicit, bool ForceRValue, + bool InOverloadResolution, + bool UserCast) { ImplicitConversionSequence ICS; - if (IsStandardConversion(From, ToType, ICS.Standard)) + OverloadCandidateSet Conversions; + OverloadingResult UserDefResult = OR_Success; + if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; else if (getLangOptions().CPlusPlus && - IsUserDefinedConversion(From, ToType, ICS.UserDefined, + (UserDefResult = IsUserDefinedConversion(From, ToType, + ICS.UserDefined, + Conversions, !SuppressUserConversions, AllowExplicit, - ForceRValue)) { + ForceRValue, UserCast)) == OR_Success) { ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class @@ -425,9 +431,9 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, // given Conversion rank, in spite of the fact that a copy // constructor (i.e., a user-defined conversion function) is // called for those cases. - if (CXXConstructorDecl *Constructor + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) { - QualType FromCanon + QualType FromCanon = Context.getCanonicalType(From->getType().getUnqualifiedType()); QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { @@ -453,8 +459,15 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, if (SuppressUserConversions && ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - } else + } else { ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + if (UserDefResult == OR_Ambiguous) { + for (OverloadCandidateSet::iterator Cand = Conversions.begin(); + Cand != Conversions.end(); ++Cand) + if (Cand->Viable) + ICS.ConversionFunctionSet.push_back(Cand->Function); + } + } return ICS; } @@ -467,10 +480,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, /// contain the standard conversion sequence required to perform this /// conversion and this routine will return true. Otherwise, this /// routine will return false and the value of SCS is unspecified. -bool -Sema::IsStandardConversion(Expr* From, QualType ToType, - StandardConversionSequence &SCS) -{ +bool +Sema::IsStandardConversion(Expr* From, QualType ToType, + bool InOverloadResolution, + StandardConversionSequence &SCS) { QualType FromType = From->getType(); // Standard conversions (C++ [conv]) @@ -481,23 +494,23 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.CopyConstructor = 0; // There are no standard conversions for class types in C++, so - // abort early. When overloading in C, however, we do permit + // abort early. When overloading in C, however, we do permit if (FromType->isRecordType() || ToType->isRecordType()) { if (getLangOptions().CPlusPlus) return false; - // When we're overloading in C, we allow, as standard conversions, + // When we're overloading in C, we allow, as standard conversions, } // The first conversion can be an lvalue-to-rvalue conversion, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). - // Lvalue-to-rvalue conversion (C++ 4.1): + // Lvalue-to-rvalue conversion (C++ 4.1): // An lvalue (3.10) of a non-function, non-array type T can be // converted to an rvalue. Expr::isLvalueResult argIsLvalue = From->isLvalue(Context); - if (argIsLvalue == Expr::LV_Valid && + if (argIsLvalue == Expr::LV_Valid && !FromType->isFunctionType() && !FromType->isArrayType() && Context.getCanonicalType(FromType) != Context.OverloadTy) { SCS.First = ICK_Lvalue_To_Rvalue; @@ -509,9 +522,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // FIXME: Doesn't see through to qualifiers behind a typedef! FromType = FromType.getUnqualifiedType(); - } - // Array-to-pointer conversion (C++ 4.2) - else if (FromType->isArrayType()) { + } else if (FromType->isArrayType()) { + // Array-to-pointer conversion (C++ 4.2) SCS.First = ICK_Array_To_Pointer; // An lvalue or rvalue of type "array of N T" or "array of unknown @@ -532,19 +544,17 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.ToTypePtr = ToType.getAsOpaquePtr(); return true; } - } - // Function-to-pointer conversion (C++ 4.3). - else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { + } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { + // Function-to-pointer conversion (C++ 4.3). SCS.First = ICK_Function_To_Pointer; // An lvalue of function type T can be converted to an rvalue of // type "pointer to T." The result is a pointer to the // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); - } - // Address of overloaded function (C++ [over.over]). - else if (FunctionDecl *Fn + } else if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + // Address of overloaded function (C++ [over.over]). SCS.First = ICK_Function_To_Pointer; // We were able to resolve the address of the overloaded function, @@ -566,9 +576,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, Context.getTypeDeclType(M->getParent()).getTypePtr()); } else FromType = Context.getPointerType(FromType); - } - // We don't require any conversions for the first step. - else { + } else { + // We don't require any conversions for the first step. SCS.First = ICK_Identity; } @@ -583,79 +592,68 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // The unqualified versions of the types are the same: there's no // conversion to do. SCS.Second = ICK_Identity; - } - // Integral promotion (C++ 4.5). - else if (IsIntegralPromotion(From, FromType, ToType)) { + } else if (IsIntegralPromotion(From, FromType, ToType)) { + // Integral promotion (C++ 4.5). SCS.Second = ICK_Integral_Promotion; FromType = ToType.getUnqualifiedType(); - } - // Floating point promotion (C++ 4.6). - else if (IsFloatingPointPromotion(FromType, ToType)) { + } else if (IsFloatingPointPromotion(FromType, ToType)) { + // Floating point promotion (C++ 4.6). SCS.Second = ICK_Floating_Promotion; FromType = ToType.getUnqualifiedType(); - } - // Complex promotion (Clang extension) - else if (IsComplexPromotion(FromType, ToType)) { + } else if (IsComplexPromotion(FromType, ToType)) { + // Complex promotion (Clang extension) SCS.Second = ICK_Complex_Promotion; FromType = ToType.getUnqualifiedType(); - } - // Integral conversions (C++ 4.7). - // FIXME: isIntegralType shouldn't be true for enums in C++. - else if ((FromType->isIntegralType() || FromType->isEnumeralType()) && + } else if ((FromType->isIntegralType() || FromType->isEnumeralType()) && (ToType->isIntegralType() && !ToType->isEnumeralType())) { + // Integral conversions (C++ 4.7). + // FIXME: isIntegralType shouldn't be true for enums in C++. SCS.Second = ICK_Integral_Conversion; FromType = ToType.getUnqualifiedType(); - } - // Floating point conversions (C++ 4.8). - else if (FromType->isFloatingType() && ToType->isFloatingType()) { + } else if (FromType->isFloatingType() && ToType->isFloatingType()) { + // Floating point conversions (C++ 4.8). SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); - } - // Complex conversions (C99 6.3.1.6) - else if (FromType->isComplexType() && ToType->isComplexType()) { + } else if (FromType->isComplexType() && ToType->isComplexType()) { + // Complex conversions (C99 6.3.1.6) SCS.Second = ICK_Complex_Conversion; FromType = ToType.getUnqualifiedType(); - } - // Floating-integral conversions (C++ 4.9). - // FIXME: isIntegralType shouldn't be true for enums in C++. - else if ((FromType->isFloatingType() && - ToType->isIntegralType() && !ToType->isBooleanType() && - !ToType->isEnumeralType()) || - ((FromType->isIntegralType() || FromType->isEnumeralType()) && - ToType->isFloatingType())) { + } else if ((FromType->isFloatingType() && + ToType->isIntegralType() && (!ToType->isBooleanType() && + !ToType->isEnumeralType())) || + ((FromType->isIntegralType() || FromType->isEnumeralType()) && + ToType->isFloatingType())) { + // Floating-integral conversions (C++ 4.9). + // FIXME: isIntegralType shouldn't be true for enums in C++. SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); - } - // Complex-real conversions (C99 6.3.1.7) - else if ((FromType->isComplexType() && ToType->isArithmeticType()) || - (ToType->isComplexType() && FromType->isArithmeticType())) { + } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || + (ToType->isComplexType() && FromType->isArithmeticType())) { + // Complex-real conversions (C99 6.3.1.7) SCS.Second = ICK_Complex_Real; FromType = ToType.getUnqualifiedType(); - } - // Pointer conversions (C++ 4.10). - else if (IsPointerConversion(From, FromType, ToType, FromType, - IncompatibleObjC)) { + } else if (IsPointerConversion(From, FromType, ToType, InOverloadResolution, + FromType, IncompatibleObjC)) { + // Pointer conversions (C++ 4.10). SCS.Second = ICK_Pointer_Conversion; SCS.IncompatibleObjC = IncompatibleObjC; - } - // Pointer to member conversions (4.11). - else if (IsMemberPointerConversion(From, FromType, ToType, FromType)) { + } else if (IsMemberPointerConversion(From, FromType, ToType, + InOverloadResolution, FromType)) { + // Pointer to member conversions (4.11). SCS.Second = ICK_Pointer_Member; - } - // Boolean conversions (C++ 4.12). - else if (ToType->isBooleanType() && - (FromType->isArithmeticType() || - FromType->isEnumeralType() || - FromType->isPointerType() || - FromType->isBlockPointerType() || - FromType->isMemberPointerType() || - FromType->isNullPtrType())) { + } else if (ToType->isBooleanType() && + (FromType->isArithmeticType() || + FromType->isEnumeralType() || + FromType->isPointerType() || + FromType->isBlockPointerType() || + FromType->isMemberPointerType() || + FromType->isNullPtrType())) { + // Boolean conversions (C++ 4.12). SCS.Second = ICK_Boolean_Conversion; FromType = Context.BoolTy; - } - // Compatible conversions (Clang extension for C function overloading) - else if (!getLangOptions().CPlusPlus && - Context.typesAreCompatible(ToType, FromType)) { + } else if (!getLangOptions().CPlusPlus && + Context.typesAreCompatible(ToType, FromType)) { + // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; } else { // No second conversion required. @@ -674,12 +672,12 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // No conversion required SCS.Third = ICK_Identity; - // C++ [over.best.ics]p6: + // C++ [over.best.ics]p6: // [...] Any difference in top-level cv-qualification is // subsumed by the initialization itself and does not constitute // a conversion. [...] CanonFrom = Context.getCanonicalType(FromType); - CanonTo = Context.getCanonicalType(ToType); + CanonTo = Context.getCanonicalType(ToType); if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() && CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) { FromType = ToType; @@ -700,9 +698,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, /// expression From (whose potentially-adjusted type is FromType) to /// ToType is an integral promotion (C++ 4.5). If so, returns true and /// sets PromotedType to the promoted type. -bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) -{ - const BuiltinType *To = ToType->getAsBuiltinType(); +bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { + const BuiltinType *To = ToType->getAs<BuiltinType>(); // All integers are built-in. if (!To) { return false; @@ -718,7 +715,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) (FromType->isSignedIntegerType() || // We can promote any unsigned integer type whose size is // less than int to an int. - (!FromType->isSignedIntegerType() && + (!FromType->isSignedIntegerType() && Context.getTypeSize(FromType) < Context.getTypeSize(ToType)))) { return To->getKind() == BuiltinType::Int; } @@ -736,7 +733,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) // unsigned. bool FromIsSigned; uint64_t FromSize = Context.getTypeSize(FromType); - if (const EnumType *FromEnumType = FromType->getAsEnumType()) { + if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) { QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType(); FromIsSigned = UnderlyingType->isSignedIntegerType(); } else { @@ -746,15 +743,15 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) // The types we'll try to promote to, in the appropriate // order. Try each of these types. - QualType PromoteTypes[6] = { - Context.IntTy, Context.UnsignedIntTy, + QualType PromoteTypes[6] = { + Context.IntTy, Context.UnsignedIntTy, Context.LongTy, Context.UnsignedLongTy , Context.LongLongTy, Context.UnsignedLongLongTy }; for (int Idx = 0; Idx < 6; ++Idx) { uint64_t ToSize = Context.getTypeSize(PromoteTypes[Idx]); if (FromSize < ToSize || - (FromSize == ToSize && + (FromSize == ToSize && FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType())) { // We found the type that we can promote to. If this is the // type we wanted, we have a promotion. Otherwise, no @@ -782,23 +779,23 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) { APSInt ToSize(BitWidth.getBitWidth(), BitWidth.isUnsigned()); ToSize = Context.getTypeSize(ToType); - + // Are we promoting to an int from a bitfield that fits in an int? if (BitWidth < ToSize || (FromType->isSignedIntegerType() && BitWidth <= ToSize)) { return To->getKind() == BuiltinType::Int; } - + // Are we promoting to an unsigned int from an unsigned bitfield // that fits into an unsigned int? if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) { return To->getKind() == BuiltinType::UInt; } - + return false; } } - + // An rvalue of type bool can be converted to an rvalue of type int, // with false becoming zero and true becoming one (C++ 4.5p4). if (FromType->isBooleanType() && To->getKind() == BuiltinType::Int) { @@ -811,12 +808,11 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) /// IsFloatingPointPromotion - Determines whether the conversion from /// FromType to ToType is a floating point promotion (C++ 4.6). If so, /// returns true and sets PromotedType to the promoted type. -bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) -{ +bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { /// An rvalue of type float can be converted to an rvalue of type /// double. (C++ 4.6p1). - if (const BuiltinType *FromBuiltin = FromType->getAsBuiltinType()) - if (const BuiltinType *ToBuiltin = ToType->getAsBuiltinType()) { + if (const BuiltinType *FromBuiltin = FromType->getAs<BuiltinType>()) + if (const BuiltinType *ToBuiltin = ToType->getAs<BuiltinType>()) { if (FromBuiltin->getKind() == BuiltinType::Float && ToBuiltin->getKind() == BuiltinType::Double) return true; @@ -840,11 +836,11 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) /// where the conversion between the underlying real types is a /// floating-point or integral promotion. bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) { - const ComplexType *FromComplex = FromType->getAsComplexType(); + const ComplexType *FromComplex = FromType->getAs<ComplexType>(); if (!FromComplex) return false; - const ComplexType *ToComplex = ToType->getAsComplexType(); + const ComplexType *ToComplex = ToType->getAs<ComplexType>(); if (!ToComplex) return false; @@ -859,18 +855,18 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) { /// same type qualifiers as FromPtr has on its pointee type. ToType, /// if non-empty, will be a pointer to ToType that may or may not have /// the right set of qualifiers on its pointee. -static QualType -BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, +static QualType +BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, QualType ToPointee, QualType ToType, ASTContext &Context) { QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType()); QualType CanonToPointee = Context.getCanonicalType(ToPointee); - unsigned Quals = CanonFromPointee.getCVRQualifiers(); - - // Exact qualifier match -> return the pointer type we're converting to. - if (CanonToPointee.getCVRQualifiers() == Quals) { + Qualifiers Quals = CanonFromPointee.getQualifiers(); + + // Exact qualifier match -> return the pointer type we're converting to. + if (CanonToPointee.getQualifiers() == Quals) { // ToType is exactly what we need. Return it. - if (ToType.getTypePtr()) + if (!ToType.isNull()) return ToType; // Build a pointer to ToPointee. It has the right qualifiers @@ -879,7 +875,22 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, } // Just build a canonical type that has the right qualifiers. - return Context.getPointerType(CanonToPointee.getQualifiedType(Quals)); + return Context.getPointerType( + Context.getQualifiedType(CanonToPointee.getUnqualifiedType(), Quals)); +} + +static bool isNullPointerConstantForConversion(Expr *Expr, + bool InOverloadResolution, + ASTContext &Context) { + // Handle value-dependent integral null pointer constants correctly. + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903 + if (Expr->isValueDependent() && !Expr->isTypeDependent() && + Expr->getType()->isIntegralType()) + return !InOverloadResolution; + + return Expr->isNullPointerConstant(Context, + InOverloadResolution? Expr::NPC_ValueDependentIsNotNull + : Expr::NPC_ValueDependentIsNull); } /// IsPointerConversion - Determines whether the conversion of the @@ -899,52 +910,54 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, /// set if the conversion is an allowed Objective-C conversion that /// should result in a warning. bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, QualType& ConvertedType, - bool &IncompatibleObjC) -{ + bool &IncompatibleObjC) { IncompatibleObjC = false; if (isObjCPointerConversion(FromType, ToType, ConvertedType, IncompatibleObjC)) return true; - // Conversion from a null pointer constant to any Objective-C pointer type. - if (Context.isObjCObjectPointerType(ToType) && - From->isNullPointerConstant(Context)) { + // Conversion from a null pointer constant to any Objective-C pointer type. + if (ToType->isObjCObjectPointerType() && + isNullPointerConstantForConversion(From, InOverloadResolution, Context)) { ConvertedType = ToType; return true; } // Blocks: Block pointers can be converted to void*. if (FromType->isBlockPointerType() && ToType->isPointerType() && - ToType->getAsPointerType()->getPointeeType()->isVoidType()) { + ToType->getAs<PointerType>()->getPointeeType()->isVoidType()) { ConvertedType = ToType; return true; } // Blocks: A null pointer constant can be converted to a block // pointer type. - if (ToType->isBlockPointerType() && From->isNullPointerConstant(Context)) { + if (ToType->isBlockPointerType() && + isNullPointerConstantForConversion(From, InOverloadResolution, Context)) { ConvertedType = ToType; return true; } // If the left-hand-side is nullptr_t, the right side can be a null // pointer constant. - if (ToType->isNullPtrType() && From->isNullPointerConstant(Context)) { + if (ToType->isNullPtrType() && + isNullPointerConstantForConversion(From, InOverloadResolution, Context)) { ConvertedType = ToType; return true; } - const PointerType* ToTypePtr = ToType->getAsPointerType(); + const PointerType* ToTypePtr = ToType->getAs<PointerType>(); if (!ToTypePtr) return false; // A null pointer constant can be converted to a pointer type (C++ 4.10p1). - if (From->isNullPointerConstant(Context)) { + if (isNullPointerConstantForConversion(From, InOverloadResolution, Context)) { ConvertedType = ToType; return true; } // Beyond this point, both types need to be pointers. - const PointerType *FromTypePtr = FromType->getAsPointerType(); + const PointerType *FromTypePtr = FromType->getAs<PointerType>(); if (!FromTypePtr) return false; @@ -955,7 +968,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // can be converted to an rvalue of type "pointer to cv void" (C++ // 4.10p2). if (FromPointeeType->isObjectType() && ToPointeeType->isVoidType()) { - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, ToType, Context); return true; @@ -963,16 +976,16 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // When we're overloading in C, we allow a special kind of pointer // conversion for compatible-but-not-identical pointee types. - if (!getLangOptions().CPlusPlus && + if (!getLangOptions().CPlusPlus && Context.typesAreCompatible(FromPointeeType, ToPointeeType)) { - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, - ToType, Context); + ToType, Context); return true; } // C++ [conv.ptr]p3: - // + // // An rvalue of type "pointer to cv D," where D is a class type, // can be converted to an rvalue of type "pointer to cv B," where // B is a base class (clause 10) of D. If B is an inaccessible @@ -987,7 +1000,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, if (getLangOptions().CPlusPlus && FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && IsDerivedFrom(FromPointeeType, ToPointeeType)) { - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, ToType, Context); return true; @@ -999,83 +1012,65 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, /// isObjCPointerConversion - Determines whether this is an /// Objective-C pointer conversion. Subroutine of IsPointerConversion, /// with the same arguments and return values. -bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, +bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC) { if (!getLangOptions().ObjC1) return false; - // Conversions with Objective-C's id<...>. - if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) && - ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) { - ConvertedType = ToType; - return true; - } + // First, we handle all conversions on ObjC object pointer types. + const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *FromObjCPtr = + FromType->getAs<ObjCObjectPointerType>(); + + if (ToObjCPtr && FromObjCPtr) { + // Objective C++: We're able to convert between "id" or "Class" and a + // pointer to any interface (in both directions). + if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) { + ConvertedType = ToType; + return true; + } + // Conversions with Objective-C's id<...>. + if ((FromObjCPtr->isObjCQualifiedIdType() || + ToObjCPtr->isObjCQualifiedIdType()) && + Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType, + /*compare=*/false)) { + ConvertedType = ToType; + return true; + } + // Objective C++: We're able to convert from a pointer to an + // interface to a pointer to a different interface. + if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) { + ConvertedType = ToType; + return true; + } - // Beyond this point, both types need to be pointers or block pointers. + if (Context.canAssignObjCInterfaces(FromObjCPtr, ToObjCPtr)) { + // Okay: this is some kind of implicit downcast of Objective-C + // interfaces, which is permitted. However, we're going to + // complain about it. + IncompatibleObjC = true; + ConvertedType = FromType; + return true; + } + } + // Beyond this point, both types need to be C pointers or block pointers. QualType ToPointeeType; - const PointerType* ToTypePtr = ToType->getAsPointerType(); - if (ToTypePtr) - ToPointeeType = ToTypePtr->getPointeeType(); - else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType()) + if (const PointerType *ToCPtr = ToType->getAs<PointerType>()) + ToPointeeType = ToCPtr->getPointeeType(); + else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>()) ToPointeeType = ToBlockPtr->getPointeeType(); else return false; QualType FromPointeeType; - const PointerType *FromTypePtr = FromType->getAsPointerType(); - if (FromTypePtr) - FromPointeeType = FromTypePtr->getPointeeType(); - else if (const BlockPointerType *FromBlockPtr - = FromType->getAsBlockPointerType()) + if (const PointerType *FromCPtr = FromType->getAs<PointerType>()) + FromPointeeType = FromCPtr->getPointeeType(); + else if (const BlockPointerType *FromBlockPtr = FromType->getAs<BlockPointerType>()) FromPointeeType = FromBlockPtr->getPointeeType(); else return false; - // Objective C++: We're able to convert from a pointer to an - // interface to a pointer to a different interface. - const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType(); - const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType(); - if (FromIface && ToIface && - Context.canAssignObjCInterfaces(ToIface, FromIface)) { - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, - ToPointeeType, - ToType, Context); - return true; - } - - if (FromIface && ToIface && - Context.canAssignObjCInterfaces(FromIface, ToIface)) { - // Okay: this is some kind of implicit downcast of Objective-C - // interfaces, which is permitted. However, we're going to - // complain about it. - IncompatibleObjC = true; - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, - ToPointeeType, - ToType, Context); - return true; - } - - // Objective C++: We're able to convert between "id" and a pointer - // to any interface (in both directions). - if ((FromIface && Context.isObjCIdStructType(ToPointeeType)) - || (ToIface && Context.isObjCIdStructType(FromPointeeType))) { - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, - ToPointeeType, - ToType, Context); - return true; - } - - // Objective C++: Allow conversions between the Objective-C "id" and - // "Class", in either direction. - if ((Context.isObjCIdStructType(FromPointeeType) && - Context.isObjCClassStructType(ToPointeeType)) || - (Context.isObjCClassStructType(FromPointeeType) && - Context.isObjCIdStructType(ToPointeeType))) { - ConvertedType = ToType; - return true; - } - // If we have pointers to pointers, recursively check whether this // is an Objective-C conversion. if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() && @@ -1086,15 +1081,14 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = ToType; return true; } - // If we have pointers to functions or blocks, check whether the only // differences in the argument and result types are in Objective-C // pointer conversions. If so, we permit the conversion (but // complain about it). - const FunctionProtoType *FromFunctionType - = FromPointeeType->getAsFunctionProtoType(); + const FunctionProtoType *FromFunctionType + = FromPointeeType->getAs<FunctionProtoType>(); const FunctionProtoType *ToFunctionType - = ToPointeeType->getAsFunctionProtoType(); + = ToPointeeType->getAs<FunctionProtoType>(); if (FromFunctionType && ToFunctionType) { // If the function types are exactly the same, this isn't an // Objective-C pointer conversion. @@ -1122,7 +1116,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // Function types are too different. Abort. return false; } - + // Check argument types. for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs(); ArgIdx != NumArgs; ++ArgIdx) { @@ -1155,37 +1149,43 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, /// CheckPointerConversion - Check the pointer conversion from the /// expression From to the type ToType. This routine checks for -/// ambiguous (FIXME: or inaccessible) derived-to-base pointer +/// ambiguous or inaccessible derived-to-base pointer /// conversions for which IsPointerConversion has already returned /// true. It returns true and produces a diagnostic if there was an /// error, or returns false otherwise. -bool Sema::CheckPointerConversion(Expr *From, QualType ToType) { +bool Sema::CheckPointerConversion(Expr *From, QualType ToType, + CastExpr::CastKind &Kind) { QualType FromType = From->getType(); - if (const PointerType *FromPtrType = FromType->getAsPointerType()) - if (const PointerType *ToPtrType = ToType->getAsPointerType()) { + if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) + if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) { QualType FromPointeeType = FromPtrType->getPointeeType(), ToPointeeType = ToPtrType->getPointeeType(); - // Objective-C++ conversions are always okay. - // FIXME: We should have a different class of conversions for the - // Objective-C++ implicit conversions. - if (Context.isObjCIdStructType(FromPointeeType) || - Context.isObjCIdStructType(ToPointeeType) || - Context.isObjCClassStructType(FromPointeeType) || - Context.isObjCClassStructType(ToPointeeType)) - return false; - if (FromPointeeType->isRecordType() && ToPointeeType->isRecordType()) { // We must have a derived-to-base conversion. Check an // ambiguous or inaccessible conversion. - return CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType, - From->getExprLoc(), - From->getSourceRange()); + if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType, + From->getExprLoc(), + From->getSourceRange())) + return true; + + // The conversion was successful. + Kind = CastExpr::CK_DerivedToBase; } } + if (const ObjCObjectPointerType *FromPtrType = + FromType->getAs<ObjCObjectPointerType>()) + if (const ObjCObjectPointerType *ToPtrType = + ToType->getAs<ObjCObjectPointerType>()) { + // Objective-C++ conversions are always okay. + // FIXME: We should have a different class of conversions for the + // Objective-C++ implicit conversions. + if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType()) + return false; + } return false; } @@ -1195,20 +1195,23 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) { /// If so, returns true and places the converted type (that might differ from /// ToType in its cv-qualifiers at some level) into ConvertedType. bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, - QualType ToType, QualType &ConvertedType) -{ - const MemberPointerType *ToTypePtr = ToType->getAsMemberPointerType(); + QualType ToType, + bool InOverloadResolution, + QualType &ConvertedType) { + const MemberPointerType *ToTypePtr = ToType->getAs<MemberPointerType>(); if (!ToTypePtr) return false; // A null pointer constant can be converted to a member pointer (C++ 4.11p1) - if (From->isNullPointerConstant(Context)) { + if (From->isNullPointerConstant(Context, + InOverloadResolution? Expr::NPC_ValueDependentIsNotNull + : Expr::NPC_ValueDependentIsNull)) { ConvertedType = ToType; return true; } // Otherwise, both types have to be member pointers. - const MemberPointerType *FromTypePtr = FromType->getAsMemberPointerType(); + const MemberPointerType *FromTypePtr = FromType->getAs<MemberPointerType>(); if (!FromTypePtr) return false; @@ -1233,13 +1236,20 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// for which IsMemberPointerConversion has already returned true. It returns /// true and produces a diagnostic if there was an error, or returns false /// otherwise. -bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) { +bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, + CastExpr::CastKind &Kind) { QualType FromType = From->getType(); - const MemberPointerType *FromPtrType = FromType->getAsMemberPointerType(); - if (!FromPtrType) + const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>(); + if (!FromPtrType) { + // This must be a null pointer to member pointer conversion + assert(From->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull) && + "Expr must be null pointer constant!"); + Kind = CastExpr::CK_NullToMemberPointer; return false; + } - const MemberPointerType *ToPtrType = ToType->getAsMemberPointerType(); + const MemberPointerType *ToPtrType = ToType->getAs<MemberPointerType>(); assert(ToPtrType && "No member pointer cast has a target type " "that is not a member pointer."); @@ -1250,8 +1260,8 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) { assert(FromClass->isRecordType() && "Pointer into non-class."); assert(ToClass->isRecordType() && "Pointer into non-class."); - BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, - /*DetectVirtual=*/true); + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/true); bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths); assert(DerivationOkay && "Should not have been called if derivation isn't OK."); @@ -1279,15 +1289,16 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) { return true; } + // Must be a base to derived member conversion. + Kind = CastExpr::CK_BaseToDerivedMemberPointer; return false; } /// IsQualificationConversion - Determines whether the conversion from /// an rvalue of type FromType to ToType is a qualification conversion /// (C++ 4.4). -bool -Sema::IsQualificationConversion(QualType FromType, QualType ToType) -{ +bool +Sema::IsQualificationConversion(QualType FromType, QualType ToType) { FromType = Context.getCanonicalType(FromType); ToType = Context.getCanonicalType(ToType); @@ -1314,16 +1325,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) // 2,j, and similarly for volatile. if (!ToType.isAtLeastAsQualifiedAs(FromType)) return false; - + // -- if the cv 1,j and cv 2,j are different, then const is in // every cv for 0 < k < j. if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers() && !PreviousToQualsIncludeConst) return false; - + // Keep track of whether all prior cv-qualifiers in the "to" type // include const. - PreviousToQualsIncludeConst + PreviousToQualsIncludeConst = PreviousToQualsIncludeConst && ToType.isConstQualified(); } @@ -1336,6 +1347,18 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) FromType.getUnqualifiedType() == ToType.getUnqualifiedType(); } +/// \brief Given a function template or function, extract the function template +/// declaration (if any) and the underlying function declaration. +template<typename T> +static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function, + FunctionTemplateDecl *&FunctionTemplate) { + FunctionTemplate = dyn_cast<FunctionTemplateDecl>(Orig); + if (FunctionTemplate) + Function = cast<T>(FunctionTemplate->getTemplatedDecl()); + else + Function = cast<T>(Orig); +} + /// Determines whether there is a user-defined conversion sequence /// (C++ [over.ics.user]) that converts expression From to the type /// ToType. If such a conversion exists, User will contain the @@ -1353,14 +1376,17 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) /// /// \param ForceRValue true if the expression should be treated as an rvalue /// for overload resolution. -bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, +/// \param UserCast true if looking for user defined conversion for a static +/// cast. +Sema::OverloadingResult Sema::IsUserDefinedConversion( + Expr *From, QualType ToType, UserDefinedConversionSequence& User, + OverloadCandidateSet& CandidateSet, bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue) -{ - OverloadCandidateSet CandidateSet; - if (const RecordType *ToRecordType = ToType->getAsRecordType()) { - if (CXXRecordDecl *ToRecordDecl + bool AllowExplicit, bool ForceRValue, + bool UserCast) { + if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { + if (CXXRecordDecl *ToRecordDecl = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { // C++ [over.match.ctor]p1: // When objects of class type are direct-initialized (8.5), or @@ -1370,37 +1396,72 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // functions are all the converting constructors (12.3.1) of // that class. The argument list is the expression-list within // the parentheses of the initializer. - DeclarationName ConstructorName + DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ToType).getUnqualifiedType()); DeclContext::lookup_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) + for (llvm::tie(Con, ConEnd) = ToRecordDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isConvertingConstructor()) - AddOverloadCandidate(Constructor, &From, 1, CandidateSet, - /*SuppressUserConversions=*/true, ForceRValue); + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast<FunctionTemplateDecl>(*Con); + if (ConstructorTmpl) + Constructor + = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast<CXXConstructorDecl>(*Con); + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From, + 1, CandidateSet, + /*SuppressUserConversions=*/!UserCast, + ForceRValue); + else + // Allow one user-defined conversion when user specifies a + // From->ToType conversion via an static cast (c-style, etc). + AddOverloadCandidate(Constructor, &From, 1, CandidateSet, + /*SuppressUserConversions=*/!UserCast, + ForceRValue); + } } } } if (!AllowConversionFunctions) { // Don't allow any conversion functions to enter the overload set. - } else if (const RecordType *FromRecordType - = From->getType()->getAsRecordType()) { - if (CXXRecordDecl *FromRecordDecl - = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { + } else if (RequireCompleteType(From->getLocStart(), From->getType(), + PDiag(0) + << From->getSourceRange())) { + // No conversion functions from incomplete types. + } else if (const RecordType *FromRecordType + = From->getType()->getAs<RecordType>()) { + if (CXXRecordDecl *FromRecordDecl + = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { // Add all of the conversion functions as candidates. - // FIXME: Look for conversions in base classes! - OverloadedFunctionDecl *Conversions - = FromRecordDecl->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator Func + OverloadedFunctionDecl *Conversions + = FromRecordDecl->getVisibleConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator Func = Conversions->function_begin(); Func != Conversions->function_end(); ++Func) { - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); - if (AllowExplicit || !Conv->isExplicit()) - AddConversionCandidate(Conv, From, ToType, CandidateSet); + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + GetFunctionAndTemplate(*Func, Conv, ConvTemplate); + if (ConvTemplate) + Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = dyn_cast<CXXConversionDecl>(*Func); + + if (AllowExplicit || !Conv->isExplicit()) { + if (ConvTemplate) + AddTemplateConversionCandidate(ConvTemplate, From, ToType, + CandidateSet); + else + AddConversionCandidate(Conv, From, ToType, CandidateSet); + } } } } @@ -1409,7 +1470,7 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, switch (BestViableFunction(CandidateSet, From->getLocStart(), Best)) { case OR_Success: // Record the standard conversion we used and the conversion function. - if (CXXConstructorDecl *Constructor + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Best->Function)) { // C++ [over.ics.user]p1: // If the user-defined conversion is specified by a @@ -1422,10 +1483,10 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, User.Before = Best->Conversions[0].Standard; User.ConversionFunction = Constructor; User.After.setAsIdentityConversion(); - User.After.FromTypePtr - = ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr(); + User.After.FromTypePtr + = ThisType->getAs<PointerType>()->getPointeeType().getAsOpaquePtr(); User.After.ToTypePtr = ToType.getAsOpaquePtr(); - return true; + return OR_Success; } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(Best->Function)) { // C++ [over.ics.user]p1: @@ -1436,8 +1497,8 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // implicit object parameter of the conversion function. User.Before = Best->Conversions[0].Standard; User.ConversionFunction = Conversion; - - // C++ [over.ics.user]p2: + + // C++ [over.ics.user]p2: // The second standard conversion sequence converts the // result of the user-defined conversion to the target type // for the sequence. Since an implicit conversion sequence @@ -1447,30 +1508,45 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // user-defined conversion sequence (see 13.3.3 and // 13.3.3.1). User.After = Best->FinalConversion; - return true; + return OR_Success; } else { assert(false && "Not a constructor or conversion function?"); - return false; + return OR_No_Viable_Function; } - + case OR_No_Viable_Function: + return OR_No_Viable_Function; case OR_Deleted: // No conversion here! We're done. - return false; + return OR_Deleted; case OR_Ambiguous: - // FIXME: See C++ [over.best.ics]p10 for the handling of - // ambiguous conversion sequences. - return false; + return OR_Ambiguous; } - return false; + return OR_No_Viable_Function; +} + +bool +Sema::DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType) { + ImplicitConversionSequence ICS; + OverloadCandidateSet CandidateSet; + OverloadingResult OvResult = + IsUserDefinedConversion(From, ToType, ICS.UserDefined, + CandidateSet, true, false, false); + if (OvResult != OR_Ambiguous) + return false; + Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_ambiguous_condition) + << From->getType() << ToType << From->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + return true; } /// CompareImplicitConversionSequences - Compare two implicit /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2). -ImplicitConversionSequence::CompareKind +ImplicitConversionSequence::CompareKind Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, const ImplicitConversionSequence& ICS2) { @@ -1482,7 +1558,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // -- a user-defined conversion sequence (13.3.3.1.2) is a better // conversion sequence than an ellipsis conversion sequence // (13.3.3.1.3). - // + // if (ICS1.ConversionKind < ICS2.ConversionKind) return ImplicitConversionSequence::Better; else if (ICS2.ConversionKind < ICS1.ConversionKind) @@ -1493,7 +1569,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // following rules apply: (C++ 13.3.3.2p3): if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion) return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard); - else if (ICS1.ConversionKind == + else if (ICS1.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) { // User-defined conversion sequence U1 is a better conversion // sequence than another user-defined conversion sequence U2 if @@ -1501,7 +1577,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // constructor and if the second standard conversion sequence of // U1 is better than the second standard conversion sequence of // U2 (C++ 13.3.3.2p3). - if (ICS1.UserDefined.ConversionFunction == + if (ICS1.UserDefined.ConversionFunction == ICS2.UserDefined.ConversionFunction) return CompareStandardConversionSequences(ICS1.UserDefined.After, ICS2.UserDefined.After); @@ -1513,7 +1589,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). -ImplicitConversionSequence::CompareKind +ImplicitConversionSequence::CompareKind Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { @@ -1530,13 +1606,13 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, ; else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) || (SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) || - (SCS1.Second == ICK_Identity && + (SCS1.Second == ICK_Identity && SCS1.Third == ICK_Identity)) // SCS1 is a proper subsequence of SCS2. return ImplicitConversionSequence::Better; else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) || (SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) || - (SCS2.Second == ICK_Identity && + (SCS2.Second == ICK_Identity && SCS2.Third == ICK_Identity)) // SCS2 is a proper subsequence of SCS1. return ImplicitConversionSequence::Worse; @@ -1553,7 +1629,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // (C++ 13.3.3.2p4): Two conversion sequences with the same rank // are indistinguishable unless one of the following rules // applies: - + // A conversion that is not a conversion of a pointer, or // pointer to member, to bool is better than another conversion // that is such a conversion. @@ -1568,9 +1644,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // conversion of B* to A* is better than conversion of B* to // void*, and conversion of A* to void* is better than conversion // of B* to void*. - bool SCS1ConvertsToVoid + bool SCS1ConvertsToVoid = SCS1.isPointerConversionToVoidPointer(Context); - bool SCS2ConvertsToVoid + bool SCS2ConvertsToVoid = SCS2.isPointerConversionToVoidPointer(Context); if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) { // Exactly one of the conversion sequences is a conversion to @@ -1597,10 +1673,10 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, if (SCS2.First == ICK_Array_To_Pointer) FromType2 = Context.getArrayDecayedType(FromType2); - QualType FromPointee1 - = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType(); + QualType FromPointee1 + = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); QualType FromPointee2 - = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType(); + = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); if (IsDerivedFrom(FromPointee2, FromPointee1)) return ImplicitConversionSequence::Better; @@ -1609,8 +1685,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->getAsObjCInterfaceType(); - const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType(); + const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>(); + const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>(); if (FromIface1 && FromIface1) { if (Context.canAssignObjCInterfaces(FromIface2, FromIface1)) return ImplicitConversionSequence::Better; @@ -1621,7 +1697,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Compare based on qualification conversions (C++ 13.3.3.2p3, // bullet 3). - if (ImplicitConversionSequence::CompareKind QualCK + if (ImplicitConversionSequence::CompareKind QualCK = CompareQualificationConversions(SCS1, SCS2)) return QualCK; @@ -1661,11 +1737,10 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, /// CompareQualificationConversions - Compares two standard conversion /// sequences to determine whether they can be ranked based on their -/// qualification conversions (C++ 13.3.3.2p3 bullet 3). -ImplicitConversionSequence::CompareKind +/// qualification conversions (C++ 13.3.3.2p3 bullet 3). +ImplicitConversionSequence::CompareKind Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, - const StandardConversionSequence& SCS2) -{ + const StandardConversionSequence& SCS2) { // C++ 13.3.3.2p3: // -- S1 and S2 differ only in their qualification conversion and // yield similar types T1 and T2 (C++ 4.4), respectively, and the @@ -1688,7 +1763,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) return ImplicitConversionSequence::Indistinguishable; - ImplicitConversionSequence::CompareKind Result + ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; while (UnwrapSimilarPointerTypes(T1, T2)) { // Within each iteration of the loop, we check the qualifiers to @@ -1709,7 +1784,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // Neither has qualifiers that are a subset of the other's // qualifiers. return ImplicitConversionSequence::Indistinguishable; - + Result = ImplicitConversionSequence::Better; } else if (T1.isMoreQualifiedThan(T2)) { // T2 has fewer qualifiers, so it could be the better sequence. @@ -1717,7 +1792,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // Neither has qualifiers that are a subset of the other's // qualifiers. return ImplicitConversionSequence::Indistinguishable; - + Result = ImplicitConversionSequence::Worse; } else { // Qualifiers are disjoint. @@ -1784,24 +1859,24 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, // interfaces. // Compare based on pointer conversions. - if (SCS1.Second == ICK_Pointer_Conversion && + if (SCS1.Second == ICK_Pointer_Conversion && SCS2.Second == ICK_Pointer_Conversion && /*FIXME: Remove if Objective-C id conversions get their own rank*/ FromType1->isPointerType() && FromType2->isPointerType() && ToType1->isPointerType() && ToType2->isPointerType()) { - QualType FromPointee1 - = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType(); - QualType ToPointee1 - = ToType1->getAsPointerType()->getPointeeType().getUnqualifiedType(); + QualType FromPointee1 + = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); + QualType ToPointee1 + = ToType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); QualType FromPointee2 - = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType(); + = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); QualType ToPointee2 - = ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType(); + = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType(); - const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType(); - const ObjCInterfaceType* ToIface1 = ToPointee1->getAsObjCInterfaceType(); - const ObjCInterfaceType* ToIface2 = ToPointee2->getAsObjCInterfaceType(); + const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>(); + const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>(); + const ObjCInterfaceType* ToIface1 = ToPointee1->getAs<ObjCInterfaceType>(); + const ObjCInterfaceType* ToIface2 = ToPointee2->getAs<ObjCInterfaceType>(); // -- conversion of C* to B* is better than conversion of C* to A*, if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { @@ -1824,7 +1899,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, return ImplicitConversionSequence::Better; else if (IsDerivedFrom(FromPointee1, FromPointee2)) return ImplicitConversionSequence::Worse; - + if (FromIface1 && FromIface2) { if (Context.canAssignObjCInterfaces(FromIface1, FromIface2)) return ImplicitConversionSequence::Better; @@ -1898,17 +1973,25 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, /// a parameter of this type). If @p SuppressUserConversions, then we /// do not permit any user-defined conversion sequences. If @p ForceRValue, /// then we treat @p From as an rvalue, even if it is an lvalue. -ImplicitConversionSequence -Sema::TryCopyInitialization(Expr *From, QualType ToType, - bool SuppressUserConversions, bool ForceRValue) { +ImplicitConversionSequence +Sema::TryCopyInitialization(Expr *From, QualType ToType, + bool SuppressUserConversions, bool ForceRValue, + bool InOverloadResolution) { if (ToType->isReferenceType()) { ImplicitConversionSequence ICS; - CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions, - /*AllowExplicit=*/false, ForceRValue); + CheckReferenceInit(From, ToType, + /*FIXME:*/From->getLocStart(), + SuppressUserConversions, + /*AllowExplicit=*/false, + ForceRValue, + &ICS); return ICS; } else { - return TryImplicitConversion(From, ToType, SuppressUserConversions, - ForceRValue); + return TryImplicitConversion(From, ToType, + SuppressUserConversions, + /*AllowExplicit=*/false, + ForceRValue, + InOverloadResolution); } } @@ -1917,32 +2000,37 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, /// an error, returns false if the initialization succeeded. Elidable should /// be true when the copy may be elided (C++ 12.8p15). Overload resolution works /// differently in C++0x for this case. -bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, +bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, const char* Flavor, bool Elidable) { if (!getLangOptions().CPlusPlus) { // In C, argument passing is the same as performing an assignment. QualType FromType = From->getType(); - + AssignConvertType ConvTy = CheckSingleAssignmentConstraints(ToType, From); if (ConvTy != Compatible && CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible) ConvTy = Compatible; - + return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType, FromType, From, Flavor); } if (ToType->isReferenceType()) - return CheckReferenceInit(From, ToType); + return CheckReferenceInit(From, ToType, + /*FIXME:*/From->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false); if (!PerformImplicitConversion(From, ToType, Flavor, /*AllowExplicit=*/false, Elidable)) return false; - - return Diag(From->getSourceRange().getBegin(), - diag::err_typecheck_convert_incompatible) - << ToType << From->getType() << Flavor << From->getSourceRange(); + if (!DiagnoseAmbiguousUserDefinedConversion(From, ToType)) + return Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_convert_incompatible) + << ToType << From->getType() << Flavor << From->getSourceRange(); + return true; } /// TryObjectArgumentInitialization - Try to initialize the object @@ -1951,8 +2039,8 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, ImplicitConversionSequence Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { QualType ClassType = Context.getTypeDeclType(Method->getParent()); - unsigned MethodQuals = Method->getTypeQualifiers(); - QualType ImplicitParamType = ClassType.getQualifiedType(MethodQuals); + QualType ImplicitParamType + = Context.getCVRQualifiedType(ClassType, Method->getTypeQualifiers()); // Set up the conversion sequence as a "bad" conversion, to allow us // to exit early. @@ -1962,7 +2050,7 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { // We need to have an object of class type. QualType FromType = From->getType(); - if (const PointerType *PT = FromType->getAsPointerType()) + if (const PointerType *PT = FromType->getAs<PointerType>()) FromType = PT->getPointeeType(); assert(FromType->isRecordType()); @@ -1971,7 +2059,7 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { // where X is the class of which the function is a member // (C++ [over.match.funcs]p4). However, when finding an implicit // conversion sequence for the argument, we are not allowed to - // create temporaries or perform user-defined conversions + // create temporaries or perform user-defined conversions // (C++ [over.match.funcs]p5). We perform a simplified version of // reference binding here, that allows class rvalues to bind to // non-constant references. @@ -2009,10 +2097,10 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { bool Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { QualType FromRecordType, DestType; - QualType ImplicitParamRecordType = - Method->getThisType(Context)->getAsPointerType()->getPointeeType(); - - if (const PointerType *PT = From->getType()->getAsPointerType()) { + QualType ImplicitParamRecordType = + Method->getThisType(Context)->getAs<PointerType>()->getPointeeType(); + + if (const PointerType *PT = From->getType()->getAs<PointerType>()) { FromRecordType = PT->getPointeeType(); DestType = Method->getThisType(Context); } else { @@ -2020,13 +2108,13 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { DestType = ImplicitParamRecordType; } - ImplicitConversionSequence ICS + ImplicitConversionSequence ICS = TryObjectArgumentInitialization(From, Method); if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) return Diag(From->getSourceRange().getBegin(), diag::err_implicit_object_parameter_init) << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); - + if (ICS.Standard.Second == ICK_Derived_To_Base && CheckDerivedToBaseConversion(FromRecordType, ImplicitParamRecordType, @@ -2034,14 +2122,20 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { From->getSourceRange())) return true; - ImpCastExprToType(From, DestType, /*isLvalue=*/true); + ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, + /*isLvalue=*/true); return false; } /// TryContextuallyConvertToBool - Attempt to contextually convert the /// expression From to bool (C++0x [conv]p3). ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { - return TryImplicitConversion(From, Context.BoolTy, false, true); + return TryImplicitConversion(From, Context.BoolTy, + // FIXME: Are these flags correct? + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/true, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -2050,10 +2144,12 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From); if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting")) return false; - - return Diag(From->getSourceRange().getBegin(), - diag::err_typecheck_bool_condition) - << From->getType() << From->getSourceRange(); + + if (!DiagnoseAmbiguousUserDefinedConversion(From, Context.BoolTy)) + return Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_bool_condition) + << From->getType() << From->getSourceRange(); + return true; } /// AddOverloadCandidate - Adds the given function to the set of @@ -2063,21 +2159,25 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// If @p ForceRValue, treat all arguments as rvalues. This is a slightly /// hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). -void -Sema::AddOverloadCandidate(FunctionDecl *Function, +/// +/// \para PartialOverloading true if we are performing "partial" overloading +/// based on an incomplete set of function arguments. This feature is used by +/// code completion. +void +Sema::AddOverloadCandidate(FunctionDecl *Function, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, - bool ForceRValue) -{ - const FunctionProtoType* Proto - = dyn_cast<FunctionProtoType>(Function->getType()->getAsFunctionType()); + bool ForceRValue, + bool PartialOverloading) { + const FunctionProtoType* Proto + = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); - assert(!isa<CXXConversionDecl>(Function) && + assert(!isa<CXXConversionDecl>(Function) && "Use AddConversionCandidate for conversion functions"); - assert(!Function->getDescribedFunctionTemplate() && + assert(!Function->getDescribedFunctionTemplate() && "Use AddTemplateOverloadCandidate for function templates"); - + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) { if (!isa<CXXConstructorDecl>(Method)) { // If we get here, it's because we're calling a member function @@ -2086,7 +2186,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // implicitly. This can happen with a qualified call to a member // function, e.g., X::f(). We use a NULL object as the implied // object argument (C++ [over.call.func]p3). - AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet, + AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); return; } @@ -2094,7 +2194,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // argument doesn't participate in overload resolution. } - + if (!CandidateSet.isNewCandidate(Function)) + return; + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -2108,7 +2210,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // (C++ 13.3.2p2): A candidate function having fewer than m // parameters is viable only if it has an ellipsis in its parameter // list (8.3.5). - if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { + if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto && + !Proto->isVariadic()) { Candidate.Viable = false; return; } @@ -2119,7 +2222,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // parameter list is truncated on the right, so that there are // exactly m parameters. unsigned MinRequiredArgs = Function->getMinRequiredArguments(); - if (NumArgs < MinRequiredArgs) { + if (NumArgs < MinRequiredArgs && !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; return; @@ -2135,19 +2238,38 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // (13.3.3.1) that converts that argument to the corresponding // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); - Candidate.Conversions[ArgIdx] - = TryCopyInitialization(Args[ArgIdx], ParamType, - SuppressUserConversions, ForceRValue); - if (Candidate.Conversions[ArgIdx].ConversionKind + Candidate.Conversions[ArgIdx] + = TryCopyInitialization(Args[ArgIdx], ParamType, + SuppressUserConversions, ForceRValue, + /*InOverloadResolution=*/true); + if (Candidate.Conversions[ArgIdx].ConversionKind == ImplicitConversionSequence::BadConversion) { - Candidate.Viable = false; - break; + // 13.3.3.1-p10 If several different sequences of conversions exist that + // each convert the argument to the parameter type, the implicit conversion + // sequence associated with the parameter is defined to be the unique conversion + // sequence designated the ambiguous conversion sequence. For the purpose of + // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous + // conversion sequence is treated as a user-defined sequence that is + // indistinguishable from any other user-defined conversion sequence + if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) { + Candidate.Conversions[ArgIdx].ConversionKind = + ImplicitConversionSequence::UserDefinedConversion; + // Set the conversion function to one of them. As due to ambiguity, + // they carry the same weight and is needed for overload resolution + // later. + Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction = + Candidate.Conversions[ArgIdx].ConversionFunctionSet[0]; + } + else { + Candidate.Viable = false; + break; + } } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx].ConversionKind + Candidate.Conversions[ArgIdx].ConversionKind = ImplicitConversionSequence::EllipsisConversion; } } @@ -2159,17 +2281,32 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { - for (FunctionSet::const_iterator F = Functions.begin(), + for (FunctionSet::const_iterator F = Functions.begin(), FEnd = Functions.end(); F != FEnd; ++F) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) - AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, - SuppressUserConversions); - else - AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*F), + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) { + if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) + AddMethodCandidate(cast<CXXMethodDecl>(FD), + Args[0], Args + 1, NumArgs - 1, + CandidateSet, SuppressUserConversions); + else + AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, + SuppressUserConversions); + } else { + FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F); + if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) && + !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) + AddMethodTemplateCandidate(FunTmpl, /*FIXME: explicit args */false, 0, 0, - Args, NumArgs, CandidateSet, + Args[0], Args + 1, NumArgs - 1, + CandidateSet, SuppressUserConversions); + else + AddTemplateOverloadCandidate(FunTmpl, + /*FIXME: explicit args */false, 0, 0, + Args, NumArgs, CandidateSet, + SuppressUserConversions); + } } } @@ -2182,20 +2319,22 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, /// operators. If @p ForceRValue, treat all arguments as rvalues. This is /// a slightly hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). -void +void Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, bool ForceRValue) -{ - const FunctionProtoType* Proto - = dyn_cast<FunctionProtoType>(Method->getType()->getAsFunctionType()); + bool SuppressUserConversions, bool ForceRValue) { + const FunctionProtoType* Proto + = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>()); assert(Proto && "Methods without a prototype cannot be overloaded"); assert(!isa<CXXConversionDecl>(Method) && "Use AddConversionCandidate for conversion functions"); assert(!isa<CXXConstructorDecl>(Method) && "Use AddOverloadCandidate for constructors"); + if (!CandidateSet.isNewCandidate(Method)) + return; + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -2235,7 +2374,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, // Determine the implicit conversion sequence for the object // parameter. Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method); - if (Candidate.Conversions[0].ConversionKind + if (Candidate.Conversions[0].ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; return; @@ -2251,10 +2390,11 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, // (13.3.3.1) that converts that argument to the corresponding // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); - Candidate.Conversions[ArgIdx + 1] - = TryCopyInitialization(Args[ArgIdx], ParamType, - SuppressUserConversions, ForceRValue); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind + Candidate.Conversions[ArgIdx + 1] + = TryCopyInitialization(Args[ArgIdx], ParamType, + SuppressUserConversions, ForceRValue, + /*InOverloadResolution=*/true); + if (Candidate.Conversions[ArgIdx + 1].ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; break; @@ -2263,16 +2403,61 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind + Candidate.Conversions[ArgIdx + 1].ConversionKind = ImplicitConversionSequence::EllipsisConversion; } } } -/// \brief Add a C++ function template as a candidate in the candidate set, -/// using template argument deduction to produce an appropriate function -/// template specialization. -void +/// \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. +void +Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + Expr *Object, Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions, + bool ForceRValue) { + if (!CandidateSet.isNewCandidate(MethodTmpl)) + return; + + // C++ [over.match.funcs]p7: + // In each case where a candidate is a function template, candidate + // function template specializations are generated using template argument + // deduction (14.8.3, 14.8.2). Those candidates are then handled as + // candidate functions in the usual way.113) A given name can refer to one + // or more function templates and also to a set of overloaded non-template + // functions. In such a case, the candidate functions generated from each + // function template are combined with the set of non-template candidate + // functions. + TemplateDeductionInfo Info(Context); + FunctionDecl *Specialization = 0; + if (TemplateDeductionResult Result + = DeduceTemplateArguments(MethodTmpl, HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + 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; + } + + // Add the function template specialization produced by template argument + // deduction as a candidate. + assert(Specialization && "Missing member function template specialization?"); + assert(isa<CXXMethodDecl>(Specialization) && + "Specialization is not a member function?"); + AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Object, Args, NumArgs, + CandidateSet, SuppressUserConversions, ForceRValue); +} + +/// \brief Add a C++ function template specialization as a candidate +/// in the candidate set, using template argument deduction to produce +/// an appropriate function template specialization. +void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, const TemplateArgument *ExplicitTemplateArgs, @@ -2281,10 +2466,13 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { + if (!CandidateSet.isNewCandidate(FunctionTemplate)) + return; + // C++ [over.match.funcs]p7: - // In each case where a candidate is a function template, candidate + // In each case where a candidate is a function template, candidate // function template specializations are generated using template argument - // deduction (14.8.3, 14.8.2). Those candidates are then handled as + // deduction (14.8.3, 14.8.2). Those candidates are then handled as // candidate functions in the usual way.113) A given name can refer to one // or more function templates and also to a set of overloaded non-template // functions. In such a case, the candidate functions generated from each @@ -2301,24 +2489,30 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, (void)Result; return; } - + // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } - + /// AddConversionCandidate - Add a C++ conversion function as a -/// candidate in the candidate set (C++ [over.match.conv], +/// candidate in the candidate set (C++ [over.match.conv], /// C++ [over.match.copy]). From is the expression we're converting from, -/// and ToType is the type that we're eventually trying to convert to +/// and ToType is the type that we're eventually trying to convert to /// (which may or may not be the same type as the type that the /// conversion function produces). void Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet) { + assert(!Conversion->getDescribedFunctionTemplate() && + "Conversion function templates use AddTemplateConversionCandidate"); + + if (!CandidateSet.isNewCandidate(Conversion)) + return; + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -2326,7 +2520,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); - Candidate.FinalConversion.FromTypePtr + Candidate.FinalConversion.FromTypePtr = Conversion->getConversionType().getAsOpaquePtr(); Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr(); @@ -2335,8 +2529,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.Viable = true; Candidate.Conversions.resize(1); Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion); - - if (Candidate.Conversions[0].ConversionKind + // Conversion functions to a different type in the base class is visible in + // the derived class. So, a derived to base conversion should not participate + // in overload resolution. + if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base) + Candidate.Conversions[0].Standard.Second = ICK_Identity; + if (Candidate.Conversions[0].ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; return; @@ -2350,18 +2548,24 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // lvalues/rvalues and the type. Fortunately, we can allocate this // call on the stack and we don't need its arguments to be // well-formed. - DeclRefExpr ConversionRef(Conversion, Conversion->getType(), + DeclRefExpr ConversionRef(Conversion, Conversion->getType(), SourceLocation()); ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), + CastExpr::CK_Unknown, &ConversionRef, false); - - // Note that it is safe to allocate CallExpr on the stack here because + + // Note that it is safe to allocate CallExpr on the stack here because // there are 0 arguments (i.e., nothing is allocated using ASTContext's // allocator). - CallExpr Call(Context, &ConversionFn, 0, 0, + CallExpr Call(Context, &ConversionFn, 0, 0, Conversion->getConversionType().getNonReferenceType(), SourceLocation()); - ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, true); + ImplicitConversionSequence ICS = + TryCopyInitialization(&Call, ToType, + /*SuppressUserConversions=*/true, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + switch (ICS.ConversionKind) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; @@ -2372,11 +2576,43 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, break; default: - assert(false && + assert(false && "Can only end up with a standard conversion sequence or failure"); } } +/// \brief Adds a conversion function template specialization +/// candidate to the overload set, using template argument deduction +/// to deduce the template arguments of the conversion function +/// template from the type that we are converting to (C++ +/// [temp.deduct.conv]). +void +Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet) { + assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) && + "Only conversion function templates permitted here"); + + if (!CandidateSet.isNewCandidate(FunctionTemplate)) + return; + + TemplateDeductionInfo Info(Context); + CXXConversionDecl *Specialization = 0; + 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; + return; + } + + // Add the conversion function template specialization produced by + // template argument deduction as a candidate. + assert(Specialization && "Missing function template specialization?"); + AddConversionCandidate(Specialization, From, ToType, CandidateSet); +} + /// AddSurrogateCandidate - Adds a "surrogate" candidate function that /// converts the given @c Object to a function pointer via the /// conversion function @c Conversion, and then attempts to call it @@ -2386,6 +2622,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, const FunctionProtoType *Proto, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { + if (!CandidateSet.isNewCandidate(Conversion)) + return; + CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); Candidate.Function = 0; @@ -2397,7 +2636,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // Determine the implicit conversion sequence for the implicit // object parameter. - ImplicitConversionSequence ObjectInit + ImplicitConversionSequence ObjectInit = TryObjectArgumentInitialization(Object, Conversion); if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; @@ -2407,15 +2646,15 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // The first conversion is actually a user-defined conversion whose // first conversion is ObjectInit's standard conversion (which is // effectively a reference binding). Record it as such. - Candidate.Conversions[0].ConversionKind + Candidate.Conversions[0].ConversionKind = ImplicitConversionSequence::UserDefinedConversion; Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; - Candidate.Conversions[0].UserDefined.After + Candidate.Conversions[0].UserDefined.After = Candidate.Conversions[0].UserDefined.Before; Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion(); - // Find the + // Find the unsigned NumArgsInProto = Proto->getNumArgs(); // (C++ 13.3.2p2): A candidate function having fewer than m @@ -2443,10 +2682,12 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // (13.3.3.1) that converts that argument to the corresponding // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); - Candidate.Conversions[ArgIdx + 1] - = TryCopyInitialization(Args[ArgIdx], ParamType, - /*SuppressUserConversions=*/false); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind + Candidate.Conversions[ArgIdx + 1] + = TryCopyInitialization(Args[ArgIdx], ParamType, + /*SuppressUserConversions=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + if (Candidate.Conversions[ArgIdx + 1].ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; break; @@ -2455,7 +2696,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind + Candidate.Conversions[ArgIdx + 1].ConversionKind = ImplicitConversionSequence::EllipsisConversion; } } @@ -2469,7 +2710,6 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, SourceRange OpRange) { - FunctionSet Functions; QualType T1 = Args[0]->getType(); @@ -2518,14 +2758,32 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, // result of the qualified lookup of T1::operator@ // (13.3.1.1.1); otherwise, the set of member candidates is // empty. - // FIXME: Lookup in base classes, too! - if (const RecordType *T1Rec = T1->getAsRecordType()) { - DeclContext::lookup_const_iterator Oper, OperEnd; - for (llvm::tie(Oper, OperEnd) = T1Rec->getDecl()->lookup(OpName); - Oper != OperEnd; ++Oper) - AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Args[0], - Args+1, NumArgs - 1, CandidateSet, - /*SuppressUserConversions=*/false); + if (const RecordType *T1Rec = T1->getAs<RecordType>()) { + // Complete the type if it can be completed. Otherwise, we're done. + if (RequireCompleteType(OpLoc, T1, PDiag())) + return; + + LookupResult Operators; + LookupQualifiedName(Operators, T1Rec->getDecl(), OpName, + LookupOrdinaryName, false); + for (LookupResult::iterator Oper = Operators.begin(), + OperEnd = Operators.end(); + Oper != OperEnd; + ++Oper) { + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Oper)) { + AddMethodCandidate(Method, Args[0], Args+1, NumArgs - 1, CandidateSet, + /*SuppressUserConversions=*/false); + continue; + } + + assert(isa<FunctionTemplateDecl>(*Oper) && + isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(*Oper) + ->getTemplatedDecl()) && + "Expected a member function template"); + AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Oper), false, 0, 0, + Args[0], Args+1, NumArgs - 1, CandidateSet, + /*SuppressUserConversions=*/false); + } } } @@ -2537,7 +2795,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, /// operator. NumContextualBoolArguments is the number of arguments /// (at the beginning of the argument list) that will be contextually /// converted to bool. -void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, +void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator, @@ -2563,22 +2821,24 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, // -- no temporaries are introduced to hold the left operand, and // -- no user-defined conversions are applied to the left // operand to achieve a type match with the left-most - // parameter of a built-in candidate. + // parameter of a built-in candidate. // // We block these conversions by turning off user-defined // conversions, since that is the only way that initialization of // a reference to a non-class type can occur from something that // is not of the same type. if (ArgIdx < NumContextualBoolArguments) { - assert(ParamTys[ArgIdx] == Context.BoolTy && + assert(ParamTys[ArgIdx] == Context.BoolTy && "Contextual conversion to bool requires bool type"); Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]); } else { - Candidate.Conversions[ArgIdx] - = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], - ArgIdx == 0 && IsAssignmentOperator); + Candidate.Conversions[ArgIdx] + = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], + ArgIdx == 0 && IsAssignmentOperator, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } - if (Candidate.Conversions[ArgIdx].ConversionKind + if (Candidate.Conversions[ArgIdx].ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; break; @@ -2606,6 +2866,10 @@ class BuiltinCandidateTypeSet { /// used in the built-in candidates. TypeSet EnumerationTypes; + /// Sema - The semantic analysis instance where we are building the + /// candidate type set. + Sema &SemaRef; + /// Context - The AST context in which we will build the type sets. ASTContext &Context; @@ -2616,7 +2880,8 @@ public: /// iterator - Iterates through the types that are part of the set. typedef TypeSet::iterator iterator; - BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { } + BuiltinCandidateTypeSet(Sema &SemaRef) + : SemaRef(SemaRef), Context(SemaRef.Context) { } void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions, bool AllowExplicitConversions); @@ -2647,27 +2912,27 @@ public: /// restrict *", and "int const volatile restrict *" to the set of /// pointer types. Returns true if the add of @p Ty itself succeeded, /// false otherwise. +/// +/// FIXME: what to do about extended qualifiers? bool BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { + // Insert this type. if (!PointerTypes.insert(Ty)) return false; - if (const PointerType *PointerTy = Ty->getAsPointerType()) { - QualType PointeeTy = PointerTy->getPointeeType(); - // FIXME: Optimize this so that we don't keep trying to add the same types. - - // FIXME: Do we have to add CVR qualifiers at *all* levels to deal with all - // pointer conversions that don't cast away constness? - if (!PointeeTy.isConstQualified()) - AddPointerWithMoreQualifiedTypeVariants - (Context.getPointerType(PointeeTy.withConst())); - if (!PointeeTy.isVolatileQualified()) - AddPointerWithMoreQualifiedTypeVariants - (Context.getPointerType(PointeeTy.withVolatile())); - if (!PointeeTy.isRestrictQualified()) - AddPointerWithMoreQualifiedTypeVariants - (Context.getPointerType(PointeeTy.withRestrict())); + const PointerType *PointerTy = Ty->getAs<PointerType>(); + assert(PointerTy && "type was not a pointer type!"); + + QualType PointeeTy = PointerTy->getPointeeType(); + unsigned BaseCVR = PointeeTy.getCVRQualifiers(); + + // Iterate through all strict supersets of BaseCVR. + for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { + if ((CVR | BaseCVR) != CVR) continue; + + QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); + PointerTypes.insert(Context.getPointerType(QPointeeTy)); } return true; @@ -2680,6 +2945,8 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { /// restrict *", and "int const volatile restrict *" to the set of /// pointer types. Returns true if the add of @p Ty itself succeeded, /// false otherwise. +/// +/// FIXME: what to do about extended qualifiers? bool BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( QualType Ty) { @@ -2687,20 +2954,20 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( if (!MemberPointerTypes.insert(Ty)) return false; - if (const MemberPointerType *PointerTy = Ty->getAsMemberPointerType()) { - QualType PointeeTy = PointerTy->getPointeeType(); - const Type *ClassTy = PointerTy->getClass(); - // FIXME: Optimize this so that we don't keep trying to add the same types. - - if (!PointeeTy.isConstQualified()) - AddMemberPointerWithMoreQualifiedTypeVariants - (Context.getMemberPointerType(PointeeTy.withConst(), ClassTy)); - if (!PointeeTy.isVolatileQualified()) - AddMemberPointerWithMoreQualifiedTypeVariants - (Context.getMemberPointerType(PointeeTy.withVolatile(), ClassTy)); - if (!PointeeTy.isRestrictQualified()) - AddMemberPointerWithMoreQualifiedTypeVariants - (Context.getMemberPointerType(PointeeTy.withRestrict(), ClassTy)); + const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>(); + assert(PointerTy && "type was not a member pointer type!"); + + QualType PointeeTy = PointerTy->getPointeeType(); + const Type *ClassTy = PointerTy->getClass(); + + // Iterate through all strict supersets of the pointee type's CVR + // qualifiers. + unsigned BaseCVR = PointeeTy.getCVRQualifiers(); + for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { + if ((CVR | BaseCVR) != CVR) continue; + + QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); + MemberPointerTypes.insert(Context.getMemberPointerType(QPointeeTy, ClassTy)); } return true; @@ -2714,7 +2981,7 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( /// functions of a class type, and AllowExplicitConversions if we /// should also include the explicit conversion functions of a class /// type. -void +void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions, bool AllowExplicitConversions) { @@ -2723,13 +2990,13 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // Look through reference types; they aren't part of the type of an // expression for the purposes of conversions. - if (const ReferenceType *RefTy = Ty->getAsReferenceType()) + if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>()) Ty = RefTy->getPointeeType(); // We don't care about qualifiers on the type. Ty = Ty.getUnqualifiedType(); - if (const PointerType *PointerTy = Ty->getAsPointerType()) { + if (const PointerType *PointerTy = Ty->getAs<PointerType>()) { QualType PointeeTy = PointerTy->getPointeeType(); // Insert our type, and its more-qualified variants, into the set @@ -2739,20 +3006,22 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // Add 'cv void*' to our set of types. if (!Ty->isVoidType()) { - QualType QualVoid - = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers()); + QualType QualVoid + = Context.getCVRQualifiedType(Context.VoidTy, + PointeeTy.getCVRQualifiers()); AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid)); } // If this is a pointer to a class type, add pointers to its bases // (with the same level of cv-qualification as the original // derived class, of course). - if (const RecordType *PointeeRec = PointeeTy->getAsRecordType()) { + if (const RecordType *PointeeRec = PointeeTy->getAs<RecordType>()) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl()); for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { QualType BaseTy = Context.getCanonicalType(Base->getType()); - BaseTy = BaseTy.getQualifiedType(PointeeTy.getCVRQualifiers()); + BaseTy = Context.getCVRQualifiedType(BaseTy.getUnqualifiedType(), + PointeeTy.getCVRQualifiers()); // Add the pointer type, recursively, so that we get all of // the indirect base classes, too. @@ -2766,15 +3035,27 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } else if (Ty->isEnumeralType()) { EnumerationTypes.insert(Ty); } else if (AllowUserConversions) { - if (const RecordType *TyRec = Ty->getAsRecordType()) { + if (const RecordType *TyRec = Ty->getAs<RecordType>()) { + if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) { + // No conversion functions in incomplete types. + return; + } + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - // FIXME: Visit conversion functions in the base classes, too. - OverloadedFunctionDecl *Conversions - = ClassDecl->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator Func + OverloadedFunctionDecl *Conversions + = ClassDecl->getVisibleConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator Func = Conversions->function_begin(); Func != Conversions->function_end(); ++Func) { - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + GetFunctionAndTemplate(*Func, Conv, ConvTemplate); + + // Skip conversion function templates; they don't tell us anything + // about which builtin types we can convert to. + if (ConvTemplate) + continue; + if (AllowExplicitConversions || !Conv->isExplicit()) AddTypesConvertedFrom(Conv->getConversionType(), false, false); } @@ -2782,13 +3063,39 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } } +/// \brief Helper function for AddBuiltinOperatorCandidates() that adds +/// the volatile- and non-volatile-qualified assignment operators for the +/// given type to the candidate set. +static void AddBuiltinAssignmentOperatorCandidates(Sema &S, + QualType T, + Expr **Args, + unsigned NumArgs, + OverloadCandidateSet &CandidateSet) { + QualType ParamTypes[2]; + + // T& operator=(T&, T) + ParamTypes[0] = S.Context.getLValueReferenceType(T); + ParamTypes[1] = T; + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssignmentOperator=*/true); + + if (!S.Context.getCanonicalType(T).isVolatileQualified()) { + // volatile T& operator=(volatile T&, T) + ParamTypes[0] + = S.Context.getLValueReferenceType(S.Context.getVolatileType(T)); + ParamTypes[1] = T; + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssignmentOperator=*/true); + } +} + /// AddBuiltinOperatorCandidates - Add the appropriate built-in /// operator overloads to the candidate set (C++ [over.built]), based /// on the operator @p Op and the arguments given. For example, if the /// operator is a binary '+', this routine might add "int /// operator+(int, int)" to cover integer addition. void -Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, +Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { // The set of "promoted arithmetic types", which are the arithmetic @@ -2798,13 +3105,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // FIXME: What about complex? const unsigned FirstIntegralType = 0; const unsigned LastIntegralType = 13; - const unsigned FirstPromotedIntegralType = 7, + const unsigned FirstPromotedIntegralType = 7, LastPromotedIntegralType = 13; const unsigned FirstPromotedArithmeticType = 7, LastPromotedArithmeticType = 16; const unsigned NumArithmeticTypes = 16; QualType ArithmeticTypes[NumArithmeticTypes] = { Context.BoolTy, Context.CharTy, Context.WCharTy, +// FIXME: Context.Char16Ty, Context.Char32Ty, Context.SignedCharTy, Context.ShortTy, Context.UnsignedCharTy, Context.UnsignedShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy, @@ -2815,7 +3123,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // Find all of the types that the arguments can convert to, but only // if the operator we're looking at has built-in operator candidates // that make use of these types. - BuiltinCandidateTypeSet CandidateTypes(Context); + 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 || @@ -2838,7 +3146,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Star: // '*' is either unary or binary - if (NumArgs == 1) + if (NumArgs == 1) goto UnaryStar; else goto BinaryStar; @@ -2883,10 +3191,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // VQ T& operator--(VQ T&); // T operator--(VQ T&, int); - for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); + for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); Arith < NumArithmeticTypes; ++Arith) { QualType ArithTy = ArithmeticTypes[Arith]; - QualType ParamTypes[2] + QualType ParamTypes[2] = { Context.getLValueReferenceType(ArithTy), Context.IntTy }; // Non-volatile version. @@ -2896,7 +3204,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); // Volatile version - ParamTypes[0] = Context.getLValueReferenceType(ArithTy.withVolatile()); + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(ArithTy)); if (NumArgs == 1) AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); else @@ -2916,13 +3225,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); Ptr != CandidateTypes.pointer_end(); ++Ptr) { // Skip pointer types that aren't pointers to object types. - if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType()) + if (!(*Ptr)->getAs<PointerType>()->getPointeeType()->isObjectType()) continue; - QualType ParamTypes[2] = { - Context.getLValueReferenceType(*Ptr), Context.IntTy + QualType ParamTypes[2] = { + Context.getLValueReferenceType(*Ptr), Context.IntTy }; - + // Without volatile if (NumArgs == 1) AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); @@ -2931,7 +3240,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { // With volatile - ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile()); + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); if (NumArgs == 1) AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); else @@ -2954,8 +3264,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); Ptr != CandidateTypes.pointer_end(); ++Ptr) { QualType ParamTy = *Ptr; - QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType(); - AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy), + QualType PointeeTy = ParamTy->getAs<PointerType>()->getPointeeType(); + AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy), &ParamTy, Args, 1, CandidateSet); } break; @@ -2971,7 +3281,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType ParamTy = *Ptr; AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); } - + // Fall through UnaryMinus: @@ -2981,7 +3291,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // T operator+(T); // T operator-(T); - for (unsigned Arith = FirstPromotedArithmeticType; + for (unsigned Arith = FirstPromotedArithmeticType; Arith < LastPromotedArithmeticType; ++Arith) { QualType ArithTy = ArithmeticTypes[Arith]; AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); @@ -2994,7 +3304,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // operator functions of the form // // T operator~(T); - for (unsigned Int = FirstPromotedIntegralType; + for (unsigned Int = FirstPromotedIntegralType; Int < LastPromotedIntegralType; ++Int) { QualType IntTy = ArithmeticTypes[Int]; AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); @@ -3017,17 +3327,34 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // operator '->', the built-in candidates set is empty. break; + case OO_EqualEqual: + case OO_ExclaimEqual: + // C++ [over.match.oper]p16: + // For every pointer to member type T, there exist candidate operator + // functions of the form + // + // bool operator==(T,T); + // bool operator!=(T,T); + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes.member_pointer_begin(), + MemPtrEnd = CandidateTypes.member_pointer_end(); + MemPtr != MemPtrEnd; + ++MemPtr) { + QualType ParamTypes[2] = { *MemPtr, *MemPtr }; + AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + } + + // Fall through + case OO_Less: case OO_Greater: case OO_LessEqual: case OO_GreaterEqual: - case OO_EqualEqual: - case OO_ExclaimEqual: // C++ [over.built]p15: // // For every pointer or enumeration type T, there exist // candidate operator functions of the form - // + // // bool operator<(T, T); // bool operator>(T, T); // bool operator<=(T, T); @@ -3039,7 +3366,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType ParamTypes[2] = { *Ptr, *Ptr }; AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); } - for (BuiltinCandidateTypeSet::iterator Enum + for (BuiltinCandidateTypeSet::iterator Enum = CandidateTypes.enumeration_begin(); Enum != CandidateTypes.enumeration_end(); ++Enum) { QualType ParamTypes[2] = { *Enum, *Enum }; @@ -3058,7 +3385,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // For every cv-qualified or cv-unqualified object type T // there exist candidate operator functions of the form - // + // // T* operator+(T*, ptrdiff_t); // T& operator[](T*, ptrdiff_t); [BELOW] // T* operator-(T*, ptrdiff_t); @@ -3071,7 +3398,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // exist candidate operator functions of the form // // ptrdiff_t operator-(T, T); - for (BuiltinCandidateTypeSet::iterator Ptr + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); Ptr != CandidateTypes.pointer_end(); ++Ptr) { QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; @@ -3126,14 +3453,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // where LR is the result of the usual arithmetic conversions // between types L and R. // Our candidates ignore the first parameter. - for (unsigned Left = FirstPromotedArithmeticType; + for (unsigned Left = FirstPromotedArithmeticType; Left < LastPromotedArithmeticType; ++Left) { - for (unsigned Right = FirstPromotedArithmeticType; + for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] }; - QualType Result - = isComparison? Context.BoolTy - : UsualArithmeticConversionsType(LandR[0], LandR[1]); + QualType Result + = isComparison + ? Context.BoolTy + : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]); AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } @@ -3159,14 +3487,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // where LR is the result of the usual arithmetic conversions // between types L and R. - for (unsigned Left = FirstPromotedIntegralType; + for (unsigned Left = FirstPromotedIntegralType; Left < LastPromotedIntegralType; ++Left) { - for (unsigned Right = FirstPromotedIntegralType; + for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] }; QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater) ? LandR[0] - : UsualArithmeticConversionsType(LandR[0], LandR[1]); + : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]); AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } @@ -3176,30 +3504,23 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // C++ [over.built]p20: // // For every pair (T, VQ), where T is an enumeration or - // (FIXME:) pointer to member type and VQ is either volatile or + // pointer to member type and VQ is either volatile or // empty, there exist candidate operator functions of the form // // VQ T& operator=(VQ T&, T); - for (BuiltinCandidateTypeSet::iterator Enum - = CandidateTypes.enumeration_begin(); - Enum != CandidateTypes.enumeration_end(); ++Enum) { - QualType ParamTypes[2]; - - // T& operator=(T&, T) - ParamTypes[0] = Context.getLValueReferenceType(*Enum); - ParamTypes[1] = *Enum; - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssignmentOperator=*/false); - - if (!Context.getCanonicalType(*Enum).isVolatileQualified()) { - // volatile T& operator=(volatile T&, T) - ParamTypes[0] = Context.getLValueReferenceType((*Enum).withVolatile()); - ParamTypes[1] = *Enum; - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssignmentOperator=*/false); - } - } - // Fall through. + for (BuiltinCandidateTypeSet::iterator + Enum = CandidateTypes.enumeration_begin(), + EnumEnd = CandidateTypes.enumeration_end(); + Enum != EnumEnd; ++Enum) + AddBuiltinAssignmentOperatorCandidates(*this, *Enum, Args, 2, + CandidateSet); + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes.member_pointer_begin(), + MemPtrEnd = CandidateTypes.member_pointer_end(); + MemPtr != MemPtrEnd; ++MemPtr) + AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2, + CandidateSet); + // Fall through. case OO_PlusEqual: case OO_MinusEqual: @@ -3231,7 +3552,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { // volatile version - ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile()); + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, /*IsAssigmentOperator=*/Op == OO_Equal); } @@ -3253,7 +3575,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // VQ L& operator+=(VQ L&, R); // VQ L& operator-=(VQ L&, R); for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) { - for (unsigned Right = FirstPromotedArithmeticType; + for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { QualType ParamTypes[2]; ParamTypes[1] = ArithmeticTypes[Right]; @@ -3264,7 +3586,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, /*IsAssigmentOperator=*/Op == OO_Equal); // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = ArithmeticTypes[Left].withVolatile(); + ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]); ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, /*IsAssigmentOperator=*/Op == OO_Equal); @@ -3291,7 +3613,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // VQ L& operator^=(VQ L&, R); // VQ L& operator|=(VQ L&, R); for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) { - for (unsigned Right = FirstPromotedIntegralType; + for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { QualType ParamTypes[2]; ParamTypes[1] = ArithmeticTypes[Right]; @@ -3302,7 +3624,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // Add this built-in operator as a candidate (VQ is 'volatile'). ParamTypes[0] = ArithmeticTypes[Left]; - ParamTypes[0].addVolatile(); + ParamTypes[0] = Context.getVolatileType(ParamTypes[0]); ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); } @@ -3314,7 +3636,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // There also exist candidate operator functions of the form // - // bool operator!(bool); + // bool operator!(bool); // bool operator&&(bool, bool); [BELOW] // bool operator||(bool, bool); [BELOW] QualType ParamTy = Context.BoolTy; @@ -3345,7 +3667,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // For every cv-qualified or cv-unqualified object type T there // exist candidate operator functions of the form - // + // // T* operator+(T*, ptrdiff_t); [ABOVE] // T& operator[](T*, ptrdiff_t); // T* operator-(T*, ptrdiff_t); [ABOVE] @@ -3354,7 +3676,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); Ptr != CandidateTypes.pointer_end(); ++Ptr) { QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; - QualType PointeeType = (*Ptr)->getAsPointerType()->getPointeeType(); + QualType PointeeType = (*Ptr)->getAs<PointerType>()->getPointeeType(); QualType ResultTy = Context.getLValueReferenceType(PointeeType); // T& operator[](T*, ptrdiff_t) @@ -3368,7 +3690,43 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_ArrowStar: - // FIXME: No support for pointer-to-members yet. + // C++ [over.built]p11: + // For every quintuple (C1, C2, T, CV1, CV2), where C2 is a class type, + // C1 is the same type as C2 or is a derived class of C2, T is an object + // type or a function type, and CV1 and CV2 are cv-qualifier-seqs, + // there exist candidate operator functions of the form + // CV12 T& operator->*(CV1 C1*, CV2 T C2::*); + // where CV12 is the union of CV1 and CV2. + { + for (BuiltinCandidateTypeSet::iterator Ptr = + CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType C1Ty = (*Ptr); + QualType C1; + QualifierCollector Q1; + if (const PointerType *PointerTy = C1Ty->getAs<PointerType>()) { + C1 = QualType(Q1.strip(PointerTy->getPointeeType()), 0); + if (!isa<RecordType>(C1)) + continue; + } + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes.member_pointer_begin(), + MemPtrEnd = CandidateTypes.member_pointer_end(); + MemPtr != MemPtrEnd; ++MemPtr) { + const MemberPointerType *mptr = cast<MemberPointerType>(*MemPtr); + QualType C2 = QualType(mptr->getClass(), 0); + C2 = C2.getUnqualifiedType(); + if (C1 != C2 && !IsDerivedFrom(C1, C2)) + break; + QualType ParamTypes[2] = { *Ptr, *MemPtr }; + // build CV12 T& + QualType T = mptr->getPointeeType(); + T = Q1.apply(T); + QualType ResultTy = Context.getLValueReferenceType(T); + AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + } + } + } break; case OO_Conditional: @@ -3404,12 +3762,18 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, /// given function name (which may also be an operator name) and adds /// all of the overload candidates found by ADL to the overload /// candidate set (C++ [basic.lookup.argdep]). -void +void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet) { + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + OverloadCandidateSet& CandidateSet, + bool PartialOverloading) { FunctionSet Functions; + // FIXME: Should we be trafficking in canonical function decls throughout? + // Record all of the function candidates that we've already // added to the overload set, so that we don't add those same // candidates a second time. @@ -3422,6 +3786,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, Functions.insert(FunTmpl); } + // FIXME: Pass in the explicit template arguments? ArgumentDependentLookup(Name, Args, NumArgs, Functions); // Erase all of the candidates we already knew about. @@ -3440,21 +3805,26 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, for (FunctionSet::iterator Func = Functions.begin(), FuncEnd = Functions.end(); Func != FuncEnd; ++Func) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) - AddOverloadCandidate(FD, Args, NumArgs, CandidateSet); - else - AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func), - /*FIXME: explicit args */false, 0, 0, + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) { + if (HasExplicitTemplateArgs) + continue; + + AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, + false, false, PartialOverloading); + } else + AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func), + HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, Args, NumArgs, CandidateSet); } } /// isBetterOverloadCandidate - Determines whether the first overload /// candidate is a better candidate than the second (C++ 13.3.3p1). -bool +bool Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2) -{ + const OverloadCandidate& Cand2) { // Define viable functions to be better candidates than non-viable // functions. if (!Cand2.Viable) @@ -3472,10 +3842,10 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument) StartArg = 1; - // (C++ 13.3.3p1): a viable function F1 is defined to be a better - // function than another viable function F2 if for all arguments i, - // ICSi(F1) is not a worse conversion sequence than ICSi(F2), and - // then... + // C++ [over.match.best]p1: + // A viable function F1 is defined to be a better function than another + // viable function F2 if for all arguments i, ICSi(F1) is not a worse + // conversion sequence than ICSi(F2), and then... unsigned NumArgs = Cand1.Conversions.size(); assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch"); bool HasBetterConversion = false; @@ -3497,22 +3867,38 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, } } + // -- for some argument j, ICSj(F1) is a better conversion sequence than + // ICSj(F2), or, if not that, if (HasBetterConversion) return true; - // FIXME: Several other bullets in (C++ 13.3.3p1) need to be - // implemented, but they require template support. + // - F1 is a non-template function and F2 is a function template + // specialization, or, if not that, + if (Cand1.Function && !Cand1.Function->getPrimaryTemplate() && + Cand2.Function && Cand2.Function->getPrimaryTemplate()) + return true; + + // -- F1 and F2 are function template specializations, and the function + // template for F1 is more specialized than the template for F2 + // according to the partial ordering rules described in 14.5.5.2, or, + // if not that, + if (Cand1.Function && Cand1.Function->getPrimaryTemplate() && + Cand2.Function && Cand2.Function->getPrimaryTemplate()) + if (FunctionTemplateDecl *BetterTemplate + = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), + Cand2.Function->getPrimaryTemplate(), + isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion + : TPOC_Call)) + return BetterTemplate == Cand1.Function->getPrimaryTemplate(); - // C++ [over.match.best]p1b4: - // // -- the context is an initialization by user-defined conversion // (see 8.5, 13.3.1.5) and the standard conversion sequence // from the return type of F1 to the destination type (i.e., // the type of the entity being initialized) is a better // conversion sequence than the standard conversion sequence // from the return type of F2 to the destination type. - if (Cand1.Function && Cand2.Function && - isa<CXXConversionDecl>(Cand1.Function) && + if (Cand1.Function && Cand2.Function && + isa<CXXConversionDecl>(Cand1.Function) && isa<CXXConversionDecl>(Cand2.Function)) { switch (CompareStandardConversionSequences(Cand1.FinalConversion, Cand2.FinalConversion)) { @@ -3533,7 +3919,7 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, return false; } -/// \brief Computes the best viable function (C++ 13.3.3) +/// \brief Computes the best viable function (C++ 13.3.3) /// within an overload candidate set. /// /// \param CandidateSet the set of candidate functions. @@ -3541,15 +3927,14 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, /// \param Loc the location of the function name (or operator symbol) for /// which overload resolution occurs. /// -/// \param Best f overload resolution was successful or found a deleted +/// \param Best f overload resolution was successful or found a deleted /// function, Best points to the candidate function found. /// /// \returns The result of overload resolution. -Sema::OverloadingResult +Sema::OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, SourceLocation Loc, - OverloadCandidateSet::iterator& Best) -{ + OverloadCandidateSet::iterator& Best) { // Find the best viable function. Best = CandidateSet.end(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); @@ -3568,24 +3953,24 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, // function. If not, we have an ambiguity. for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); Cand != CandidateSet.end(); ++Cand) { - if (Cand->Viable && + if (Cand->Viable && Cand != Best && !isBetterOverloadCandidate(*Best, *Cand)) { Best = CandidateSet.end(); return OR_Ambiguous; } } - + // Best is the best viable function. if (Best->Function && - (Best->Function->isDeleted() || + (Best->Function->isDeleted() || Best->Function->getAttr<UnavailableAttr>())) return OR_Deleted; // C++ [basic.def.odr]p2: // An overloaded function is used if it is selected by overload resolution - // when referred to from a potentially-evaluated expression. [Note: this - // covers calls to named functions (5.2.2), operator overloading + // when referred to from a potentially-evaluated expression. [Note: this + // covers calls to named functions (5.2.2), operator overloading // (clause 13), user-defined conversions (12.3.2), allocation function for // placement new (5.3.4), as well as non-default initialization (8.5). if (Best->Function) @@ -3596,12 +3981,14 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, /// PrintOverloadCandidates - When overload resolution fails, prints /// diagnostic messages containing the candidates in the candidate /// set. If OnlyViable is true, only viable candidates will be printed. -void +void Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - bool OnlyViable) -{ + bool OnlyViable, + const char *Opc, + SourceLocation OpLoc) { OverloadCandidateSet::iterator Cand = CandidateSet.begin(), LastCand = CandidateSet.end(); + bool Reported = false; for (; Cand != LastCand; ++Cand) { if (Cand->Viable || !OnlyViable) { if (Cand->Function) { @@ -3610,10 +3997,36 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, // Deleted or "unavailable" function. Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted) << Cand->Function->isDeleted(); + } else if (FunctionTemplateDecl *FunTmpl + = Cand->Function->getPrimaryTemplate()) { + // Function template specialization + // FIXME: Give a better reason! + Diag(Cand->Function->getLocation(), diag::err_ovl_template_candidate) + << getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(), + *Cand->Function->getTemplateSpecializationArgs()); } else { // Normal function - // FIXME: Give a better reason! - Diag(Cand->Function->getLocation(), diag::err_ovl_candidate); + bool errReported = false; + if (!Cand->Viable && Cand->Conversions.size() > 0) { + for (int i = Cand->Conversions.size()-1; i >= 0; i--) { + const ImplicitConversionSequence &Conversion = + Cand->Conversions[i]; + if ((Conversion.ConversionKind != + ImplicitConversionSequence::BadConversion) || + Conversion.ConversionFunctionSet.size() == 0) + continue; + Diag(Cand->Function->getLocation(), + diag::err_ovl_candidate_not_viable) << (i+1); + errReported = true; + for (int j = Conversion.ConversionFunctionSet.size()-1; + j >= 0; j--) { + FunctionDecl *Func = Conversion.ConversionFunctionSet[j]; + Diag(Func->getLocation(), diag::err_ovl_candidate); + } + } + } + if (!errReported) + Diag(Cand->Function->getLocation(), diag::err_ovl_candidate); } } else if (Cand->IsSurrogate) { // Desugar the type of the surrogate down to a function type, @@ -3624,20 +4037,20 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, bool isRValueReference = false; bool isPointer = false; if (const LValueReferenceType *FnTypeRef = - FnType->getAsLValueReferenceType()) { + FnType->getAs<LValueReferenceType>()) { FnType = FnTypeRef->getPointeeType(); isLValueReference = true; } else if (const RValueReferenceType *FnTypeRef = - FnType->getAsRValueReferenceType()) { + FnType->getAs<RValueReferenceType>()) { FnType = FnTypeRef->getPointeeType(); isRValueReference = true; } - if (const PointerType *FnTypePtr = FnType->getAsPointerType()) { + if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) { FnType = FnTypePtr->getPointeeType(); isPointer = true; } // Desugar down to a function type. - FnType = QualType(FnType->getAsFunctionType(), 0); + FnType = QualType(FnType->getAs<FunctionType>(), 0); // Reconstruct the pointer/reference as appropriate. if (isPointer) FnType = Context.getPointerType(FnType); if (isRValueReference) FnType = Context.getRValueReferenceType(FnType); @@ -3645,17 +4058,42 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand) << FnType; - } else { - // FIXME: We need to get the identifier in here - // FIXME: Do we want the error message to point at the operator? - // (built-ins won't have a location) - QualType FnType - = Context.getFunctionType(Cand->BuiltinTypes.ResultTy, - Cand->BuiltinTypes.ParamTypes, - Cand->Conversions.size(), - false, 0); - - Diag(SourceLocation(), diag::err_ovl_builtin_candidate) << FnType; + } else if (OnlyViable) { + assert(Cand->Conversions.size() <= 2 && + "builtin-binary-operator-not-binary"); + if (Cand->Conversions.size() == 1) + Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) + << Opc << Cand->BuiltinTypes.ParamTypes[0]; + else + Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) + << Opc << Cand->BuiltinTypes.ParamTypes[0] + << Cand->BuiltinTypes.ParamTypes[1]; + } + else if (!Cand->Viable && !Reported) { + // Non-viability might be due to ambiguous user-defined conversions, + // needed for built-in operators. Report them as well, but only once + // as we have typically many built-in candidates. + unsigned NoOperands = Cand->Conversions.size(); + for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) { + const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; + if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion || + ICS.ConversionFunctionSet.empty()) + continue; + if (CXXConversionDecl *Func = dyn_cast<CXXConversionDecl>( + Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) { + QualType FromTy = + QualType( + static_cast<Type*>(ICS.UserDefined.Before.FromTypePtr),0); + Diag(OpLoc,diag::note_ambiguous_type_conversion) + << FromTy << Func->getConversionType(); + } + for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) { + FunctionDecl *Func = + Cand->Conversions[ArgIdx].ConversionFunctionSet[j]; + Diag(Func->getLocation(),diag::err_ovl_candidate); + } + } + Reported = true; } } } @@ -3669,7 +4107,7 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, /// @code /// int f(double); /// int f(int); -/// +/// /// int (*pfd)(double) = f; // selects f(double) /// @endcode /// @@ -3681,23 +4119,24 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain) { QualType FunctionType = ToType; bool IsMember = false; - if (const PointerType *ToTypePtr = ToType->getAsPointerType()) + if (const PointerType *ToTypePtr = ToType->getAs<PointerType>()) FunctionType = ToTypePtr->getPointeeType(); - else if (const ReferenceType *ToTypeRef = ToType->getAsReferenceType()) + else if (const ReferenceType *ToTypeRef = ToType->getAs<ReferenceType>()) FunctionType = ToTypeRef->getPointeeType(); else if (const MemberPointerType *MemTypePtr = - ToType->getAsMemberPointerType()) { + ToType->getAs<MemberPointerType>()) { FunctionType = MemTypePtr->getPointeeType(); IsMember = true; } // We only look at pointers or references to functions. - if (!FunctionType->isFunctionType()) + FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); + if (!FunctionType->isFunctionType()) return 0; // Find the actual overloaded function declaration. OverloadedFunctionDecl *Ovl = 0; - + // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] @@ -3712,27 +4151,76 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } // Try to dig out the overloaded function. - if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) + FunctionTemplateDecl *FunctionTemplate = 0; + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) { Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl()); + FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DR->getDecl()); + } else if (MemberExpr *ME = dyn_cast<MemberExpr>(OvlExpr)) { + Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl()); + FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl()); + // FIXME: Explicit template arguments + } + // FIXME: TemplateIdRefExpr? - // If there's no overloaded function declaration, we're done. - if (!Ovl) + // If there's no overloaded function declaration or function template, + // we're done. + if (!Ovl && !FunctionTemplate) return 0; - + + OverloadIterator Fun; + if (Ovl) + Fun = Ovl; + else + Fun = FunctionTemplate; + // Look through all of the overloaded functions, searching for one // whose type matches exactly. - // FIXME: When templates or using declarations come along, we'll actually - // have to deal with duplicates, partial ordering, etc. For now, we - // can just do a simple search. - FunctionType = Context.getCanonicalType(FunctionType.getUnqualifiedType()); - for (OverloadedFunctionDecl::function_iterator Fun = Ovl->function_begin(); - Fun != Ovl->function_end(); ++Fun) { + llvm::SmallPtrSet<FunctionDecl *, 4> Matches; + bool FoundNonTemplateFunction = false; + for (OverloadIterator FunEnd; Fun != FunEnd; ++Fun) { // C++ [over.over]p3: // Non-member functions and static member functions match // targets of type "pointer-to-function" or "reference-to-function." // Nonstatic member functions match targets of // type "pointer-to-member-function." // Note that according to DR 247, the containing class does not matter. + + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast<FunctionTemplateDecl>(*Fun)) { + if (CXXMethodDecl *Method + = dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) { + // Skip non-static function templates when converting to pointer, and + // static when converting to member pointer. + if (Method->isStatic() == IsMember) + continue; + } else if (IsMember) + continue; + + // C++ [over.over]p2: + // If the name is a function template, template argument deduction is + // done (14.8.2.2), and if the argument deduction succeeds, the + // resulting template argument list is used to generate a single + // function template specialization, which is added to the set of + // overloaded functions considered. + // FIXME: We don't really want to build the specialization here, do we? + FunctionDecl *Specialization = 0; + TemplateDeductionInfo Info(Context); + if (TemplateDeductionResult Result + = DeduceTemplateArguments(FunctionTemplate, /*FIXME*/false, + /*FIXME:*/0, /*FIXME:*/0, + FunctionType, Specialization, Info)) { + // FIXME: make a note of the failed deduction for diagnostics. + (void)Result; + } else { + // FIXME: If the match isn't exact, shouldn't we just drop this as + // a candidate? Find a testcase before changing the code. + assert(FunctionType + == Context.getCanonicalType(Specialization->getType())); + Matches.insert( + cast<FunctionDecl>(Specialization->getCanonicalDecl())); + } + } + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Fun)) { // Skip non-static functions when converting to pointer, and static // when converting to member pointer. @@ -3742,38 +4230,106 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, continue; if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Fun)) { - if (FunctionType == Context.getCanonicalType(FunDecl->getType())) - return FunDecl; - } else { - unsigned DiagID - = PP.getDiagnostics().getCustomDiagID(Diagnostic::Warning, - "Clang does not yet support templated conversion functions"); - Diag(From->getLocStart(), DiagID); + if (FunctionType == Context.getCanonicalType(FunDecl->getType())) { + Matches.insert(cast<FunctionDecl>(Fun->getCanonicalDecl())); + FoundNonTemplateFunction = true; + } } } + // If there were 0 or 1 matches, we're done. + if (Matches.empty()) + return 0; + else if (Matches.size() == 1) + return *Matches.begin(); + + // C++ [over.over]p4: + // If more than one function is selected, [...] + typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter; + if (!FoundNonTemplateFunction) { + // [...] and any given function template specialization F1 is + // eliminated if the set contains a second function template + // specialization whose function template is more specialized + // than the function template of F1 according to the partial + // ordering rules of 14.5.5.2. + + // The algorithm specified above is quadratic. We instead use a + // two-pass algorithm (similar to the one used to identify the + // best viable function in an overload set) that identifies the + // best function template (if it exists). + llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(), + Matches.end()); + return getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(), + TPOC_Other, From->getLocStart(), + PDiag(), + PDiag(diag::err_addr_ovl_ambiguous) + << TemplateMatches[0]->getDeclName(), + PDiag(diag::err_ovl_template_candidate)); + } + + // [...] any function template specializations in the set are + // eliminated if the set also contains a non-template function, [...] + llvm::SmallVector<FunctionDecl *, 4> RemainingMatches; + for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M) + if ((*M)->getPrimaryTemplate() == 0) + RemainingMatches.push_back(*M); + + // [...] After such eliminations, if any, there shall remain exactly one + // selected function. + if (RemainingMatches.size() == 1) + return RemainingMatches.front(); + + // FIXME: We should probably return the same thing that BestViableFunction + // returns (even if we issue the diagnostics here). + Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) + << RemainingMatches[0]->getDeclName(); + for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I) + Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate); return 0; } -/// ResolveOverloadedCallFn - Given the call expression that calls Fn -/// (which eventually refers to the declaration Func) and the call -/// arguments Args/NumArgs, attempt to resolve the function call down -/// to a specific function. If overload resolution succeeds, returns -/// the function declaration produced by overload -/// resolution. Otherwise, emits diagnostics, deletes all of the -/// arguments and Fn, and returns NULL. -FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, - DeclarationName UnqualifiedName, - bool HasExplicitTemplateArgs, +/// \brief Add a single candidate to the overload set. +static void AddOverloadedCallCandidate(Sema &S, + AnyFunctionDecl Callee, + bool &ArgumentDependentLookup, + bool HasExplicitTemplateArgs, const TemplateArgument *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc, - bool &ArgumentDependentLookup) { - OverloadCandidateSet CandidateSet; - + unsigned NumExplicitTemplateArgs, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading) { + if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) { + assert(!HasExplicitTemplateArgs && "Explicit template arguments?"); + S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false, + PartialOverloading); + + if (Func->getDeclContext()->isRecord() || + Func->getDeclContext()->isFunctionOrMethod()) + ArgumentDependentLookup = false; + return; + } + + FunctionTemplateDecl *FuncTemplate = cast<FunctionTemplateDecl>(Callee); + S.AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + Args, NumArgs, CandidateSet); + + if (FuncTemplate->getDeclContext()->isRecord()) + ArgumentDependentLookup = false; +} + +/// \brief Add the overload candidates named by callee and/or found by argument +/// dependent lookup to the given overload set. +void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, + DeclarationName &UnqualifiedName, + bool &ArgumentDependentLookup, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading) { // Add the functions denoted by Callee to the set of candidate // functions. While we're doing so, track whether argument-dependent // lookup still applies, per: @@ -3783,66 +4339,75 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, // and let Y be the lookup set produced by argument dependent // lookup (defined as follows). If X contains // - // -- a declaration of a class member, or + // -- a declaration of a class member, or // // -- a block-scope function declaration that is not a - // using-declaration, or - // + // using-declaration (FIXME: check for using declaration), or + // // -- a declaration that is neither a function or a function // template // - // then Y is empty. - if (OverloadedFunctionDecl *Ovl - = dyn_cast_or_null<OverloadedFunctionDecl>(Callee)) { + // then Y is empty. + if (!Callee) { + // Nothing to do. + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(Callee)) { for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) { - DeclContext *Ctx = 0; - if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) { - if (HasExplicitTemplateArgs) - continue; - - AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet); - Ctx = FunDecl->getDeclContext(); - } else { - FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func); - AddTemplateOverloadCandidate(FunTmpl, HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - Args, NumArgs, CandidateSet); - Ctx = FunTmpl->getDeclContext(); - } - - - if (Ctx->isRecord() || Ctx->isFunctionOrMethod()) - ArgumentDependentLookup = false; - } - } else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) { - assert(!HasExplicitTemplateArgs && "Explicit template arguments?"); - AddOverloadCandidate(Func, Args, NumArgs, CandidateSet); - - if (Func->getDeclContext()->isRecord() || - Func->getDeclContext()->isFunctionOrMethod()) - ArgumentDependentLookup = false; - } else if (FunctionTemplateDecl *FuncTemplate - = dyn_cast_or_null<FunctionTemplateDecl>(Callee)) { - AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - Args, NumArgs, CandidateSet); - - if (FuncTemplate->getDeclContext()->isRecord()) - ArgumentDependentLookup = false; - } - + Func != FuncEnd; ++Func) + AddOverloadedCallCandidate(*this, *Func, ArgumentDependentLookup, + HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + Args, NumArgs, CandidateSet, + PartialOverloading); + } else if (isa<FunctionDecl>(Callee) || isa<FunctionTemplateDecl>(Callee)) + AddOverloadedCallCandidate(*this, + AnyFunctionDecl::getFromNamedDecl(Callee), + ArgumentDependentLookup, + HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + Args, NumArgs, CandidateSet, + PartialOverloading); + // FIXME: assert isa<FunctionDecl> || isa<FunctionTemplateDecl> rather than + // checking dynamically. + if (Callee) UnqualifiedName = Callee->getDeclName(); - - // FIXME: Pass explicit template arguments through for ADL + if (ArgumentDependentLookup) AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs, - CandidateSet); + HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + CandidateSet, + PartialOverloading); +} + +/// ResolveOverloadedCallFn - Given the call expression that calls Fn +/// (which eventually refers to the declaration Func) and the call +/// arguments Args/NumArgs, attempt to resolve the function call down +/// to a specific function. If overload resolution succeeds, returns +/// the function declaration produced by overload +/// resolution. Otherwise, emits diagnostics, deletes all of the +/// arguments and Fn, and returns NULL. +FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, + DeclarationName UnqualifiedName, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc, + bool &ArgumentDependentLookup) { + OverloadCandidateSet CandidateSet; + // Add the functions denoted by Callee to the set of candidate + // functions. + AddOverloadedCallCandidates(Callee, UnqualifiedName, ArgumentDependentLookup, + HasExplicitTemplateArgs, ExplicitTemplateArgs, + NumExplicitTemplateArgs, Args, NumArgs, + CandidateSet); OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { case OR_Success: @@ -3897,7 +4462,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, FunctionSet &Functions, - ExprArg input) { + ExprArg input) { UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn); Expr *Input = (Expr *)input.get(); @@ -3907,28 +4472,28 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, Expr *Args[2] = { Input, 0 }; unsigned NumArgs = 1; - + // For post-increment and post-decrement, add the implicit '0' as // the second argument, so that we know this is a post-increment or // post-decrement. if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) { llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false); - Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy, + Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy, SourceLocation()); NumArgs = 2; } if (Input->isTypeDependent()) { - OverloadedFunctionDecl *Overloads + OverloadedFunctionDecl *Overloads = OverloadedFunctionDecl::Create(Context, CurContext, OpName); - for (FunctionSet::iterator Func = Functions.begin(), + for (FunctionSet::iterator Func = Functions.begin(), FuncEnd = Functions.end(); Func != FuncEnd; ++Func) Overloads->addOverload(*Func); DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, OpLoc, false, false); - + input.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, &Args[0], NumArgs, @@ -3954,11 +4519,11 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, case OR_Success: { // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; - + if (FnDecl) { // We matched an overloaded operator. Build a call to that // operator. - + // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { if (PerformObjectArgumentInitialization(Input, Method)) @@ -3972,19 +4537,24 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, } // Determine the result type - QualType ResultTy - = FnDecl->getType()->getAsFunctionType()->getResultType(); - ResultTy = ResultTy.getNonReferenceType(); - + QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); + // Build the actual expression node. Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), SourceLocation()); UsualUnaryConversions(FnExpr); - + input.release(); - return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, - &Input, 1, ResultTy, - OpLoc)); + + ExprOwningPtr<CallExpr> TheCall(this, + new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + &Input, 1, ResultTy, OpLoc)); + + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), + FnDecl)) + return ExprError(); + + return MaybeBindToTemporary(TheCall.release()); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -4006,7 +4576,8 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_ambiguous_oper) << UnaryOperator::getOpcodeStr(Opc) << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); case OR_Deleted: @@ -4042,12 +4613,13 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, /// /// \param LHS Left-hand argument. /// \param RHS Right-hand argument. -Sema::OwningExprResult +Sema::OwningExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, - unsigned OpcIn, + unsigned OpcIn, FunctionSet &Functions, Expr *LHS, Expr *RHS) { Expr *Args[2] = { LHS, RHS }; + LHS=RHS=0; //Please use only Args instead of LHS/RHS couple BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn); OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc); @@ -4055,24 +4627,24 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If either side is type-dependent, create an appropriate dependent // expression. - if (LHS->isTypeDependent() || RHS->isTypeDependent()) { + if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { // .* cannot be overloaded. if (Opc == BinaryOperator::PtrMemD) - return Owned(new (Context) BinaryOperator(LHS, RHS, Opc, + return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, Context.DependentTy, OpLoc)); - OverloadedFunctionDecl *Overloads + OverloadedFunctionDecl *Overloads = OverloadedFunctionDecl::Create(Context, CurContext, OpName); - for (FunctionSet::iterator Func = Functions.begin(), + for (FunctionSet::iterator Func = Functions.begin(), FuncEnd = Functions.end(); Func != FuncEnd; ++Func) Overloads->addOverload(*Func); DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, OpLoc, false, false); - + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, - Args, 2, + Args, 2, Context.DependentTy, OpLoc)); } @@ -4080,14 +4652,14 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If this is the .* operator, which is not overloadable, just // create a built-in binary operator. if (Opc == BinaryOperator::PtrMemD) - return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS); + return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // If this is one of the assignment operators, we only perform // overload resolution if the left-hand side is a class or // enumeration type (C++ [expr.ass]p3). if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign && - !LHS->getType()->isOverloadableType()) - return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS); + !Args[0]->getType()->isOverloadableType()) + return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // Build an empty overload set. OverloadCandidateSet CandidateSet; @@ -4114,39 +4686,46 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - if (PerformObjectArgumentInitialization(LHS, Method) || - PerformCopyInitialization(RHS, FnDecl->getParamDecl(0)->getType(), + if (PerformObjectArgumentInitialization(Args[0], Method) || + PerformCopyInitialization(Args[1], FnDecl->getParamDecl(0)->getType(), "passing")) return ExprError(); } else { // Convert the arguments. - if (PerformCopyInitialization(LHS, FnDecl->getParamDecl(0)->getType(), + if (PerformCopyInitialization(Args[0], FnDecl->getParamDecl(0)->getType(), "passing") || - PerformCopyInitialization(RHS, FnDecl->getParamDecl(1)->getType(), + PerformCopyInitialization(Args[1], FnDecl->getParamDecl(1)->getType(), "passing")) return ExprError(); } // Determine the result type QualType ResultTy - = FnDecl->getType()->getAsFunctionType()->getResultType(); + = FnDecl->getType()->getAs<FunctionType>()->getResultType(); ResultTy = ResultTy.getNonReferenceType(); // Build the actual expression node. Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - SourceLocation()); + OpLoc); UsualUnaryConversions(FnExpr); - return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, - Args, 2, ResultTy, - OpLoc)); + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + Args, 2, ResultTy, + OpLoc)); + + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), + FnDecl)) + return ExprError(); + + return MaybeBindToTemporary(TheCall.release()); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. - if (PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], + if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], Best->Conversions[0], "passing") || - PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1], + PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], Best->Conversions[1], "passing")) return ExprError(); @@ -4154,40 +4733,55 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } } - case OR_No_Viable_Function: + case OR_No_Viable_Function: { + // C++ [over.match.oper]p9: + // If the operator is the operator , [...] and there are no + // viable functions, then the operator is assumed to be the + // built-in operator and interpreted according to clause 5. + if (Opc == BinaryOperator::Comma) + break; + // For class as left operand for assignment or compound assigment operator // do not fall through to handling in built-in, but report that no overloaded // assignment operator found - if (LHS->getType()->isRecordType() && Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) { + OwningExprResult Result = ExprError(); + if (Args[0]->getType()->isRecordType() && + Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) << BinaryOperator::getOpcodeStr(Opc) - << LHS->getSourceRange() << RHS->getSourceRange(); - return ExprError(); + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + } else { + // No viable function; try to create a built-in operation, which will + // produce an error. Then, show the non-viable candidates. + Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. - break; + assert(Result.isInvalid() && + "C++ binary operator overloading is missing candidates!"); + if (Result.isInvalid()) + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false, + BinaryOperator::getOpcodeStr(Opc), OpLoc); + return move(Result); + } case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) << BinaryOperator::getOpcodeStr(Opc) - << LHS->getSourceRange() << RHS->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); case OR_Deleted: Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc) - << LHS->getSourceRange() << RHS->getSourceRange(); + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); return ExprError(); } - // Either we found no viable overloaded operator or we matched a - // built-in operator. In either case, try to build a built-in - // operation. - return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS); + // We matched a built-in operator; build it. + return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } /// BuildCallToMemberFunction - Build a call to a member @@ -4198,8 +4792,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, /// expression refers to a member function or an overloaded member /// function. Sema::ExprResult -Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, - SourceLocation LParenLoc, Expr **Args, +Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, + SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, SourceLocation RParenLoc) { // Dig out the member expression. This holds both the object @@ -4215,17 +4809,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Expr *ObjectArg = MemExpr->getBase(); CXXMethodDecl *Method = 0; - if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) { + if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) || + isa<FunctionTemplateDecl>(MemExpr->getMemberDecl())) { // Add overload candidates OverloadCandidateSet CandidateSet; - for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), - FuncEnd = Ovl->function_end(); + DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName(); + + for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd; Func != FuncEnd; ++Func) { - assert(isa<CXXMethodDecl>(*Func) && "Function is not a method"); - Method = cast<CXXMethodDecl>(*Func); - AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, - /*SuppressUserConversions=*/false); + if ((Method = dyn_cast<CXXMethodDecl>(*Func))) + AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, + /*SuppressUserConversions=*/false); + else + AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func), + MemExpr->hasExplicitTemplateArgumentList(), + MemExpr->getTemplateArgs(), + MemExpr->getNumTemplateArgs(), + ObjectArg, Args, NumArgs, + CandidateSet, + /*SuppressUsedConversions=*/false); } OverloadCandidateSet::iterator Best; @@ -4235,26 +4837,26 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, break; case OR_No_Viable_Function: - Diag(MemExpr->getSourceRange().getBegin(), + Diag(MemExpr->getSourceRange().getBegin(), diag::err_ovl_no_viable_member_function_in_call) - << Ovl->getDeclName() << MemExprE->getSourceRange(); + << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! return true; case OR_Ambiguous: - Diag(MemExpr->getSourceRange().getBegin(), + Diag(MemExpr->getSourceRange().getBegin(), diag::err_ovl_ambiguous_member_call) - << Ovl->getDeclName() << MemExprE->getSourceRange(); + << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! return true; case OR_Deleted: - Diag(MemExpr->getSourceRange().getBegin(), + Diag(MemExpr->getSourceRange().getBegin(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() - << Ovl->getDeclName() << MemExprE->getSourceRange(); + << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! return true; @@ -4266,43 +4868,51 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } assert(Method && "Member call to something that isn't a method?"); - ExprOwningPtr<CXXMemberCallExpr> + ExprOwningPtr<CXXMemberCallExpr> TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args, - NumArgs, + NumArgs, Method->getResultType().getNonReferenceType(), RParenLoc)); + // Check for a valid return type. + if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), + TheCall.get(), Method)) + return true; + // Convert the object argument (for a non-static member function call). - if (!Method->isStatic() && + if (!Method->isStatic() && PerformObjectArgumentInitialization(ObjectArg, Method)) return true; MemExpr->setBase(ObjectArg); // Convert the rest of the arguments const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType()); - if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs, + if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs, RParenLoc)) return true; - return CheckFunctionCall(Method, TheCall.take()).release(); + if (CheckFunctionCall(Method, TheCall.get())) + return true; + + return MaybeBindToTemporary(TheCall.release()).release(); } /// BuildCallToObjectOfClassType - Build a call to an object of class /// type (C++ [over.call.object]), which can end up invoking an /// overloaded function call operator (@c operator()) or performing a /// user-defined conversion on the object argument. -Sema::ExprResult -Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, +Sema::ExprResult +Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, + SourceLocation *CommaLocs, SourceLocation RParenLoc) { assert(Object->getType()->isRecordType() && "Requires object type argument"); - const RecordType *Record = Object->getType()->getAsRecordType(); - + const RecordType *Record = Object->getType()->getAs<RecordType>(); + // C++ [over.call.object]p1: // If the primary-expression E in the function call syntax - // evaluates to a class object of type “cv T”, then the set of + // evaluates to a class object of type "cv T", then the set of // candidate functions includes at least the function call // operators of T. The function call operators of T are obtained by // ordinary lookup of the name operator() in the context of @@ -4312,7 +4922,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, DeclContext::lookup_const_iterator Oper, OperEnd; for (llvm::tie(Oper, OperEnd) = Record->getDecl()->lookup(OpName); Oper != OperEnd; ++Oper) - AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs, + AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); // C++ [over.call.object]p2: @@ -4332,24 +4942,33 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - // - // FIXME: Look in base classes for more conversion operators! - OverloadedFunctionDecl *Conversions - = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); - // Strip the reference type (if any) and then the pointer type (if - // any) to get down to what might be a function type. - QualType ConvType = Conv->getConversionType().getNonReferenceType(); - if (const PointerType *ConvPtrType = ConvType->getAsPointerType()) - ConvType = ConvPtrType->getPointeeType(); + if (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) { + // FIXME: Look in base classes for more conversion operators! + OverloadedFunctionDecl *Conversions + = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + GetFunctionAndTemplate(*Func, Conv, ConvTemplate); + + // Skip over templated conversion functions; they aren't + // surrogates. + if (ConvTemplate) + continue; + + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); - if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType()) - AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); + if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) + AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); + } } // Perform overload resolution. @@ -4361,7 +4980,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, break; case OR_No_Viable_Function: - Diag(Object->getSourceRange().getBegin(), + Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_viable_object_call) << Object->getType() << Object->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); @@ -4381,7 +5000,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, << Object->getType() << Object->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); break; - } + } if (Best == CandidateSet.end()) { // We had an error; delete all of the subexpressions and return @@ -4395,18 +5014,20 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (Best->Function == 0) { // Since there is no function declaration, this is one of the // surrogate candidates. Dig out the conversion function. - CXXConversionDecl *Conv + CXXConversionDecl *Conv = cast<CXXConversionDecl>( Best->Conversions[0].UserDefined.ConversionFunction); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion // on the object argument, then let ActOnCallExpr finish the job. - // FIXME: Represent the user-defined conversion in the AST! - ImpCastExprToType(Object, - Conv->getConversionType().getNonReferenceType(), - Conv->getConversionType()->isLValueReferenceType()); - return ActOnCallExpr(S, ExprArg(*this, Object), LParenLoc, + + // Create an implicit member expr to refer to the conversion operator. + // and then call it. + CXXMemberCallExpr *CE = + BuildCXXMemberCallExpr(Object, Conv); + + return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), CommaLocs, RParenLoc).release(); } @@ -4415,7 +5036,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // that calls this method, using Object for the implicit object // parameter and passing along the remaining arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); - const FunctionProtoType *Proto = Method->getType()->getAsFunctionProtoType(); + const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>(); unsigned NumArgsInProto = Proto->getNumArgs(); unsigned NumArgsToCheck = NumArgs; @@ -4433,20 +5054,24 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, MethodArgs[0] = Object; for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) MethodArgs[ArgIdx + 1] = Args[ArgIdx]; - - Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(), + + Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(), SourceLocation()); UsualUnaryConversions(NewFn); // Once we've built TheCall, all of the expressions are properly // owned. QualType ResultTy = Method->getResultType().getNonReferenceType(); - ExprOwningPtr<CXXOperatorCallExpr> - TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, MethodArgs, NumArgs + 1, ResultTy, RParenLoc)); delete [] MethodArgs; + if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall.get(), + Method)) + return true; + // We may have default arguments. If so, we need to allocate more // slots in the call for them. if (NumArgs < NumArgsInProto) @@ -4466,12 +5091,12 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, Expr *Arg; if (i < NumArgs) { Arg = Args[i]; - + // Pass the argument. QualType ProtoArgType = Proto->getArgType(i); IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing"); } else { - Arg = new (Context) CXXDefaultArgExpr(Method->getParamDecl(i)); + Arg = CXXDefaultArgExpr::Create(Context, Method->getParamDecl(i)); } TheCall->setArg(i + 1, Arg); @@ -4489,37 +5114,38 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (IsError) return true; - return CheckFunctionCall(Method, TheCall.take()).release(); + if (CheckFunctionCall(Method, TheCall.get())) + return true; + + return MaybeBindToTemporary(TheCall.release()).release(); } /// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> -/// (if one exists), where @c Base is an expression of class type and +/// (if one exists), where @c Base is an expression of class type and /// @c Member is the name of the member we're trying to find. -Action::ExprResult -Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, - SourceLocation MemberLoc, - IdentifierInfo &Member) { +Sema::OwningExprResult +Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { + Expr *Base = static_cast<Expr *>(BaseIn.get()); assert(Base->getType()->isRecordType() && "left-hand side must have class type"); - + // C++ [over.ref]p1: // // [...] An expression x->m is interpreted as (x.operator->())->m // for a class object x of type T if T::operator->() exists and if // the operator is selected as the best match function by the // overload resolution mechanism (13.3). - // FIXME: look in base classes. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); OverloadCandidateSet CandidateSet; - const RecordType *BaseRecord = Base->getType()->getAsRecordType(); - - DeclContext::lookup_const_iterator Oper, OperEnd; - for (llvm::tie(Oper, OperEnd) - = BaseRecord->getDecl()->lookup(OpName); Oper != OperEnd; ++Oper) + const RecordType *BaseRecord = Base->getType()->getAs<RecordType>(); + + LookupResult R; + LookupQualifiedName(R, BaseRecord->getDecl(), OpName, LookupOrdinaryName); + + for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); + Oper != OperEnd; ++Oper) AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Base, 0, 0, CandidateSet, /*SuppressUserConversions=*/false); - ExprOwningPtr<Expr> BasePtr(this, Base); - // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, OpLoc, Best)) { @@ -4530,44 +5156,49 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, case OR_No_Viable_Function: if (CandidateSet.empty()) Diag(OpLoc, diag::err_typecheck_member_reference_arrow) - << BasePtr->getType() << BasePtr->getSourceRange(); + << Base->getType() << Base->getSourceRange(); else Diag(OpLoc, diag::err_ovl_no_viable_oper) - << "operator->" << BasePtr->getSourceRange(); + << "operator->" << Base->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); - return true; + return ExprError(); case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) - << "operator->" << BasePtr->getSourceRange(); + << "->" << Base->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return true; + return ExprError(); case OR_Deleted: Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() - << "operator->" << BasePtr->getSourceRange(); + << "->" << Base->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return true; + return ExprError(); } // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); if (PerformObjectArgumentInitialization(Base, Method)) - return true; + return ExprError(); // No concerns about early exits now. - BasePtr.take(); + BaseIn.release(); // Build the operator call. Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(), SourceLocation()); UsualUnaryConversions(FnExpr); - Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1, - Method->getResultType().getNonReferenceType(), - OpLoc); - return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow, - MemberLoc, Member, DeclPtrTy()).release(); + + QualType ResultTy = Method->getResultType().getNonReferenceType(); + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, + &Base, 1, ResultTy, OpLoc)); + + if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall.get(), + Method)) + return ExprError(); + return move(TheCall); } /// FixOverloadedFunctionReference - E is an expression that refers to @@ -4580,14 +5211,13 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { FixOverloadedFunctionReference(PE->getSubExpr(), Fn); E->setType(PE->getSubExpr()->getType()); } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { - assert(UnOp->getOpcode() == UnaryOperator::AddrOf && + assert(UnOp->getOpcode() == UnaryOperator::AddrOf && "Can only take the address of an overloaded function"); if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { if (Method->isStatic()) { // Do nothing: static member functions aren't any different // from non-member functions. - } - else if (QualifiedDeclRefExpr *DRE + } else if (QualifiedDeclRefExpr *DRE = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr())) { // We have taken the address of a pointer to member // function. Perform the computation here so that we get the @@ -4596,7 +5226,7 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { DRE->setType(Fn->getType()); QualType ClassType = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); - E->setType(Context.getMemberPointerType(Fn->getType(), + E->setType(Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr())); return; } @@ -4604,8 +5234,9 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); E->setType(Context.getPointerType(UnOp->getSubExpr()->getType())); } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { - assert(isa<OverloadedFunctionDecl>(DR->getDecl()) && - "Expected overloaded function"); + assert((isa<OverloadedFunctionDecl>(DR->getDecl()) || + isa<FunctionTemplateDecl>(DR->getDecl())) && + "Expected overloaded function or function template"); DR->setDecl(Fn); E->setType(Fn->getType()); } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) { diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 9de380657612b..898393a9e4d96 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -59,7 +59,7 @@ namespace clang { ICC_Conversion ///< Conversion }; - ImplicitConversionCategory + ImplicitConversionCategory GetConversionCategory(ImplicitConversionKind Kind); /// ImplicitConversionRank - The rank of an implicit conversion @@ -98,7 +98,7 @@ namespace clang { ImplicitConversionKind Third : 8; /// Deprecated - Whether this the deprecated conversion of a - /// string literal to a pointer to non-const character data + /// string literal to a pointer to non-const character data /// (C++ 4.2p2). bool Deprecated : 1; @@ -106,11 +106,11 @@ namespace clang { /// that we should warn about (if we actually use it). bool IncompatibleObjC : 1; - /// ReferenceBinding - True when this is a reference binding + /// ReferenceBinding - True when this is a reference binding /// (C++ [over.ics.ref]). bool ReferenceBinding : 1; - /// DirectBinding - True when this is a reference binding that is a + /// DirectBinding - True when this is a reference binding that is a /// direct binding (C++ [dcl.init.ref]). bool DirectBinding : 1; @@ -134,7 +134,7 @@ namespace clang { /// conversions. CXXConstructorDecl *CopyConstructor; - void setAsIdentityConversion(); + void setAsIdentityConversion(); ImplicitConversionRank getRank() const; bool isPointerConversionToBool() const; bool isPointerConversionToVoidPointer(ASTContext& Context) const; @@ -159,7 +159,7 @@ namespace clang { /// After - Represents the standard conversion that occurs after /// the actual user-defined conversion. StandardConversionSequence After; - + /// ConversionFunction - The function that will perform the /// user-defined conversion. FunctionDecl* ConversionFunction; @@ -168,7 +168,7 @@ namespace clang { }; /// ImplicitConversionSequence - Represents an implicit conversion - /// sequence, which may be a standard conversion sequence + /// sequence, which may be a standard conversion sequence /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), /// or an ellipsis conversion sequence (C++ 13.3.3.1.3). struct ImplicitConversionSequence { @@ -195,7 +195,11 @@ namespace clang { /// details of the user-defined conversion sequence. UserDefinedConversionSequence UserDefined; }; - + + /// When ConversionKind == BadConversion due to multiple conversion + /// functions, this will list those functions. + llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet; + // The result of a comparison between implicit conversion // sequences. Use Sema::CompareImplicitConversionSequences to // actually perform the comparison. @@ -211,8 +215,8 @@ namespace clang { /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). struct OverloadCandidate { /// Function - The actual function that this candidate - /// represents. When NULL, this is a built-in candidate - /// (C++ [over.oper]) or a surrogate for a conversion to a + /// represents. When NULL, this is a built-in candidate + /// (C++ [over.oper]) or a surrogate for a conversion to a /// function pointer or reference (C++ [over.call.object]). FunctionDecl *Function; @@ -222,7 +226,7 @@ namespace clang { QualType ResultTy; QualType ParamTypes[3]; } BuiltinTypes; - + /// Surrogate - The conversion function for which this candidate /// is a surrogate, but only if IsSurrogate is true. CXXConversionDecl *Surrogate; @@ -257,7 +261,16 @@ namespace clang { /// OverloadCandidateSet - A set of overload candidates, used in C++ /// overload resolution (C++ 13.3). - typedef llvm::SmallVector<OverloadCandidate, 16> OverloadCandidateSet; + class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> { + llvm::SmallPtrSet<Decl *, 16> Functions; + + public: + /// \brief Determine when this overload candidate will be new to the + /// overload set. + bool isNewCandidate(Decl *F) { + return Functions.insert(F->getCanonicalDecl()); + } + }; } // end namespace clang #endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 63191e0e00cce..e8cd6b081de16 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -15,16 +15,26 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" using namespace clang; Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) { Expr *E = expr->takeAs<Expr>(); assert(E && "ActOnExprStmt(): missing expression"); - + if (E->getType()->isObjCInterfaceType()) { + if (LangOpts.ObjCNonFragileABI) + Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object) + << E->getType(); + else + Diag(E->getLocEnd(), diag::err_direct_interface_unsupported) + << E->getType(); + return StmtError(); + } // C99 6.8.3p2: The expression in an expression statement is evaluated as a // void expression for its side effects. Conversion to void allows any // operand, even incomplete types. @@ -42,13 +52,57 @@ Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, SourceLocation EndLoc) { DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); - + // If we have an invalid decl, just return an error. if (DG.isNull()) return StmtError(); - + return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc)); } +void Sema::DiagnoseUnusedExprResult(const Stmt *S) { + const Expr *E = dyn_cast_or_null<Expr>(S); + if (!E) + return; + + // Ignore expressions that have void type. + if (E->getType()->isVoidType()) + return; + + SourceLocation Loc; + SourceRange R1, R2; + if (!E->isUnusedResultAWarning(Loc, R1, R2)) + return; + + // Okay, we have an unused result. Depending on what the base expression is, + // we might want to make a more specific diagnostic. Check for one of these + // cases now. + unsigned DiagID = diag::warn_unused_expr; + E = E->IgnoreParens(); + if (isa<ObjCImplicitSetterGetterRefExpr>(E)) + DiagID = diag::warn_unused_property_expr; + + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + // If the callee has attribute pure, const, or warn_unused_result, warn with + // a more specific message to make it clear what is happening. + if (const FunctionDecl *FD = CE->getDirectCallee()) { + if (FD->getAttr<WarnUnusedResultAttr>()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + return; + } + if (FD->getAttr<PureAttr>()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure"; + return; + } + if (FD->getAttr<ConstAttr>()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const"; + return; + } + } + } + + Diag(Loc, DiagID) << R1 << R2; +} + Action::OwningStmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, MultiStmtArg elts, bool isStmtExpr) { @@ -66,7 +120,7 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, // We found the end of the list or a statement. Scan for another declstmt. for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i) /*empty*/; - + if (i != NumElts) { Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin(); Diag(D->getLocation(), diag::ext_mixed_decls_code); @@ -74,20 +128,11 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, } // Warn about unused expressions in statements. for (unsigned i = 0; i != NumElts; ++i) { - Expr *E = dyn_cast<Expr>(Elts[i]); - if (!E) continue; - - // Warn about expressions with unused results if they are non-void and if - // this not the last stmt in a stmt expr. - if (E->getType()->isVoidType() || (isStmtExpr && i == NumElts-1)) - continue; - - SourceLocation Loc; - SourceRange R1, R2; - if (!E->isUnusedResultAWarning(Loc, R1, R2)) + // Ignore statements that are last in a statement expression. + if (isStmtExpr && i == NumElts - 1) continue; - Diag(Loc, diag::warn_unused_expr) << R1 << R2; + DiagnoseUnusedExprResult(Elts[i]); } return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R)); @@ -100,9 +145,9 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval, assert((lhsval.get() != 0) && "missing expression in case statement"); // C99 6.8.4.2p3: The expression shall be an integer constant. - // However, GCC allows any evaluatable integer expression. + // However, GCC allows any evaluatable integer expression. Expr *LHSVal = static_cast<Expr*>(lhsval.get()); - if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() && + if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() && VerifyIntegerConstantExpression(LHSVal)) return StmtError(); @@ -137,7 +182,7 @@ void Sema::ActOnCaseStmtBody(StmtTy *caseStmt, StmtArg subStmt) { } Action::OwningStmtResult -Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, +Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, StmtArg subStmt, Scope *CurScope) { Stmt *SubStmt = subStmt.takeAs<Stmt>(); @@ -184,40 +229,33 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal) { OwningExprResult CondResult(CondVal.release()); - + Expr *condExpr = CondResult.takeAs<Expr>(); assert(condExpr && "ActOnIfStmt(): missing expression"); - - if (!condExpr->isTypeDependent()) { - DefaultFunctionArrayConversion(condExpr); - // Take ownership again until we're past the error checking. + if (CheckBooleanCondition(condExpr, IfLoc)) { CondResult = condExpr; - QualType condType = condExpr->getType(); - - if (getLangOptions().CPlusPlus) { - if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 - return StmtError(); - } else if (!condType->isScalarType()) // C99 6.8.4.1p1 - return StmtError(Diag(IfLoc, - diag::err_typecheck_statement_requires_scalar) - << condType << condExpr->getSourceRange()); + return StmtError(); } Stmt *thenStmt = ThenVal.takeAs<Stmt>(); + DiagnoseUnusedExprResult(thenStmt); // Warn if the if block has a null body without an else value. // this helps prevent bugs due to typos, such as // if (condition); // do_stuff(); - if (!ElseVal.get()) { + if (!ElseVal.get()) { if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt)) Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); } + Stmt *elseStmt = ElseVal.takeAs<Stmt>(); + DiagnoseUnusedExprResult(elseStmt); + CondResult.release(); return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt, - ElseLoc, ElseVal.takeAs<Stmt>())); + ElseLoc, elseStmt)); } Action::OwningStmtResult @@ -234,9 +272,9 @@ Sema::ActOnStartOfSwitchStmt(ExprArg cond) { // of this section. Integral promotions are performed. if (!Cond->isTypeDependent()) { QualType Ty = Cond->getType(); - + // FIXME: Handle class types. - + // If the type is wrong a diagnostic will be emitted later at // ActOnFinishSwitchStmt. if (Ty->isIntegralType() || Ty->isEnumeralType()) { @@ -260,19 +298,19 @@ Sema::ActOnStartOfSwitchStmt(ExprArg cond) { /// the specified diagnostic. void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, unsigned NewWidth, bool NewSign, - SourceLocation Loc, + SourceLocation Loc, unsigned DiagID) { // Perform a conversion to the promoted condition type if needed. if (NewWidth > Val.getBitWidth()) { // If this is an extension, just do it. llvm::APSInt OldVal(Val); Val.extend(NewWidth); - + // If the input was signed and negative and the output is unsigned, // warn. if (!NewSign && OldVal.isSigned() && OldVal.isNegative()) Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10); - + Val.setIsSigned(NewSign); } else if (NewWidth < Val.getBitWidth()) { // If this is a truncation, check for overflow. @@ -283,7 +321,7 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, ConvVal.setIsSigned(Val.isSigned()); if (ConvVal != Val) Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10); - + // Regardless of whether a diagnostic was emitted, really do the // truncation. Val.trunc(NewWidth); @@ -293,7 +331,7 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, // overflow as well: unsigned(INTMIN) llvm::APSInt OldVal(Val); Val.setIsSigned(NewSign); - + if (Val.isNegative()) // Sign bit changes meaning. Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10); } @@ -339,12 +377,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!"); SS->setBody(BodyStmt, SwitchLoc); - getSwitchStack().pop_back(); + getSwitchStack().pop_back(); Expr *CondExpr = SS->getCond(); QualType CondType = CondExpr->getType(); - if (!CondExpr->isTypeDependent() && + if (!CondExpr->isTypeDependent() && !CondType->isIntegerType()) { // C99 6.8.4.2p1 Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) << CondType << CondExpr->getSourceRange(); @@ -353,29 +391,29 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // Get the bitwidth of the switched-on value before promotions. We must // convert the integer case values to this width before comparison. - bool HasDependentValue + bool HasDependentValue = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); - unsigned CondWidth + unsigned CondWidth = HasDependentValue? 0 : static_cast<unsigned>(Context.getTypeSize(CondType)); bool CondIsSigned = CondType->isSignedIntegerType(); - + // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after // it has been converted to the condition type. typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy; CaseValsTy CaseVals; - + // Keep track of any GNU case ranges we see. The APSInt is the low value. std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges; - + DefaultStmt *TheDefaultStmt = 0; - + bool CaseListIsErroneous = false; - + for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue; SC = SC->getNextSwitchCase()) { - + if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) { if (TheDefaultStmt) { Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined); @@ -388,10 +426,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, CaseListIsErroneous = true; } TheDefaultStmt = DS; - + } else { CaseStmt *CS = cast<CaseStmt>(SC); - + // We already verified that the expression has a i-c-e value (C99 // 6.8.4.2p3) - get that value now. Expr *Lo = CS->getLHS(); @@ -400,9 +438,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, HasDependentValue = true; break; } - + llvm::APSInt LoVal = Lo->EvaluateAsInt(Context); - + // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, CS->getLHS()->getLocStart(), @@ -412,16 +450,16 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // cast. ImpCastExprToType(Lo, CondType); CS->setLHS(Lo); - + // If this is a case range, remember it in CaseRanges, otherwise CaseVals. if (CS->getRHS()) { - if (CS->getRHS()->isTypeDependent() || + if (CS->getRHS()->isTypeDependent() || CS->getRHS()->isValueDependent()) { HasDependentValue = true; break; } CaseRanges.push_back(std::make_pair(LoVal, CS)); - } else + } else CaseVals.push_back(std::make_pair(LoVal, CS)); } } @@ -436,7 +474,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // 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(CaseVals[i].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. @@ -444,31 +482,31 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } } } - + // Detect duplicate case ranges, which usually don't exist at all in // the first place. if (!CaseRanges.empty()) { // Sort all the case ranges by their low value so we can easily detect // overlaps between ranges. std::stable_sort(CaseRanges.begin(), CaseRanges.end()); - + // 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) { CaseStmt *CR = CaseRanges[i].second; Expr *Hi = CR->getRHS(); llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); - + // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, CR->getRHS()->getLocStart(), diag::warn_case_value_overflow); - + // If the LHS is not the same type as the condition, insert an implicit // cast. ImpCastExprToType(Hi, CondType); CR->setRHS(Hi); - + // If the low value is bigger than the high value, the case is empty. if (CaseRanges[i].first > HiVal) { Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) @@ -480,7 +518,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } HiVals.push_back(HiVal); } - + // Rescan the ranges, looking for overlap with singleton values and other // ranges. Since the range list is sorted, we only need to compare case // ranges with their neighbors. @@ -488,12 +526,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, llvm::APSInt &CRLo = CaseRanges[i].first; llvm::APSInt &CRHi = HiVals[i]; CaseStmt *CR = CaseRanges[i].second; - + // Check to see whether the case range overlaps with any // singleton cases. CaseStmt *OverlapStmt = 0; llvm::APSInt OverlapVal(32); - + // Find the smallest value >= the lower bound. If I is in the // case range, then we have overlap. CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(), @@ -503,26 +541,26 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, OverlapVal = I->first; // Found overlap with scalar. OverlapStmt = I->second; } - + // Find the smallest value bigger than the upper bound. I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor()); if (I != CaseVals.begin() && (I-1)->first >= CRLo) { OverlapVal = (I-1)->first; // Found overlap with scalar. OverlapStmt = (I-1)->second; } - + // Check to see if this case stmt overlaps with the subsequent // case range. if (i && CRLo <= HiVals[i-1]) { OverlapVal = HiVals[i-1]; // Found overlap with range. OverlapStmt = CaseRanges[i-1].second; } - + if (OverlapStmt) { // If we have a duplicate, report it. Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case) << OverlapVal.toString(10); - Diag(OverlapStmt->getLHS()->getLocStart(), + Diag(OverlapStmt->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. @@ -547,23 +585,16 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) { Expr *condExpr = CondArg.takeAs<Expr>(); assert(condExpr && "ActOnWhileStmt(): missing expression"); - if (!condExpr->isTypeDependent()) { - DefaultFunctionArrayConversion(condExpr); + if (CheckBooleanCondition(condExpr, WhileLoc)) { CondArg = condExpr; - QualType condType = condExpr->getType(); - - if (getLangOptions().CPlusPlus) { - if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 - return StmtError(); - } else if (!condType->isScalarType()) // C99 6.8.5p2 - return StmtError(Diag(WhileLoc, - diag::err_typecheck_statement_requires_scalar) - << condType << condExpr->getSourceRange()); + return StmtError(); } + Stmt *bodyStmt = Body.takeAs<Stmt>(); + DiagnoseUnusedExprResult(bodyStmt); + CondArg.release(); - return Owned(new (Context) WhileStmt(condExpr, Body.takeAs<Stmt>(), - WhileLoc)); + return Owned(new (Context) WhileStmt(condExpr, bodyStmt, WhileLoc)); } Action::OwningStmtResult @@ -573,22 +604,16 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, Expr *condExpr = Cond.takeAs<Expr>(); assert(condExpr && "ActOnDoStmt(): missing expression"); - if (!condExpr->isTypeDependent()) { - DefaultFunctionArrayConversion(condExpr); + if (CheckBooleanCondition(condExpr, DoLoc)) { Cond = condExpr; - QualType condType = condExpr->getType(); - - if (getLangOptions().CPlusPlus) { - if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 - return StmtError(); - } else if (!condType->isScalarType()) // C99 6.8.5p2 - return StmtError(Diag(DoLoc, - diag::err_typecheck_statement_requires_scalar) - << condType << condExpr->getSourceRange()); + return StmtError(); } + Stmt *bodyStmt = Body.takeAs<Stmt>(); + DiagnoseUnusedExprResult(bodyStmt); + Cond.release(); - return Owned(new (Context) DoStmt(Body.takeAs<Stmt>(), condExpr, DoLoc, + return Owned(new (Context) DoStmt(bodyStmt, condExpr, DoLoc, WhileLoc, CondRParen)); } @@ -597,7 +622,7 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, StmtArg first, ExprArg second, ExprArg third, SourceLocation RParenLoc, StmtArg body) { Stmt *First = static_cast<Stmt*>(first.get()); - Expr *Second = static_cast<Expr*>(second.get()); + Expr *Second = second.takeAs<Expr>(); Expr *Third = static_cast<Expr*>(third.get()); Stmt *Body = static_cast<Stmt*>(body.get()); @@ -617,20 +642,16 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } } } - if (Second && !Second->isTypeDependent()) { - DefaultFunctionArrayConversion(Second); - QualType SecondType = Second->getType(); - - if (getLangOptions().CPlusPlus) { - if (CheckCXXBooleanCondition(Second)) // C++ 6.4p4 - return StmtError(); - } else if (!SecondType->isScalarType()) // C99 6.8.5p2 - return StmtError(Diag(ForLoc, - diag::err_typecheck_statement_requires_scalar) - << SecondType << Second->getSourceRange()); + if (Second && CheckBooleanCondition(Second, ForLoc)) { + second = Second; + return StmtError(); } + + DiagnoseUnusedExprResult(First); + DiagnoseUnusedExprResult(Third); + DiagnoseUnusedExprResult(Body); + first.release(); - second.release(); third.release(); body.release(); return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc, @@ -667,16 +688,17 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, diag::err_selector_element_not_lvalue) << First->getSourceRange()); - FirstType = static_cast<Expr*>(First)->getType(); + FirstType = static_cast<Expr*>(First)->getType(); } - if (!Context.isObjCObjectPointerType(FirstType)) + if (!FirstType->isObjCObjectPointerType() && + !FirstType->isBlockPointerType()) Diag(ForLoc, diag::err_selector_element_type) << FirstType << First->getSourceRange(); } if (Second) { DefaultFunctionArrayConversion(Second); QualType SecondType = Second->getType(); - if (!Context.isObjCObjectPointerType(SecondType)) + if (!SecondType->isObjCObjectPointerType()) Diag(ForLoc, diag::err_collection_expr_type) << SecondType << Second->getSourceRange(); } @@ -791,8 +813,8 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // we have a non-void block with an expression, continue checking QualType RetValType = RetValExp->getType(); - // 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 + // 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. @@ -834,8 +856,8 @@ static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType, } Action::OwningStmtResult -Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) { - Expr *RetValExp = rex->takeAs<Expr>(); +Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { + Expr *RetValExp = rex.takeAs<Expr>(); if (CurBlock) return ActOnBlockReturnStmt(ReturnLoc, RetValExp); @@ -849,9 +871,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) { FnRetType = MD->getResultType(); else // If we don't have a function/method context, bail. return StmtError(); - + if (FnRetType->isVoidType()) { - if (RetValExp) {// C99 6.8.6.4p1 (ext_ since GCC warns) + if (RetValExp && !RetValExp->isTypeDependent()) { + // C99 6.8.6.4p1 (ext_ since GCC warns) unsigned D = diag::ext_return_has_expr; if (RetValExp->getType()->isVoidType()) D = diag::ext_return_has_void_expr; @@ -864,6 +887,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) { << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl) << RetValExp->getSourceRange(); } + + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true); } return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); } @@ -883,8 +908,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) { 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 + // 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 @@ -912,6 +937,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) { if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } + if (RetValExp) + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true); return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); } @@ -964,7 +991,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get()); llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; - + // The parser verifies that there is a string literal here. if (AsmString->isWide()) return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) @@ -976,7 +1003,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - TargetInfo::ConstraintInfo Info(Literal->getStrData(), + TargetInfo::ConstraintInfo Info(Literal->getStrData(), Literal->getByteLength(), Names[i]); if (!Context.Target.validateOutputConstraint(Info)) @@ -991,7 +1018,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, diag::err_asm_invalid_lvalue_in_output) << OutputExpr->getSourceRange()); } - + OutputConstraintInfos.push_back(Info); } @@ -1003,7 +1030,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - TargetInfo::ConstraintInfo Info(Literal->getStrData(), + TargetInfo::ConstraintInfo Info(Literal->getStrData(), Literal->getByteLength(), Names[i]); if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(), @@ -1028,13 +1055,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, if (InputExpr->getType()->isVoidType()) { return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input) - << InputExpr->getType() << Info.getConstraintStr() + << InputExpr->getType() << Info.getConstraintStr() << InputExpr->getSourceRange()); } } - + DefaultFunctionArrayConversion(Exprs[i]); - + InputConstraintInfos.push_back(Info); } @@ -1045,13 +1072,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - llvm::SmallString<16> Clobber(Literal->getStrData(), - Literal->getStrData() + - Literal->getByteLength()); + std::string Clobber(Literal->getStrData(), + Literal->getStrData() + + Literal->getByteLength()); if (!Context.Target.isValidGCCRegisterName(Clobber.c_str())) return StmtError(Diag(Literal->getLocStart(), - diag::err_asm_unknown_register_name) << Clobber.c_str()); + diag::err_asm_unknown_register_name) << Clobber); } constraints.release(); @@ -1072,16 +1099,16 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, DeleteStmt(NS); return StmtError(); } - + // Validate tied input operands for type mismatches. for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; - + // If this is a tied constraint, verify that the output and input have // either exactly the same type, or that they are int/ptr operands with the // same size (int/long, int*/long, are ok etc). if (!Info.hasTiedOperand()) continue; - + unsigned TiedTo = Info.getTiedOperand(); Expr *OutputExpr = Exprs[TiedTo]; Expr *InputExpr = Exprs[i+NumOutputs]; @@ -1089,11 +1116,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, QualType OutTy = OutputExpr->getType(); if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. - + // Int/ptr operands have some special cases that we allow. if ((OutTy->isIntegerType() || OutTy->isPointerType()) && (InTy->isIntegerType() || InTy->isPointerType())) { - + // They are ok if they are the same size. Tying void* to int is ok if // they are the same size, for example. This also allows tying void* to // int*. @@ -1101,7 +1128,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, uint64_t InSize = Context.getTypeSize(InTy); if (OutSize == InSize) continue; - + // If the smaller input/output operand is not mentioned in the asm string, // then we can promote it and the asm string won't notice. Check this // case now. @@ -1109,7 +1136,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { AsmStmt::AsmStringPiece &Piece = Pieces[p]; if (!Piece.isOperand()) continue; - + // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. if (Piece.getOperandNo() == i+NumOutputs) { @@ -1128,7 +1155,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, } } } - + // If the smaller value wasn't mentioned in the asm string, and if the // output was a register, just extend the shorter one to the size of the // larger one. @@ -1136,7 +1163,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, OutputConstraintInfos[TiedTo].allowsRegister()) continue; } - + Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() @@ -1144,7 +1171,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, DeleteStmt(NS); return StmtError(); } - + return Owned(NS); } @@ -1154,18 +1181,18 @@ Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, StmtArg Body, StmtArg catchList) { Stmt *CatchList = catchList.takeAs<Stmt>(); ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>()); - + // PVD == 0 implies @catch(...). if (PVD) { // If we already know the decl is invalid, reject it. if (PVD->isInvalidDecl()) return StmtError(); - - if (!Context.isObjCObjectPointerType(PVD->getType())) - return StmtError(Diag(PVD->getLocation(), + + if (!PVD->getType()->isObjCObjectPointerType()) + return StmtError(Diag(PVD->getLocation(), diag::err_catch_param_not_objc_type)); if (PVD->getType()->isObjCQualifiedIdType()) - return StmtError(Diag(PVD->getLocation(), + return StmtError(Diag(PVD->getLocation(), diag::err_illegal_qualifiers_on_catch_parm)); } @@ -1203,8 +1230,8 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { } else { QualType ThrowType = ThrowExpr->getType(); // Make sure the expression type is an ObjC pointer or "void *". - if (!Context.isObjCObjectPointerType(ThrowType)) { - const PointerType *PT = ThrowType->getAsPointerType(); + if (!ThrowType->isObjCObjectPointerType()) { + const PointerType *PT = ThrowType->getAs<PointerType>(); if (!PT || !PT->getPointeeType()->isVoidType()) return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) << ThrowExpr->getType() << ThrowExpr->getSourceRange()); @@ -1220,14 +1247,14 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, // Make sure the expression type is an ObjC pointer or "void *". Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get()); - if (!Context.isObjCObjectPointerType(SyncExpr->getType())) { - const PointerType *PT = SyncExpr->getType()->getAsPointerType(); + if (!SyncExpr->getType()->isObjCObjectPointerType()) { + const PointerType *PT = SyncExpr->getType()->getAs<PointerType>(); if (!PT || !PT->getPointeeType()->isVoidType()) return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object) << SyncExpr->getType() << SyncExpr->getSourceRange()); } - - return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, + + return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, SynchExpr.takeAs<Stmt>(), SynchBody.takeAs<Stmt>())); } @@ -1243,6 +1270,35 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl, HandlerBlock.takeAs<Stmt>())); } +class TypeWithHandler { + QualType t; + CXXCatchStmt *stmt; +public: + TypeWithHandler(const QualType &type, CXXCatchStmt *statement) + : t(type), stmt(statement) {} + + // An arbitrary order is fine as long as it places identical + // types next to each other. + bool operator<(const TypeWithHandler &y) const { + if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr()) + return true; + if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr()) + return false; + else + return getTypeSpecStartLoc() < y.getTypeSpecStartLoc(); + } + + bool operator==(const TypeWithHandler& other) const { + return t == other.t; + } + + QualType getQualType() const { return t; } + CXXCatchStmt *getCatchStmt() const { return stmt; } + SourceLocation getTypeSpecStartLoc() const { + return stmt->getExceptionDecl()->getTypeSpecStartLoc(); + } +}; + /// ActOnCXXTryBlock - Takes a try compound-statement and a number of /// handlers and creates a try statement from them. Action::OwningStmtResult @@ -1253,13 +1309,44 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, "The parser shouldn't call this if there are no handlers."); Stmt **Handlers = reinterpret_cast<Stmt**>(RawHandlers.get()); - for(unsigned i = 0; i < NumHandlers - 1; ++i) { + llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers; + + for (unsigned i = 0; i < NumHandlers; ++i) { CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]); - if (!Handler->getExceptionDecl()) - return StmtError(Diag(Handler->getLocStart(), diag::err_early_catch_all)); + if (!Handler->getExceptionDecl()) { + if (i < NumHandlers - 1) + return StmtError(Diag(Handler->getLocStart(), + diag::err_early_catch_all)); + + continue; + } + + const QualType CaughtType = Handler->getCaughtType(); + const QualType CanonicalCaughtType = Context.getCanonicalType(CaughtType); + TypesWithHandlers.push_back(TypeWithHandler(CanonicalCaughtType, Handler)); } - // FIXME: We should detect handlers for the same type as an earlier one. - // This one is rather easy. + + // Detect handlers for the same type as an earlier one. + if (NumHandlers > 1) { + llvm::array_pod_sort(TypesWithHandlers.begin(), TypesWithHandlers.end()); + + TypeWithHandler prev = TypesWithHandlers[0]; + for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) { + TypeWithHandler curr = TypesWithHandlers[i]; + + if (curr == prev) { + Diag(curr.getTypeSpecStartLoc(), + diag::warn_exception_caught_by_earlier_handler) + << curr.getCatchStmt()->getCaughtType().getAsString(); + Diag(prev.getTypeSpecStartLoc(), + diag::note_previous_exception_handler) + << prev.getCatchStmt()->getCaughtType().getAsString(); + } + + prev = curr; + } + } + // FIXME: We should detect handlers that cannot catch anything because an // earlier handler catches a superclass. Need to find a method that is not // quadratic for this. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 568d68c9a7e82..d56b4e114e74c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1,104 +1,239 @@ //===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/ - // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. //===----------------------------------------------------------------------===/ - // // This file implements semantic analysis for C++ templates. //===----------------------------------------------------------------------===/ #include "Sema.h" +#include "TreeTransform.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/DeclSpec.h" #include "clang/Basic/LangOptions.h" - +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/Support/Compiler.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; -/// isTemplateName - Determines whether the identifier II is a -/// template name in the current scope, and returns the template -/// declaration if II names a template. An optional CXXScope can be -/// passed to indicate the C++ scope in which the identifier will be -/// found. -TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S, - TemplateTy &TemplateResult, - const CXXScopeSpec *SS) { - NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName); - - TemplateNameKind TNK = TNK_Non_template; - TemplateDecl *Template = 0; - - if (IIDecl) { - if ((Template = dyn_cast<TemplateDecl>(IIDecl))) { - if (isa<FunctionTemplateDecl>(IIDecl)) - TNK = TNK_Function_template; - else if (isa<ClassTemplateDecl>(IIDecl) || - isa<TemplateTemplateParmDecl>(IIDecl)) - TNK = TNK_Type_template; - else - assert(false && "Unknown template declaration kind"); - } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) { - // C++ [temp.local]p1: - // Like normal (non-template) classes, class templates have an - // injected-class-name (Clause 9). The injected-class-name - // can be used with or without a template-argument-list. When - // it is used without a template-argument-list, it is - // equivalent to the injected-class-name followed by the - // template-parameters of the class template enclosed in - // <>. When it is used with a template-argument-list, it - // refers to the specified class template specialization, - // which could be the current specialization or another - // specialization. - if (Record->isInjectedClassName()) { - Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record)); - if ((Template = Record->getDescribedClassTemplate())) - TNK = TNK_Type_template; - else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { - Template = Spec->getSpecializedTemplate(); - TNK = TNK_Type_template; - } - } +/// \brief Determine whether the declaration found is acceptable as the name +/// of a template and, if so, return that template declaration. Otherwise, +/// returns NULL. +static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { + if (!D) + return 0; + + if (isa<TemplateDecl>(D)) + return D; + + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { + // C++ [temp.local]p1: + // Like normal (non-template) classes, class templates have an + // injected-class-name (Clause 9). The injected-class-name + // can be used with or without a template-argument-list. When + // it is used without a template-argument-list, it is + // equivalent to the injected-class-name followed by the + // template-parameters of the class template enclosed in + // <>. When it is used with a template-argument-list, it + // refers to the specified class template specialization, + // which could be the current specialization or another + // specialization. + if (Record->isInjectedClassName()) { + Record = cast<CXXRecordDecl>(Record->getDeclContext()); + if (Record->getDescribedClassTemplate()) + return Record->getDescribedClassTemplate(); + + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record)) + return Spec->getSpecializedTemplate(); } - // FIXME: What follows is a slightly less gross hack than what used to - // follow. - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) { - if (FD->getDescribedFunctionTemplate()) { - TemplateResult = TemplateTy::make(FD); - return TNK_Function_template; + return 0; + } + + OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D); + if (!Ovl) + return 0; + + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) { + if (FunctionTemplateDecl *FuncTmpl = dyn_cast<FunctionTemplateDecl>(*F)) { + // We've found a function template. Determine whether there are + // any other function templates we need to bundle together in an + // OverloadedFunctionDecl + for (++F; F != FEnd; ++F) { + if (isa<FunctionTemplateDecl>(*F)) + break; } - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(IIDecl)) { - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - if (isa<FunctionTemplateDecl>(*F)) { - TemplateResult = TemplateTy::make(Ovl); - return TNK_Function_template; + + if (F != FEnd) { + // Build an overloaded function decl containing only the + // function templates in Ovl. + OverloadedFunctionDecl *OvlTemplate + = OverloadedFunctionDecl::Create(Context, + Ovl->getDeclContext(), + Ovl->getDeclName()); + OvlTemplate->addOverload(FuncTmpl); + OvlTemplate->addOverload(*F); + for (++F; F != FEnd; ++F) { + if (isa<FunctionTemplateDecl>(*F)) + OvlTemplate->addOverload(*F); } + + return OvlTemplate; } + + return FuncTmpl; } + } + + return 0; +} - if (TNK != TNK_Non_template) { - if (SS && SS->isSet() && !SS->isInvalid()) { - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, - false, - Template)); - } else - TemplateResult = TemplateTy::make(TemplateName(Template)); +TemplateNameKind Sema::isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, + const CXXScopeSpec *SS, + TypeTy *ObjectTypePtr, + bool EnteringContext, + TemplateTy &TemplateResult) { + // Determine where to perform name lookup + DeclContext *LookupCtx = 0; + bool isDependent = false; + if (ObjectTypePtr) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert((!SS || !SS->isSet()) && + "ObjectType and scope specifier cannot coexist"); + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + LookupCtx = computeDeclContext(ObjectType); + isDependent = ObjectType->isDependentType(); + } else if (SS && SS->isSet()) { + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + + LookupCtx = computeDeclContext(*SS, EnteringContext); + isDependent = isDependentScopeSpecifier(*SS); + } + + LookupResult Found; + bool ObjectTypeSearchedInScope = false; + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + + // The declaration context must be complete. + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) + return TNK_Non_template; + + LookupQualifiedName(Found, LookupCtx, &II, LookupOrdinaryName); + + if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) { + // C++ [basic.lookup.classref]p1: + // In a class member access expression (5.2.5), if the . or -> token is + // immediately followed by an identifier followed by a <, the + // identifier must be looked up to determine whether the < is the + // beginning of a template argument list (14.2) or a less-than operator. + // The identifier is first looked up in the class of the object + // expression. If the identifier is not found, it is then looked up in + // the context of the entire postfix-expression and shall name a class + // or function template. + // + // FIXME: When we're instantiating a template, do we actually have to + // look in the scope of the template? Seems fishy... + LookupName(Found, S, &II, LookupOrdinaryName); + ObjectTypeSearchedInScope = true; } + } else if (isDependent) { + // We cannot look into a dependent object type or + return TNK_Non_template; + } else { + // Perform unqualified name lookup in the current scope. + LookupName(Found, S, &II, LookupOrdinaryName); } - return TNK; + + // FIXME: Cope with ambiguous name-lookup results. + assert(!Found.isAmbiguous() && + "Cannot handle template name-lookup ambiguities"); + + NamedDecl *Template + = isAcceptableTemplateName(Context, Found.getAsSingleDecl(Context)); + if (!Template) + return TNK_Non_template; + + if (ObjectTypePtr && !ObjectTypeSearchedInScope) { + // C++ [basic.lookup.classref]p1: + // [...] If the lookup in the class of the object expression finds a + // template, the name is also looked up in the context of the entire + // postfix-expression and [...] + // + LookupResult FoundOuter; + LookupName(FoundOuter, S, &II, LookupOrdinaryName); + // FIXME: Handle ambiguities in this lookup better + NamedDecl *OuterTemplate + = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context)); + + if (!OuterTemplate) { + // - if the name is not found, the name found in the class of the + // object expression is used, otherwise + } else if (!isa<ClassTemplateDecl>(OuterTemplate)) { + // - if the name is found in the context of the entire + // postfix-expression and does not name a class template, the name + // found in the class of the object expression is used, otherwise + } else { + // - if the name found is a class template, it must refer to the same + // entity as the one found in the class of the object expression, + // otherwise the program is ill-formed. + if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) { + Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) + << &II; + Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type) + << QualType::getFromOpaquePtr(ObjectTypePtr); + Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope); + + // Recover by taking the template that we found in the object + // expression's type. + } + } + } + + if (SS && SS->isSet() && !SS->isInvalid()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(Template)) + TemplateResult + = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, + Ovl)); + else + TemplateResult + = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, + cast<TemplateDecl>(Template))); + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(Template)) { + TemplateResult = TemplateTy::make(TemplateName(Ovl)); + } else { + TemplateResult = TemplateTy::make( + TemplateName(cast<TemplateDecl>(Template))); + } + + if (isa<ClassTemplateDecl>(Template) || + isa<TemplateTemplateParmDecl>(Template)) + return TNK_Type_template; + + assert((isa<FunctionTemplateDecl>(Template) || + isa<OverloadedFunctionDecl>(Template)) && + "Unhandled template kind in Sema::isTemplateName"); + return TNK_Function_template; } /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining @@ -115,7 +250,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { // C++ [temp.local]p4: // A template-parameter shall not be redeclared within its // scope (including nested scopes). - Diag(Loc, diag::err_template_param_shadow) + Diag(Loc, diag::err_template_param_shadow) << cast<NamedDecl>(PrevDecl)->getDeclName(); Diag(PrevDecl->getLocation(), diag::note_template_param_here); return true; @@ -125,7 +260,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { /// the parameter D to reference the templated declaration and return a pointer /// to the template declaration. Otherwise, do nothing to D and return null. TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) { - if (TemplateDecl *Temp = dyn_cast<TemplateDecl>(D.getAs<Decl>())) { + if (TemplateDecl *Temp = dyn_cast_or_null<TemplateDecl>(D.getAs<Decl>())) { D = DeclPtrTy::make(Temp->getTemplatedDecl()); return Temp; } @@ -138,24 +273,24 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) { /// (otherwise, "class" was used), and KeyLoc is the location of the /// "class" or "typename" keyword. ParamName is the name of the /// parameter (NULL indicates an unnamed template parameter) and -/// ParamName is the location of the parameter name (if any). +/// ParamName is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. -Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, +Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position) { - assert(S->isTemplateParamScope() && - "Template type parameter not in template parameter scope!"); + assert(S->isTemplateParamScope() && + "Template type parameter not in template parameter scope!"); bool Invalid = false; if (ParamName) { - NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc, - PrevDecl); + PrevDecl); } SourceLocation Loc = ParamNameLoc; @@ -163,8 +298,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, Loc = KeyLoc; TemplateTypeParmDecl *Param - = TemplateTypeParmDecl::Create(Context, CurContext, Loc, - Depth, Position, ParamName, Typename, + = TemplateTypeParmDecl::Create(Context, CurContext, Loc, + Depth, Position, ParamName, Typename, Ellipsis); if (Invalid) Param->setInvalidDecl(); @@ -179,27 +314,28 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, } /// ActOnTypeParameterDefault - Adds a default argument (the type -/// Default) to the given template type parameter (TypeParam). -void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, +/// Default) to the given template type parameter (TypeParam). +void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, SourceLocation EqualLoc, - SourceLocation DefaultLoc, + SourceLocation DefaultLoc, TypeTy *DefaultT) { - TemplateTypeParmDecl *Parm + TemplateTypeParmDecl *Parm = cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>()); - QualType Default = QualType::getFromOpaquePtr(DefaultT); + // FIXME: Preserve type source info. + QualType Default = GetTypeFromParser(DefaultT); // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of - // template-parameter that is not a template parameter pack. + // template-parameter that is not a template parameter pack. if (Parm->isParameterPack()) { Diag(DefaultLoc, diag::err_template_param_pack_default_arg); return; } - + // C++ [temp.param]p14: // A template-parameter shall not be used in its own default argument. // FIXME: Implement this check! Needs a recursive walk over the types. - + // Check the template argument itself. if (CheckTemplateArgument(Parm, Default, DefaultLoc)) { Parm->setInvalidDecl(); @@ -214,7 +350,7 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, /// /// \returns the (possibly-promoted) parameter type if valid; /// otherwise, produces a diagnostic and returns a NULL type. -QualType +QualType Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { // C++ [temp.param]p4: // @@ -223,11 +359,11 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { // // -- integral or enumeration type, if (T->isIntegralType() || T->isEnumeralType() || - // -- pointer to object or pointer to function, - (T->isPointerType() && - (T->getAsPointerType()->getPointeeType()->isObjectType() || - T->getAsPointerType()->getPointeeType()->isFunctionType())) || - // -- reference to object or reference to function, + // -- pointer to object or pointer to function, + (T->isPointerType() && + (T->getAs<PointerType>()->getPointeeType()->isObjectType() || + T->getAs<PointerType>()->getPointeeType()->isFunctionType())) || + // -- reference to object or reference to function, T->isReferenceType() || // -- pointer to member. T->isMemberPointerType() || @@ -258,9 +394,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { /// class Array") has been parsed. S is the current scope and D is /// the parsed declarator. Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, - unsigned Depth, + unsigned Depth, unsigned Position) { - QualType T = GetTypeForDeclarator(D, S); + DeclaratorInfo *DInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &DInfo); assert(S->isTemplateParamScope() && "Non-type template parameter not in template parameter scope!"); @@ -268,7 +405,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, IdentifierInfo *ParamName = D.getIdentifier(); if (ParamName) { - NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -282,7 +419,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), - Depth, Position, ParamName, T); + Depth, Position, ParamName, T, DInfo); if (Invalid) Param->setInvalidDecl(); @@ -299,14 +436,14 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD, SourceLocation EqualLoc, ExprArg DefaultE) { - NonTypeTemplateParmDecl *TemplateParm + NonTypeTemplateParmDecl *TemplateParm = cast<NonTypeTemplateParmDecl>(TemplateParamD.getAs<Decl>()); Expr *Default = static_cast<Expr *>(DefaultE.get()); - + // C++ [temp.param]p14: // A template-parameter shall not be used in its own default argument. // FIXME: Implement this check! Needs a recursive walk over the types. - + // Check the well-formedness of the default template argument. TemplateArgument Converted; if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default, @@ -328,8 +465,7 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, IdentifierInfo *Name, SourceLocation NameLoc, unsigned Depth, - unsigned Position) -{ + unsigned Position) { assert(S->isTemplateParamScope() && "Template template parameter not in template parameter scope!"); @@ -363,12 +499,12 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD, SourceLocation EqualLoc, ExprArg DefaultE) { - TemplateTemplateParmDecl *TemplateParm + TemplateTemplateParmDecl *TemplateParm = cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>()); // Since a template-template parameter's default argument is an // id-expression, it must be a DeclRefExpr. - DeclRefExpr *Default + DeclRefExpr *Default = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get())); // C++ [temp.param]p14: @@ -377,12 +513,12 @@ void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD, // Check the well-formedness of the template argument. if (!isa<TemplateDecl>(Default->getDecl())) { - Diag(Default->getSourceRange().getBegin(), + Diag(Default->getSourceRange().getBegin(), diag::err_template_arg_must_be_template) << Default->getSourceRange(); TemplateParm->setInvalidDecl(); return; - } + } if (CheckTemplateArgument(TemplateParm, Default)) { TemplateParm->setInvalidDecl(); return; @@ -397,7 +533,7 @@ void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD, Sema::TemplateParamsTy * Sema::ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, - SourceLocation TemplateLoc, + SourceLocation TemplateLoc, SourceLocation LAngleLoc, DeclPtrTy *Params, unsigned NumParams, SourceLocation RAngleLoc) { @@ -405,31 +541,28 @@ Sema::ActOnTemplateParameterList(unsigned Depth, Diag(ExportLoc, diag::note_template_export_unsupported); return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, - (Decl**)Params, NumParams, RAngleLoc); + (NamedDecl**)Params, NumParams, + RAngleLoc); } Sema::DeclResult -Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, +Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, - MultiTemplateParamsArg TemplateParameterLists, + TemplateParameterList *TemplateParams, AccessSpecifier AS) { - assert(TemplateParameterLists.size() > 0 && "No template parameter lists?"); - assert(TK != TK_Reference && "Can only declare or define class templates"); + assert(TemplateParams && TemplateParams->size() > 0 && + "No template parameters"); + assert(TUK != TUK_Reference && "Can only declare or define class templates"); bool Invalid = false; // Check that we can declare a template here. - if (CheckTemplateDeclScope(S, TemplateParameterLists)) + if (CheckTemplateDeclScope(S, TemplateParams)) return true; - 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; - } + TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec); + assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type"); // There is no such thing as an unnamed class template. if (!Name) { @@ -438,31 +571,73 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, } // Find any previous declaration with this name. - LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName, - true); + DeclContext *SemanticContext; + LookupResult Previous; + if (SS.isNotEmpty() && !SS.isInvalid()) { + if (RequireCompleteDeclContext(SS)) + return true; + + SemanticContext = computeDeclContext(SS, true); + if (!SemanticContext) { + // FIXME: Produce a reasonable diagnostic here + return true; + } + + LookupQualifiedName(Previous, SemanticContext, Name, LookupOrdinaryName, + true); + } else { + SemanticContext = CurContext; + LookupName(Previous, S, Name, LookupOrdinaryName, true); + } + assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?"); NamedDecl *PrevDecl = 0; if (Previous.begin() != Previous.end()) PrevDecl = *Previous.begin(); - if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S)) + if (PrevDecl && TUK == TUK_Friend) { + // C++ [namespace.memdef]p3: + // [...] When looking for a prior declaration of a class or a function + // declared as a friend, and when the name of the friend class or + // function is neither a qualified name nor a template-id, scopes outside + // the innermost enclosing namespace scope are not considered. + DeclContext *OutermostContext = CurContext; + while (!OutermostContext->isFileContext()) + OutermostContext = OutermostContext->getLookupParent(); + + if (OutermostContext->Equals(PrevDecl->getDeclContext()) || + OutermostContext->Encloses(PrevDecl->getDeclContext())) { + SemanticContext = PrevDecl->getDeclContext(); + } else { + // Declarations in outer scopes don't matter. However, the outermost + // context we computed is the semntic context for our new + // declaration. + PrevDecl = 0; + SemanticContext = OutermostContext; + } + } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = 0; - - DeclContext *SemanticContext = CurContext; - if (SS.isNotEmpty() && !SS.isInvalid()) { - SemanticContext = computeDeclContext(SS); - - // FIXME: need to match up several levels of template parameter lists here. - } - - // FIXME: member templates! - TemplateParameterList *TemplateParams - = static_cast<TemplateParameterList *>(*TemplateParameterLists.release()); // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. - ClassTemplateDecl *PrevClassTemplate + ClassTemplateDecl *PrevClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); + + // We may have found the injected-class-name of a class template, + // class template partial specialization, or class template specialization. + // In these cases, grab the template that is being defined or specialized. + if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && + cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) { + PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext()); + PrevClassTemplate + = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate(); + if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) { + PrevClassTemplate + = cast<ClassTemplateSpecializationDecl>(PrevDecl) + ->getSpecializedTemplate(); + } + } + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, @@ -477,16 +652,16 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, // template declaration (7.1.5.3). RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) { - Diag(KWLoc, diag::err_use_with_wrong_tag) + Diag(KWLoc, diag::err_use_with_wrong_tag) << Name - << CodeModificationHint::CreateReplacement(KWLoc, + << CodeModificationHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); Diag(PrevRecordDecl->getLocation(), diag::note_previous_use); Kind = PrevRecordDecl->getTagKind(); } // Check for redefinition of this class template. - if (TK == TK_Definition) { + if (TUK == TUK_Definition) { if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) { Diag(NameLoc, diag::err_redefinition) << Name; Diag(Def->getLocation(), diag::note_previous_definition); @@ -517,13 +692,13 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, if (CheckTemplateParameterList(TemplateParams, PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0)) Invalid = true; - + // FIXME: If we had a scope specifier, we better have a previous template // declaration! - CXXRecordDecl *NewClass = - CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, - PrevClassTemplate? + CXXRecordDecl *NewClass = + CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, + PrevClassTemplate? PrevClassTemplate->getTemplatedDecl() : 0, /*DelayTypeCreation=*/true); @@ -534,27 +709,60 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, NewClass->setDescribedClassTemplate(NewTemplate); // Build the type for the class template declaration now. - QualType T = - Context.getTypeDeclType(NewClass, - PrevClassTemplate? - PrevClassTemplate->getTemplatedDecl() : 0); + QualType T = + Context.getTypeDeclType(NewClass, + PrevClassTemplate? + PrevClassTemplate->getTemplatedDecl() : 0); assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; - // Set the access specifier. - SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); + // If we are providing an explicit specialization of a member that is a + // class template, make a note of that. + if (PrevClassTemplate && + PrevClassTemplate->getInstantiatedFromMemberTemplate()) + PrevClassTemplate->setMemberSpecialization(); + // Set the access specifier. + if (!Invalid && TUK != TUK_Friend) + SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); + // Set the lexical context of these templates NewClass->setLexicalDeclContext(CurContext); NewTemplate->setLexicalDeclContext(CurContext); - if (TK == TK_Definition) + if (TUK == TUK_Definition) NewClass->startDefinition(); if (Attr) ProcessDeclAttributeList(S, NewClass, Attr); - PushOnScopeChains(NewTemplate, S); + if (TUK != TUK_Friend) + PushOnScopeChains(NewTemplate, S); + else { + if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) { + NewTemplate->setAccess(PrevClassTemplate->getAccess()); + NewClass->setAccess(PrevClassTemplate->getAccess()); + } + + NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */ + PrevClassTemplate != NULL); + + // Friend templates are visible in fairly strange ways. + if (!CurContext->isDependentContext()) { + DeclContext *DC = SemanticContext->getLookupContext(); + DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false); + if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) + PushOnScopeChains(NewTemplate, EnclosingScope, + /* AddToContext = */ false); + } + + FriendDecl *Friend = FriendDecl::Create(Context, CurContext, + NewClass->getLocation(), + NewTemplate, + /*FIXME:*/NewClass->getLocation()); + Friend->setAccess(AS_public); + CurContext->addDecl(Friend); + } if (Invalid) { NewTemplate->setInvalidDecl(); @@ -585,7 +793,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, TemplateParameterList *OldParams) { bool Invalid = false; - + // C++ [temp.param]p10: // The set of default template-arguments available for use with a // template declaration or definition is obtained by merging the @@ -618,7 +826,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // If a template parameter of a class template is a template parameter pack, // it must be the last template parameter. if (SawParameterPack) { - Diag(ParameterPackLoc, + Diag(ParameterPackLoc, diag::err_template_param_pack_must_be_last_template_parameter); Invalid = true; } @@ -626,15 +834,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge default arguments for template type parameters. if (TemplateTypeParmDecl *NewTypeParm = dyn_cast<TemplateTypeParmDecl>(*NewParam)) { - TemplateTypeParmDecl *OldTypeParm + TemplateTypeParmDecl *OldTypeParm = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0; - + if (NewTypeParm->isParameterPack()) { assert(!NewTypeParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); SawParameterPack = true; ParameterPackLoc = NewTypeParm->getLocation(); - } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() && + } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() && NewTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); @@ -654,13 +862,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc(); } else if (SawDefaultArgument) MissingDefaultArg = true; - } - // Merge default arguments for non-type template parameters - else if (NonTypeTemplateParmDecl *NewNonTypeParm + } else if (NonTypeTemplateParmDecl *NewNonTypeParm = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) { + // Merge default arguments for non-type template parameters NonTypeTemplateParmDecl *OldNonTypeParm = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0; - if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && + if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && NewNonTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); @@ -681,15 +888,14 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, SawDefaultArgument = true; PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc(); } else if (SawDefaultArgument) - MissingDefaultArg = true; - } + MissingDefaultArg = true; + } else { // Merge default arguments for template template parameters - else { TemplateTemplateParmDecl *NewTemplateParm = cast<TemplateTemplateParmDecl>(*NewParam); TemplateTemplateParmDecl *OldTemplateParm = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0; - if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && + if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && NewTemplateParm->hasDefaultArgument()) { OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc(); NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc(); @@ -709,7 +915,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, SawDefaultArgument = true; PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc(); } else if (SawDefaultArgument) - MissingDefaultArg = true; + MissingDefaultArg = true; } if (RedundantDefaultArg) { @@ -724,7 +930,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // If a template-parameter has a default template-argument, // all subsequent template-parameters shall have a default // template-argument supplied. - Diag((*NewParam)->getLocation(), + Diag((*NewParam)->getLocation(), diag::err_template_param_default_arg_missing); Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg); Invalid = true; @@ -739,11 +945,157 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, return Invalid; } +/// \brief Match the given template parameter lists to the given scope +/// specifier, returning the template parameter list that applies to the +/// name. +/// +/// \param DeclStartLoc the start of the declaration that has a scope +/// specifier or a template parameter list. +/// +/// \param SS the scope specifier that will be matched to the given template +/// parameter lists. This scope specifier precedes a qualified name that is +/// being declared. +/// +/// \param ParamLists the template parameter lists, from the outermost to the +/// innermost template parameter lists. +/// +/// \param NumParamLists the number of template parameter lists in ParamLists. +/// +/// \param IsExplicitSpecialization will be set true if the entity being +/// declared is an explicit specialization, false otherwise. +/// +/// \returns the template parameter list, if any, that corresponds to the +/// name that is preceded by the scope specifier @p SS. This template +/// parameter list may be have template parameters (if we're declaring a +/// template) or may have no template parameters (if we're declaring a +/// template specialization), or may be NULL (if we were's declaring isn't +/// itself a template). +TemplateParameterList * +Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, + const CXXScopeSpec &SS, + TemplateParameterList **ParamLists, + unsigned NumParamLists, + bool &IsExplicitSpecialization) { + IsExplicitSpecialization = false; + + // Find the template-ids that occur within the nested-name-specifier. These + // template-ids will match up with the template parameter lists. + llvm::SmallVector<const TemplateSpecializationType *, 4> + TemplateIdsInSpecifier; + for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); + NNS; NNS = NNS->getPrefix()) { + if (const TemplateSpecializationType *SpecType + = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) { + TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); + if (!Template) + continue; // FIXME: should this be an error? probably... + + if (const RecordType *Record = SpecType->getAs<RecordType>()) { + ClassTemplateSpecializationDecl *SpecDecl + = cast<ClassTemplateSpecializationDecl>(Record->getDecl()); + // If the nested name specifier refers to an explicit specialization, + // we don't need a template<> header. + // FIXME: revisit this approach once we cope with specializations + // properly. + if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) + continue; + } + + TemplateIdsInSpecifier.push_back(SpecType); + } + } + + // Reverse the list of template-ids in the scope specifier, so that we can + // more easily match up the template-ids and the template parameter lists. + std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end()); + + SourceLocation FirstTemplateLoc = DeclStartLoc; + if (NumParamLists) + FirstTemplateLoc = ParamLists[0]->getTemplateLoc(); + + // Match the template-ids found in the specifier to the template parameter + // lists. + unsigned Idx = 0; + for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size(); + Idx != NumTemplateIds; ++Idx) { + QualType TemplateId = QualType(TemplateIdsInSpecifier[Idx], 0); + bool DependentTemplateId = TemplateId->isDependentType(); + if (Idx >= NumParamLists) { + // We have a template-id without a corresponding template parameter + // list. + if (DependentTemplateId) { + // FIXME: the location information here isn't great. + Diag(SS.getRange().getBegin(), + diag::err_template_spec_needs_template_parameters) + << TemplateId + << SS.getRange(); + } else { + Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header) + << SS.getRange() + << CodeModificationHint::CreateInsertion(FirstTemplateLoc, + "template<> "); + IsExplicitSpecialization = true; + } + return 0; + } + + // Check the template parameter list against its corresponding template-id. + if (DependentTemplateId) { + TemplateDecl *Template + = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl(); + + if (ClassTemplateDecl *ClassTemplate + = dyn_cast<ClassTemplateDecl>(Template)) { + TemplateParameterList *ExpectedTemplateParams = 0; + // Is this template-id naming the primary template? + if (Context.hasSameType(TemplateId, + ClassTemplate->getInjectedClassNameType(Context))) + ExpectedTemplateParams = ClassTemplate->getTemplateParameters(); + // ... or a partial specialization? + else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = ClassTemplate->findPartialSpecialization(TemplateId)) + ExpectedTemplateParams = PartialSpec->getTemplateParameters(); + + if (ExpectedTemplateParams) + TemplateParameterListsAreEqual(ParamLists[Idx], + ExpectedTemplateParams, + true); + } + } else if (ParamLists[Idx]->size() > 0) + Diag(ParamLists[Idx]->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << TemplateId + << ParamLists[Idx]->getSourceRange(); + else + IsExplicitSpecialization = true; + } + + // If there were at least as many template-ids as there were template + // parameter lists, then there are no template parameter lists remaining for + // the declaration itself. + if (Idx >= NumParamLists) + return 0; + + // If there were too many template parameter lists, complain about that now. + if (Idx != NumParamLists - 1) { + while (Idx < NumParamLists - 1) { + Diag(ParamLists[Idx]->getTemplateLoc(), + diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[Idx]->getTemplateLoc(), + ParamLists[Idx]->getRAngleLoc()); + ++Idx; + } + } + + // Return the last template parameter list, which corresponds to the + // entity being declared. + return ParamLists[NumParamLists - 1]; +} + /// \brief Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. -static void -translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - SourceLocation *TemplateArgLocs, +void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, + SourceLocation *TemplateArgLocs, llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) { TemplateArgs.reserve(TemplateArgsIn.size()); @@ -752,72 +1104,12 @@ translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) { TemplateArgs.push_back( ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg], - QualType::getFromOpaquePtr(Args[Arg])) + //FIXME: Preserve type source info. + Sema::GetTypeFromParser(Args[Arg])) : TemplateArgument(reinterpret_cast<Expr *>(Args[Arg]))); } } -/// \brief Build a canonical version of a template argument list. -/// -/// This function builds a canonical version of the given template -/// argument list, where each of the template arguments has been -/// converted into its canonical form. This routine is typically used -/// to canonicalize a template argument list when the template name -/// itself is dependent. When the template name refers to an actual -/// template declaration, Sema::CheckTemplateArgumentList should be -/// used to check and canonicalize the template arguments. -/// -/// \param TemplateArgs The incoming template arguments. -/// -/// \param NumTemplateArgs The number of template arguments in \p -/// TemplateArgs. -/// -/// \param Canonical A vector to be filled with the canonical versions -/// of the template arguments. -/// -/// \param Context The ASTContext in which the template arguments live. -static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - llvm::SmallVectorImpl<TemplateArgument> &Canonical, - ASTContext &Context) { - Canonical.reserve(NumTemplateArgs); - for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) { - switch (TemplateArgs[Idx].getKind()) { - case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); - break; - - case TemplateArgument::Expression: - // FIXME: Build canonical expression (!) - Canonical.push_back(TemplateArgs[Idx]); - break; - - case TemplateArgument::Declaration: - Canonical.push_back( - TemplateArgument(SourceLocation(), - Context.getCanonicalDecl(TemplateArgs[Idx].getAsDecl()))); - break; - - case TemplateArgument::Integral: - Canonical.push_back(TemplateArgument(SourceLocation(), - *TemplateArgs[Idx].getAsIntegral(), - TemplateArgs[Idx].getIntegralType())); - break; - - case TemplateArgument::Type: { - QualType CanonType - = Context.getCanonicalType(TemplateArgs[Idx].getAsType()); - Canonical.push_back(TemplateArgument(SourceLocation(), CanonType)); - break; - } - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } - } -} - QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -828,34 +1120,20 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (!Template) { // The template name does not resolve to a template, so we just // build a dependent template-id type. - - // Canonicalize the template arguments to build the canonical - // template-id type. - llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs; - CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs, - CanonicalTemplateArgs, Context); - - TemplateName CanonName = Context.getCanonicalTemplateName(Name); - QualType CanonType - = Context.getTemplateSpecializationType(CanonName, - &CanonicalTemplateArgs[0], - CanonicalTemplateArgs.size()); - - // Build the dependent template-id type. return Context.getTemplateSpecializationType(Name, TemplateArgs, - NumTemplateArgs, CanonType); + NumTemplateArgs); } // Check that the template argument list is well-formed for this // template. TemplateArgumentListBuilder Converted(Template->getTemplateParameters(), NumTemplateArgs); - if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, + if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc, false, Converted)) return QualType(); - assert((Converted.structuredSize() == + assert((Converted.structuredSize() == Template->getTemplateParameters()->size()) && "Converted template argument list is too short!"); @@ -872,17 +1150,24 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // // template<typename T, typename U = T> struct A; TemplateName CanonName = Context.getCanonicalTemplateName(Name); - CanonType = Context.getTemplateSpecializationType(CanonName, + CanonType = Context.getTemplateSpecializationType(CanonName, Converted.getFlatArguments(), Converted.flatSize()); - } else if (ClassTemplateDecl *ClassTemplate + + // FIXME: CanonType is not actually the canonical type, and unfortunately + // it is a TemplateTypeSpecializationType that we will never use again. + // In the future, we need to teach getTemplateSpecializationType to only + // build the canonical type and return that to us. + CanonType = Context.getCanonicalType(CanonType); + } else if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(Template)) { // Find the class template specialization declaration that // corresponds to these arguments. llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationDecl::Profile(ID, + ClassTemplateSpecializationDecl::Profile(ID, Converted.getFlatArguments(), - Converted.flatSize()); + Converted.flatSize(), + Context); void *InsertPos = 0; ClassTemplateSpecializationDecl *Decl = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); @@ -890,9 +1175,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // This is the first time we have referenced this class template // specialization. Create the canonical declaration and add it to // the set of specializations. - Decl = ClassTemplateSpecializationDecl::Create(Context, + Decl = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), - TemplateLoc, + ClassTemplate->getLocation(), ClassTemplate, Converted, 0); ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); @@ -901,17 +1186,18 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, CanonType = Context.getTypeDeclType(Decl); } - + // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. + //FIXME: Preserve type source info. return Context.getTemplateSpecializationType(Name, TemplateArgs, NumTemplateArgs, CanonType); } Action::TypeResult Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, + SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc) { @@ -933,6 +1219,38 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, return Result.getAsOpaquePtr(); } +Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, + TagUseKind TUK, + DeclSpec::TST TagSpec, + SourceLocation TagLoc) { + if (TypeResult.isInvalid()) + return Sema::TypeResult(); + + QualType Type = QualType::getFromOpaquePtr(TypeResult.get()); + + // Verify the tag specifier. + TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); + + if (const RecordType *RT = Type->getAs<RecordType>()) { + RecordDecl *D = RT->getDecl(); + + IdentifierInfo *Id = D->getIdentifier(); + assert(Id && "templated class must have an identifier"); + + if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { + Diag(TagLoc, diag::err_use_with_wrong_tag) + << Type + << CodeModificationHint::CreateReplacement(SourceRange(TagLoc), + D->getKindName()); + Diag(D->getLocation(), diag::note_previous_use); + } + } + + QualType ElabType = Context.getElaboratedType(Type, TagKind); + + return ElabType.getAsOpaquePtr(); +} + Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, @@ -941,14 +1259,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, SourceLocation RAngleLoc) { // FIXME: Can we do any checking at this point? I guess we could check the // template arguments that we have against the template name, if the template - // name refers to a single template. That's not a terribly common case, + // name refers to a single template. That's not a terribly common case, // though. - return Owned(TemplateIdRefExpr::Create(Context, + return Owned(TemplateIdRefExpr::Create(Context, /*FIXME: New type?*/Context.OverloadTy, /*FIXME: Necessary?*/0, /*FIXME: Necessary?*/SourceRange(), Template, TemplateNameLoc, LAngleLoc, - TemplateArgs, + TemplateArgs, NumTemplateArgs, RAngleLoc)); } @@ -959,16 +1277,52 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); - + // Translate the parser's template argument list in our AST format. llvm::SmallVector<TemplateArgument, 16> TemplateArgs; translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); - + TemplateArgsIn.release(); + return BuildTemplateIdExpr(Template, TemplateNameLoc, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), RAngleLoc); } +Sema::OwningExprResult +Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TemplateTy TemplateD, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + TemplateName Template = TemplateD.getAsVal<TemplateName>(); + + // FIXME: We're going to end up looking up the template based on its name, + // twice! + DeclarationName Name; + if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) + Name = ActualTemplate->getDeclName(); + else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) + Name = Ovl->getDeclName(); + else + Name = Template.getAsDependentTemplateName()->getName(); + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + TemplateArgsIn.release(); + + // Do we have the save the actual template name? We might need it... + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc, + Name, true, LAngleLoc, + TemplateArgs.data(), TemplateArgs.size(), + RAngleLoc, DeclPtrTy(), &SS); +} + /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template @@ -976,20 +1330,15 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, /// example, given "MetaFun::template apply", the scope specifier \p /// SS will be "MetaFun::", \p TemplateKWLoc contains the location /// of the "template" keyword, and "apply" is the \p Name. -Sema::TemplateTy +Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, - const CXXScopeSpec &SS) { - if (!SS.isSet() || SS.isInvalid()) - return TemplateTy(); - - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - - // FIXME: member of the current instantiation - - if (!Qualifier->isDependent()) { + const CXXScopeSpec &SS, + TypeTy *ObjectType) { + if ((ObjectType && + computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || + (SS.isSet() && computeDeclContext(SS, false))) { // C++0x [temp.names]p5: // If a name prefixed by the keyword template is not the name of // a template, the program is ill-formed. [Note: the keyword @@ -1007,7 +1356,8 @@ 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; - TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS); + TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType, + false, Template); if (TNK == TNK_Non_template) { Diag(NameLoc, diag::err_template_kw_refers_to_non_template) << &Name; @@ -1017,10 +1367,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, return Template; } + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); } -bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, +bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgument &Arg, TemplateArgumentListBuilder &Converted) { // Check template type parameter. @@ -1033,13 +1385,13 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, // is not a type. Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); Diag(Param->getLocation(), diag::note_template_param_here); - + return true; - } + } if (CheckTemplateArgument(Param, Arg.getAsType(), Arg.getLocation())) return true; - + // Add the converted template type argument. Converted.Append( TemplateArgument(Arg.getLocation(), @@ -1062,9 +1414,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, unsigned NumArgs = NumTemplateArgs; bool Invalid = false; - bool HasParameterPack = + bool HasParameterPack = NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack(); - + if ((NumArgs > NumParams && !HasParameterPack) || (NumArgs < Params->getMinRequiredArguments() && !PartialTemplateArgs)) { @@ -1084,8 +1436,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, << Params->getSourceRange(); Invalid = true; } - - // C++ [temp.arg]p1: + + // C++ [temp.arg]p1: // [...] The type and form of each template-argument specified in // a template-id shall match the type and form specified for the // corresponding parameter declared by the template in its @@ -1096,7 +1448,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, Param != ParamEnd; ++Param, ++ArgIdx) { if (ArgIdx > NumArgs && PartialTemplateArgs) break; - + // Decode the template argument TemplateArgument Arg; if (ArgIdx >= NumArgs) { @@ -1109,7 +1461,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, Converted.EndPack(); break; } - + if (!TTP->hasDefaultArgument()) break; @@ -1118,49 +1470,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. if (ArgType->isDependentType()) { - InstantiatingTemplate Inst(*this, TemplateLoc, + InstantiatingTemplate Inst(*this, TemplateLoc, Template, Converted.getFlatArguments(), Converted.flatSize(), SourceRange(TemplateLoc, RAngleLoc)); TemplateArgumentList TemplateArgs(Context, Converted, /*TakeArgs=*/false); - ArgType = InstantiateType(ArgType, TemplateArgs, - TTP->getDefaultArgumentLoc(), - TTP->getDeclName()); + ArgType = SubstType(ArgType, + MultiLevelTemplateArgumentList(TemplateArgs), + TTP->getDefaultArgumentLoc(), + TTP->getDeclName()); } if (ArgType.isNull()) return true; Arg = TemplateArgument(TTP->getLocation(), ArgType); - } else if (NonTypeTemplateParmDecl *NTTP + } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { if (!NTTP->hasDefaultArgument()) break; - InstantiatingTemplate Inst(*this, TemplateLoc, + InstantiatingTemplate Inst(*this, TemplateLoc, Template, Converted.getFlatArguments(), Converted.flatSize(), SourceRange(TemplateLoc, RAngleLoc)); - + TemplateArgumentList TemplateArgs(Context, Converted, /*TakeArgs=*/false); - Sema::OwningExprResult E = InstantiateExpr(NTTP->getDefaultArgument(), - TemplateArgs); + Sema::OwningExprResult E + = SubstExpr(NTTP->getDefaultArgument(), + MultiLevelTemplateArgumentList(TemplateArgs)); if (E.isInvalid()) return true; - + Arg = TemplateArgument(E.takeAs<Expr>()); } else { - TemplateTemplateParmDecl *TempParm - = cast<TemplateTemplateParmDecl>(*Param); + TemplateTemplateParmDecl *TempParm + = cast<TemplateTemplateParmDecl>(*Param); if (!TempParm->hasDefaultArgument()) break; - // FIXME: Instantiate default argument + // FIXME: Subst default argument Arg = TemplateArgument(TempParm->getDefaultArgument()); } } else { @@ -1177,35 +1531,36 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted)) Invalid = true; } - + Converted.EndPack(); } else { if (CheckTemplateTypeArgument(TTP, Arg, Converted)) Invalid = true; } - } else if (NonTypeTemplateParmDecl *NTTP + } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { // Check non-type template parameters. - // Instantiate the type of the non-type template parameter with - // the template arguments we've seen thus far. + // Do substitution on the type of the non-type template parameter + // with the template arguments we've seen thus far. QualType NTTPType = NTTP->getType(); if (NTTPType->isDependentType()) { - // Instantiate the type of the non-type template parameter. - InstantiatingTemplate Inst(*this, TemplateLoc, + // Do substitution on the type of the non-type template parameter. + InstantiatingTemplate Inst(*this, TemplateLoc, Template, Converted.getFlatArguments(), Converted.flatSize(), SourceRange(TemplateLoc, RAngleLoc)); TemplateArgumentList TemplateArgs(Context, Converted, /*TakeArgs=*/false); - NTTPType = InstantiateType(NTTPType, TemplateArgs, - NTTP->getLocation(), - NTTP->getDeclName()); + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); // If that worked, check the non-type template parameter type // for validity. if (!NTTPType.isNull()) - NTTPType = CheckNonTypeTemplateParameterType(NTTPType, + NTTPType = CheckNonTypeTemplateParameterType(NTTPType, NTTP->getLocation()); if (NTTPType.isNull()) { Invalid = true; @@ -1217,7 +1572,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); break; - + case TemplateArgument::Expression: { Expr *E = Arg.getAsExpr(); TemplateArgument Result; @@ -1238,7 +1593,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, case TemplateArgument::Type: // We have a non-type template parameter but the template // argument is a type. - + // C++ [temp.arg]p2: // In a template-argument, an ambiguity between a type-id and // an expression is resolved to a type-id, regardless of the @@ -1254,37 +1609,37 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, Diag((*Param)->getLocation(), diag::note_template_param_here); Invalid = true; break; - + case TemplateArgument::Pack: assert(0 && "FIXME: Implement!"); break; } - } else { + } else { // Check template template parameters. - TemplateTemplateParmDecl *TempParm + TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - + switch (Arg.getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); break; - + case TemplateArgument::Expression: { Expr *ArgExpr = Arg.getAsExpr(); if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) { if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr))) Invalid = true; - + // Add the converted template argument. - Decl *D - = Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl()); + Decl *D + = cast<DeclRefExpr>(ArgExpr)->getDecl()->getCanonicalDecl(); Converted.Append(TemplateArgument(Arg.getLocation(), D)); continue; } } // fall through - + case TemplateArgument::Type: { // We have a template template parameter but the template // argument does not refer to a template. @@ -1298,11 +1653,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // it to the list of converted arguments. Converted.Append(Arg); break; - + case TemplateArgument::Integral: assert(false && "Integral argument with template template parameter"); break; - + case TemplateArgument::Pack: assert(0 && "FIXME: Implement!"); break; @@ -1318,7 +1673,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, /// /// This routine implements the semantics of C++ [temp.arg.type]. It /// returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, +bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg, SourceLocation ArgLoc) { // C++ [temp.arg.type]p2: // A local type, a type with no linkage, an unnamed type or a type @@ -1327,14 +1682,14 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, // // FIXME: Perform the recursive and no-linkage type checks. const TagType *Tag = 0; - if (const EnumType *EnumT = Arg->getAsEnumType()) + if (const EnumType *EnumT = Arg->getAs<EnumType>()) Tag = EnumT; - else if (const RecordType *RecordT = Arg->getAsRecordType()) + else if (const RecordType *RecordT = Arg->getAs<RecordType>()) Tag = RecordT; if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) return Diag(ArgLoc, diag::err_template_arg_local_type) << QualType(Tag, 0); - else if (Tag && !Tag->getDecl()->getDeclName() && + else if (Tag && !Tag->getDecl()->getDeclName() && !Tag->getDecl()->getTypedefForAnonDecl()) { Diag(ArgLoc, diag::err_template_arg_unnamed_type); Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here); @@ -1359,7 +1714,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, return false; // C++ [temp.arg.nontype]p1: - // + // // A template-argument for a non-type, non-template // template-parameter shall be one of: [...] // @@ -1370,11 +1725,11 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // the name refers to a function or array, or if the // corresponding template-parameter is a reference; or DeclRefExpr *DRE = 0; - + // Ignore (and complain about) any excess parentheses. while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { if (!Invalid) { - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_extra_parens) << Arg->getSourceRange(); Invalid = true; @@ -1390,7 +1745,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, DRE = dyn_cast<DeclRefExpr>(Arg); if (!DRE || !isa<ValueDecl>(DRE->getDecl())) - return Diag(Arg->getSourceRange().getBegin(), + return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_object_or_func_form) << Arg->getSourceRange(); @@ -1402,14 +1757,14 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // Cannot refer to non-static member functions if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl())) if (!Method->isStatic()) - return Diag(Arg->getSourceRange().getBegin(), + return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_method) << Method << Arg->getSourceRange(); - + // Functions must have external linkage. if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) { if (Func->getStorageClass() == FunctionDecl::Static) { - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_function_not_extern) << Func << Arg->getSourceRange(); Diag(Func->getLocation(), diag::note_template_arg_internal_object) @@ -1424,7 +1779,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { if (!Var->hasGlobalStorage()) { - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_object_not_extern) << Var << Arg->getSourceRange(); Diag(Var->getLocation(), diag::note_template_arg_internal_object) @@ -1436,19 +1791,19 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, Entity = Var; return Invalid; } - + // We found something else, but we don't know specifically what it is. - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_object_or_func) << Arg->getSourceRange(); - Diag(DRE->getDecl()->getLocation(), + Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here); return true; } /// \brief Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -bool +bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { bool Invalid = false; @@ -1461,7 +1816,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { return false; // C++ [temp.arg.nontype]p1: - // + // // A template-argument for a non-type, non-template // template-parameter shall be one of: [...] // @@ -1471,7 +1826,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { // Ignore (and complain about) any excess parentheses. while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { if (!Invalid) { - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_extra_parens) << Arg->getSourceRange(); Invalid = true; @@ -1501,10 +1856,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { } // We found something else, but we don't know specifically what it is. - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_pointer_to_member_form) << Arg->getSourceRange(); - Diag(DRE->getDecl()->getLocation(), + Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here); return true; } @@ -1519,7 +1874,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { /// /// If no error was detected, Converted receives the converted template argument. bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, - QualType InstantiatedParamType, Expr *&Arg, + QualType InstantiatedParamType, Expr *&Arg, TemplateArgument &Converted) { SourceLocation StartLoc = Arg->getSourceRange().getBegin(); @@ -1555,7 +1910,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, SourceLocation NonConstantLoc; llvm::APSInt Value; if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) { - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_integral_or_enumeral) << ArgType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); @@ -1584,7 +1939,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ImpCastExprToType(Arg, ParamType); } else { // We can't perform this conversion. - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); @@ -1592,7 +1947,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } QualType IntegerType = Context.getCanonicalType(ParamType); - if (const EnumType *Enum = IntegerType->getAsEnumType()) + if (const EnumType *Enum = IntegerType->getAs<EnumType>()) IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); if (!Arg->isValueDependent()) { @@ -1610,7 +1965,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Check that we don't overflow the template parameter type. unsigned AllowedBits = Context.getTypeSize(IntegerType); if (Value.getActiveBits() > AllowedBits) { - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_too_large) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); @@ -1634,7 +1989,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } Converted = TemplateArgument(StartLoc, Value, - ParamType->isEnumeralType() ? ParamType + ParamType->isEnumeralType() ? ParamType : IntegerType); return false; } @@ -1648,13 +2003,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // function is selected from the set (13.4). // In C++0x, any std::nullptr_t value can be converted. (ParamType->isPointerType() && - ParamType->getAsPointerType()->getPointeeType()->isFunctionType()) || + ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type reference to // function, no conversions apply. If the template-argument // represents a set of overloaded functions, the matching // function is selected from the set (13.4). (ParamType->isReferenceType() && - ParamType->getAsReferenceType()->getPointeeType()->isFunctionType()) || + ParamType->getAs<ReferenceType>()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type pointer to // member function, no conversions apply. If the // template-argument represents a set of overloaded member @@ -1662,9 +2017,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // the set (13.4). // Again, C++0x allows a std::nullptr_t value. (ParamType->isMemberPointerType() && - ParamType->getAsMemberPointerType()->getPointeeType() + ParamType->getAs<MemberPointerType>()->getPointeeType() ->isFunctionType())) { - if (Context.hasSameUnqualifiedType(ArgType, + if (Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { // We don't have to do anything: the types already match. } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() || @@ -1674,7 +2029,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else if (ArgType->isFunctionType() && ParamType->isPointerType()) { ArgType = Context.getPointerType(ArgType); ImpCastExprToType(Arg, ArgType); - } else if (FunctionDecl *Fn + } else if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) return true; @@ -1687,31 +2042,33 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } } - if (!Context.hasSameUnqualifiedType(ArgType, + if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { // We can't perform this conversion. - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; } - + if (ParamType->isMemberPointerType()) { NamedDecl *Member = 0; if (CheckTemplateArgumentPointerToMember(Arg, Member)) return true; - Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); + if (Member) + Member = cast<NamedDecl>(Member->getCanonicalDecl()); Converted = TemplateArgument(StartLoc, Member); return false; } - + NamedDecl *Entity = 0; if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); + if (Entity) + Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); Converted = TemplateArgument(StartLoc, Entity); return false; } @@ -1721,7 +2078,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // object, qualification conversions (4.4) and the // array-to-pointer conversion (4.2) are applied. // C++0x also allows a value of std::nullptr_t. - assert(ParamType->getAsPointerType()->getPointeeType()->isObjectType() && + assert(ParamType->getAs<PointerType>()->getPointeeType()->isObjectType() && "Only object pointers allowed here"); if (ArgType->isNullPtrType()) { @@ -1736,26 +2093,27 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ArgType = ParamType; ImpCastExprToType(Arg, ParamType); } - + if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) { // We can't perform this conversion. - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; } - + NamedDecl *Entity = 0; if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); + if (Entity) + Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); Converted = TemplateArgument(StartLoc, Entity); return false; } - - if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) { + + if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) { // -- For a non-type template-parameter of type reference to // object, no conversions apply. The type referred to by the // reference may be more cv-qualified than the (otherwise @@ -1766,7 +2124,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, "Only object references allowed here"); if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) { - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_no_ref_bind) << InstantiatedParamType << Arg->getType() << Arg->getSourceRange(); @@ -1774,10 +2132,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - unsigned ParamQuals + unsigned ParamQuals = Context.getCanonicalType(ParamType).getCVRQualifiers(); unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers(); - + if ((ParamQuals | ArgQuals) != ParamQuals) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_ref_bind_ignores_quals) @@ -1786,12 +2144,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Diag(Param->getLocation(), diag::note_template_param_here); return true; } - + NamedDecl *Entity = 0; if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity)); + Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); Converted = TemplateArgument(StartLoc, Entity); return false; } @@ -1809,18 +2167,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ImpCastExprToType(Arg, ParamType); } else { // We can't perform this conversion. - Diag(Arg->getSourceRange().getBegin(), + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; + return true; } NamedDecl *Member = 0; if (CheckTemplateArgumentPointerToMember(Arg, Member)) return true; - - Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); + + if (Member) + Member = cast<NamedDecl>(Member->getCanonicalDecl()); Converted = TemplateArgument(StartLoc, Member); return false; } @@ -1846,9 +2205,9 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, // Note that we also allow template template parameters here, which // will happen when we are dealing with, e.g., class template // partial specializations. - if (!isa<ClassTemplateDecl>(Template) && + if (!isa<ClassTemplateDecl>(Template) && !isa<TemplateTemplateParmDecl>(Template)) { - assert(isa<FunctionTemplateDecl>(Template) && + assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template); Diag(Template->getLocation(), diag::note_template_arg_refers_here_func) @@ -1864,7 +2223,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, /// \brief Determine whether the given template parameter lists are /// equivalent. /// -/// \param New The new template parameter list, typically written in the +/// \param New The new template parameter list, typically written in the /// source code as part of a new template declaration. /// /// \param Old The old template parameter list, typically found via @@ -1886,7 +2245,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, /// /// \returns True if the template parameter lists are equal, false /// otherwise. -bool +bool Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, @@ -1898,7 +2257,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, if (TemplateArgLoc.isValid()) { Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); NextDiag = diag::note_template_param_list_different_arity; - } + } Diag(New->getTemplateLoc(), NextDiag) << (New->size() > Old->size()) << IsTemplateTemplateParm @@ -1939,15 +2298,15 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // types within the template parameter list of the template template // parameter can be checked, and (2) the template type parameter depths // will match up. - QualType OldParmType + QualType OldParmType = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm)); - QualType NewParmType + QualType NewParmType = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm)); - assert(Context.getCanonicalType(OldParmType) == - Context.getCanonicalType(NewParmType) && + assert(Context.getCanonicalType(OldParmType) == + Context.getCanonicalType(NewParmType) && "type parameter mismatch?"); #endif - } else if (NonTypeTemplateParmDecl *OldNTTP + } else if (NonTypeTemplateParmDecl *OldNTTP = dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) { // The types of non-type template parameters must agree. NonTypeTemplateParmDecl *NewNTTP @@ -1957,14 +2316,14 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, if (Complain) { unsigned NextDiag = diag::err_template_nontype_parm_different_type; if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, + Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); NextDiag = diag::note_template_nontype_parm_different_type; } Diag(NewNTTP->getLocation(), NextDiag) << NewNTTP->getType() << IsTemplateTemplateParm; - Diag(OldNTTP->getLocation(), + Diag(OldNTTP->getLocation(), diag::note_template_nontype_parm_prev_declaration) << OldNTTP->getType(); } @@ -1974,9 +2333,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // The template parameter lists of template template // parameters must agree. // FIXME: Could we perform a faster "type" comparison here? - assert(isa<TemplateTemplateParmDecl>(*OldParm) && + assert(isa<TemplateTemplateParmDecl>(*OldParm) && "Only template template parameters handled here"); - TemplateTemplateParmDecl *OldTTP + TemplateTemplateParmDecl *OldTTP = cast<TemplateTemplateParmDecl>(*OldParm); TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(*NewParm); @@ -1996,56 +2355,105 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, /// /// If the template declaration is valid in this scope, returns /// false. Otherwise, issues a diagnostic and returns true. -bool -Sema::CheckTemplateDeclScope(Scope *S, - MultiTemplateParamsArg &TemplateParameterLists) { - assert(TemplateParameterLists.size() > 0 && "Not a template"); - +bool +Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { // Find the nearest enclosing declaration scope. while ((S->getFlags() & Scope::DeclScope) == 0 || (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); - - TemplateParameterList *TemplateParams = - static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); - SourceLocation TemplateLoc = TemplateParams->getTemplateLoc(); - SourceRange TemplateRange - = SourceRange(TemplateLoc, TemplateParams->getRAngleLoc()); // C++ [temp]p2: // A template-declaration can appear only as a namespace scope or // class scope declaration. DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); - while (Ctx && isa<LinkageSpecDecl>(Ctx)) { - if (cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx) - return Diag(TemplateLoc, diag::err_template_linkage) - << TemplateRange; + if (Ctx && isa<LinkageSpecDecl>(Ctx) && + cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx) + return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) + << TemplateParams->getSourceRange(); + while (Ctx && isa<LinkageSpecDecl>(Ctx)) Ctx = Ctx->getParent(); - } if (Ctx && (Ctx->isFileContext() || Ctx->isRecord())) return false; - return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope) - << TemplateRange; + return Diag(TemplateParams->getTemplateLoc(), + diag::err_template_outside_namespace_or_class_scope) + << TemplateParams->getSourceRange(); +} + +/// \brief Determine what kind of template specialization the given declaration +/// is. +static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) { + if (!D) + return TSK_Undeclared; + + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) + return Record->getTemplateSpecializationKind(); + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) + return Function->getTemplateSpecializationKind(); + if (VarDecl *Var = dyn_cast<VarDecl>(D)) + return Var->getTemplateSpecializationKind(); + + return TSK_Undeclared; } -/// \brief Check whether a class template specialization or explicit -/// instantiation in the current context is well-formed. +/// \brief Check whether a specialization or explicit instantiation is +/// well-formed in the current context. /// -/// This routine determines whether a class template specialization or -/// explicit instantiation can be declared in the current context -/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2) and emits -/// appropriate diagnostics if there was an error. It returns true if -// there was an error that we cannot recover from, and false otherwise. -bool -Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, - ClassTemplateSpecializationDecl *PrevDecl, - SourceLocation TemplateNameLoc, - SourceRange ScopeSpecifierRange, - bool PartialSpecialization, - bool ExplicitInstantiation) { +/// This routine determines whether a template specialization or +/// explicit instantiation can be declared in the current context +/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2). +/// +/// \param S the semantic analysis object for which this check is being +/// performed. +/// +/// \param Specialized the entity being specialized or instantiated, which +/// may be a kind of template (class template, function template, etc.) or +/// a member of a class template (member function, static data member, +/// member class). +/// +/// \param PrevDecl the previous declaration of this entity, if any. +/// +/// \param Loc the location of the explicit specialization or instantiation of +/// this entity. +/// +/// \param IsPartialSpecialization whether this is a partial specialization of +/// a class template. +/// +/// \param TSK the kind of specialization or implicit instantiation being +/// performed. +/// +/// \returns true if there was an error that we cannot recover from, false +/// otherwise. +static bool CheckTemplateSpecializationScope(Sema &S, + NamedDecl *Specialized, + NamedDecl *PrevDecl, + SourceLocation Loc, + bool IsPartialSpecialization, + TemplateSpecializationKind TSK) { + // Keep these "kind" numbers in sync with the %select statements in the + // various diagnostics emitted by this routine. + int EntityKind = 0; + bool isTemplateSpecialization = false; + if (isa<ClassTemplateDecl>(Specialized)) { + EntityKind = IsPartialSpecialization? 1 : 0; + isTemplateSpecialization = true; + } else if (isa<FunctionTemplateDecl>(Specialized)) { + EntityKind = 2; + isTemplateSpecialization = true; + } else if (isa<CXXMethodDecl>(Specialized)) + EntityKind = 3; + else if (isa<VarDecl>(Specialized)) + EntityKind = 4; + else if (isa<RecordDecl>(Specialized)) + EntityKind = 5; + else { + S.Diag(Loc, diag::err_template_spec_unknown_kind) << TSK; + S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK; + return true; + } + // C++ [temp.expl.spec]p2: // An explicit specialization shall be declared in the namespace // of which the template is a member, or, for member templates, in @@ -2059,66 +2467,79 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, // the explicit specialization was declared, or in a namespace // that encloses the one in which the explicit specialization was // declared. - if (CurContext->getLookupContext()->isFunctionOrMethod()) { - int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0; - Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope) - << Kind << ClassTemplate; + if (S.CurContext->getLookupContext()->isFunctionOrMethod()) { + S.Diag(Loc, diag::err_template_spec_decl_function_scope) + << TSK << Specialized; return true; } - DeclContext *DC = CurContext->getEnclosingNamespaceContext(); - DeclContext *TemplateContext - = ClassTemplate->getDeclContext()->getEnclosingNamespaceContext(); - if ((!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) && - !ExplicitInstantiation) { - // There is no prior declaration of this entity, so this - // specialization must be in the same context as the template - // itself. - if (DC != TemplateContext) { - if (isa<TranslationUnitDecl>(TemplateContext)) - Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global) - << PartialSpecialization - << ClassTemplate << ScopeSpecifierRange; - else if (isa<NamespaceDecl>(TemplateContext)) - Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope) - << PartialSpecialization << ClassTemplate - << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange; - - Diag(ClassTemplate->getLocation(), diag::note_template_decl_here); - } - - return false; + if (S.CurContext->isRecord() && !IsPartialSpecialization) { + S.Diag(Loc, diag::err_template_spec_decl_class_scope) + << TSK << Specialized; + return true; } - - // We have a previous declaration of this entity. Make sure that - // this redeclaration (or definition) occurs in an enclosing namespace. - if (!CurContext->Encloses(TemplateContext)) { - // FIXME: In C++98, we would like to turn these errors into warnings, - // dependent on a -Wc++0x flag. - bool SuppressedDiag = false; - int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0; - if (isa<TranslationUnitDecl>(TemplateContext)) { - if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x) - Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope) - << Kind << ClassTemplate << ScopeSpecifierRange; - else - SuppressedDiag = true; - } else if (isa<NamespaceDecl>(TemplateContext)) { - if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x) - Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope) - << Kind << ClassTemplate - << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange; - else - SuppressedDiag = true; + + // C++ [temp.class.spec]p6: + // A class template partial specialization may be declared or redeclared + // in any namespace scope in which its definition may be defined (14.5.1 + // and 14.5.2). + bool ComplainedAboutScope = false; + DeclContext *SpecializedContext + = Specialized->getDeclContext()->getEnclosingNamespaceContext(); + DeclContext *DC = S.CurContext->getEnclosingNamespaceContext(); + if (TSK == TSK_ExplicitSpecialization) { + if ((!PrevDecl || + getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared || + getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){ + // There is no prior declaration of this entity, so this + // specialization must be in the same context as the template + // itself. + if (!DC->Equals(SpecializedContext)) { + if (isa<TranslationUnitDecl>(SpecializedContext)) + S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global) + << EntityKind << Specialized; + else if (isa<NamespaceDecl>(SpecializedContext)) + S.Diag(Loc, diag::err_template_spec_decl_out_of_scope) + << EntityKind << Specialized + << cast<NamedDecl>(SpecializedContext); + + S.Diag(Specialized->getLocation(), diag::note_specialized_entity) + << TSK; + ComplainedAboutScope = true; + } } - - if (!SuppressedDiag) - Diag(ClassTemplate->getLocation(), diag::note_template_decl_here); } - + + // Make sure that this redeclaration (or definition) occurs in an enclosing + // namespace. We perform this check for explicit specializations and, in + // C++0x, for explicit instantiations as well (per DR275). + // FIXME: -Wc++0x should make these warnings. + // Note that HandleDeclarator() performs this check for explicit + // specializations of function templates, static data members, and member + // functions, so we skip the check here for those kinds of entities. + // FIXME: HandleDeclarator's diagnostics aren't quite as good, though. + // Should we refactor that check, so that it occurs later? + if (!ComplainedAboutScope && !DC->Encloses(SpecializedContext) && + ((TSK == TSK_ExplicitSpecialization && + !(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) || + isa<FunctionDecl>(Specialized))) || + S.getLangOptions().CPlusPlus0x)) { + if (isa<TranslationUnitDecl>(SpecializedContext)) + S.Diag(Loc, diag::err_template_spec_redecl_global_scope) + << EntityKind << Specialized; + else if (isa<NamespaceDecl>(SpecializedContext)) + S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope) + << EntityKind << Specialized + << cast<NamedDecl>(SpecializedContext); + + S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK; + } + + // FIXME: check for specialization-after-instantiation errors and such. + return false; } - + /// \brief Check the non-type template arguments of a class template /// partial specialization according to C++ [temp.class.spec]p9. /// @@ -2142,16 +2563,16 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // FIXME: the interface to this function will have to change to // accommodate variadic templates. MirrorsPrimaryTemplate = true; - + const TemplateArgument *ArgList = TemplateArgs.getFlatArguments(); - + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { // Determine whether the template argument list of the partial // specialization is identical to the implicit argument list of // the primary template. The caller may need to diagnostic this as // an error per C++ [temp.class.spec]p9b3. if (MirrorsPrimaryTemplate) { - if (TemplateTypeParmDecl *TTP + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(I))) { if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) != Context.getCanonicalType(ArgList[I].getAsType())) @@ -2161,11 +2582,11 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( TemplateParams->getParam(I))) { // FIXME: We should settle on either Declaration storage or // Expression storage for template template parameters. - TemplateTemplateParmDecl *ArgDecl + TemplateTemplateParmDecl *ArgDecl = dyn_cast_or_null<TemplateTemplateParmDecl>( ArgList[I].getAsDecl()); if (!ArgDecl) - if (DeclRefExpr *DRE + if (DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(ArgList[I].getAsExpr())) ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl()); @@ -2176,7 +2597,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( } } - NonTypeTemplateParmDecl *Param + NonTypeTemplateParmDecl *Param = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I)); if (!Param) { continue; @@ -2197,9 +2618,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // specialized non-type arguments, so skip any non-specialized // arguments. if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) - if (NonTypeTemplateParmDecl *NTTP + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) { - if (MirrorsPrimaryTemplate && + if (MirrorsPrimaryTemplate && (Param->getIndex() != NTTP->getIndex() || Param->getDepth() != NTTP->getDepth())) MirrorsPrimaryTemplate = false; @@ -2215,7 +2636,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // specialization except when the argument expression is a // simple identifier. if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) { - Diag(ArgExpr->getLocStart(), + Diag(ArgExpr->getLocStart(), diag::err_dependent_non_type_arg_in_partial_spec) << ArgExpr->getSourceRange(); return true; @@ -2225,7 +2646,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // specialized non-type argument shall not be dependent on a // parameter of the specialization. if (Param->getType()->isDependentType()) { - Diag(ArgExpr->getLocStart(), + Diag(ArgExpr->getLocStart(), diag::err_dependent_typed_non_type_arg_in_partial_spec) << Param->getType() << ArgExpr->getSourceRange(); @@ -2240,8 +2661,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( } Sema::DeclResult -Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, - SourceLocation KWLoc, +Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, + TagUseKind TUK, + SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy TemplateD, SourceLocation TemplateNameLoc, @@ -2251,65 +2673,72 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation RAngleLoc, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists) { + assert(TUK != TUK_Reference && "References are not specializations"); + // Find the class template we're specializing TemplateName Name = TemplateD.getAsVal<TemplateName>(); - ClassTemplateDecl *ClassTemplate + ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); + bool isExplicitSpecialization = false; bool isPartialSpecialization = false; // Check the validity of the template headers that introduce this // template. - // FIXME: Once we have member templates, we'll need to check - // C++ [temp.expl.spec]p17-18, where we could have multiple levels of - // template<> headers. - if (TemplateParameterLists.size() == 0) - Diag(KWLoc, diag::err_template_spec_needs_header) - << CodeModificationHint::CreateInsertion(KWLoc, "template<> "); - else { - TemplateParameterList *TemplateParams - = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); - if (TemplateParameterLists.size() > 1) { - Diag(TemplateParams->getTemplateLoc(), - diag::err_template_spec_extra_headers); - return true; - } - - if (TemplateParams->size() > 0) { - isPartialSpecialization = true; - - // C++ [temp.class.spec]p10: - // The template parameter list of a specialization shall not - // contain default template argument values. - for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { - Decl *Param = TemplateParams->getParam(I); - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { - if (TTP->hasDefaultArgument()) { - Diag(TTP->getDefaultArgumentLoc(), - diag::err_default_arg_in_partial_spec); - TTP->setDefaultArgument(QualType(), SourceLocation(), false); - } - } else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (Expr *DefArg = NTTP->getDefaultArgument()) { - Diag(NTTP->getDefaultArgumentLoc(), - diag::err_default_arg_in_partial_spec) - << DefArg->getSourceRange(); - NTTP->setDefaultArgument(0); - DefArg->Destroy(Context); - } - } else { - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param); - if (Expr *DefArg = TTP->getDefaultArgument()) { - Diag(TTP->getDefaultArgumentLoc(), - diag::err_default_arg_in_partial_spec) - << DefArg->getSourceRange(); - TTP->setDefaultArgument(0); - DefArg->Destroy(Context); - } + // FIXME: We probably shouldn't complain about these headers for + // friend declarations. + TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, + (TemplateParameterList**)TemplateParameterLists.get(), + TemplateParameterLists.size(), + isExplicitSpecialization); + if (TemplateParams && TemplateParams->size() > 0) { + isPartialSpecialization = true; + + // C++ [temp.class.spec]p10: + // The template parameter list of a specialization shall not + // contain default template argument values. + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + Decl *Param = TemplateParams->getParam(I); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { + if (TTP->hasDefaultArgument()) { + Diag(TTP->getDefaultArgumentLoc(), + diag::err_default_arg_in_partial_spec); + TTP->setDefaultArgument(QualType(), SourceLocation(), false); + } + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (Expr *DefArg = NTTP->getDefaultArgument()) { + Diag(NTTP->getDefaultArgumentLoc(), + diag::err_default_arg_in_partial_spec) + << DefArg->getSourceRange(); + NTTP->setDefaultArgument(0); + DefArg->Destroy(Context); + } + } else { + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param); + if (Expr *DefArg = TTP->getDefaultArgument()) { + Diag(TTP->getDefaultArgumentLoc(), + diag::err_default_arg_in_partial_spec) + << DefArg->getSourceRange(); + TTP->setDefaultArgument(0); + DefArg->Destroy(Context); } } } + } else if (TemplateParams) { + if (TUK == TUK_Friend) + Diag(KWLoc, diag::err_template_spec_friend) + << CodeModificationHint::CreateRemoval( + SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc())) + << SourceRange(LAngleLoc, RAngleLoc); + else + isExplicitSpecialization = true; + } else if (TUK != TUK_Friend) { + Diag(KWLoc, diag::err_template_spec_needs_header) + << CodeModificationHint::CreateInsertion(KWLoc, "template<> "); + isExplicitSpecialization = true; } // Check that the specialization uses the same tag kind as the @@ -2322,13 +2751,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; } if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, KWLoc, *ClassTemplate->getIdentifier())) { - Diag(KWLoc, diag::err_use_with_wrong_tag) + Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate - << CodeModificationHint::CreateReplacement(KWLoc, + << CodeModificationHint::CreateReplacement(KWLoc, ClassTemplate->getTemplatedDecl()->getKindName()); - Diag(ClassTemplate->getTemplatedDecl()->getLocation(), + Diag(ClassTemplate->getTemplatedDecl()->getLocation(), diag::note_previous_use); Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); } @@ -2341,15 +2770,15 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // template. TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), TemplateArgs.size()); - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), RAngleLoc, false, Converted)) return true; - assert((Converted.structuredSize() == + assert((Converted.structuredSize() == ClassTemplate->getTemplateParameters()->size()) && "Converted template argument list is too short!"); - + // Find the class template (partial) specialization declaration that // corresponds to these arguments. llvm::FoldingSetNodeID ID; @@ -2363,35 +2792,38 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, if (MirrorsPrimaryTemplate) { // C++ [temp.class.spec]p9b3: // - // -- The argument list of the specialization shall not be identical - // to the implicit argument list of the primary template. + // -- The argument list of the specialization shall not be identical + // to the implicit argument list of the primary template. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) - << (TK == TK_Definition) - << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc, + << (TUK == TUK_Definition) + << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); - return ActOnClassTemplate(S, TagSpec, TK, KWLoc, SS, + return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), TemplateNameLoc, Attr, - move(TemplateParameterLists), + TemplateParams, AS_none); } + // FIXME: Diagnose friend partial specializations + // FIXME: Template parameter list matters, too - ClassTemplatePartialSpecializationDecl::Profile(ID, + ClassTemplatePartialSpecializationDecl::Profile(ID, Converted.getFlatArguments(), - Converted.flatSize()); - } - else + Converted.flatSize(), + Context); + } else ClassTemplateSpecializationDecl::Profile(ID, Converted.getFlatArguments(), - Converted.flatSize()); + Converted.flatSize(), + Context); void *InsertPos = 0; ClassTemplateSpecializationDecl *PrevDecl = 0; if (isPartialSpecialization) PrevDecl - = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID, + = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID, InsertPos); else PrevDecl @@ -2401,29 +2833,41 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // Check whether we can declare a class template specialization in // the current scope. - if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl, - TemplateNameLoc, - SS.getRange(), - isPartialSpecialization, - /*ExplicitInstantiation=*/false)) + if (TUK != TUK_Friend && + CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, + TemplateNameLoc, isPartialSpecialization, + TSK_ExplicitSpecialization)) return true; - - if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) { + + // The canonical type + QualType CanonType; + if (PrevDecl && + (PrevDecl->getSpecializationKind() == TSK_Undeclared || + TUK == TUK_Friend)) { // Since the only prior class template specialization with these - // arguments was referenced but not declared, reuse that + // arguments was referenced but not declared, or we're only + // referencing this specialization as a friend, reuse that // declaration node as our own, updating its source location to // reflect our new declaration. Specialization = PrevDecl; Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; + CanonType = Context.getTypeDeclType(Specialization); } else if (isPartialSpecialization) { + // Build the canonical type that describes the converted template + // arguments of the class template partial specialization. + CanonType = Context.getTemplateSpecializationType( + TemplateName(ClassTemplate), + Converted.getFlatArguments(), + Converted.flatSize()); + // Create a new class template partial specialization declaration node. - TemplateParameterList *TemplateParams + TemplateParameterList *TemplateParams = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); - ClassTemplatePartialSpecializationDecl *Partial - = ClassTemplatePartialSpecializationDecl::Create(Context, + ClassTemplatePartialSpecializationDecl *Partial + = ClassTemplatePartialSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), TemplateNameLoc, TemplateParams, @@ -2445,7 +2889,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // will never be used. llvm::SmallVector<bool, 8> DeducibleParams; DeducibleParams.resize(TemplateParams->size()); - MarkDeducedTemplateParameters(Partial->getTemplateArgs(), DeducibleParams); + MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + DeducibleParams); unsigned NumNonDeducible = 0; for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) if (!DeducibleParams[I]) @@ -2459,25 +2904,24 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, if (!DeducibleParams[I]) { NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); if (Param->getDeclName()) - Diag(Param->getLocation(), + Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) << Param->getDeclName(); else - Diag(Param->getLocation(), + Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) << std::string("<anonymous>"); } } } - } else { // Create a new class template specialization declaration node for - // this explicit specialization. + // this explicit specialization or friend declaration. Specialization - = ClassTemplateSpecializationDecl::Create(Context, + = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), TemplateNameLoc, - ClassTemplate, + ClassTemplate, Converted, PrevDecl); @@ -2485,21 +2929,40 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, ClassTemplate->getSpecializations().RemoveNode(PrevDecl); ClassTemplate->getSpecializations().GetOrInsertNode(Specialization); } else { - ClassTemplate->getSpecializations().InsertNode(Specialization, + ClassTemplate->getSpecializations().InsertNode(Specialization, InsertPos); } + + CanonType = Context.getTypeDeclType(Specialization); } - // Note that this is an explicit specialization. - Specialization->setSpecializationKind(TSK_ExplicitSpecialization); + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that specialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Context.getTypeDeclType(Specialization) << Range; + + Diag(PrevDecl->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (PrevDecl->getTemplateSpecializationKind() + != TSK_ImplicitInstantiation); + return true; + } + + // If this is not a friend, note that this is an explicit specialization. + if (TUK != TUK_Friend) + Specialization->setSpecializationKind(TSK_ExplicitSpecialization); // Check that this isn't a redefinition of this specialization. - if (TK == TK_Definition) { + if (TUK == TUK_Definition) { if (RecordDecl *Def = Specialization->getDefinition(Context)) { - // FIXME: Should also handle explicit specialization after implicit - // instantiation with a special diagnostic. SourceRange Range(TemplateNameLoc, RAngleLoc); - Diag(TemplateNameLoc, diag::err_redefinition) + Diag(TemplateNameLoc, diag::err_redefinition) << Context.getTypeDeclType(Specialization) << Range; Diag(Def->getLocation(), diag::note_previous_definition); Specialization->setInvalidDecl(); @@ -2514,12 +2977,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // actually wrote the specialization, rather than formatting the // name based on the "canonical" representation used to store the // template arguments in the specialization. - QualType WrittenTy - = Context.getTemplateSpecializationType(Name, + QualType WrittenTy + = Context.getTemplateSpecializationType(Name, TemplateArgs.data(), TemplateArgs.size(), - Context.getTypeDeclType(Specialization)); - Specialization->setTypeAsWritten(WrittenTy); + CanonType); + if (TUK != TUK_Friend) + Specialization->setTypeAsWritten(WrittenTy); TemplateArgsIn.release(); // C++ [temp.expl.spec]p9: @@ -2531,56 +2995,343 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // but we also maintain the lexical context where the actual // definition occurs. Specialization->setLexicalDeclContext(CurContext); - + // We may be starting the definition of this specialization. - if (TK == TK_Definition) + if (TUK == TUK_Definition) Specialization->startDefinition(); - // Add the specialization into its lexical context, so that it can - // be seen when iterating through the list of declarations in that - // context. However, specializations are not found by name lookup. - CurContext->addDecl(Specialization); + if (TUK == TUK_Friend) { + FriendDecl *Friend = FriendDecl::Create(Context, CurContext, + TemplateNameLoc, + WrittenTy.getTypePtr(), + /*FIXME:*/KWLoc); + Friend->setAccess(AS_public); + CurContext->addDecl(Friend); + } else { + // Add the specialization into its lexical context, so that it can + // be seen when iterating through the list of declarations in that + // context. However, specializations are not found by name lookup. + CurContext->addDecl(Specialization); + } return DeclPtrTy::make(Specialization); } -Sema::DeclPtrTy -Sema::ActOnTemplateDeclarator(Scope *S, +Sema::DeclPtrTy +Sema::ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D) { return HandleDeclarator(S, D, move(TemplateParameterLists), false); } -Sema::DeclPtrTy -Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, +Sema::DeclPtrTy +Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, MultiTemplateParamsArg TemplateParameterLists, Declarator &D) { assert(getCurFunctionDecl() == 0 && "Function parsing confused"); assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && "Not a function declarator!"); DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; - + if (FTI.hasPrototype) { - // FIXME: Diagnose arguments without names in C. + // FIXME: Diagnose arguments without names in C. } - + Scope *ParentScope = FnBodyScope->getParent(); - - DeclPtrTy DP = HandleDeclarator(ParentScope, D, + + DeclPtrTy DP = HandleDeclarator(ParentScope, D, move(TemplateParameterLists), /*IsFunctionDefinition=*/true); - FunctionTemplateDecl *FunctionTemplate - = cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>()); - if (FunctionTemplate) - return ActOnStartOfFunctionDef(FnBodyScope, + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>())) + return ActOnStartOfFunctionDef(FnBodyScope, DeclPtrTy::make(FunctionTemplate->getTemplatedDecl())); - + if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(DP.getAs<Decl>())) + return ActOnStartOfFunctionDef(FnBodyScope, DeclPtrTy::make(Function)); return DeclPtrTy(); } +/// \brief Perform semantic analysis for the given function template +/// specialization. +/// +/// 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. +/// +/// \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 RAngleLoc the location of the right angle bracket ('>'), if +/// template arguments were explicitly provided. +/// +/// \param PrevDecl the set of declarations that +bool +Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + NamedDecl *&PrevDecl) { + // The set of function template specializations that could match this + // explicit function template specialization. + typedef llvm::SmallVector<FunctionDecl *, 8> CandidateSet; + CandidateSet Candidates; + + DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); + for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) { + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl)) { + // Only consider templates found within the same semantic lookup scope as + // FD. + if (!FDLookupContext->Equals(Ovl->getDeclContext()->getLookupContext())) + continue; + + // C++ [temp.expl.spec]p11: + // A trailing template-argument can be left unspecified in the + // template-id naming an explicit function template specialization + // provided it can be deduced from the function argument type. + // Perform template argument deduction to determine whether we may be + // specializing this template. + // FIXME: It is somewhat wasteful to build + TemplateDeductionInfo Info(Context); + FunctionDecl *Specialization = 0; + if (TemplateDeductionResult TDK + = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + FD->getType(), + Specialization, + Info)) { + // FIXME: Template argument deduction failed; record why it failed, so + // that we can provide nifty diagnostics. + (void)TDK; + continue; + } + + // Record this candidate. + Candidates.push_back(Specialization); + } + } + + // Find the most specialized function template. + FunctionDecl *Specialization = getMostSpecialized(Candidates.data(), + Candidates.size(), + TPOC_Other, + FD->getLocation(), + PartialDiagnostic(diag::err_function_template_spec_no_match) + << FD->getDeclName(), + PartialDiagnostic(diag::err_function_template_spec_ambiguous) + << FD->getDeclName() << HasExplicitTemplateArgs, + PartialDiagnostic(diag::note_function_template_spec_matched)); + if (!Specialization) + return true; + + // FIXME: Check if the prior specialization has a point of instantiation. + // If so, we have run afoul of . + + // Check the scope of this explicit specialization. + if (CheckTemplateSpecializationScope(*this, + Specialization->getPrimaryTemplate(), + Specialization, FD->getLocation(), + false, TSK_ExplicitSpecialization)) + return true; + + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that spe- cialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + FunctionTemplateSpecializationInfo *SpecInfo + = Specialization->getTemplateSpecializationInfo(); + assert(SpecInfo && "Function template specialization info missing?"); + if (SpecInfo->getPointOfInstantiation().isValid()) { + Diag(FD->getLocation(), diag::err_specialization_after_instantiation) + << FD; + Diag(SpecInfo->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (Specialization->getTemplateSpecializationKind() + != TSK_ImplicitInstantiation); + return true; + } + + // Mark the prior declaration as an explicit specialization, so that later + // clients know that this is an explicit specialization. + SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + + // Turn the given function declaration into a function template + // specialization, with the template arguments from the previous + // specialization. + FD->setFunctionTemplateSpecialization(Context, + Specialization->getPrimaryTemplate(), + new (Context) TemplateArgumentList( + *Specialization->getTemplateSpecializationArgs()), + /*InsertPos=*/0, + TSK_ExplicitSpecialization); + + // The "previous declaration" for this function template specialization is + // the prior function template specialization. + PrevDecl = Specialization; + return false; +} + +/// \brief Perform semantic analysis for the given non-template member +/// specialization. +/// +/// This routine performs all of the semantic analysis required for an +/// explicit member function specialization. On successful completion, +/// the function declaration \p FD will become a member function +/// specialization. +/// +/// \param Member the member declaration, which will be updated to become a +/// specialization. +/// +/// \param PrevDecl the set of declarations, one of which may be specialized +/// by this function specialization. +bool +Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { + assert(!isa<TemplateDecl>(Member) && "Only for non-template members"); + + // Try to find the member we are instantiating. + NamedDecl *Instantiation = 0; + NamedDecl *InstantiatedFrom = 0; + MemberSpecializationInfo *MSInfo = 0; + + if (!PrevDecl) { + // Nowhere to look anyway. + } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) { + for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) { + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) { + if (Context.hasSameType(Function->getType(), Method->getType())) { + Instantiation = Method; + InstantiatedFrom = Method->getInstantiatedFromMemberFunction(); + MSInfo = Method->getMemberSpecializationInfo(); + break; + } + } + } + } else if (isa<VarDecl>(Member)) { + if (VarDecl *PrevVar = dyn_cast<VarDecl>(PrevDecl)) + if (PrevVar->isStaticDataMember()) { + Instantiation = PrevDecl; + InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember(); + MSInfo = PrevVar->getMemberSpecializationInfo(); + } + } else if (isa<RecordDecl>(Member)) { + if (CXXRecordDecl *PrevRecord = dyn_cast<CXXRecordDecl>(PrevDecl)) { + Instantiation = PrevDecl; + InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass(); + MSInfo = PrevRecord->getMemberSpecializationInfo(); + } + } + + if (!Instantiation) { + // There is no previous declaration that matches. Since member + // specializations are always out-of-line, the caller will complain about + // this mismatch later. + return false; + } + + // Make sure that this is a specialization of a member. + if (!InstantiatedFrom) { + Diag(Member->getLocation(), diag::err_spec_member_not_instantiated) + << Member; + Diag(Instantiation->getLocation(), diag::note_specialized_decl); + return true; + } + + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that spe- cialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + assert(MSInfo && "Member specialization info missing?"); + if (MSInfo->getPointOfInstantiation().isValid()) { + Diag(Member->getLocation(), diag::err_specialization_after_instantiation) + << Member; + Diag(MSInfo->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (MSInfo->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); + return true; + } + + // Check the scope of this explicit specialization. + if (CheckTemplateSpecializationScope(*this, + InstantiatedFrom, + Instantiation, Member->getLocation(), + false, TSK_ExplicitSpecialization)) + return true; + + // Note that this is an explicit instantiation of a member. + // the original declaration to note that it is an explicit specialization + // (if it was previously an implicit instantiation). This latter step + // makes bookkeeping easier. + if (isa<FunctionDecl>(Member)) { + FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation); + if (InstantiationFunction->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation) { + InstantiationFunction->setTemplateSpecializationKind( + TSK_ExplicitSpecialization); + InstantiationFunction->setLocation(Member->getLocation()); + } + + cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( + cast<CXXMethodDecl>(InstantiatedFrom), + TSK_ExplicitSpecialization); + } else if (isa<VarDecl>(Member)) { + VarDecl *InstantiationVar = cast<VarDecl>(Instantiation); + if (InstantiationVar->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation) { + InstantiationVar->setTemplateSpecializationKind( + TSK_ExplicitSpecialization); + InstantiationVar->setLocation(Member->getLocation()); + } + + Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member), + cast<VarDecl>(InstantiatedFrom), + TSK_ExplicitSpecialization); + } else { + assert(isa<CXXRecordDecl>(Member) && "Only member classes remain"); + CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation); + if (InstantiationClass->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation) { + InstantiationClass->setTemplateSpecializationKind( + TSK_ExplicitSpecialization); + InstantiationClass->setLocation(Member->getLocation()); + } + + cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass( + cast<CXXRecordDecl>(InstantiatedFrom), + TSK_ExplicitSpecialization); + } + + // Save the caller the trouble of having to figure out which declaration + // this specialization matches. + PrevDecl = Instantiation; + return false; +} + // Explicit instantiation of a class template specialization +// FIXME: Implement extern template semantics Sema::DeclResult -Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, - unsigned TagSpec, +Sema::ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy TemplateD, @@ -2592,7 +3343,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, AttributeList *Attr) { // Find the class template we're specializing TemplateName Name = TemplateD.getAsVal<TemplateName>(); - ClassTemplateDecl *ClassTemplate + ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); // Check that the specialization uses the same tag kind as the @@ -2605,29 +3356,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; } if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, KWLoc, *ClassTemplate->getIdentifier())) { - Diag(KWLoc, diag::err_use_with_wrong_tag) + Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate - << CodeModificationHint::CreateReplacement(KWLoc, + << CodeModificationHint::CreateReplacement(KWLoc, ClassTemplate->getTemplatedDecl()->getKindName()); - Diag(ClassTemplate->getTemplatedDecl()->getLocation(), + Diag(ClassTemplate->getTemplatedDecl()->getLocation(), diag::note_previous_use); Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); } - // C++0x [temp.explicit]p2: - // [...] An explicit instantiation shall appear in an enclosing - // namespace of its template. [...] - // - // This is C++ DR 275. - if (CheckClassTemplateSpecializationScope(ClassTemplate, 0, - TemplateNameLoc, - SS.getRange(), - /*PartialSpecialization=*/false, - /*ExplicitInstantiation=*/true)) - return true; - + TemplateSpecializationKind TSK + = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition + : TSK_ExplicitInstantiationDeclaration; + // Translate the parser's template argument list in our AST format. llvm::SmallVector<TemplateArgument, 16> TemplateArgs; translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); @@ -2636,35 +3379,47 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // template. TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), TemplateArgs.size()); - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), RAngleLoc, false, Converted)) return true; - assert((Converted.structuredSize() == + assert((Converted.structuredSize() == ClassTemplate->getTemplateParameters()->size()) && "Converted template argument list is too short!"); - + // Find the class template specialization declaration that // corresponds to these arguments. llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationDecl::Profile(ID, + ClassTemplateSpecializationDecl::Profile(ID, Converted.getFlatArguments(), - Converted.flatSize()); + Converted.flatSize(), + Context); void *InsertPos = 0; ClassTemplateSpecializationDecl *PrevDecl = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + // C++0x [temp.explicit]p2: + // [...] An explicit instantiation shall appear in an enclosing + // namespace of its template. [...] + // + // This is C++ DR 275. + if (CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, + TemplateNameLoc, false, + TSK)) + return true; + ClassTemplateSpecializationDecl *Specialization = 0; bool SpecializationRequiresInstantiation = true; if (PrevDecl) { - if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) { + if (PrevDecl->getSpecializationKind() + == TSK_ExplicitInstantiationDefinition) { // This particular specialization has already been declared or // instantiated. We cannot explicitly instantiate it. Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate) << Context.getTypeDeclType(PrevDecl); - Diag(PrevDecl->getLocation(), + Diag(PrevDecl->getLocation(), diag::note_previous_explicit_instantiation); return DeclPtrTy::make(PrevDecl); } @@ -2676,10 +3431,10 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // an explicit specialization for that template, the explicit // instantiation has no effect. if (!getLangOptions().CPlusPlus0x) { - Diag(TemplateNameLoc, + Diag(TemplateNameLoc, diag::ext_explicit_instantiation_after_specialization) << Context.getTypeDeclType(PrevDecl); - Diag(PrevDecl->getLocation(), + Diag(PrevDecl->getLocation(), diag::note_previous_template_specialization); } @@ -2689,14 +3444,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // accurate reproduction of the source code; we don't actually // use it for anything, since it is semantically irrelevant. Specialization - = ClassTemplateSpecializationDecl::Create(Context, + = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, Converted, 0); Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); - return DeclPtrTy::make(Specialization); + return DeclPtrTy::make(PrevDecl); } // If we have already (implicitly) instantiated this @@ -2704,25 +3459,37 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation) SpecializationRequiresInstantiation = false; - // Since the only prior class template specialization with these - // arguments was referenced but not declared, reuse that - // declaration node as our own, updating its source location to - // reflect our new declaration. - Specialization = PrevDecl; - Specialization->setLocation(TemplateNameLoc); - PrevDecl = 0; - } else { + if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation || + PrevDecl->getSpecializationKind() == TSK_Undeclared) { + // Since the only prior class template specialization with these + // arguments was referenced but not declared, reuse that + // declaration node as our own, updating its source location to + // reflect our new declaration. + Specialization = PrevDecl; + Specialization->setLocation(TemplateNameLoc); + PrevDecl = 0; + } + } + + if (!Specialization) { // Create a new class template specialization declaration node for // this explicit specialization. Specialization - = ClassTemplateSpecializationDecl::Create(Context, + = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, - Converted, 0); + Converted, PrevDecl); - ClassTemplate->getSpecializations().InsertNode(Specialization, - InsertPos); + if (PrevDecl) { + // Remove the previous declaration from the folding set, since we want + // to introduce a new declaration. + ClassTemplate->getSpecializations().RemoveNode(PrevDecl); + ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + } + + // Insert the new specialization. + ClassTemplate->getSpecializations().InsertNode(Specialization, InsertPos); } // Build the fully-sugared type for this explicit instantiation as @@ -2732,8 +3499,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // the explicit instantiation, rather than formatting the name based // on the "canonical" representation used to store the template // arguments in the specialization. - QualType WrittenTy - = Context.getTemplateSpecializationType(Name, + QualType WrittenTy + = Context.getTemplateSpecializationType(Name, TemplateArgs.data(), TemplateArgs.size(), Context.getTypeDeclType(Specialization)); @@ -2746,6 +3513,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); + Specialization->setPointOfInstantiation(TemplateNameLoc); + // C++ [temp.explicit]p3: // A definition of a class template or class member template // shall be in scope at the point of the explicit instantiation of @@ -2754,17 +3523,20 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // This check comes when we actually try to perform the // instantiation. if (SpecializationRequiresInstantiation) - InstantiateClassTemplateSpecialization(Specialization, true); + InstantiateClassTemplateSpecialization(Specialization, TSK); else // Instantiate the members of this class template specialization. - InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization); + InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization, + TSK); return DeclPtrTy::make(Specialization); } // Explicit instantiation of a member class of a class template. Sema::DeclResult -Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, - unsigned TagSpec, +Sema::ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, @@ -2772,8 +3544,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, AttributeList *Attr) { bool Owned = false; - DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference, - KWLoc, SS, Name, NameLoc, Attr, AS_none, Owned); + bool IsDependent = false; + DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TUK_Reference, + KWLoc, SS, Name, NameLoc, Attr, AS_none, + MultiTemplateParamsArg(*this, 0, 0), + Owned, IsDependent); + assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); + if (!TagD) return true; @@ -2804,7 +3581,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, if (getLangOptions().CPlusPlus0x) { // FIXME: In C++98, we would like to turn these errors into warnings, // dependent on a -Wc++0x flag. - DeclContext *PatternContext + DeclContext *PatternContext = Pattern->getDeclContext()->getEnclosingNamespaceContext(); if (!CurContext->Encloses(PatternContext)) { Diag(TemplateLoc, diag::err_explicit_instantiation_out_of_scope) @@ -2813,17 +3590,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, } } + TemplateSpecializationKind TSK + = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition + : TSK_ExplicitInstantiationDeclaration; + if (!Record->getDefinition(Context)) { // If the class has a definition, instantiate it (and all of its // members, recursively). Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); - if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, + if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, getTemplateInstantiationArgs(Record), - /*ExplicitInstantiation=*/true)) + TSK)) return true; - } else // Instantiate all of the members of class. - InstantiateClassMembers(TemplateLoc, Record, - getTemplateInstantiationArgs(Record)); + } else // Instantiate all of the members of the class. + InstantiateClassMembers(TemplateLoc, Record, + getTemplateInstantiationArgs(Record), TSK); // FIXME: We don't have any representation for explicit instantiations of // member classes. Such a representation is not needed for compilation, but it @@ -2832,10 +3613,221 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, return TagD; } +Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + Declarator &D) { + // Explicit instantiations always require a name. + DeclarationName Name = GetNameForDeclarator(D); + if (!Name) { + if (!D.isInvalidType()) + Diag(D.getDeclSpec().getSourceRange().getBegin(), + diag::err_explicit_instantiation_requires_name) + << D.getDeclSpec().getSourceRange() + << D.getSourceRange(); + + return true; + } + + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + while ((S->getFlags() & Scope::DeclScope) == 0 || + (S->getFlags() & Scope::TemplateParamScope) != 0) + S = S->getParent(); + + // Determine the type of the declaration. + QualType R = GetTypeForDeclarator(D, S, 0); + if (R.isNull()) + return true; + + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { + // Cannot explicitly instantiate a typedef. + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef) + << Name; + return true; + } + + // Determine what kind of explicit instantiation we have. + TemplateSpecializationKind TSK + = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition + : TSK_ExplicitInstantiationDeclaration; + + LookupResult Previous; + LookupParsedName(Previous, S, &D.getCXXScopeSpec(), + Name, LookupOrdinaryName); + + if (!R->isFunctionType()) { + // C++ [temp.explicit]p1: + // A [...] static data member of a class template can be explicitly + // instantiated from the member definition associated with its class + // template. + if (Previous.isAmbiguous()) { + return DiagnoseAmbiguousLookup(Previous, Name, D.getIdentifierLoc(), + D.getSourceRange()); + } + + VarDecl *Prev = dyn_cast_or_null<VarDecl>( + Previous.getAsSingleDecl(Context)); + if (!Prev || !Prev->isStaticDataMember()) { + // We expect to see a data data member here. + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) + << Name; + for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); + P != PEnd; ++P) + Diag((*P)->getLocation(), diag::note_explicit_instantiation_here); + return true; + } + + if (!Prev->getInstantiatedFromStaticDataMember()) { + // FIXME: Check for explicit specialization? + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_data_member_not_instantiated) + << Prev; + Diag(Prev->getLocation(), diag::note_explicit_instantiation_here); + // FIXME: Can we provide a note showing where this was declared? + return true; + } + + // Instantiate static data member. + // FIXME: Check for prior specializations and such. + Prev->setTemplateSpecializationKind(TSK); + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false); + + // FIXME: Create an ExplicitInstantiation node? + return DeclPtrTy(); + } + + // If the declarator is a template-id, translate the parser's template + // argument list into our AST format. + bool HasExplicitTemplateArgs = false; + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + if (D.getKind() == Declarator::DK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getTemplateId(); + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateArgs); + HasExplicitTemplateArgs = true; + TemplateArgsPtr.release(); + } + + // C++ [temp.explicit]p1: + // A [...] function [...] can be explicitly instantiated from its template. + // A member function [...] of a class template can be explicitly + // instantiated from the member definition associated with its class + // template. + llvm::SmallVector<FunctionDecl *, 8> Matches; + for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); + P != PEnd; ++P) { + NamedDecl *Prev = *P; + if (!HasExplicitTemplateArgs) { + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) { + if (Context.hasSameUnqualifiedType(Method->getType(), R)) { + Matches.clear(); + Matches.push_back(Method); + break; + } + } + } + + FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Prev); + if (!FunTmpl) + continue; + + TemplateDeductionInfo Info(Context); + FunctionDecl *Specialization = 0; + if (TemplateDeductionResult TDK + = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs, + TemplateArgs.data(), TemplateArgs.size(), + R, Specialization, Info)) { + // FIXME: Keep track of almost-matches? + (void)TDK; + continue; + } + + Matches.push_back(Specialization); + } + + // Find the most specialized function template specialization. + FunctionDecl *Specialization + = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other, + D.getIdentifierLoc(), + PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name, + PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name, + PartialDiagnostic(diag::note_explicit_instantiation_candidate)); + + if (!Specialization) + return true; + + switch (Specialization->getTemplateSpecializationKind()) { + case TSK_Undeclared: + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_member_function_not_instantiated) + << Specialization + << (Specialization->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization); + Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here); + return true; + + case TSK_ExplicitSpecialization: + // C++ [temp.explicit]p4: + // For a given set of template parameters, if an explicit instantiation + // of a template appears after a declaration of an explicit + // specialization for that template, the explicit instantiation has no + // effect. + break; + + case TSK_ExplicitInstantiationDefinition: + // FIXME: Check that we aren't trying to perform an explicit instantiation + // declaration now. + // Fall through + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + // Instantiate the function, if this is an explicit instantiation + // definition. + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, + false); + + Specialization->setTemplateSpecializationKind(TSK); + break; + } + + // FIXME: Create some kind of ExplicitInstantiationDecl here. + return DeclPtrTy(); +} + +Sema::TypeResult +Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, + const CXXScopeSpec &SS, IdentifierInfo *Name, + SourceLocation TagLoc, SourceLocation NameLoc) { + // This has to hold, because SS is expected to be defined. + assert(Name && "Expected a name in a dependent tag"); + + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (!NNS) + return true; + + QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc)); + if (T.isNull()) + return true; + + TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); + QualType ElabType = Context.getElaboratedType(T, TagKind); + + return ElabType.getAsOpaquePtr(); +} + Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { - NestedNameSpecifier *NNS + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); if (!NNS) return true; @@ -2849,17 +3841,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TypeTy *Ty) { - QualType T = QualType::getFromOpaquePtr(Ty); - NestedNameSpecifier *NNS + QualType T = GetTypeFromParser(Ty); + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - const TemplateSpecializationType *TemplateId - = T->getAsTemplateSpecializationType(); + const TemplateSpecializationType *TemplateId + = T->getAs<TemplateSpecializationType>(); assert(TemplateId && "Expected a template specialization type"); - if (NNS->isDependent()) - return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr(); + if (computeDeclContext(SS, false)) { + // If we can compute a declaration context, then the "typename" + // keyword was superfluous. Just build a QualifiedNameType to keep + // track of the nested-name-specifier. - return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr(); + // FIXME: Note that the QualifiedNameType had the "typename" keyword! + return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr(); + } + + return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr(); } /// \brief Build the type that describes a C++ typename specifier, @@ -2875,6 +3873,12 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, // instantiation, then build a typename type. if (!CurrentInstantiation) return Context.getTypenameType(NNS, &II); + + // The nested-name-specifier refers to the current instantiation, so the + // "typename" keyword itself is superfluous. In C++03, the program is + // actually ill-formed. However, DR 382 (in C++0x CD1) allows such + // extraneous "typename" keywords, and we retroactively apply this DR to + // C++03 code. } DeclContext *Ctx = 0; @@ -2893,20 +3897,17 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, assert(Ctx && "No declaration context?"); DeclarationName Name(&II); - LookupResult Result = LookupQualifiedName(Ctx, Name, LookupOrdinaryName, - false); + LookupResult Result; + LookupQualifiedName(Result, Ctx, Name, LookupOrdinaryName, false); unsigned DiagID = 0; Decl *Referenced = 0; switch (Result.getKind()) { case LookupResult::NotFound: - if (Ctx->isTranslationUnit()) - DiagID = diag::err_typename_nested_not_found_global; - else - DiagID = diag::err_typename_nested_not_found; + DiagID = diag::err_typename_nested_not_found; break; case LookupResult::Found: - if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getAsDecl())) { + 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. @@ -2914,7 +3915,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, } DiagID = diag::err_typename_nested_not_type; - Referenced = Result.getAsDecl(); + Referenced = Result.getFoundDecl(); break; case LookupResult::FoundOverloaded: @@ -2922,21 +3923,207 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, Referenced = *Result.begin(); break; - case LookupResult::AmbiguousBaseSubobjectTypes: - case LookupResult::AmbiguousBaseSubobjects: - case LookupResult::AmbiguousReference: + case LookupResult::Ambiguous: DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range); return QualType(); } // If we get here, it's because name lookup did not find a // type. Emit an appropriate diagnostic and return an error. - if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx)) - Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx; - else - Diag(Range.getEnd(), DiagID) << Range << Name; + Diag(Range.getEnd(), DiagID) << Range << Name << Ctx; if (Referenced) Diag(Referenced->getLocation(), diag::note_typename_refers_here) << Name; return QualType(); } + +namespace { + // See Sema::RebuildTypeInCurrentInstantiation + class VISIBILITY_HIDDEN CurrentInstantiationRebuilder + : public TreeTransform<CurrentInstantiationRebuilder> { + SourceLocation Loc; + DeclarationName Entity; + + public: + CurrentInstantiationRebuilder(Sema &SemaRef, + SourceLocation Loc, + DeclarationName Entity) + : TreeTransform<CurrentInstantiationRebuilder>(SemaRef), + Loc(Loc), Entity(Entity) { } + + /// \brief Determine whether the given type \p T has already been + /// transformed. + /// + /// For the purposes of type reconstruction, 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(); + } + + /// \brief Returns the location of the entity whose type is being + /// rebuilt. + SourceLocation getBaseLocation() { return Loc; } + + /// \brief Returns the name of the entity whose type is being rebuilt. + DeclarationName getBaseEntity() { return Entity; } + + /// \brief Transforms an expression by returning the expression itself + /// (an identity function). + /// + /// FIXME: This is completely unsafe; we will need to actually clone the + /// expressions. + Sema::OwningExprResult TransformExpr(Expr *E) { + return getSema().Owned(E); + } + + /// \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 TransformTypenameType(const TypenameType *T); + }; +} + +QualType +CurrentInstantiationRebuilder::TransformTypenameType(const TypenameType *T) { + NestedNameSpecifier *NNS + = TransformNestedNameSpecifier(T->getQualifier(), + /*FIXME:*/SourceRange(getBaseLocation())); + if (!NNS) + return QualType(); + + // If the nested-name-specifier did not change, and we cannot compute the + // context corresponding to the nested-name-specifier, then this + // typename type will not change; exit early. + CXXScopeSpec SS; + SS.setRange(SourceRange(getBaseLocation())); + SS.setScopeRep(NNS); + if (NNS == T->getQualifier() && getSema().computeDeclContext(SS) == 0) + return QualType(T, 0); + + // Rebuild the typename type, which will probably turn into a + // QualifiedNameType. + if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { + QualType NewTemplateId + = TransformType(QualType(TemplateId, 0)); + if (NewTemplateId.isNull()) + return QualType(); + + if (NNS == T->getQualifier() && + NewTemplateId == QualType(TemplateId, 0)) + return QualType(T, 0); + + return getDerived().RebuildTypenameType(NNS, NewTemplateId); + } + + return getDerived().RebuildTypenameType(NNS, T->getIdentifier()); +} + +/// \brief Rebuilds a type within the context of the current instantiation. +/// +/// The type \p T is part of the type of an out-of-line member definition of +/// a class template (or class template partial specialization) that was parsed +/// and constructed before we entered the scope of the class template (or +/// partial specialization thereof). This routine will rebuild that type now +/// that we have entered the declarator's scope, which may produce different +/// canonical types, e.g., +/// +/// \code +/// template<typename T> +/// struct X { +/// typedef T* pointer; +/// pointer data(); +/// }; +/// +/// template<typename T> +/// typename X<T>::pointer X<T>::data() { ... } +/// \endcode +/// +/// Here, the type "typename X<T>::pointer" will be created as a TypenameType, +/// 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 +/// as the canonical type of T*, allowing the return types of the out-of-line +/// definition and the declaration to match. +QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, + DeclarationName Name) { + if (T.isNull() || !T->isDependentType()) + return T; + + CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name); + return Rebuilder.TransformType(T); +} + +/// \brief Produces a formatted string that describes the binding of +/// template parameters to template arguments. +std::string +Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgumentList &Args) { + std::string Result; + + if (!Params || Params->size() == 0) + return Result; + + for (unsigned I = 0, N = Params->size(); I != N; ++I) { + if (I == 0) + Result += "[with "; + else + Result += ", "; + + if (const IdentifierInfo *Id = Params->getParam(I)->getIdentifier()) { + Result += Id->getName(); + } else { + Result += '$'; + Result += llvm::utostr(I); + } + + Result += " = "; + + switch (Args[I].getKind()) { + case TemplateArgument::Null: + Result += "<no value>"; + break; + + case TemplateArgument::Type: { + std::string TypeStr; + Args[I].getAsType().getAsStringInternal(TypeStr, + Context.PrintingPolicy); + Result += TypeStr; + break; + } + + case TemplateArgument::Declaration: { + bool Unnamed = true; + if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Args[I].getAsDecl())) { + if (ND->getDeclName()) { + Unnamed = false; + Result += ND->getNameAsString(); + } + } + + if (Unnamed) { + Result += "<anonymous>"; + } + break; + } + + case TemplateArgument::Integral: { + Result += Args[I].getAsIntegral()->toString(10); + break; + } + + case TemplateArgument::Expression: { + assert(false && "No expressions in deduced template arguments!"); + Result += "<expression>"; + break; + } + + case TemplateArgument::Pack: + // FIXME: Format template argument packs + Result += "<template argument pack>"; + break; + } + } + + Result += ']'; + return Result; +} diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h new file mode 100644 index 0000000000000..2bfb25a3d1048 --- /dev/null +++ b/lib/Sema/SemaTemplate.h @@ -0,0 +1,104 @@ +//===------- SemaTemplate.h - C++ Templates ---------------------*- C++ -*-===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file provides types used in the semantic analysis of C++ templates. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TEMPLATE_H +#define LLVM_CLANG_SEMA_TEMPLATE_H + +#include "clang/AST/DeclTemplate.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> + +namespace clang { + /// \brief Data structure that captures multiple levels of template argument + /// lists for use in template instantiation. + /// + /// Multiple levels of template arguments occur when instantiating the + /// definitions of member templates. For example: + /// + /// \code + /// template<typename T> + /// struct X { + /// template<T Value> + /// struct Y { + /// void f(); + /// }; + /// }; + /// \endcode + /// + /// When instantiating X<int>::Y<17>::f, the multi-level template argument + /// list will contain a template argument list (int) at depth 0 and a + /// template argument list (17) at depth 1. + struct MultiLevelTemplateArgumentList { + /// \brief The template argument lists, stored from the innermost template + /// argument list (first) to the outermost template argument list (last). + llvm::SmallVector<const TemplateArgumentList *, 4> TemplateArgumentLists; + + public: + /// \brief Construct an empty set of template argument lists. + MultiLevelTemplateArgumentList() { } + + /// \brief Construct a single-level template argument list. + explicit + MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { + TemplateArgumentLists.push_back(&TemplateArgs); + } + + /// \brief Determine the number of levels in this template argument + /// list. + unsigned getNumLevels() const { return TemplateArgumentLists.size(); } + + /// \brief Retrieve the template argument at a given depth and index. + const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { + assert(Depth < TemplateArgumentLists.size()); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1]->size()); + return TemplateArgumentLists[getNumLevels() - Depth - 1]->get(Index); + } + + /// \brief Determine whether there is a non-NULL template argument at the + /// given depth and index. + /// + /// There must exist a template argument list at the given depth. + bool hasTemplateArgument(unsigned Depth, unsigned Index) const { + assert(Depth < TemplateArgumentLists.size()); + + if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1]->size()) + return false; + + return !(*this)(Depth, Index).isNull(); + } + + /// \brief Add a new outermost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { + TemplateArgumentLists.push_back(TemplateArgs); + } + + /// \brief Retrieve the innermost template argument list. + const TemplateArgumentList &getInnermost() const { + return *TemplateArgumentLists.front(); + } + }; + + /// \brief The context in which partial ordering of function templates occurs. + enum TemplatePartialOrderingContext { + /// \brief Partial ordering of function templates for a function call. + TPOC_Call, + /// \brief Partial ordering of function templates for a call to a + /// conversion function. + TPOC_Conversion, + /// \brief Partial ordering of function templates in other contexts, e.g., + /// taking the address of a function template or matching a function + /// template specialization to a function template. + TPOC_Other + }; +} + +#endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 5a0578f6bcb70..b981389d1d15b 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/Parse/DeclSpec.h" #include "llvm/Support/Compiler.h" +#include <algorithm> namespace clang { /// \brief Various flags that control template argument deduction. @@ -38,14 +39,18 @@ namespace clang { /// \brief Within template argument deduction from a function call, /// we are matching in a case where we can perform template argument /// deduction from a template-id of a derived class of the argument type. - TDF_DerivedClass = 0x04 + TDF_DerivedClass = 0x04, + /// \brief Allow non-dependent types to differ, e.g., when performing + /// template argument deduction from a function call where conversions + /// may apply. + TDF_SkipNonDependent = 0x08 }; } using namespace clang; static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(ASTContext &Context, TemplateParameterList *TemplateParams, const TemplateArgument &Param, const TemplateArgument &Arg, @@ -58,27 +63,27 @@ DeduceTemplateArguments(ASTContext &Context, static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E)) E = IC->getSubExpr(); - + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()); - + return 0; } -/// \brief Deduce the value of the given non-type template parameter +/// \brief Deduce the value of the given non-type template parameter /// from the given constant. static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(ASTContext &Context, - NonTypeTemplateParmDecl *NTTP, +DeduceNonTypeTemplateArgument(ASTContext &Context, + NonTypeTemplateParmDecl *NTTP, llvm::APSInt Value, Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - assert(NTTP->getDepth() == 0 && + assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); - + if (Deduced[NTTP->getIndex()].isNull()) { QualType T = NTTP->getType(); - + // FIXME: Make sure we didn't overflow our data type! unsigned AllowedBits = Context.getTypeSize(T); if (Value.getBitWidth() != AllowedBits) @@ -88,10 +93,10 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), Value, T); return Sema::TDK_Success; } - + assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral); - - // If the template argument was previously deduced to a negative value, + + // If the template argument was previously deduced to a negative value, // then our deduction fails. const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral(); if (PrevValuePtr->isNegative()) { @@ -117,36 +122,47 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, return Sema::TDK_Success; } -/// \brief Deduce the value of the given non-type template parameter +/// \brief Deduce the value of the given non-type template parameter /// from the given type- or value-dependent expression. /// /// \returns true if deduction succeeded, false otherwise. static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(ASTContext &Context, +DeduceNonTypeTemplateArgument(ASTContext &Context, NonTypeTemplateParmDecl *NTTP, Expr *Value, Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - assert(NTTP->getDepth() == 0 && + assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); assert((Value->isTypeDependent() || Value->isValueDependent()) && "Expression template argument must be type- or value-dependent."); - + if (Deduced[NTTP->getIndex()].isNull()) { // FIXME: Clone the Value? Deduced[NTTP->getIndex()] = TemplateArgument(Value); return Sema::TDK_Success; } - + if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) { - // Okay, we deduced a constant in one case and a dependent expression - // in another case. FIXME: Later, we will check that instantiating the + // Okay, we deduced a constant in one case and a dependent expression + // in another case. FIXME: Later, we will check that instantiating the // dependent expression gives us the constant value. return Sema::TDK_Success; } - - // FIXME: Compare the expressions for equality! + + if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) { + // Compare the expressions for equality + llvm::FoldingSetNodeID ID1, ID2; + Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, Context, true); + Value->Profile(ID2, Context, true); + if (ID1 == ID2) + return Sema::TDK_Success; + + // FIXME: Fill in argument mismatch information + return Sema::TDK_NonDeducedMismatch; + } + return Sema::TDK_Success; } @@ -164,14 +180,14 @@ DeduceTemplateArguments(ASTContext &Context, TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); TemplateDecl *ArgDecl = Arg.getAsTemplateDecl(); - + if (!ParamDecl || !ArgDecl) { // FIXME: fill in Info.Param/Info.FirstArg return Sema::TDK_Inconsistent; } - ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl)); - ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl)); + ParamDecl = cast<TemplateDecl>(ParamDecl->getCanonicalDecl()); + ArgDecl = cast<TemplateDecl>(ArgDecl->getCanonicalDecl()); if (ParamDecl != ArgDecl) { // FIXME: fill in Info.Param/Info.FirstArg return Sema::TDK_Inconsistent; @@ -180,6 +196,161 @@ DeduceTemplateArguments(ASTContext &Context, return Sema::TDK_Success; } +/// \brief Deduce the template arguments by comparing the template parameter +/// type (which is a template-id) with the template argument type. +/// +/// \param Context the AST context in which this deduction occurs. +/// +/// \param TemplateParams the template parameters that we are deducing +/// +/// \param Param the parameter type +/// +/// \param Arg the argument type +/// +/// \param Info information about the template argument deduction itself +/// +/// \param Deduced the deduced template arguments +/// +/// \returns the result of template argument deduction so far. Note that a +/// "success" result means that template argument deduction has not yet failed, +/// but it may still fail, later, for other reasons. +static Sema::TemplateDeductionResult +DeduceTemplateArguments(ASTContext &Context, + TemplateParameterList *TemplateParams, + const TemplateSpecializationType *Param, + QualType Arg, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(Arg->isCanonical() && "Argument type must be canonical"); + + // Check whether the template argument is a dependent template-id. + // FIXME: This is untested code; it can be tested when we implement + // partial ordering of class template partial specializations. + if (const TemplateSpecializationType *SpecArg + = dyn_cast<TemplateSpecializationType>(Arg)) { + // Perform template argument deduction for the template name. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, + Param->getTemplateName(), + SpecArg->getTemplateName(), + Info, Deduced)) + return Result; + + unsigned NumArgs = Param->getNumArgs(); + + // FIXME: When one of the template-names refers to a + // declaration with default template arguments, do we need to + // fill in those default template arguments here? Most likely, + // the answer is "yes", but I don't see any references. This + // issue may be resolved elsewhere, because we may want to + // instantiate default template arguments when we actually write + // the template-id. + if (SpecArg->getNumArgs() != NumArgs) + return Sema::TDK_NonDeducedMismatch; + + // Perform template argument deduction on each template + // argument. + for (unsigned I = 0; I != NumArgs; ++I) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + Param->getArg(I), + SpecArg->getArg(I), + Info, Deduced)) + return Result; + + return Sema::TDK_Success; + } + + // If the argument type is a class template specialization, we + // perform template argument deduction using its template + // arguments. + const RecordType *RecordArg = dyn_cast<RecordType>(Arg); + if (!RecordArg) + return Sema::TDK_NonDeducedMismatch; + + ClassTemplateSpecializationDecl *SpecArg + = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl()); + if (!SpecArg) + return Sema::TDK_NonDeducedMismatch; + + // Perform template argument deduction for the template name. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, + Param->getTemplateName(), + TemplateName(SpecArg->getSpecializedTemplate()), + Info, Deduced)) + return Result; + + // FIXME: Can the # of arguments in the parameter and the argument + // differ due to default arguments? + unsigned NumArgs = Param->getNumArgs(); + const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs(); + if (NumArgs != ArgArgs.size()) + return Sema::TDK_NonDeducedMismatch; + + for (unsigned I = 0; I != NumArgs; ++I) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + Param->getArg(I), + ArgArgs.get(I), + Info, Deduced)) + return Result; + + return Sema::TDK_Success; +} + +/// \brief Returns a completely-unqualified array type, capturing the +/// qualifiers in Quals. +/// +/// \param Context the AST context in which the array type was built. +/// +/// \param T a canonical type that may be an array type. +/// +/// \param Quals will receive the full set of qualifiers that were +/// applied to the element type of the array. +/// +/// \returns if \p T is an array type, the completely unqualified array type +/// that corresponds to T. Otherwise, returns T. +static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T, + Qualifiers &Quals) { + assert(T->isCanonical() && "Only operates on canonical types"); + if (!isa<ArrayType>(T)) { + Quals = T.getQualifiers(); + return T.getUnqualifiedType(); + } + + assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); + + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) { + QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(), + Quals); + if (Elt == CAT->getElementType()) + return T; + + return Context.getConstantArrayType(Elt, CAT->getSize(), + CAT->getSizeModifier(), 0); + } + + if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) { + QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(), + Quals); + if (Elt == IAT->getElementType()) + return T; + + return Context.getIncompleteArrayType(Elt, IAT->getSizeModifier(), 0); + } + + const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T); + QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(), + Quals); + if (Elt == DSAT->getElementType()) + return T; + + return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr()->Retain(), + DSAT->getSizeModifier(), 0, + SourceRange()); +} + /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -196,13 +367,13 @@ DeduceTemplateArguments(ASTContext &Context, /// \param Deduced the deduced template arguments /// /// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe -/// how template argument deduction is performed. +/// how template argument deduction is performed. /// /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(ASTContext &Context, TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, Sema::TemplateDeductionInfo &Info, @@ -215,28 +386,47 @@ DeduceTemplateArguments(ASTContext &Context, // C++0x [temp.deduct.call]p4 bullet 1: // - If the original P is a reference type, the deduced A (i.e., the type - // referred to by the reference) can be more cv-qualified than the + // referred to by the reference) can be more cv-qualified than the // transformed A. if (TDF & TDF_ParamWithReferenceType) { - unsigned ExtraQualsOnParam - = Param.getCVRQualifiers() & ~Arg.getCVRQualifiers(); - Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam); + Qualifiers Quals = Param.getQualifiers(); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiers()); + Param = Context.getQualifiedType(Param.getUnqualifiedType(), Quals); } - + // If the parameter type is not dependent, there is nothing to deduce. - if (!Param->isDependentType()) + if (!Param->isDependentType()) { + if (!(TDF & TDF_SkipNonDependent) && Param != Arg) { + + return Sema::TDK_NonDeducedMismatch; + } + return Sema::TDK_Success; + } // C++ [temp.deduct.type]p9: - // A template type argument T, a template template argument TT or a - // template non-type argument i can be deduced if P and A have one of + // A template type argument T, a template template argument TT or a + // template non-type argument i can be deduced if P and A have one of // the following forms: // // T // cv-list T - if (const TemplateTypeParmType *TemplateTypeParm - = Param->getAsTemplateTypeParmType()) { + if (const TemplateTypeParmType *TemplateTypeParm + = Param->getAs<TemplateTypeParmType>()) { unsigned Index = TemplateTypeParm->getIndex(); + bool RecanonicalizeArg = false; + + // If the argument type is an array type, move the qualifiers up to the + // top level, so they can be matched with the qualifiers on the parameter. + // FIXME: address spaces, ObjC GC qualifiers + if (isa<ArrayType>(Arg)) { + Qualifiers Quals; + Arg = getUnqualifiedArrayType(Context, Arg, Quals); + if (Quals) { + Arg = Context.getQualifiedType(Arg, Quals); + RecanonicalizeArg = true; + } + } // The argument type can not be less qualified than the parameter // type. @@ -248,21 +438,23 @@ DeduceTemplateArguments(ASTContext &Context, } assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); - - unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers(); - QualType DeducedType = Arg.getQualifiedType(Quals); + + QualType DeducedType = Arg; + DeducedType.removeCVRQualifiers(Param.getCVRQualifiers()); + if (RecanonicalizeArg) + DeducedType = Context.getCanonicalType(DeducedType); if (Deduced[Index].isNull()) Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType); else { - // C++ [temp.deduct.type]p2: + // C++ [temp.deduct.type]p2: // [...] If type deduction cannot be done for any P/A pair, or if for - // any pair the deduction leads to more than one possible set of - // deduced values, or if different pairs yield different deduced - // values, or if any template argument remains neither deduced nor + // any pair the deduction leads to more than one possible set of + // deduced values, or if different pairs yield different deduced + // values, or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. if (Deduced[Index].getAsType() != DeducedType) { - Info.Param + Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; Info.SecondArg = TemplateArgument(SourceLocation(), Arg); @@ -283,7 +475,7 @@ DeduceTemplateArguments(ASTContext &Context, return Sema::TDK_NonDeducedMismatch; } else { if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) - return Sema::TDK_NonDeducedMismatch; + return Sema::TDK_NonDeducedMismatch; } } @@ -291,26 +483,26 @@ DeduceTemplateArguments(ASTContext &Context, // No deduction possible for these types case Type::Builtin: return Sema::TDK_NonDeducedMismatch; - + // T * case Type::Pointer: { - const PointerType *PointerArg = Arg->getAsPointerType(); + const PointerType *PointerArg = Arg->getAs<PointerType>(); if (!PointerArg) return Sema::TDK_NonDeducedMismatch; - + unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); return DeduceTemplateArguments(Context, TemplateParams, cast<PointerType>(Param)->getPointeeType(), PointerArg->getPointeeType(), Info, Deduced, SubTDF); } - + // T & case Type::LValueReference: { - const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType(); + const LValueReferenceType *ReferenceArg = Arg->getAs<LValueReferenceType>(); if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - + return DeduceTemplateArguments(Context, TemplateParams, cast<LValueReferenceType>(Param)->getPointeeType(), ReferenceArg->getPointeeType(), @@ -319,23 +511,23 @@ DeduceTemplateArguments(ASTContext &Context, // T && [C++0x] case Type::RValueReference: { - const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType(); + const RValueReferenceType *ReferenceArg = Arg->getAs<RValueReferenceType>(); if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - + return DeduceTemplateArguments(Context, TemplateParams, cast<RValueReferenceType>(Param)->getPointeeType(), ReferenceArg->getPointeeType(), Info, Deduced, 0); } - + // T [] (implied, but not stated explicitly) case Type::IncompleteArray: { - const IncompleteArrayType *IncompleteArrayArg = + const IncompleteArrayType *IncompleteArrayArg = Context.getAsIncompleteArrayType(Arg); if (!IncompleteArrayArg) return Sema::TDK_NonDeducedMismatch; - + return DeduceTemplateArguments(Context, TemplateParams, Context.getAsIncompleteArrayType(Param)->getElementType(), IncompleteArrayArg->getElementType(), @@ -344,16 +536,16 @@ DeduceTemplateArguments(ASTContext &Context, // T [integer-constant] case Type::ConstantArray: { - const ConstantArrayType *ConstantArrayArg = + const ConstantArrayType *ConstantArrayArg = Context.getAsConstantArrayType(Arg); if (!ConstantArrayArg) return Sema::TDK_NonDeducedMismatch; - - const ConstantArrayType *ConstantArrayParm = + + const ConstantArrayType *ConstantArrayParm = Context.getAsConstantArrayType(Param); if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) return Sema::TDK_NonDeducedMismatch; - + return DeduceTemplateArguments(Context, TemplateParams, ConstantArrayParm->getElementType(), ConstantArrayArg->getElementType(), @@ -365,7 +557,7 @@ DeduceTemplateArguments(ASTContext &Context, const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg); if (!ArrayArg) return Sema::TDK_NonDeducedMismatch; - + // Check the element type of the arrays const DependentSizedArrayType *DependentArrayParm = cast<DependentSizedArrayType>(Param); @@ -375,18 +567,18 @@ DeduceTemplateArguments(ASTContext &Context, ArrayArg->getElementType(), Info, Deduced, 0)) return Result; - + // Determine the array bound is something we can deduce. - NonTypeTemplateParmDecl *NTTP + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; - - // We can perform template argument deduction for the given non-type + + // We can perform template argument deduction for the given non-type // template parameter. - assert(NTTP->getDepth() == 0 && + assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument at depth > 0"); - if (const ConstantArrayType *ConstantArrayArg + if (const ConstantArrayType *ConstantArrayArg = dyn_cast<ConstantArrayType>(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); return DeduceNonTypeTemplateArgument(Context, NTTP, Size, @@ -397,30 +589,30 @@ DeduceTemplateArguments(ASTContext &Context, return DeduceNonTypeTemplateArgument(Context, NTTP, DependentArrayArg->getSizeExpr(), Info, Deduced); - + // Incomplete type does not match a dependently-sized array type return Sema::TDK_NonDeducedMismatch; } - - // type(*)(T) - // T(*)() - // T(*)(T) + + // type(*)(T) + // T(*)() + // T(*)(T) case Type::FunctionProto: { - const FunctionProtoType *FunctionProtoArg = + const FunctionProtoType *FunctionProtoArg = dyn_cast<FunctionProtoType>(Arg); if (!FunctionProtoArg) return Sema::TDK_NonDeducedMismatch; - - const FunctionProtoType *FunctionProtoParam = + + const FunctionProtoType *FunctionProtoParam = cast<FunctionProtoType>(Param); - if (FunctionProtoParam->getTypeQuals() != + if (FunctionProtoParam->getTypeQuals() != FunctionProtoArg->getTypeQuals()) return Sema::TDK_NonDeducedMismatch; - + if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs()) return Sema::TDK_NonDeducedMismatch; - + if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) return Sema::TDK_NonDeducedMismatch; @@ -431,7 +623,7 @@ DeduceTemplateArguments(ASTContext &Context, FunctionProtoArg->getResultType(), Info, Deduced, 0)) return Result; - + for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) { // Check argument types. if (Sema::TemplateDeductionResult Result @@ -441,10 +633,10 @@ DeduceTemplateArguments(ASTContext &Context, Info, Deduced, 0)) return Result; } - + return Sema::TDK_Success; } - + // template-name<T> (where template-name refers to a class template) // template-name<i> // TT<T> (TODO) @@ -454,83 +646,69 @@ DeduceTemplateArguments(ASTContext &Context, const TemplateSpecializationType *SpecParam = cast<TemplateSpecializationType>(Param); - // Check whether the template argument is a dependent template-id. - // FIXME: This is untested code; it can be tested when we implement - // partial ordering of class template partial specializations. - if (const TemplateSpecializationType *SpecArg - = dyn_cast<TemplateSpecializationType>(Arg)) { - // Perform template argument deduction for the template name. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, - SpecParam->getTemplateName(), - SpecArg->getTemplateName(), - Info, Deduced)) - return Result; - - unsigned NumArgs = SpecParam->getNumArgs(); - - // FIXME: When one of the template-names refers to a - // declaration with default template arguments, do we need to - // fill in those default template arguments here? Most likely, - // the answer is "yes", but I don't see any references. This - // issue may be resolved elsewhere, because we may want to - // instantiate default template arguments when - if (SpecArg->getNumArgs() != NumArgs) - return Sema::TDK_NonDeducedMismatch; - - // Perform template argument deduction on each template - // argument. - for (unsigned I = 0; I != NumArgs; ++I) - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, - SpecParam->getArg(I), - SpecArg->getArg(I), - Info, Deduced)) - return Result; - - return Sema::TDK_Success; - } - - // If the argument type is a class template specialization, we - // perform template argument deduction using its template - // arguments. - const RecordType *RecordArg = dyn_cast<RecordType>(Arg); - if (!RecordArg) - return Sema::TDK_NonDeducedMismatch; - - // FIXME: Check TDF_DerivedClass here. When this flag is set, we need - // to troll through the base classes of the argument and try matching - // all of them. Failure to match does not mean that there is a problem, - // of course. - - ClassTemplateSpecializationDecl *SpecArg - = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl()); - if (!SpecArg) - return Sema::TDK_NonDeducedMismatch; - - // Perform template argument deduction for the template name. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, - SpecParam->getTemplateName(), - TemplateName(SpecArg->getSpecializedTemplate()), - Info, Deduced)) - return Result; + // Try to deduce template arguments from the template-id. + Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, SpecParam, Arg, + Info, Deduced); + + if (Result && (TDF & TDF_DerivedClass)) { + // C++ [temp.deduct.call]p3b3: + // If P is a class, and P has the form template-id, then A can be a + // derived class of the deduced A. Likewise, if P is a pointer to a + // class of the form template-id, A can be a pointer to a derived + // class pointed to by the deduced A. + // + // More importantly: + // These alternatives are considered only if type deduction would + // otherwise fail. + if (const RecordType *RecordT = dyn_cast<RecordType>(Arg)) { + // Use data recursion to crawl through the list of base classes. + // Visited contains the set of nodes we have already visited, while + // ToVisit is our stack of records that we still need to visit. + llvm::SmallPtrSet<const RecordType *, 8> Visited; + llvm::SmallVector<const RecordType *, 8> ToVisit; + ToVisit.push_back(RecordT); + bool Successful = false; + while (!ToVisit.empty()) { + // Retrieve the next class in the inheritance hierarchy. + const RecordType *NextT = ToVisit.back(); + ToVisit.pop_back(); + + // If we have already seen this type, skip it. + if (!Visited.insert(NextT)) + continue; + + // If this is a base class, try to perform template argument + // deduction from it. + if (NextT != RecordT) { + Sema::TemplateDeductionResult BaseResult + = DeduceTemplateArguments(Context, TemplateParams, SpecParam, + QualType(NextT, 0), Info, Deduced); + + // If template argument deduction for this base was successful, + // note that we had some success. + if (BaseResult == Sema::TDK_Success) + Successful = true; + } + + // Visit base classes + CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl()); + for (CXXRecordDecl::base_class_iterator Base = Next->bases_begin(), + BaseEnd = Next->bases_end(); + Base != BaseEnd; ++Base) { + assert(Base->getType()->isRecordType() && + "Base class that isn't a record?"); + ToVisit.push_back(Base->getType()->getAs<RecordType>()); + } + } + + if (Successful) + return Sema::TDK_Success; + } - // FIXME: Can the # of arguments in the parameter and the argument differ? - unsigned NumArgs = SpecParam->getNumArgs(); - const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs(); - if (NumArgs != ArgArgs.size()) - return Sema::TDK_NonDeducedMismatch; + } - for (unsigned I = 0; I != NumArgs; ++I) - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, - SpecParam->getArg(I), - ArgArgs.get(I), - Info, Deduced)) - return Result; - - return Sema::TDK_Success; + return Result; } // T type::* @@ -564,16 +742,16 @@ DeduceTemplateArguments(ASTContext &Context, // (clang extension) // - // type(^)(T) - // T(^)() - // T(^)(T) + // type(^)(T) + // T(^)() + // T(^)(T) case Type::BlockPointer: { const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param); const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg); - + if (!BlockPtrArg) return Sema::TDK_NonDeducedMismatch; - + return DeduceTemplateArguments(Context, TemplateParams, BlockPtrParam->getPointeeType(), BlockPtrArg->getPointeeType(), Info, @@ -595,7 +773,7 @@ DeduceTemplateArguments(ASTContext &Context, } static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(ASTContext &Context, TemplateParameterList *TemplateParams, const TemplateArgument &Param, const TemplateArgument &Arg, @@ -605,8 +783,8 @@ DeduceTemplateArguments(ASTContext &Context, case TemplateArgument::Null: assert(false && "Null template argument in parameter list"); break; - - case TemplateArgument::Type: + + case TemplateArgument::Type: assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch"); return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(), Arg.getAsType(), Info, Deduced, 0); @@ -617,7 +795,7 @@ DeduceTemplateArguments(ASTContext &Context, Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; - + case TemplateArgument::Integral: if (Arg.getKind() == TemplateArgument::Integral) { // FIXME: Zero extension + sign checking here? @@ -639,25 +817,25 @@ DeduceTemplateArguments(ASTContext &Context, Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; - + case TemplateArgument::Expression: { - if (NonTypeTemplateParmDecl *NTTP + if (NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Param.getAsExpr())) { if (Arg.getKind() == TemplateArgument::Integral) // FIXME: Sign problems here - return DeduceNonTypeTemplateArgument(Context, NTTP, - *Arg.getAsIntegral(), + return DeduceNonTypeTemplateArgument(Context, NTTP, + *Arg.getAsIntegral(), Info, Deduced); if (Arg.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(), Info, Deduced); - + assert(false && "Type/value mismatch"); Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; } - + // Can't deduce anything, but that's okay. return Sema::TDK_Success; } @@ -665,11 +843,11 @@ DeduceTemplateArguments(ASTContext &Context, assert(0 && "FIXME: Implement!"); break; } - + return Sema::TDK_Success; } -static Sema::TemplateDeductionResult +static Sema::TemplateDeductionResult DeduceTemplateArguments(ASTContext &Context, TemplateParameterList *TemplateParams, const TemplateArgumentList &ParamList, @@ -680,7 +858,7 @@ DeduceTemplateArguments(ASTContext &Context, for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(Context, TemplateParams, - ParamList[I], ArgList[I], + ParamList[I], ArgList[I], Info, Deduced)) return Result; } @@ -688,41 +866,41 @@ DeduceTemplateArguments(ASTContext &Context, } /// \brief Determine whether two template arguments are the same. -static bool isSameTemplateArg(ASTContext &Context, +static bool isSameTemplateArg(ASTContext &Context, const TemplateArgument &X, const TemplateArgument &Y) { if (X.getKind() != Y.getKind()) return false; - + switch (X.getKind()) { case TemplateArgument::Null: assert(false && "Comparing NULL template argument"); break; - + case TemplateArgument::Type: return Context.getCanonicalType(X.getAsType()) == Context.getCanonicalType(Y.getAsType()); - + case TemplateArgument::Declaration: - return Context.getCanonicalDecl(X.getAsDecl()) == - Context.getCanonicalDecl(Y.getAsDecl()); - + return X.getAsDecl()->getCanonicalDecl() == + Y.getAsDecl()->getCanonicalDecl(); + case TemplateArgument::Integral: return *X.getAsIntegral() == *Y.getAsIntegral(); - + case TemplateArgument::Expression: // FIXME: We assume that all expressions are distinct, but we should // really check their canonical forms. return false; - + case TemplateArgument::Pack: if (X.pack_size() != Y.pack_size()) return false; - - for (TemplateArgument::pack_iterator XP = X.pack_begin(), - XPEnd = X.pack_end(), + + for (TemplateArgument::pack_iterator XP = X.pack_begin(), + XPEnd = X.pack_end(), YP = Y.pack_begin(); - XP != XPEnd; ++XP, ++YP) + XP != XPEnd; ++XP, ++YP) if (!isSameTemplateArg(Context, *XP, *YP)) return false; @@ -739,7 +917,7 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(TTP); else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) return TemplateParameter(NTTP); - + return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); } @@ -759,9 +937,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, llvm::SmallVector<TemplateArgument, 4> Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(Context, + = ::DeduceTemplateArguments(Context, Partial->getTemplateParameters(), - Partial->getTemplateArgs(), + Partial->getTemplateArgs(), TemplateArgs, Info, Deduced)) return Result; @@ -777,11 +955,12 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Deduced.size()); for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { if (Deduced[I].isNull()) { - Decl *Param - = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I)); + Decl *Param + = const_cast<NamedDecl *>( + Partial->getTemplateParameters()->getParam(I)); if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) Info.Param = TTP; - else if (NonTypeTemplateParmDecl *NTTP + else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) Info.Param = NTTP; else @@ -793,7 +972,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, } // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList + TemplateArgumentList *DeducedArgumentList = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); Info.reset(DeducedArgumentList); @@ -801,44 +980,45 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // arguments of the class template partial specialization, and // verify that the instantiated template arguments are both valid // and are equivalent to the template arguments originally provided - // to the class template. + // to the class template. ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs(); for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) { - Decl *Param = const_cast<Decl *>( + Decl *Param = const_cast<NamedDecl *>( ClassTemplate->getTemplateParameters()->getParam(I)); - TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I], - *DeducedArgumentList); + TemplateArgument InstArg + = Subst(PartialTemplateArgs[I], + MultiLevelTemplateArgumentList(*DeducedArgumentList)); if (InstArg.isNull()) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = PartialTemplateArgs[I]; - return TDK_SubstitutionFailure; + return TDK_SubstitutionFailure; } - + if (InstArg.getKind() == TemplateArgument::Expression) { - // When the argument is an expression, check the expression result + // When the argument is an expression, check the expression result // against the actual template parameter to get down to the canonical // template argument. Expr *InstExpr = InstArg.getAsExpr(); - if (NonTypeTemplateParmDecl *NTTP + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = PartialTemplateArgs[I]; - return TDK_SubstitutionFailure; + return TDK_SubstitutionFailure; } - } else if (TemplateTemplateParmDecl *TTP + } else if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) { // FIXME: template template arguments should really resolve to decls DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr); if (!DRE || CheckTemplateArgument(TTP, DRE)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = PartialTemplateArgs[I]; - return TDK_SubstitutionFailure; + return TDK_SubstitutionFailure; } } } - + if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = TemplateArgs[I]; @@ -855,27 +1035,244 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, /// \brief Determine whether the given type T is a simple-template-id type. static bool isSimpleTemplateIdType(QualType T) { - if (const TemplateSpecializationType *Spec - = T->getAsTemplateSpecializationType()) + if (const TemplateSpecializationType *Spec + = T->getAs<TemplateSpecializationType>()) return Spec->getTemplateName().getAsTemplateDecl() != 0; - + return false; } - + +/// \brief Substitute the explicitly-provided template arguments into the +/// given function template according to C++ [temp.arg.explicit]. +/// +/// \param FunctionTemplate the function template into which the explicit +/// template arguments will be substituted. +/// +/// \param ExplicitTemplateArguments the explicitly-specified template +/// arguments. +/// +/// \param NumExplicitTemplateArguments the number of explicitly-specified +/// template arguments in @p ExplicitTemplateArguments. This value may be zero. +/// +/// \param Deduced the deduced template arguments, which will be populated +/// with the converted and checked explicit template arguments. +/// +/// \param ParamTypes will be populated with the instantiated function +/// parameters. +/// +/// \param FunctionType if non-NULL, the result type of the function template +/// will also be instantiated and the pointed-to value will be updated with +/// the instantiated function type. +/// +/// \param Info if substitution fails for any reason, this object will be +/// populated with more information about the failure. +/// +/// \returns TDK_Success if substitution was successful, or some failure +/// condition. +Sema::TemplateDeductionResult +Sema::SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<QualType> &ParamTypes, + QualType *FunctionType, + TemplateDeductionInfo &Info) { + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + + if (NumExplicitTemplateArgs == 0) { + // No arguments to substitute; just copy over the parameter types and + // fill in the function type. + for (FunctionDecl::param_iterator P = Function->param_begin(), + PEnd = Function->param_end(); + P != PEnd; + ++P) + ParamTypes.push_back((*P)->getType()); + + if (FunctionType) + *FunctionType = Function->getType(); + return TDK_Success; + } + + // Substitution of the explicit template arguments into a function template + /// is a SFINAE context. Trap any errors that might occur. + SFINAETrap Trap(*this); + + // C++ [temp.arg.explicit]p3: + // Template arguments that are present shall be specified in the + // declaration order of their corresponding template-parameters. The + // template argument list shall not specify more template-arguments than + // there are corresponding template-parameters. + TemplateArgumentListBuilder Builder(TemplateParams, + NumExplicitTemplateArgs); + + // Enter a new template instantiation context where we check the + // explicitly-specified template arguments against this function template, + // and then substitute them into the function parameter types. + InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution); + if (Inst) + return TDK_InstantiationDepth; + + if (CheckTemplateArgumentList(FunctionTemplate, + SourceLocation(), SourceLocation(), + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + SourceLocation(), + true, + Builder) || Trap.hasErrorOccurred()) + return TDK_InvalidExplicitArguments; + + // Form the template argument list from the explicitly-specified + // template arguments. + TemplateArgumentList *ExplicitArgumentList + = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + Info.reset(ExplicitArgumentList); + + // Instantiate the types of each of the function parameters given the + // explicitly-specified template arguments. + for (FunctionDecl::param_iterator P = Function->param_begin(), + PEnd = Function->param_end(); + P != PEnd; + ++P) { + QualType ParamType + = SubstType((*P)->getType(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + (*P)->getLocation(), (*P)->getDeclName()); + if (ParamType.isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + + ParamTypes.push_back(ParamType); + } + + // If the caller wants a full function type back, instantiate the return + // type and form that function type. + if (FunctionType) { + // FIXME: exception-specifications? + const FunctionProtoType *Proto + = Function->getType()->getAs<FunctionProtoType>(); + assert(Proto && "Function template does not have a prototype?"); + + QualType ResultType + = SubstType(Proto->getResultType(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + Function->getTypeSpecStartLoc(), + Function->getDeclName()); + if (ResultType.isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + + *FunctionType = BuildFunctionType(ResultType, + ParamTypes.data(), ParamTypes.size(), + Proto->isVariadic(), + Proto->getTypeQuals(), + Function->getLocation(), + Function->getDeclName()); + if (FunctionType->isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + } + + // C++ [temp.arg.explicit]p2: + // Trailing template arguments that can be deduced (14.8.2) may be + // omitted from the list of explicit template-arguments. If all of the + // template arguments can be deduced, they may all be omitted; in this + // case, the empty template argument list <> itself may also be omitted. + // + // Take all of the explicitly-specified arguments and put them into the + // set of deduced template arguments. + Deduced.reserve(TemplateParams->size()); + for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) + Deduced.push_back(ExplicitArgumentList->get(I)); + + return TDK_Success; +} + +/// \brief Finish template argument deduction for a function template, +/// checking the deduced template arguments for completeness and forming +/// the function template specialization. +Sema::TemplateDeductionResult +Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl<TemplateArgument> &Deduced, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info) { + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); + for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { + if (Deduced[I].isNull()) { + Info.Param = makeTemplateParameter( + const_cast<NamedDecl *>(TemplateParams->getParam(I))); + return TDK_Incomplete; + } + + Builder.Append(Deduced[I]); + } + + // Form the template argument list from the deduced template arguments. + TemplateArgumentList *DeducedArgumentList + = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + Info.reset(DeducedArgumentList); + + // Template argument deduction for function templates in a SFINAE context. + // Trap any errors that might occur. + SFINAETrap Trap(*this); + + // Enter a new template instantiation context while we instantiate the + // actual function declaration. + InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + if (Inst) + return TDK_InstantiationDepth; + + // Substitute the deduced template arguments into the function template + // declaration to produce the function template specialization. + Specialization = cast_or_null<FunctionDecl>( + SubstDecl(FunctionTemplate->getTemplatedDecl(), + FunctionTemplate->getDeclContext(), + MultiLevelTemplateArgumentList(*DeducedArgumentList))); + if (!Specialization) + return TDK_SubstitutionFailure; + + assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == + FunctionTemplate->getCanonicalDecl()); + + // If the template argument list is owned by the function template + // specialization, release it. + if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList) + Info.take(); + + // There may have been an error that did not prevent us from constructing a + // declaration. Mark the declaration invalid and return with a substitution + // failure. + if (Trap.hasErrorOccurred()) { + Specialization->setInvalidDecl(true); + return TDK_SubstitutionFailure; + } + + return TDK_Success; +} + /// \brief Perform template argument deduction from a function call /// (C++ [temp.deduct.call]). /// /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param HasExplicitTemplateArgs whether any template arguments were +/// \param HasExplicitTemplateArgs whether any template arguments were /// explicitly specified. /// /// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, /// the explicitly-specified template arguments. /// /// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the number of explicitly-specified template arguments in +/// the number of explicitly-specified template arguments in /// @p ExplicitTemplateArguments. This value may be zero. /// /// \param Args the function call arguments @@ -883,7 +1280,7 @@ static bool isSimpleTemplateIdType(QualType T) { /// \param NumArgs the number of arguments in Args /// /// \param Specialization if template argument deduction was successful, -/// this will be set to the function template specialization produced by +/// this will be set to the function template specialization produced by /// template argument deduction. /// /// \param Info the argument will be updated to provide additional information @@ -908,17 +1305,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, if (NumArgs < Function->getMinRequiredArguments()) return TDK_TooFewArguments; else if (NumArgs > Function->getNumParams()) { - const FunctionProtoType *Proto - = Function->getType()->getAsFunctionProtoType(); + const FunctionProtoType *Proto + = Function->getType()->getAs<FunctionProtoType>(); if (!Proto->isVariadic()) return TDK_TooManyArguments; - + CheckArgs = Function->getNumParams(); } - - // Template argument deduction for function templates in a SFINAE context. - // Trap any errors that might occur. - SFINAETrap Trap(*this); // The types of the parameters from which we will perform template argument // deduction. @@ -927,89 +1320,40 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVector<TemplateArgument, 4> Deduced; llvm::SmallVector<QualType, 4> ParamTypes; if (NumExplicitTemplateArgs) { - // C++ [temp.arg.explicit]p3: - // Template arguments that are present shall be specified in the - // declaration order of their corresponding template-parameters. The - // template argument list shall not specify more template-arguments than - // there are corresponding template-parameters. - TemplateArgumentListBuilder Builder(TemplateParams, - NumExplicitTemplateArgs); - - // Enter a new template instantiation context where we check the - // explicitly-specified template arguments against this function template, - // and then substitute them into the function parameter types. - InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution); - if (Inst) - return TDK_InstantiationDepth; - - if (CheckTemplateArgumentList(FunctionTemplate, - SourceLocation(), SourceLocation(), - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - SourceLocation(), - true, - Builder) || Trap.hasErrorOccurred()) - return TDK_InvalidExplicitArguments; - - // Form the template argument list from the explicitly-specified - // template arguments. - TemplateArgumentList *ExplicitArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); - Info.reset(ExplicitArgumentList); - - // Instantiate the types of each of the function parameters given the - // explicitly-specified template arguments. - for (FunctionDecl::param_iterator P = Function->param_begin(), - PEnd = Function->param_end(); - P != PEnd; - ++P) { - QualType ParamType = InstantiateType((*P)->getType(), - *ExplicitArgumentList, - (*P)->getLocation(), - (*P)->getDeclName()); - if (ParamType.isNull() || Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; - - ParamTypes.push_back(ParamType); - } - - // C++ [temp.arg.explicit]p2: - // Trailing template arguments that can be deduced (14.8.2) may be - // omitted from the list of explicit template- arguments. If all of the - // template arguments can be deduced, they may all be omitted; in this - // case, the empty template argument list <> itself may also be omitted. - // - // Take all of the explicitly-specified arguments and put them into the - // set of deduced template arguments. - Deduced.reserve(TemplateParams->size()); - for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) - Deduced.push_back(ExplicitArgumentList->get(I)); + TemplateDeductionResult Result = + SubstituteExplicitTemplateArguments(FunctionTemplate, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + Deduced, + ParamTypes, + 0, + Info); + if (Result) + return Result; } else { // Just fill in the parameter types from the function declaration. for (unsigned I = 0; I != CheckArgs; ++I) ParamTypes.push_back(Function->getParamDecl(I)->getType()); } - + // Deduce template arguments from the function parameters. - Deduced.resize(TemplateParams->size()); + Deduced.resize(TemplateParams->size()); for (unsigned I = 0; I != CheckArgs; ++I) { QualType ParamType = ParamTypes[I]; QualType ArgType = Args[I]->getType(); - + // C++ [temp.deduct.call]p2: // If P is not a reference type: QualType CanonParamType = Context.getCanonicalType(ParamType); bool ParamWasReference = isa<ReferenceType>(CanonParamType); if (!ParamWasReference) { - // - If A is an array type, the pointer type produced by the - // array-to-pointer standard conversion (4.2) is used in place of + // - If A is an array type, the pointer type produced by the + // array-to-pointer standard conversion (4.2) is used in place of // A for type deduction; otherwise, if (ArgType->isArrayType()) ArgType = Context.getArrayDecayedType(ArgType); - // - If A is a function type, the pointer type produced by the - // function-to-pointer standard conversion (4.3) is used in place + // - If A is a function type, the pointer type produced by the + // function-to-pointer standard conversion (4.3) is used in place // of A for type deduction; otherwise, else if (ArgType->isFunctionType()) ArgType = Context.getPointerType(ArgType); @@ -1021,252 +1365,884 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, ArgType = CanonArgType.getUnqualifiedType(); } } - + // C++0x [temp.deduct.call]p3: // If P is a cv-qualified type, the top level cv-qualifiers of P’s type - // are ignored for type deduction. + // are ignored for type deduction. if (CanonParamType.getCVRQualifiers()) ParamType = CanonParamType.getUnqualifiedType(); - if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) { - // [...] If P is a reference type, the type referred to by P is used - // for type deduction. + if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) { + // [...] If P is a reference type, the type referred to by P is used + // for type deduction. ParamType = ParamRefType->getPointeeType(); - - // [...] If P is of the form T&&, where T is a template parameter, and - // the argument is an lvalue, the type A& is used in place of A for + + // [...] If P is of the form T&&, where T is a template parameter, and + // the argument is an lvalue, the type A& is used in place of A for // type deduction. if (isa<RValueReferenceType>(ParamRefType) && - ParamRefType->getAsTemplateTypeParmType() && + ParamRefType->getAs<TemplateTypeParmType>() && Args[I]->isLvalue(Context) == Expr::LV_Valid) ArgType = Context.getLValueReferenceType(ArgType); } - + // C++0x [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument // values that will make the deduced A identical to A (after the type A // is transformed as described above). [...] - unsigned TDF = 0; - + unsigned TDF = TDF_SkipNonDependent; + // - If the original P is a reference type, the deduced A (i.e., the // type referred to by the reference) can be more cv-qualified than // the transformed A. if (ParamWasReference) TDF |= TDF_ParamWithReferenceType; - // - The transformed A can be another pointer or pointer to member - // type that can be converted to the deduced A via a qualification + // - The transformed A can be another pointer or pointer to member + // type that can be converted to the deduced A via a qualification // conversion (4.4). if (ArgType->isPointerType() || ArgType->isMemberPointerType()) TDF |= TDF_IgnoreQualifiers; - // - If P is a class and P has the form simple-template-id, then the + // - If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. Likewise, // if P is a pointer to a class of the form simple-template-id, the // transformed A can be a pointer to a derived class pointed to by // the deduced A. if (isSimpleTemplateIdType(ParamType) || - (isa<PointerType>(ParamType) && + (isa<PointerType>(ParamType) && isSimpleTemplateIdType( - ParamType->getAsPointerType()->getPointeeType()))) + ParamType->getAs<PointerType>()->getPointeeType()))) TDF |= TDF_DerivedClass; - + if (TemplateDeductionResult Result = ::DeduceTemplateArguments(Context, TemplateParams, ParamType, ArgType, Info, Deduced, TDF)) return Result; + + // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function + // pointer parameters. + + // FIXME: we need to check that the deduced A is the same as A, + // modulo the various allowed differences. + } + + return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + Specialization, Info); +} + +/// \brief Deduce template arguments when taking the address of a function +/// template (C++ [temp.deduct.funcaddr]) or matching a +/// +/// \param FunctionTemplate the function template for which we are performing +/// template argument deduction. +/// +/// \param HasExplicitTemplateArgs whether any template arguments were +/// explicitly specified. +/// +/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, +/// the explicitly-specified template arguments. +/// +/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, +/// the number of explicitly-specified template arguments in +/// @p ExplicitTemplateArguments. This value may be zero. +/// +/// \param ArgFunctionType the function type that will be used as the +/// "argument" type (A) when performing template argument deduction from the +/// function template's function type. +/// +/// \param Specialization if template argument deduction was successful, +/// this will be set to the function template specialization produced by +/// template argument deduction. +/// +/// \param Info the argument will be updated to provide additional information +/// about template argument deduction. +/// +/// \returns the result of template argument deduction. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + QualType ArgFunctionType, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info) { + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + QualType FunctionType = Function->getType(); + + // Substitute any explicit template arguments. + llvm::SmallVector<TemplateArgument, 4> Deduced; + llvm::SmallVector<QualType, 4> ParamTypes; + if (HasExplicitTemplateArgs) { + if (TemplateDeductionResult Result + = SubstituteExplicitTemplateArguments(FunctionTemplate, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + Deduced, ParamTypes, + &FunctionType, Info)) + return Result; + } + + // Template argument deduction for function templates in a SFINAE context. + // Trap any errors that might occur. + SFINAETrap Trap(*this); + + // Deduce template arguments from the function type. + Deduced.resize(TemplateParams->size()); + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(Context, TemplateParams, + FunctionType, ArgFunctionType, Info, + Deduced, 0)) + return Result; + + return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + Specialization, Info); +} + +/// \brief Deduce template arguments for a templated conversion +/// function (C++ [temp.deduct.conv]) and, if successful, produce a +/// conversion function template specialization. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + QualType ToType, + CXXConversionDecl *&Specialization, + TemplateDeductionInfo &Info) { + CXXConversionDecl *Conv + = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()); + QualType FromType = Conv->getConversionType(); + + // Canonicalize the types for deduction. + QualType P = Context.getCanonicalType(FromType); + QualType A = Context.getCanonicalType(ToType); + + // C++0x [temp.deduct.conv]p3: + // If P is a reference type, the type referred to by P is used for + // type deduction. + if (const ReferenceType *PRef = P->getAs<ReferenceType>()) + P = PRef->getPointeeType(); + + // C++0x [temp.deduct.conv]p3: + // If A is a reference type, the type referred to by A is used + // for type deduction. + if (const ReferenceType *ARef = A->getAs<ReferenceType>()) + A = ARef->getPointeeType(); + // C++ [temp.deduct.conv]p2: + // + // If A is not a reference type: + else { + assert(!A->isReferenceType() && "Reference types were handled above"); + + // - If P is an array type, the pointer type produced by the + // array-to-pointer standard conversion (4.2) is used in place + // of P for type deduction; otherwise, + if (P->isArrayType()) + P = Context.getArrayDecayedType(P); + // - If P is a function type, the pointer type produced by the + // function-to-pointer standard conversion (4.3) is used in + // place of P for type deduction; otherwise, + else if (P->isFunctionType()) + P = Context.getPointerType(P); + // - If P is a cv-qualified type, the top level cv-qualifiers of + // P’s type are ignored for type deduction. + else + P = P.getUnqualifiedType(); + + // C++0x [temp.deduct.conv]p3: + // If A is a cv-qualified type, the top level cv-qualifiers of A’s + // type are ignored for type deduction. + A = A.getUnqualifiedType(); + } + + // Template argument deduction for function templates in a SFINAE context. + // Trap any errors that might occur. + SFINAETrap Trap(*this); + + // C++ [temp.deduct.conv]p1: + // Template argument deduction is done by comparing the return + // type of the template conversion function (call it P) with the + // type that is required as the result of the conversion (call it + // A) as described in 14.8.2.4. + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + llvm::SmallVector<TemplateArgument, 4> Deduced; + Deduced.resize(TemplateParams->size()); + + // C++0x [temp.deduct.conv]p4: + // In general, the deduction process attempts to find template + // argument values that will make the deduced A identical to + // A. However, there are two cases that allow a difference: + unsigned TDF = 0; + // - If the original A is a reference type, A can be more + // cv-qualified than the deduced A (i.e., the type referred to + // by the reference) + if (ToType->isReferenceType()) + TDF |= TDF_ParamWithReferenceType; + // - The deduced A can be another pointer or pointer to member + // type that can be converted to A via a qualification + // conversion. + // + // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when + // both P and A are pointers or member pointers. In this case, we + // just ignore cv-qualifiers completely). + if ((P->isPointerType() && A->isPointerType()) || + (P->isMemberPointerType() && P->isMemberPointerType())) + TDF |= TDF_IgnoreQualifiers; + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(Context, TemplateParams, + P, A, Info, Deduced, TDF)) + return Result; + + // FIXME: we need to check that the deduced A is the same as A, + // modulo the various allowed differences. + + // Finish template argument deduction. + FunctionDecl *Spec = 0; + TemplateDeductionResult Result + = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info); + Specialization = cast_or_null<CXXConversionDecl>(Spec); + return Result; +} + +/// \brief Stores the result of comparing the qualifiers of two types. +enum DeductionQualifierComparison { + NeitherMoreQualified = 0, + ParamMoreQualified, + ArgMoreQualified +}; + +/// \brief Deduce the template arguments during partial ordering by comparing +/// the parameter type and the argument type (C++0x [temp.deduct.partial]). +/// +/// \param Context the AST context in which this deduction occurs. +/// +/// \param TemplateParams the template parameters that we are deducing +/// +/// \param ParamIn the parameter type +/// +/// \param ArgIn the argument type +/// +/// \param Info information about the template argument deduction itself +/// +/// \param Deduced the deduced template arguments +/// +/// \returns the result of template argument deduction so far. Note that a +/// "success" result means that template argument deduction has not yet failed, +/// but it may still fail, later, for other reasons. +static Sema::TemplateDeductionResult +DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context, + TemplateParameterList *TemplateParams, + QualType ParamIn, QualType ArgIn, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) { + CanQualType Param = Context.getCanonicalType(ParamIn); + CanQualType Arg = Context.getCanonicalType(ArgIn); + + // C++0x [temp.deduct.partial]p5: + // Before the partial ordering is done, certain transformations are + // performed on the types used for partial ordering: + // - If P is a reference type, P is replaced by the type referred to. + CanQual<ReferenceType> ParamRef = Param->getAs<ReferenceType>(); + if (ParamRef) + Param = ParamRef->getPointeeType(); + + // - If A is a reference type, A is replaced by the type referred to. + CanQual<ReferenceType> ArgRef = Arg->getAs<ReferenceType>(); + if (ArgRef) + Arg = ArgRef->getPointeeType(); + + if (QualifierComparisons && ParamRef && ArgRef) { + // C++0x [temp.deduct.partial]p6: + // If both P and A were reference types (before being replaced with the + // type referred to above), determine which of the two types (if any) is + // more cv-qualified than the other; otherwise the types are considered to + // be equally cv-qualified for partial ordering purposes. The result of this + // determination will be used below. + // + // We save this information for later, using it only when deduction + // succeeds in both directions. + DeductionQualifierComparison QualifierResult = NeitherMoreQualified; + if (Param.isMoreQualifiedThan(Arg)) + QualifierResult = ParamMoreQualified; + else if (Arg.isMoreQualifiedThan(Param)) + QualifierResult = ArgMoreQualified; + QualifierComparisons->push_back(QualifierResult); + } + + // C++0x [temp.deduct.partial]p7: + // Remove any top-level cv-qualifiers: + // - If P is a cv-qualified type, P is replaced by the cv-unqualified + // version of P. + Param = Param.getUnqualifiedType(); + // - If A is a cv-qualified type, A is replaced by the cv-unqualified + // version of A. + Arg = Arg.getUnqualifiedType(); + + // C++0x [temp.deduct.partial]p8: + // Using the resulting types P and A the deduction is then done as + // described in 14.9.2.5. If deduction succeeds for a given type, the type + // from the argument template is considered to be at least as specialized + // as the type from the parameter template. + return DeduceTemplateArguments(Context, TemplateParams, Param, Arg, Info, + Deduced, TDF_None); +} + +static void +MarkUsedTemplateParameters(Sema &SemaRef, QualType T, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Deduced); + +/// \brief Determine whether the function template \p FT1 is at least as +/// specialized as \p FT2. +static bool isAtLeastAsSpecializedAs(Sema &S, + FunctionTemplateDecl *FT1, + FunctionTemplateDecl *FT2, + TemplatePartialOrderingContext TPOC, + llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) { + FunctionDecl *FD1 = FT1->getTemplatedDecl(); + FunctionDecl *FD2 = FT2->getTemplatedDecl(); + const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *Proto2 = FD2->getType()->getAs<FunctionProtoType>(); + + assert(Proto1 && Proto2 && "Function templates must have prototypes"); + TemplateParameterList *TemplateParams = FT2->getTemplateParameters(); + llvm::SmallVector<TemplateArgument, 4> Deduced; + Deduced.resize(TemplateParams->size()); + + // C++0x [temp.deduct.partial]p3: + // The types used to determine the ordering depend on the context in which + // the partial ordering is done: + Sema::TemplateDeductionInfo Info(S.Context); + switch (TPOC) { + case TPOC_Call: { + // - In the context of a function call, the function parameter types are + // used. + unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs()); + for (unsigned I = 0; I != NumParams; ++I) + if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context, + TemplateParams, + Proto2->getArgType(I), + Proto1->getArgType(I), + Info, + Deduced, + QualifierComparisons)) + return false; + + break; + } + + case TPOC_Conversion: + // - In the context of a call to a conversion operator, the return types + // of the conversion function templates are used. + if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context, + TemplateParams, + Proto2->getResultType(), + Proto1->getResultType(), + Info, + Deduced, + QualifierComparisons)) + return false; + break; - // FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function - // pointer parameters. + case TPOC_Other: + // - In other contexts (14.6.6.2) the function template’s function type + // is used. + if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context, + TemplateParams, + FD2->getType(), + FD1->getType(), + Info, + Deduced, + QualifierComparisons)) + return false; + break; } - // C++ [temp.deduct.type]p2: - // [...] or if any template argument remains neither deduced nor - // explicitly specified, template argument deduction fails. - TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); - for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { - if (Deduced[I].isNull()) { - Decl *Param - = const_cast<Decl *>(TemplateParams->getParam(I)); - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) - Info.Param = TTP; - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Param)) - Info.Param = NTTP; - else - Info.Param = cast<TemplateTemplateParmDecl>(Param); - return TDK_Incomplete; - } + // C++0x [temp.deduct.partial]p11: + // In most cases, all template parameters must have values in order for + // deduction to succeed, but for partial ordering purposes a template + // parameter may remain without a value provided it is not used in the + // types being used for partial ordering. [ Note: a template parameter used + // in a non-deduced context is considered used. -end note] + unsigned ArgIdx = 0, NumArgs = Deduced.size(); + for (; ArgIdx != NumArgs; ++ArgIdx) + if (Deduced[ArgIdx].isNull()) + break; + + if (ArgIdx == NumArgs) { + // All template arguments were deduced. FT1 is at least as specialized + // as FT2. + return true; + } + + // Figure out which template parameters were used. + llvm::SmallVector<bool, 4> UsedParameters; + UsedParameters.resize(TemplateParams->size()); + switch (TPOC) { + case TPOC_Call: { + unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs()); + for (unsigned I = 0; I != NumParams; ++I) + ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, + UsedParameters); + break; + } - Builder.Append(Deduced[I]); + case TPOC_Conversion: + ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, + UsedParameters); + break; + + case TPOC_Other: + ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters); + break; } - // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); - Info.reset(DeducedArgumentList); + for (; ArgIdx != NumArgs; ++ArgIdx) + // If this argument had no value deduced but was used in one of the types + // used for partial ordering, then deduction fails. + if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx]) + return false; - // Enter a new template instantiation context while we instantiate the - // actual function declaration. - InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); - if (Inst) - return TDK_InstantiationDepth; - - // Substitute the deduced template arguments into the function template - // declaration to produce the function template specialization. - Specialization = cast_or_null<FunctionDecl>( - InstantiateDecl(FunctionTemplate->getTemplatedDecl(), - FunctionTemplate->getDeclContext(), - *DeducedArgumentList)); - if (!Specialization) - return TDK_SubstitutionFailure; + return true; +} + + +/// \brief Returns the more specialized function template according +/// to the rules of function template partial ordering (C++ [temp.func.order]). +/// +/// \param FT1 the first function template +/// +/// \param FT2 the second function template +/// +/// \param TPOC the context in which we are performing partial ordering of +/// function templates. +/// +/// \returns the more specialized function template. If neither +/// template is more specialized, returns NULL. +FunctionTemplateDecl * +Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, + FunctionTemplateDecl *FT2, + TemplatePartialOrderingContext TPOC) { + llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons; + bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0); + bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC, + &QualifierComparisons); - // If the template argument list is owned by the function template - // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList) - Info.take(); + if (Better1 != Better2) // We have a clear winner + return Better1? FT1 : FT2; + + if (!Better1 && !Better2) // Neither is better than the other + return 0; + + + // C++0x [temp.deduct.partial]p10: + // If for each type being considered a given template is at least as + // specialized for all types and more specialized for some set of types and + // the other template is not more specialized for any types or is not at + // least as specialized for any types, then the given template is more + // specialized than the other template. Otherwise, neither template is more + // specialized than the other. + Better1 = false; + Better2 = false; + for (unsigned I = 0, N = QualifierComparisons.size(); I != N; ++I) { + // C++0x [temp.deduct.partial]p9: + // If, for a given type, deduction succeeds in both directions (i.e., the + // types are identical after the transformations above) and if the type + // from the argument template is more cv-qualified than the type from the + // parameter template (as described above) that type is considered to be + // more specialized than the other. If neither type is more cv-qualified + // than the other then neither type is more specialized than the other. + switch (QualifierComparisons[I]) { + case NeitherMoreQualified: + break; + + case ParamMoreQualified: + Better1 = true; + if (Better2) + return 0; + break; + + case ArgMoreQualified: + Better2 = true; + if (Better1) + return 0; + break; + } + } + + assert(!(Better1 && Better2) && "Should have broken out in the loop above"); + if (Better1) + return FT1; + else if (Better2) + return FT2; + else + return 0; +} - // There may have been an error that did not prevent us from constructing a - // declaration. Mark the declaration invalid and return with a substitution - // failure. - if (Trap.hasErrorOccurred()) { - Specialization->setInvalidDecl(true); - return TDK_SubstitutionFailure; +/// \brief Determine if the two templates are equivalent. +static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { + if (T1 == T2) + return true; + + if (!T1 || !T2) + return false; + + return T1->getCanonicalDecl() == T2->getCanonicalDecl(); +} + +/// \brief Retrieve the most specialized of the given function template +/// specializations. +/// +/// \param Specializations the set of function template specializations that +/// we will be comparing. +/// +/// \param NumSpecializations the number of function template specializations in +/// \p Specializations +/// +/// \param TPOC the partial ordering context to use to compare the function +/// template specializations. +/// +/// \param Loc the location where the ambiguity or no-specializations +/// diagnostic should occur. +/// +/// \param NoneDiag partial diagnostic used to diagnose cases where there are +/// no matching candidates. +/// +/// \param AmbigDiag partial diagnostic used to diagnose an ambiguity, if one +/// occurs. +/// +/// \param CandidateDiag partial diagnostic used for each function template +/// specialization that is a candidate in the ambiguous ordering. One parameter +/// in this diagnostic should be unbound, which will correspond to the string +/// describing the template arguments for the function template specialization. +/// +/// \param Index if non-NULL and the result of this function is non-nULL, +/// receives the index corresponding to the resulting function template +/// specialization. +/// +/// \returns the most specialized function template specialization, if +/// found. Otherwise, returns NULL. +/// +/// \todo FIXME: Consider passing in the "also-ran" candidates that failed +/// template argument deduction. +FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, + unsigned NumSpecializations, + TemplatePartialOrderingContext TPOC, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag, + unsigned *Index) { + if (NumSpecializations == 0) { + Diag(Loc, NoneDiag); + return 0; } - return TDK_Success; + if (NumSpecializations == 1) { + if (Index) + *Index = 0; + + return Specializations[0]; + } + + + // Find the function template that is better than all of the templates it + // has been compared to. + unsigned Best = 0; + FunctionTemplateDecl *BestTemplate + = Specializations[Best]->getPrimaryTemplate(); + assert(BestTemplate && "Not a function template specialization?"); + for (unsigned I = 1; I != NumSpecializations; ++I) { + FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate(); + assert(Challenger && "Not a function template specialization?"); + if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, + TPOC), + Challenger)) { + Best = I; + BestTemplate = Challenger; + } + } + + // Make sure that the "best" function template is more specialized than all + // of the others. + bool Ambiguous = false; + for (unsigned I = 0; I != NumSpecializations; ++I) { + FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate(); + if (I != Best && + !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, + TPOC), + BestTemplate)) { + Ambiguous = true; + break; + } + } + + if (!Ambiguous) { + // We found an answer. Return it. + if (Index) + *Index = Best; + return Specializations[Best]; + } + + // Diagnose the ambiguity. + Diag(Loc, AmbigDiag); + + // FIXME: Can we order the candidates in some sane way? + for (unsigned I = 0; I != NumSpecializations; ++I) + Diag(Specializations[I]->getLocation(), CandidateDiag) + << getTemplateArgumentBindingsText( + Specializations[I]->getPrimaryTemplate()->getTemplateParameters(), + *Specializations[I]->getTemplateSpecializationArgs()); + + return 0; +} + +/// \brief Returns the more specialized class template partial specialization +/// according to the rules of partial ordering of class template partial +/// specializations (C++ [temp.class.order]). +/// +/// \param PS1 the first class template partial specialization +/// +/// \param PS2 the second class template partial specialization +/// +/// \returns the more specialized class template partial specialization. If +/// neither partial specialization is more specialized, returns NULL. +ClassTemplatePartialSpecializationDecl * +Sema::getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2) { + // C++ [temp.class.order]p1: + // For two class template partial specializations, the first is at least as + // specialized as the second if, given the following rewrite to two + // function templates, the first function template is at least as + // specialized as the second according to the ordering rules for function + // templates (14.6.6.2): + // - the first function template has the same template parameters as the + // first partial specialization and has a single function parameter + // whose type is a class template specialization with the template + // arguments of the first partial specialization, and + // - the second function template has the same template parameters as the + // second partial specialization and has a single function parameter + // whose type is a class template specialization with the template + // arguments of the second partial specialization. + // + // Rather than synthesize function templates, we merely perform the + // equivalent partial ordering by performing deduction directly on the + // template arguments of the class template partial specializations. This + // computation is slightly simpler than the general problem of function + // template partial ordering, because class template partial specializations + // are more constrained. We know that every template parameter is deduc + llvm::SmallVector<TemplateArgument, 4> Deduced; + Sema::TemplateDeductionInfo Info(Context); + + // Determine whether PS1 is at least as specialized as PS2 + Deduced.resize(PS2->getTemplateParameters()->size()); + bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(Context, + PS2->getTemplateParameters(), + Context.getTypeDeclType(PS2), + Context.getTypeDeclType(PS1), + Info, + Deduced, + 0); + + // Determine whether PS2 is at least as specialized as PS1 + Deduced.resize(PS1->getTemplateParameters()->size()); + bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context, + PS1->getTemplateParameters(), + Context.getTypeDeclType(PS1), + Context.getTypeDeclType(PS2), + Info, + Deduced, + 0); + + if (Better1 == Better2) + return 0; + + return Better1? PS1 : PS2; } -static void -MarkDeducedTemplateParameters(Sema &SemaRef, - const TemplateArgument &TemplateArg, - llvm::SmallVectorImpl<bool> &Deduced); +static void +MarkUsedTemplateParameters(Sema &SemaRef, + const TemplateArgument &TemplateArg, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used); -/// \brief Mark the template arguments that are deduced by the given +/// \brief Mark the template parameters that are used by the given /// expression. -static void -MarkDeducedTemplateParameters(const Expr *E, - llvm::SmallVectorImpl<bool> &Deduced) { +static void +MarkUsedTemplateParameters(Sema &SemaRef, + const Expr *E, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used) { + // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to + // find other occurrences of template parameters. const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); if (!E) return; - const NonTypeTemplateParmDecl *NTTP + const NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()); if (!NTTP) return; - Deduced[NTTP->getIndex()] = true; + Used[NTTP->getIndex()] = true; +} + +/// \brief Mark the template parameters that are used by the given +/// nested name specifier. +static void +MarkUsedTemplateParameters(Sema &SemaRef, + NestedNameSpecifier *NNS, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used) { + if (!NNS) + return; + + MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), + OnlyDeduced, Used); +} + +/// \brief Mark the template parameters that are used by the given +/// template name. +static void +MarkUsedTemplateParameters(Sema &SemaRef, + TemplateName Name, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) + Used[TTP->getIndex()] = true; + return; + } + + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) + MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used); } -/// \brief Mark the template parameters that are deduced by the given +/// \brief Mark the template parameters that are used by the given /// type. -static void -MarkDeducedTemplateParameters(Sema &SemaRef, QualType T, - llvm::SmallVectorImpl<bool> &Deduced) { +static void +MarkUsedTemplateParameters(Sema &SemaRef, QualType T, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used) { + if (T.isNull()) + return; + // Non-dependent types have nothing deducible if (!T->isDependentType()) return; T = SemaRef.Context.getCanonicalType(T); switch (T->getTypeClass()) { - case Type::ExtQual: - MarkDeducedTemplateParameters(SemaRef, - QualType(cast<ExtQualType>(T)->getBaseType(), 0), - Deduced); - break; - case Type::Pointer: - MarkDeducedTemplateParameters(SemaRef, - cast<PointerType>(T)->getPointeeType(), - Deduced); + MarkUsedTemplateParameters(SemaRef, + cast<PointerType>(T)->getPointeeType(), + OnlyDeduced, + Used); break; case Type::BlockPointer: - MarkDeducedTemplateParameters(SemaRef, - cast<BlockPointerType>(T)->getPointeeType(), - Deduced); + MarkUsedTemplateParameters(SemaRef, + cast<BlockPointerType>(T)->getPointeeType(), + OnlyDeduced, + Used); break; case Type::LValueReference: case Type::RValueReference: - MarkDeducedTemplateParameters(SemaRef, - cast<ReferenceType>(T)->getPointeeType(), - Deduced); + MarkUsedTemplateParameters(SemaRef, + cast<ReferenceType>(T)->getPointeeType(), + OnlyDeduced, + Used); break; case Type::MemberPointer: { const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr()); - MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced); - MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0), - Deduced); + MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced, + Used); + MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0), + OnlyDeduced, Used); break; } case Type::DependentSizedArray: - MarkDeducedTemplateParameters(cast<DependentSizedArrayType>(T)->getSizeExpr(), - Deduced); + MarkUsedTemplateParameters(SemaRef, + cast<DependentSizedArrayType>(T)->getSizeExpr(), + OnlyDeduced, Used); // Fall through to check the element type case Type::ConstantArray: case Type::IncompleteArray: - MarkDeducedTemplateParameters(SemaRef, - cast<ArrayType>(T)->getElementType(), - Deduced); + MarkUsedTemplateParameters(SemaRef, + cast<ArrayType>(T)->getElementType(), + OnlyDeduced, Used); break; case Type::Vector: case Type::ExtVector: - MarkDeducedTemplateParameters(SemaRef, - cast<VectorType>(T)->getElementType(), - Deduced); + MarkUsedTemplateParameters(SemaRef, + cast<VectorType>(T)->getElementType(), + OnlyDeduced, Used); break; case Type::DependentSizedExtVector: { const DependentSizedExtVectorType *VecType = cast<DependentSizedExtVectorType>(T); - MarkDeducedTemplateParameters(SemaRef, VecType->getElementType(), Deduced); - MarkDeducedTemplateParameters(VecType->getSizeExpr(), Deduced); + MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced, + Used); + MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, + Used); break; } case Type::FunctionProto: { const FunctionProtoType *Proto = cast<FunctionProtoType>(T); - MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced); + MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced, + Used); for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I) - MarkDeducedTemplateParameters(SemaRef, Proto->getArgType(I), Deduced); + MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced, + Used); break; } case Type::TemplateTypeParm: - Deduced[cast<TemplateTypeParmType>(T)->getIndex()] = true; + Used[cast<TemplateTypeParmType>(T)->getIndex()] = true; break; case Type::TemplateSpecialization: { - const TemplateSpecializationType *Spec + const TemplateSpecializationType *Spec = cast<TemplateSpecializationType>(T); - if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl()) - if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(Template)) - Deduced[TTP->getIndex()] = true; - - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkDeducedTemplateParameters(SemaRef, Spec->getArg(I), Deduced); - + MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced, + Used); + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used); break; } - // None of these types have any deducible parts. + case Type::Complex: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<ComplexType>(T)->getElementType(), + OnlyDeduced, Used); + break; + + case Type::Typename: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<TypenameType>(T)->getQualifier(), + OnlyDeduced, Used); + break; + + // None of these types have any template parameters in them. case Type::Builtin: case Type::FixedWidthInt: - case Type::Complex: case Type::VariableArray: case Type::FunctionNoProto: case Type::Record: case Type::Enum: - case Type::Typename: case Type::ObjCInterface: - case Type::ObjCQualifiedInterface: case Type::ObjCObjectPointer: #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1277,32 +2253,39 @@ MarkDeducedTemplateParameters(Sema &SemaRef, QualType T, } } -/// \brief Mark the template parameters that are deduced by this +/// \brief Mark the template parameters that are used by this /// template argument. -static void -MarkDeducedTemplateParameters(Sema &SemaRef, - const TemplateArgument &TemplateArg, - llvm::SmallVectorImpl<bool> &Deduced) { +static void +MarkUsedTemplateParameters(Sema &SemaRef, + const TemplateArgument &TemplateArg, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used) { switch (TemplateArg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: break; - + case TemplateArgument::Type: - MarkDeducedTemplateParameters(SemaRef, TemplateArg.getAsType(), Deduced); + MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced, + Used); break; case TemplateArgument::Declaration: - if (TemplateTemplateParmDecl *TTP + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) - Deduced[TTP->getIndex()] = true; + Used[TTP->getIndex()] = true; break; case TemplateArgument::Expression: - MarkDeducedTemplateParameters(TemplateArg.getAsExpr(), Deduced); + MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, + Used); break; + case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); + for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(), + PEnd = TemplateArg.pack_end(); + P != PEnd; ++P) + MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used); break; } } @@ -1316,9 +2299,25 @@ MarkDeducedTemplateParameters(Sema &SemaRef, /// \param Deduced a bit vector whose elements will be set to \c true /// to indicate when the corresponding template parameter will be /// deduced. -void -Sema::MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<bool> &Deduced) { +void +Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, + bool OnlyDeduced, + llvm::SmallVectorImpl<bool> &Used) { for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - ::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced); + ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used); +} + +/// \brief Marks all of the template parameters that will be deduced by a +/// call to the given function template. +void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl<bool> &Deduced) { + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + Deduced.clear(); + Deduced.resize(TemplateParams->size()); + + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); + for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) + ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(), + true, Deduced); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 6c2dc77b4cce0..65260c8e1e63b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===/ #include "Sema.h" +#include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" @@ -25,32 +26,65 @@ using namespace clang; // Template Instantiation Support //===----------------------------------------------------------------------===/ -/// \brief Retrieve the template argument list that should be used to -/// instantiate the given declaration. -const TemplateArgumentList & +/// \brief Retrieve the template argument list(s) that should be used to +/// instantiate the definition of the given declaration. +MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(NamedDecl *D) { - // Template arguments for a class template specialization. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(D)) - return Spec->getTemplateArgs(); - - // Template arguments for a function template specialization. - if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) - if (const TemplateArgumentList *TemplateArgs - = Function->getTemplateSpecializationArgs()) - return *TemplateArgs; + // Accumulate the set of template argument lists in this structure. + MultiLevelTemplateArgumentList Result; + + DeclContext *Ctx = dyn_cast<DeclContext>(D); + if (!Ctx) + Ctx = D->getDeclContext(); + + while (!Ctx->isFileContext()) { + // Add template arguments from a class template instantiation. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { + // We're done when we hit an explicit specialization. + if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization) + break; + + Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - // Template arguments for a member of a class template specialization. - DeclContext *EnclosingTemplateCtx = D->getDeclContext(); - while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) { - assert(!EnclosingTemplateCtx->isFileContext() && - "Tried to get the instantiation arguments of a non-template"); - EnclosingTemplateCtx = EnclosingTemplateCtx->getParent(); + // If this class template specialization was instantiated from a + // specialized member that is a class template, we're done. + assert(Spec->getSpecializedTemplate() && "No class template?"); + if (Spec->getSpecializedTemplate()->isMemberSpecialization()) + break; + } + // Add template arguments from a function template specialization. + else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) { + if (Function->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + break; + + if (const TemplateArgumentList *TemplateArgs + = Function->getTemplateSpecializationArgs()) { + // Add the template arguments for this specialization. + Result.addOuterTemplateArguments(TemplateArgs); + + // If this function was instantiated from a specialized member that is + // a function template, we're done. + assert(Function->getPrimaryTemplate() && "No function template?"); + if (Function->getPrimaryTemplate()->isMemberSpecialization()) + break; + } + + // If this is a friend declaration and it declares an entity at + // namespace scope, take arguments from its lexical parent + // instead of its semantic parent. + if (Function->getFriendObjectKind() && + Function->getDeclContext()->isFileContext()) { + Ctx = Function->getLexicalDeclContext(); + continue; + } + } + + Ctx = Ctx->getParent(); } - ClassTemplateSpecializationDecl *EnclosingTemplate - = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx); - return EnclosingTemplate->getTemplateArgs(); + return Result; } Sema::InstantiatingTemplate:: @@ -74,7 +108,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, } } -Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, const TemplateArgument *TemplateArgs, @@ -86,7 +120,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; - Inst.Kind + Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation; Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast<uintptr_t>(Template); @@ -98,7 +132,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, } } -Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, const TemplateArgument *TemplateArgs, @@ -106,7 +140,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind, SourceRange InstantiationRange) : SemaRef(SemaRef) { - + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -122,7 +156,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, } } -Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgument *TemplateArgs, @@ -134,7 +168,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; - Inst.Kind + Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec); @@ -146,6 +180,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, } } +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, + SourceLocation PointOfInstantation, + ParmVarDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange) + : SemaRef(SemaRef) { + + Invalid = CheckInstantiationDepth(PointOfInstantation, InstantiationRange); + + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind + = ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation; + Inst.PointOfInstantiation = PointOfInstantation; + Inst.Entity = reinterpret_cast<uintptr_t>(Param); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + Invalid = false; + } +} + void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { SemaRef.ActiveTemplateInstantiations.pop_back(); @@ -156,11 +214,11 @@ void Sema::InstantiatingTemplate::Clear() { bool Sema::InstantiatingTemplate::CheckInstantiationDepth( SourceLocation PointOfInstantiation, SourceRange InstantiationRange) { - if (SemaRef.ActiveTemplateInstantiations.size() + if (SemaRef.ActiveTemplateInstantiations.size() <= SemaRef.getLangOptions().InstantiationDepth) return false; - SemaRef.Diag(PointOfInstantiation, + SemaRef.Diag(PointOfInstantiation, diag::err_template_recursion_depth_exceeded) << SemaRef.getLangOptions().InstantiationDepth << InstantiationRange; @@ -185,21 +243,25 @@ void Sema::PrintInstantiationStack() { unsigned DiagID = diag::note_template_member_class_here; if (isa<ClassTemplateSpecializationDecl>(Record)) DiagID = diag::note_template_class_instantiation_here; - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), DiagID) << Context.getTypeDeclType(Record) << Active->InstantiationRange; - } else { - FunctionDecl *Function = cast<FunctionDecl>(D); + } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { unsigned DiagID; if (Function->getPrimaryTemplate()) DiagID = diag::note_function_template_spec_here; else DiagID = diag::note_template_member_function_here; - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), DiagID) << Function << Active->InstantiationRange; + } else { + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_template_static_data_member_def_here) + << cast<VarDecl>(D) + << Active->InstantiationRange; } break; } @@ -208,7 +270,7 @@ void Sema::PrintInstantiationStack() { TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( - Active->TemplateArgs, + Active->TemplateArgs, Active->NumTemplateArgs, Context.PrintingPolicy); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), @@ -219,14 +281,14 @@ void Sema::PrintInstantiationStack() { } case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: { - FunctionTemplateDecl *FnTmpl + FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_explicit_template_arg_substitution_here) << FnTmpl << Active->InstantiationRange; break; } - + case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>( @@ -244,6 +306,22 @@ void Sema::PrintInstantiationStack() { } break; + case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: { + ParmVarDecl *Param = cast<ParmVarDecl>((Decl *)Active->Entity); + FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext()); + + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + Active->TemplateArgs, + Active->NumTemplateArgs, + Context.PrintingPolicy); + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_default_function_arg_instantiation_here) + << (FD->getNameAsString() + TemplateArgsStr) + << Active->InstantiationRange; + break; + } + } } } @@ -258,14 +336,16 @@ bool Sema::isSFINAEContext() const { switch(Active->Kind) { case ActiveTemplateInstantiation::TemplateInstantiation: + case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: + // This is a template instantiation, so there is no SFINAE. return false; - + case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: // A default template argument instantiation may or may not be a // SFINAE context; look further up the stack. break; - + case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: // We're either substitution explicitly-specified template arguments @@ -281,482 +361,274 @@ bool Sema::isSFINAEContext() const { // Template Instantiation for Types //===----------------------------------------------------------------------===/ namespace { - class VISIBILITY_HIDDEN TemplateTypeInstantiator { - Sema &SemaRef; - const TemplateArgumentList &TemplateArgs; + class VISIBILITY_HIDDEN TemplateInstantiator + : public TreeTransform<TemplateInstantiator> { + const MultiLevelTemplateArgumentList &TemplateArgs; SourceLocation Loc; DeclarationName Entity; public: - TemplateTypeInstantiator(Sema &SemaRef, - const TemplateArgumentList &TemplateArgs, - SourceLocation Loc, - DeclarationName Entity) - : SemaRef(SemaRef), TemplateArgs(TemplateArgs), - Loc(Loc), Entity(Entity) { } - - QualType operator()(QualType T) const { return Instantiate(T); } - - QualType Instantiate(QualType T) const; - - // Declare instantiate functions for each type. -#define TYPE(Class, Base) \ - QualType Instantiate##Class##Type(const Class##Type *T) const; -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" - }; -} - -QualType -TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate ExtQualType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T) const { - assert(false && "Builtin types are not dependent and cannot be instantiated"); - return QualType(T, 0); -} - -QualType -TemplateTypeInstantiator:: -InstantiateFixedWidthIntType(const FixedWidthIntType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate FixedWidthIntType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate ComplexType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T) const { - QualType PointeeType = Instantiate(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - return SemaRef.BuildPointerType(PointeeType, 0, Loc, Entity); -} + typedef TreeTransform<TemplateInstantiator> inherited; + + TemplateInstantiator(Sema &SemaRef, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity) + : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), + Entity(Entity) { } + + /// \brief Determine whether the given type \p T has already been + /// transformed. + /// + /// 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(); + } -QualType -TemplateTypeInstantiator::InstantiateBlockPointerType( - const BlockPointerType *T) const { - QualType PointeeType = Instantiate(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - return SemaRef.BuildBlockPointerType(PointeeType, 0, Loc, Entity); -} + /// \brief Returns the location of the entity being instantiated, if known. + SourceLocation getBaseLocation() { return Loc; } -QualType -TemplateTypeInstantiator::InstantiateLValueReferenceType( - const LValueReferenceType *T) const { - QualType ReferentType = Instantiate(T->getPointeeType()); - if (ReferentType.isNull()) - return QualType(); + /// \brief Returns the name of the entity being instantiated, if any. + DeclarationName getBaseEntity() { return Entity; } - return SemaRef.BuildReferenceType(ReferentType, true, 0, Loc, Entity); -} + /// \brief Transform the given declaration by instantiating a reference to + /// this declaration. + Decl *TransformDecl(Decl *D); -QualType -TemplateTypeInstantiator::InstantiateRValueReferenceType( - const RValueReferenceType *T) const { - QualType ReferentType = Instantiate(T->getPointeeType()); - if (ReferentType.isNull()) - return QualType(); + /// \brief Transform the definition of the given declaration by + /// instantiating it. + Decl *TransformDefinition(Decl *D); - return SemaRef.BuildReferenceType(ReferentType, false, 0, Loc, Entity); -} + /// \brief Rebuild the exception declaration and register the declaration + /// as an instantiated local. + VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, + DeclaratorInfo *Declarator, + IdentifierInfo *Name, + SourceLocation Loc, SourceRange TypeRange); -QualType -TemplateTypeInstantiator:: -InstantiateMemberPointerType(const MemberPointerType *T) const { - QualType PointeeType = Instantiate(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); + /// \brief Check for tag mismatches when instantiating an + /// elaborated type. + QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); - QualType ClassType = Instantiate(QualType(T->getClass(), 0)); - if (ClassType.isNull()) - return QualType(); + Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); + Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); - return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0, Loc, - Entity); -} - -QualType -TemplateTypeInstantiator:: -InstantiateConstantArrayType(const ConstantArrayType *T) const { - QualType ElementType = Instantiate(T->getElementType()); - if (ElementType.isNull()) - return ElementType; - - // Build a temporary integer literal to specify the size for - // BuildArrayType. Since we have already checked the size as part of - // creating the dependent array type in the first place, we know - // there aren't any errors. However, we do need to determine what - // C++ type to give the size expression. - llvm::APInt Size = T->getSize(); - QualType Types[] = { - SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy, - SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy, - SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty + /// \brief Transforms a template type parameter type by performing + /// substitution of the corresponding template type argument. + QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T); }; - const unsigned NumTypes = sizeof(Types) / sizeof(QualType); - QualType SizeType; - for (unsigned I = 0; I != NumTypes; ++I) - if (Size.getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) { - SizeType = Types[I]; - break; - } - - if (SizeType.isNull()) - SizeType = SemaRef.Context.getFixedWidthIntType(Size.getBitWidth(), false); - - IntegerLiteral ArraySize(Size, SizeType, Loc); - return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), - &ArraySize, T->getIndexTypeQualifier(), - Loc, Entity); } -QualType -TemplateTypeInstantiator:: -InstantiateIncompleteArrayType(const IncompleteArrayType *T) const { - QualType ElementType = Instantiate(T->getElementType()); - if (ElementType.isNull()) - return ElementType; - - return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), - 0, T->getIndexTypeQualifier(), - Loc, Entity); -} +Decl *TemplateInstantiator::TransformDecl(Decl *D) { + if (!D) + return 0; -QualType -TemplateTypeInstantiator:: -InstantiateVariableArrayType(const VariableArrayType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate VariableArrayType yet"); - return QualType(); -} + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { + if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() && + "Wrong kind of template template argument"); + return cast<TemplateDecl>(TemplateArgs(TTP->getDepth(), + TTP->getPosition()).getAsDecl()); + } -QualType -TemplateTypeInstantiator:: -InstantiateDependentSizedArrayType(const DependentSizedArrayType *T) const { - Expr *ArraySize = T->getSizeExpr(); - assert(ArraySize->isValueDependent() && - "dependent sized array types must have value dependent size expr"); - - // Instantiate the element type if needed - QualType ElementType = T->getElementType(); - if (ElementType->isDependentType()) { - ElementType = Instantiate(ElementType); - if (ElementType.isNull()) - return QualType(); - } - - // Instantiate the size expression - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult InstantiatedArraySize = - SemaRef.InstantiateExpr(ArraySize, TemplateArgs); - if (InstantiatedArraySize.isInvalid()) - return QualType(); - - return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), - InstantiatedArraySize.takeAs<Expr>(), - T->getIndexTypeQualifier(), Loc, Entity); -} + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), + TTP->getPosition())) + return D; -QualType -TemplateTypeInstantiator:: -InstantiateDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) const { - - // Instantiate the element type if needed. - QualType ElementType = T->getElementType(); - if (ElementType->isDependentType()) { - ElementType = Instantiate(ElementType); - if (ElementType.isNull()) - return QualType(); + // FIXME: Implement depth reduction of template template parameters + assert(false && + "Reducing depth of template template parameters is not yet implemented"); } - // The expression in a dependent-sized extended vector type is not - // potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - - // Instantiate the size expression. - const Expr *SizeExpr = T->getSizeExpr(); - Sema::OwningExprResult InstantiatedArraySize = - SemaRef.InstantiateExpr(const_cast<Expr *>(SizeExpr), TemplateArgs); - if (InstantiatedArraySize.isInvalid()) - return QualType(); - - return SemaRef.BuildExtVectorType(ElementType, - SemaRef.Owned( - InstantiatedArraySize.takeAs<Expr>()), - T->getAttributeLoc()); + return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs); } -QualType -TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate VectorType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiateExtVectorType( - const ExtVectorType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate ExtVectorType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator:: -InstantiateFunctionProtoType(const FunctionProtoType *T) const { - QualType ResultType = Instantiate(T->getResultType()); - if (ResultType.isNull()) - return ResultType; - - llvm::SmallVector<QualType, 4> ParamTypes; - for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(), - ParamEnd = T->arg_type_end(); - Param != ParamEnd; ++Param) { - QualType P = Instantiate(*Param); - if (P.isNull()) - return P; - - ParamTypes.push_back(P); - } - - return SemaRef.BuildFunctionType(ResultType, ParamTypes.data(), - ParamTypes.size(), - T->isVariadic(), T->getTypeQuals(), - Loc, Entity); -} +Decl *TemplateInstantiator::TransformDefinition(Decl *D) { + Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs); + if (!Inst) + return 0; -QualType -TemplateTypeInstantiator:: -InstantiateFunctionNoProtoType(const FunctionNoProtoType *T) const { - assert(false && "Functions without prototypes cannot be dependent."); - return QualType(); + getSema().CurrentInstantiationScope->InstantiatedLocal(D, Inst); + return Inst; } -QualType -TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T) const { - TypedefDecl *Typedef - = cast_or_null<TypedefDecl>( - SemaRef.InstantiateCurrentDeclRef(T->getDecl())); - if (!Typedef) - return QualType(); - - return SemaRef.Context.getTypeDeclType(Typedef); +VarDecl * +TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, + QualType T, + DeclaratorInfo *Declarator, + IdentifierInfo *Name, + SourceLocation Loc, + SourceRange TypeRange) { + VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator, + Name, Loc, TypeRange); + if (Var && !Var->isInvalidDecl()) + getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); + return Var; } -QualType -TemplateTypeInstantiator::InstantiateTypeOfExprType( - const TypeOfExprType *T) const { - // The expression in a typeof is not potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - - Sema::OwningExprResult E - = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs); - if (E.isInvalid()) - return QualType(); +QualType +TemplateInstantiator::RebuildElaboratedType(QualType T, + ElaboratedType::TagKind Tag) { + if (const TagType *TT = T->getAs<TagType>()) { + TagDecl* TD = TT->getDecl(); + + // FIXME: this location is very wrong; we really need typelocs. + SourceLocation TagLocation = TD->getTagKeywordLoc(); + + // FIXME: type might be anonymous. + IdentifierInfo *Id = TD->getIdentifier(); + + // 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 + << CodeModificationHint::CreateReplacement(SourceRange(TagLocation), + TD->getKindName()); + SemaRef.Diag(TD->getLocation(), diag::note_previous_use); + } + } - return SemaRef.BuildTypeofExprType(E.takeAs<Expr>()); + return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag); } -QualType -TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T) const { - QualType Underlying = Instantiate(T->getUnderlyingType()); - if (Underlying.isNull()) - return QualType(); +Sema::OwningExprResult +TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { + if (!E->isTypeDependent()) + return SemaRef.Owned(E->Retain()); - return SemaRef.Context.getTypeOfType(Underlying); -} + FunctionDecl *currentDecl = getSema().getCurFunctionDecl(); + assert(currentDecl && "Must have current function declaration when " + "instantiating."); -QualType -TemplateTypeInstantiator::InstantiateDecltypeType(const DecltypeType *T) const { - // C++0x [dcl.type.simple]p4: - // The operand of the decltype specifier is an unevaluated operand. - EnterExpressionEvaluationContext Unevaluated(SemaRef, - Action::Unevaluated); - - Sema::OwningExprResult E - = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs); + PredefinedExpr::IdentType IT = E->getIdentType(); - if (E.isInvalid()) - return QualType(); - - return SemaRef.BuildDecltypeType(E.takeAs<Expr>()); -} + unsigned Length = + PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length(); -QualType -TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T) const { - RecordDecl *Record - = cast_or_null<RecordDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl())); - if (!Record) - return QualType(); - - return SemaRef.Context.getTypeDeclType(Record); + llvm::APInt LengthI(32, Length + 1); + QualType ResTy = getSema().Context.CharTy.withConst(); + ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI, + ArrayType::Normal, 0); + PredefinedExpr *PE = + new (getSema().Context) PredefinedExpr(E->getLocation(), ResTy, IT); + return getSema().Owned(PE); } -QualType -TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T) const { - EnumDecl *Enum - = cast_or_null<EnumDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl())); - if (!Enum) - return QualType(); - - return SemaRef.Context.getTypeDeclType(Enum); -} +Sema::OwningExprResult +TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { + // FIXME: Clean this up a bit + NamedDecl *D = E->getDecl(); + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { + if (NTTP->getDepth() >= TemplateArgs.getNumLevels()) { + assert(false && "Cannot reduce non-type template parameter depth yet"); + return getSema().ExprError(); + } -QualType -TemplateTypeInstantiator:: -InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const { - if (T->getDepth() == 0) { - // Replace the template type parameter with its corresponding - // template argument. - - // If the corresponding template argument is NULL or doesn't exist, it's - // because we are performing instantiation from explicitly-specified - // template arguments in a function template class, but there were some + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some // arguments left unspecified. - if (T->getIndex() >= TemplateArgs.size() || - TemplateArgs[T->getIndex()].isNull()) - return QualType(T, 0); // Would be nice to keep the original type here - - assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type && - "Template argument kind mismatch"); - return TemplateArgs[T->getIndex()].getAsType(); - } + if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), + NTTP->getPosition())) + return SemaRef.Owned(E->Retain()); - // The template type parameter comes from an inner template (e.g., - // the template parameter list of a member template inside the - // template we are instantiating). Create a new template type - // parameter with the template "level" reduced by one. - return SemaRef.Context.getTemplateTypeParmType(T->getDepth() - 1, - T->getIndex(), - T->isParameterPack(), - T->getName()); -} + const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), + NTTP->getPosition()); -QualType -TemplateTypeInstantiator:: -InstantiateTemplateSpecializationType( - const TemplateSpecializationType *T) const { - llvm::SmallVector<TemplateArgument, 4> InstantiatedTemplateArgs; - InstantiatedTemplateArgs.reserve(T->getNumArgs()); - for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); - Arg != ArgEnd; ++Arg) { - TemplateArgument InstArg = SemaRef.Instantiate(*Arg, TemplateArgs); - if (InstArg.isNull()) - return QualType(); - - InstantiatedTemplateArgs.push_back(InstArg); - } + // The template argument itself might be an expression, in which + // case we just return that expression. + if (Arg.getKind() == TemplateArgument::Expression) + return SemaRef.Owned(Arg.getAsExpr()->Retain()); - // FIXME: We're missing the locations of the template name, '<', and '>'. + if (Arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); - TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(), - Loc, - TemplateArgs); + VD = cast_or_null<ValueDecl>( + getSema().FindInstantiatedDecl(VD, TemplateArgs)); + if (!VD) + return SemaRef.ExprError(); - return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(), - InstantiatedTemplateArgs.data(), - InstantiatedTemplateArgs.size(), - SourceLocation()); -} - -QualType -TemplateTypeInstantiator:: -InstantiateQualifiedNameType(const QualifiedNameType *T) const { - // When we instantiated a qualified name type, there's no point in - // keeping the qualification around in the instantiated result. So, - // just instantiate the named type. - return (*this)(T->getNamedType()); -} + return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), + /*FIXME:*/false, /*FIXME:*/false); + } -QualType -TemplateTypeInstantiator:: -InstantiateTypenameType(const TypenameType *T) const { - if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { - // When the typename type refers to a template-id, the template-id - // is dependent and has enough information to instantiate the - // result of the typename type. Since we don't care about keeping - // the spelling of the typename type in template instantiations, - // we just instantiate the template-id. - return InstantiateTemplateSpecializationType(TemplateId); + assert(Arg.getKind() == TemplateArgument::Integral); + QualType T = Arg.getIntegralType(); + if (T->isCharType() || T->isWideCharType()) + return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( + Arg.getAsIntegral()->getZExtValue(), + T->isWideCharType(), + T, + E->getSourceRange().getBegin())); + if (T->isBooleanType()) + return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( + Arg.getAsIntegral()->getBoolValue(), + T, + E->getSourceRange().getBegin())); + + assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); + return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( + *Arg.getAsIntegral(), + T, + E->getSourceRange().getBegin())); } - NestedNameSpecifier *NNS - = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(), - SourceRange(Loc), - TemplateArgs); - if (!NNS) - return QualType(); + NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs); + if (!InstD) + return SemaRef.ExprError(); - return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc)); -} + // If we instantiated an UnresolvedUsingDecl and got back an UsingDecl, + // we need to get the underlying decl. + // FIXME: Is this correct? Maybe FindInstantiatedDecl should do this? + InstD = InstD->getUnderlyingDecl(); -QualType -TemplateTypeInstantiator:: -InstantiateObjCObjectPointerType(const ObjCObjectPointerType *T) const { - assert(false && "Objective-C types cannot be dependent"); - return QualType(); + // FIXME: nested-name-specifier for QualifiedDeclRefExpr + return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD, + /*FIXME:*/false, + /*FIXME:*/0, + /*FIXME:*/false); } QualType -TemplateTypeInstantiator:: -InstantiateObjCInterfaceType(const ObjCInterfaceType *T) const { - assert(false && "Objective-C types cannot be dependent"); - return QualType(); -} +TemplateInstantiator::TransformTemplateTypeParmType( + const TemplateTypeParmType *T) { + if (T->getDepth() < TemplateArgs.getNumLevels()) { + // Replace the template type parameter with its corresponding + // template argument. -QualType -TemplateTypeInstantiator:: -InstantiateObjCQualifiedInterfaceType( - const ObjCQualifiedInterfaceType *T) const { - assert(false && "Objective-C types cannot be dependent"); - return QualType(); -} + // If the corresponding template argument is NULL or doesn't exist, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template class, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) + return QualType(T, 0); -/// \brief The actual implementation of Sema::InstantiateType(). -QualType TemplateTypeInstantiator::Instantiate(QualType T) const { - // If T is not a dependent type, there is nothing to do. - if (!T->isDependentType()) - return T; + assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind() + == TemplateArgument::Type && + "Template argument kind mismatch"); - QualType Result; - switch (T->getTypeClass()) { -#define TYPE(Class, Base) \ - case Type::Class: \ - Result = Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr())); \ - break; -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" + return TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); } - // C++ [dcl.ref]p1: - // [...] Cv-qualified references are ill-formed except when - // the cv-qualifiers are introduced through the use of a - // typedef (7.1.3) or of a template type argument (14.3), in - // which case the cv-qualifiers are ignored. - // - // The same rule applies to function types. - if (!Result.isNull() && T.getCVRQualifiers() && - !Result->isFunctionType() && !Result->isReferenceType()) - Result = Result.getWithAdditionalQualifiers(T.getCVRQualifiers()); - return Result; + // The template type parameter comes from an inner template (e.g., + // the template parameter list of a member template inside the + // template we are instantiating). Create a new template type + // parameter with the template "level" reduced by one. + return getSema().Context.getTemplateTypeParmType( + T->getDepth() - TemplateArgs.getNumLevels(), + T->getIndex(), + T->isParameterPack(), + T->getName()); } -/// \brief Instantiate the type T with a given set of template arguments. +/// \brief Perform substitution on the type T with a given set of template +/// arguments. /// /// This routine substitutes the given template arguments into the /// type T and produces the instantiated type. @@ -782,9 +654,9 @@ QualType TemplateTypeInstantiator::Instantiate(QualType T) const { /// /// \returns If the instantiation succeeds, the instantiated /// type. Otherwise, produces diagnostics and returns a NULL type. -QualType Sema::InstantiateType(QualType T, - const TemplateArgumentList &TemplateArgs, - SourceLocation Loc, DeclarationName Entity) { +QualType Sema::SubstType(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -793,35 +665,34 @@ QualType Sema::InstantiateType(QualType T, if (!T->isDependentType()) return T; - TemplateTypeInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); - return Instantiator(T); + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); + return Instantiator.TransformType(T); } -/// \brief Instantiate the base class specifiers of the given class -/// template specialization. +/// \brief Perform substitution on the base class specifiers of the +/// given class template specialization. /// /// Produces a diagnostic and returns true on error, returns false and /// attaches the instantiated base classes to the class template /// specialization if successful. -bool -Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, - CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs) { +bool +Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs) { bool Invalid = false; llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases; - for (ClassTemplateSpecializationDecl::base_class_iterator + for (ClassTemplateSpecializationDecl::base_class_iterator Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); Base != BaseEnd; ++Base) { if (!Base->getType()->isDependentType()) { - // FIXME: Allocate via ASTContext - InstantiatedBases.push_back(new CXXBaseSpecifier(*Base)); + InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base)); continue; } - QualType BaseType = InstantiateType(Base->getType(), - TemplateArgs, - Base->getSourceRange().getBegin(), - DeclarationName()); + QualType BaseType = SubstType(Base->getType(), + TemplateArgs, + Base->getSourceRange().getBegin(), + DeclarationName()); if (BaseType.isNull()) { Invalid = true; continue; @@ -864,25 +735,33 @@ Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, /// \param TemplateArgs The template arguments to be substituted into /// the pattern. /// +/// \param TSK the kind of implicit or explicit instantiation to perform. +/// +/// \param Complain whether to complain if the class cannot be instantiated due +/// to the lack of a definition. +/// /// \returns true if an error occurred, false otherwise. bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs, - bool ExplicitInstantiation) { + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, + bool Complain) { bool Invalid = false; - - CXXRecordDecl *PatternDef + + CXXRecordDecl *PatternDef = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); if (!PatternDef) { - if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { + if (!Complain) { + // Say nothing + } else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_member_of_template_here); } else { Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) - << ExplicitInstantiation + << (TSK != TSK_ImplicitInstantiation) << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_template_decl_here); } @@ -902,20 +781,22 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Start the definition of this instantiation. Instantiation->startDefinition(); - // Instantiate the base class specifiers. - if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) + // Do substitution on the base class specifiers. + if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) Invalid = true; llvm::SmallVector<DeclPtrTy, 4> Fields; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), - MemberEnd = Pattern->decls_end(); + MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { - Decl *NewMember = InstantiateDecl(*Member, Instantiation, TemplateArgs); + Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs); if (NewMember) { if (NewMember->isInvalidDecl()) Invalid = true; else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) Fields.push_back(DeclPtrTy::make(Field)); + else if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember)) + Instantiation->addDecl(UD); } else { // FIXME: Eventually, a NULL return will mean that one of the // instantiations was a semantic disaster, and we'll want to set Invalid = @@ -938,32 +819,52 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Consumer.HandleTagDeclDefinition(Instantiation); // If this is an explicit instantiation, instantiate our members, too. - if (!Invalid && ExplicitInstantiation) { + if (!Invalid && TSK != TSK_ImplicitInstantiation) { Inst.Clear(); - InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs); + InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs, + TSK); } return Invalid; } -bool +bool Sema::InstantiateClassTemplateSpecialization( ClassTemplateSpecializationDecl *ClassTemplateSpec, - bool ExplicitInstantiation) { + TemplateSpecializationKind TSK, + bool Complain) { // Perform the actual instantiation on the canonical declaration. ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>( - Context.getCanonicalDecl(ClassTemplateSpec)); - - // We can only instantiate something that hasn't already been - // instantiated or specialized. Fail without any diagnostics: our - // caller will provide an error message. - if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) + ClassTemplateSpec->getCanonicalDecl()); + + // Check whether we have already instantiated or specialized this class + // template specialization. + if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) { + if (ClassTemplateSpec->getSpecializationKind() == + TSK_ExplicitInstantiationDeclaration && + TSK == TSK_ExplicitInstantiationDefinition) { + // An explicit instantiation definition follows an explicit instantiation + // declaration (C++0x [temp.explicit]p10); go ahead and perform the + // explicit instantiation. + ClassTemplateSpec->setSpecializationKind(TSK); + InstantiateClassTemplateSpecializationMembers( + /*FIXME?*/ClassTemplateSpec->getPointOfInstantiation(), + ClassTemplateSpec, + TSK); + return false; + } + + // We can only instantiate something that hasn't already been + // instantiated or specialized. Fail without any diagnostics: our + // caller will provide an error message. return true; + } + if (ClassTemplateSpec->isInvalidDecl()) + return true; + ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); - CXXRecordDecl *Pattern = Template->getTemplatedDecl(); - const TemplateArgumentList *TemplateArgs - = &ClassTemplateSpec->getTemplateArgs(); + CXXRecordDecl *Pattern = 0; // C++ [temp.class.spec.match]p1: // When a class template is used in a context that requires an @@ -976,14 +877,14 @@ Sema::InstantiateClassTemplateSpecialization( typedef std::pair<ClassTemplatePartialSpecializationDecl *, TemplateArgumentList *> MatchResult; llvm::SmallVector<MatchResult, 4> Matched; - for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator Partial = Template->getPartialSpecializations().begin(), PartialEnd = Template->getPartialSpecializations().end(); Partial != PartialEnd; ++Partial) { TemplateDeductionInfo Info(Context); if (TemplateDeductionResult Result - = DeduceTemplateArguments(&*Partial, + = DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { // FIXME: Store the failed-deduction information for use in @@ -998,7 +899,7 @@ Sema::InstantiateClassTemplateSpecialization( // -- If exactly one matching specialization is found, the // instantiation is generated from that specialization. Pattern = Matched[0].first; - TemplateArgs = Matched[0].second; + ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second); } else if (Matched.size() > 1) { // -- If more than one matching specialization is found, the // partial order rules (14.5.4.2) are used to determine @@ -1007,61 +908,137 @@ Sema::InstantiateClassTemplateSpecialization( // specialized than all of the other matching // specializations, then the use of the class template is // ambiguous and the program is ill-formed. - // FIXME: Implement partial ordering of class template partial - // specializations. - Diag(ClassTemplateSpec->getLocation(), - diag::unsup_template_partial_spec_ordering); + llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); + for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, + PEnd = Matched.end(); + P != PEnd; ++P) { + if (getMoreSpecializedPartialSpecialization(P->first, Best->first) + == P->first) + Best = P; + } + + // Determine if the best partial specialization is more specialized than + // the others. + bool Ambiguous = false; + for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) { + if (P != Best && + getMoreSpecializedPartialSpecialization(P->first, Best->first) + != Best->first) { + Ambiguous = true; + break; + } + } + + if (Ambiguous) { + // Partial ordering did not produce a clear winner. Complain. + ClassTemplateSpec->setInvalidDecl(); + Diag(ClassTemplateSpec->getPointOfInstantiation(), + diag::err_partial_spec_ordering_ambiguous) + << ClassTemplateSpec; + + // Print the matching partial specializations. + for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) + Diag(P->first->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText(P->first->getTemplateParameters(), + *P->second); + + return true; + } + + // Instantiate using the best class template partial specialization. + Pattern = Best->first; + ClassTemplateSpec->setInstantiationOf(Best->first, Best->second); } else { // -- If no matches are found, the instantiation is generated // from the primary template. - - // Since we initialized the pattern and template arguments from - // the primary template, there is nothing more we need to do here. + ClassTemplateDecl *OrigTemplate = Template; + while (OrigTemplate->getInstantiatedFromMemberTemplate()) { + // If we've found an explicit specialization of this class template, + // stop here and use that as the pattern. + if (OrigTemplate->isMemberSpecialization()) + break; + + OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate(); + } + + Pattern = OrigTemplate->getTemplatedDecl(); } - // Note that this is an instantiation. - ClassTemplateSpec->setSpecializationKind( - ExplicitInstantiation? TSK_ExplicitInstantiation - : TSK_ImplicitInstantiation); + // Note that this is an instantiation. + ClassTemplateSpec->setSpecializationKind(TSK); + + bool Result = InstantiateClass(ClassTemplateSpec->getPointOfInstantiation(), + ClassTemplateSpec, Pattern, + getTemplateInstantiationArgs(ClassTemplateSpec), + TSK, + Complain); - bool Result = InstantiateClass(ClassTemplateSpec->getLocation(), - ClassTemplateSpec, Pattern, *TemplateArgs, - ExplicitInstantiation); - for (unsigned I = 0, N = Matched.size(); I != N; ++I) { // FIXME: Implement TemplateArgumentList::Destroy! // if (Matched[I].first != Pattern) // Matched[I].second->Destroy(Context); } - + return Result; } -/// \brief Instantiate the definitions of all of the member of the -/// given class, which is an instantiation of a class template or a -/// member class of a template. +/// \brief Instantiates the definitions of all of the member +/// of the given class, which is an instantiation of a class template +/// or a member class of a template. void Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, - const TemplateArgumentList &TemplateArgs) { + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK) { for (DeclContext::decl_iterator D = Instantiation->decls_begin(), DEnd = Instantiation->decls_end(); D != DEnd; ++D) { if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) { - if (!Function->getBody()) + if (Function->getInstantiatedFromMemberFunction()) { + // If this member was explicitly specialized, do nothing. + if (Function->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization) + continue; + + Function->setTemplateSpecializationKind(TSK); + } + + if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition) InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) { - const VarDecl *Def = 0; - if (!Var->getDefinition(Def)) - InstantiateVariableDefinition(Var); + if (Var->isStaticDataMember()) { + // If this member was explicitly specialized, do nothing. + if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + continue; + + Var->setTemplateSpecializationKind(TSK); + + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); + } } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { - if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) { - assert(Record->getInstantiatedFromMemberClass() && - "Missing instantiated-from-template information"); + if (Record->isInjectedClassName()) + continue; + + assert(Record->getInstantiatedFromMemberClass() && + "Missing instantiated-from-template information"); + + // If this member was explicitly specialized, do nothing. + if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + continue; + + if (!Record->getDefinition(Context)) InstantiateClass(PointOfInstantiation, Record, Record->getInstantiatedFromMemberClass(), - TemplateArgs, true); - } + TemplateArgs, + TSK); + + InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs, + TSK); } } } @@ -1069,9 +1046,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, /// \brief Instantiate the definitions of all of the members of the /// given class template specialization, which was named as part of an /// explicit instantiation. -void Sema::InstantiateClassTemplateSpecializationMembers( +void +Sema::InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, - ClassTemplateSpecializationDecl *ClassTemplateSpec) { + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK) { // C++0x [temp.explicit]p7: // An explicit instantiation that names a class template // specialization is an explicit instantion of the same kind @@ -1081,172 +1060,53 @@ void Sema::InstantiateClassTemplateSpecializationMembers( // containing the explicit instantiation, except as described // below. InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec, - ClassTemplateSpec->getTemplateArgs()); + getTemplateInstantiationArgs(ClassTemplateSpec), + TSK); } -/// \brief Instantiate a nested-name-specifier. -NestedNameSpecifier * -Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range, - const TemplateArgumentList &TemplateArgs) { - // Instantiate the prefix of this nested name specifier. - NestedNameSpecifier *Prefix = NNS->getPrefix(); - if (Prefix) { - Prefix = InstantiateNestedNameSpecifier(Prefix, Range, TemplateArgs); - if (!Prefix) - return 0; - } +Sema::OwningStmtResult +Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) { + if (!S) + return Owned(S); - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: { - assert(Prefix && - "Can't have an identifier nested-name-specifier with no prefix"); - CXXScopeSpec SS; - // FIXME: The source location information is all wrong. - SS.setRange(Range); - SS.setScopeRep(Prefix); - return static_cast<NestedNameSpecifier *>( - ActOnCXXNestedNameSpecifier(0, SS, - Range.getEnd(), - Range.getEnd(), - *NNS->getAsIdentifier())); - break; - } + TemplateInstantiator Instantiator(*this, TemplateArgs, + SourceLocation(), + DeclarationName()); + return Instantiator.TransformStmt(S); +} - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: - return NNS; - - case NestedNameSpecifier::TypeSpecWithTemplate: - case NestedNameSpecifier::TypeSpec: { - QualType T = QualType(NNS->getAsType(), 0); - if (!T->isDependentType()) - return NNS; - - T = InstantiateType(T, TemplateArgs, Range.getBegin(), DeclarationName()); - if (T.isNull()) - return 0; - - if (T->isDependentType() || T->isRecordType() || - (getLangOptions().CPlusPlus0x && T->isEnumeralType())) { - assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here"); - return NestedNameSpecifier::Create(Context, Prefix, - NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, - T.getTypePtr()); - } +Sema::OwningExprResult +Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { + if (!E) + return Owned(E); - Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T; - return 0; - } - } + TemplateInstantiator Instantiator(*this, TemplateArgs, + SourceLocation(), + DeclarationName()); + return Instantiator.TransformExpr(E); +} - // Required to silence a GCC warning - return 0; +/// \brief Do template substitution on a nested-name-specifier. +NestedNameSpecifier * +Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range, + const MultiLevelTemplateArgumentList &TemplateArgs) { + TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(), + DeclarationName()); + return Instantiator.TransformNestedNameSpecifier(NNS, Range); } TemplateName -Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc, - const TemplateArgumentList &TemplateArgs) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null<TemplateTemplateParmDecl>( - Name.getAsTemplateDecl())) { - assert(TTP->getDepth() == 0 && - "Cannot reduce depth of a template template parameter"); - assert(TemplateArgs[TTP->getPosition()].getAsDecl() && - "Wrong kind of template template argument"); - ClassTemplateDecl *ClassTemplate - = dyn_cast<ClassTemplateDecl>( - TemplateArgs[TTP->getPosition()].getAsDecl()); - assert(ClassTemplate && "Expected a class template"); - if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { - NestedNameSpecifier *NNS - = InstantiateNestedNameSpecifier(QTN->getQualifier(), - /*FIXME=*/SourceRange(Loc), - TemplateArgs); - if (NNS) - return Context.getQualifiedTemplateName(NNS, - QTN->hasTemplateKeyword(), - ClassTemplate); - } - - return TemplateName(ClassTemplate); - } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { - NestedNameSpecifier *NNS - = InstantiateNestedNameSpecifier(DTN->getQualifier(), - /*FIXME=*/SourceRange(Loc), - TemplateArgs); - - if (!NNS) // FIXME: Not the best recovery strategy. - return Name; - - if (NNS->isDependent()) - return Context.getDependentTemplateName(NNS, DTN->getName()); - - // Somewhat redundant with ActOnDependentTemplateName. - CXXScopeSpec SS; - SS.setRange(SourceRange(Loc)); - SS.setScopeRep(NNS); - TemplateTy Template; - TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS); - if (TNK == TNK_Non_template) { - Diag(Loc, diag::err_template_kw_refers_to_non_template) - << DTN->getName(); - return Name; - } else if (TNK == TNK_Function_template) { - Diag(Loc, diag::err_template_kw_refers_to_non_template) - << DTN->getName(); - return Name; - } - - return Template.getAsVal<TemplateName>(); - } - - - - // FIXME: Even if we're referring to a Decl that isn't a template template - // parameter, we may need to instantiate the outer contexts of that - // Decl. However, this won't be needed until we implement member templates. - return Name; +Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc, + const MultiLevelTemplateArgumentList &TemplateArgs) { + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, + DeclarationName()); + return Instantiator.TransformTemplateName(Name); } -TemplateArgument Sema::Instantiate(TemplateArgument Arg, - const TemplateArgumentList &TemplateArgs) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - assert(false && "Should never have a NULL template argument"); - break; - - case TemplateArgument::Type: { - QualType T = InstantiateType(Arg.getAsType(), TemplateArgs, - Arg.getLocation(), DeclarationName()); - if (T.isNull()) - return TemplateArgument(); - - return TemplateArgument(Arg.getLocation(), T); - } - - case TemplateArgument::Declaration: - // FIXME: Template instantiation for template template parameters. - return Arg; - - case TemplateArgument::Integral: - return Arg; - - case TemplateArgument::Expression: { - // Template argument expressions are not potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); - - Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs); - if (E.isInvalid()) - return TemplateArgument(); - return TemplateArgument(E.takeAs<Expr>()); - } - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } - - assert(false && "Unhandled template argument kind"); - return TemplateArgument(); +TemplateArgument Sema::Subst(TemplateArgument Arg, + const MultiLevelTemplateArgumentList &TemplateArgs) { + TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), + DeclarationName()); + return Instantiator.TransformTemplateArgument(Arg); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index f597199920666..33fa28866e52e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -15,24 +15,26 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/Support/Compiler.h" using namespace clang; namespace { - class VISIBILITY_HIDDEN TemplateDeclInstantiator + class VISIBILITY_HIDDEN TemplateDeclInstantiator : public DeclVisitor<TemplateDeclInstantiator, Decl *> { Sema &SemaRef; DeclContext *Owner; - const TemplateArgumentList &TemplateArgs; - + const MultiLevelTemplateArgumentList &TemplateArgs; + public: typedef Sema::OwningExprResult OwningExprResult; TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, - const TemplateArgumentList &TemplateArgs) + const MultiLevelTemplateArgumentList &TemplateArgs) : SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { } - + // FIXME: Once we get closer to completion, replace these manually-written // declarations with automatically-generated ones from // clang/AST/DeclNodes.def. @@ -44,26 +46,42 @@ namespace { Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitEnumDecl(EnumDecl *D); Decl *VisitEnumConstantDecl(EnumConstantDecl *D); - Decl *VisitFunctionDecl(FunctionDecl *D); + Decl *VisitFriendDecl(FriendDecl *D); + Decl *VisitFunctionDecl(FunctionDecl *D, + TemplateParameterList *TemplateParams = 0); Decl *VisitCXXRecordDecl(CXXRecordDecl *D); - Decl *VisitCXXMethodDecl(CXXMethodDecl *D); + Decl *VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams = 0); Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitCXXConversionDecl(CXXConversionDecl *D); ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); + Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); // Base case. FIXME: Remove once we can instantiate everything. - Decl *VisitDecl(Decl *) { + Decl *VisitDecl(Decl *) { assert(false && "Template instantiation of unknown declaration kind!"); return 0; } + const LangOptions &getLangOptions() { + return SemaRef.getLangOptions(); + } + // Helper functions for instantiating methods. - QualType InstantiateFunctionType(FunctionDecl *D, + QualType SubstFunctionType(FunctionDecl *D, llvm::SmallVectorImpl<ParmVarDecl *> &Params); bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + + TemplateParameterList * + SubstTemplateParams(TemplateParameterList *List); }; } @@ -83,14 +101,14 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; QualType T = D->getUnderlyingType(); if (T->isDependentType()) { - T = SemaRef.InstantiateType(T, TemplateArgs, - D->getLocation(), D->getDeclName()); + T = SemaRef.SubstType(T, TemplateArgs, + D->getLocation(), D->getDeclName()); if (T.isNull()) { Invalid = true; T = SemaRef.Context.IntTy; } } - + // Create the new typedef TypedefDecl *Typedef = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(), @@ -99,44 +117,86 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Typedef->setInvalidDecl(); Owner->addDecl(Typedef); - + return Typedef; } Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { - // Instantiate the type of the declaration - QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs, - D->getTypeSpecStartLoc(), - D->getDeclName()); + // Do substitution on the type of the declaration + QualType T = SemaRef.SubstType(D->getType(), TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); if (T.isNull()) return 0; // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), - T, D->getStorageClass(), - D->getTypeSpecStartLoc()); + T, D->getDeclaratorInfo(), + D->getStorageClass()); Var->setThreadSpecified(D->isThreadSpecified()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setDeclaredInCondition(D->isDeclaredInCondition()); - + + // If we are instantiating a static data member defined + // out-of-line, the instantiation will have the same lexical + // context (which will be a namespace scope) as the template. + if (D->isOutOfLine()) + Var->setLexicalDeclContext(D->getLexicalDeclContext()); + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration); - Owner->addDecl(Var); + if (D->isOutOfLine()) { + D->getLexicalDeclContext()->addDecl(Var); + Owner->makeDeclVisibleInContext(Var); + } else { + Owner->addDecl(Var); + } + + // Link instantiations of static data members back to the template from + // which they were instantiated. + if (Var->isStaticDataMember()) + SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, + TSK_ImplicitInstantiation); + if (D->getInit()) { - OwningExprResult Init - = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs); + OwningExprResult Init + = SemaRef.SubstExpr(D->getInit(), TemplateArgs); if (Init.isInvalid()) Var->setInvalidDecl(); - else + else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) { + // FIXME: We're faking all of the comma locations, which is suboptimal. + // Do we even need these comma locations? + llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; + if (PLE->getNumExprs() > 0) { + FakeCommaLocs.reserve(PLE->getNumExprs() - 1); + for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) { + Expr *E = PLE->getExpr(I)->Retain(); + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken(E->getLocEnd())); + } + PLE->getExpr(PLE->getNumExprs() - 1)->Retain(); + } + + // Add the direct initializer to the declaration. + SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), + PLE->getLParenLoc(), + Sema::MultiExprArg(SemaRef, + (void**)PLE->getExprs(), + PLE->getNumExprs()), + FakeCommaLocs.data(), + PLE->getRParenLoc()); + + // When Init is destroyed, it will destroy the instantiated ParenListExpr; + // we've explicitly retained all of its subexpressions already. + } else SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), D->hasCXXDirectInitializer()); - } else { - // FIXME: Call ActOnUninitializedDecl? (Not always) - } + } else if (!Var->isStaticDataMember() || Var->isOutOfLine()) + SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); return Var; } @@ -145,8 +205,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; QualType T = D->getType(); if (T->isDependentType()) { - T = SemaRef.InstantiateType(T, TemplateArgs, - D->getLocation(), D->getDeclName()); + T = SemaRef.SubstType(T, TemplateArgs, + D->getLocation(), D->getDeclName()); if (!T.isNull() && T->isFunctionType()) { // C++ [temp.arg.type]p3: // If a declaration acquires a function type through a type @@ -167,9 +227,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { else if (BitWidth) { // The bit-width expression is not potentially evaluated. EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - + OwningExprResult InstantiatedBitWidth - = SemaRef.InstantiateExpr(BitWidth, TemplateArgs); + = SemaRef.SubstExpr(BitWidth, TemplateArgs); if (InstantiatedBitWidth.isInvalid()) { Invalid = true; BitWidth = 0; @@ -178,44 +238,90 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T, - cast<RecordDecl>(Owner), + D->getDeclaratorInfo(), + cast<RecordDecl>(Owner), D->getLocation(), D->isMutable(), BitWidth, + D->getTypeSpecStartLoc(), D->getAccess(), 0); - if (Field) { - if (Invalid) - Field->setInvalidDecl(); - - Owner->addDecl(Field); + if (!Field) + return 0; + + if (Invalid) + Field->setInvalidDecl(); + + if (!Field->getDeclName()) { + // Keep track of where this decl came from. + SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D); } + Field->setImplicit(D->isImplicit()); + Owner->addDecl(Field); + return Field; } +Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { + FriendDecl::FriendUnion FU; + + // Handle friend type expressions by simply substituting template + // parameters into the pattern type. + if (Type *Ty = D->getFriendType()) { + QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs, + D->getLocation(), DeclarationName()); + if (T.isNull()) return 0; + + assert(getLangOptions().CPlusPlus0x || T->isRecordType()); + FU = T.getTypePtr(); + + // Handle everything else by appropriate substitution. + } else { + NamedDecl *ND = D->getFriendDecl(); + assert(ND && "friend decl must be a decl or a type!"); + + // FIXME: We have a problem here, because the nested call to Visit(ND) + // will inject the thing that the friend references into the current + // owner, which is wrong. + Decl *NewND = Visit(ND); + if (!NewND) return 0; + + FU = cast<NamedDecl>(NewND); + } + + FriendDecl *FD = + FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU, + D->getFriendLoc()); + FD->setAccess(AS_public); + Owner->addDecl(FD); + return FD; +} + Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { Expr *AssertExpr = D->getAssertExpr(); - + // The expression in a static assertion is not potentially evaluated. EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - + OwningExprResult InstantiatedAssertExpr - = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs); + = SemaRef.SubstExpr(AssertExpr, TemplateArgs); if (InstantiatedAssertExpr.isInvalid()) return 0; - OwningExprResult Message = SemaRef.Clone(D->getMessage()); - Decl *StaticAssert - = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(), + OwningExprResult Message(SemaRef, D->getMessage()); + D->getMessage()->Retain(); + Decl *StaticAssert + = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(), move(InstantiatedAssertExpr), move(Message)).getAs<Decl>(); return StaticAssert; } Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { - EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, + EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), + D->getTagKeywordLoc(), /*PrevDecl=*/0); Enum->setInstantiationOfMemberEnum(D); Enum->setAccess(D->getAccess()); @@ -232,10 +338,10 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { OwningExprResult Value = SemaRef.Owned((Expr *)0); if (Expr *UninstValue = EC->getInitExpr()) { // The enumerator's value expression is not potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(SemaRef, + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - - Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs); + + Value = SemaRef.SubstExpr(UninstValue, TemplateArgs); } // Drop the initial value and continue. @@ -245,7 +351,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { isInvalid = true; } - EnumConstantDecl *EnumConst + EnumConstantDecl *EnumConst = SemaRef.CheckEnumConstant(Enum, LastEnumConst, EC->getLocation(), EC->getIdentifier(), move(Value)); @@ -262,11 +368,13 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { LastEnumConst = EnumConst; } } - + // FIXME: Fixup LBraceLoc and RBraceLoc + // FIXME: Empty Scope and AttributeList (required to handle attribute packed). SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(), Sema::DeclPtrTy::make(Enum), - &Enumerators[0], Enumerators.size()); + &Enumerators[0], Enumerators.size(), + 0, 0); return Enum; } @@ -276,100 +384,337 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { return 0; } +Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return NULL; + + CXXRecordDecl *Pattern = D->getTemplatedDecl(); + CXXRecordDecl *RecordInst + = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner, + Pattern->getLocation(), Pattern->getIdentifier(), + Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL, + /*DelayTypeCreation=*/true); + + ClassTemplateDecl *Inst + = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), InstParams, RecordInst, 0); + RecordInst->setDescribedClassTemplate(Inst); + Inst->setAccess(D->getAccess()); + Inst->setInstantiatedFromMemberTemplate(D); + + // Trigger creation of the type for the instantiation. + SemaRef.Context.getTypeDeclType(RecordInst); + + Owner->addDecl(Inst); + return Inst; +} + +Decl * +TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + assert(false &&"Partial specializations of member templates are unsupported"); + return 0; +} + +Decl * +TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + // FIXME: Dig out the out-of-line definition of this function template? + + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return NULL; + + FunctionDecl *Instantiated = 0; + if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl())) + Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, + InstParams)); + else + Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl( + D->getTemplatedDecl(), + InstParams)); + + if (!Instantiated) + return 0; + + // Link the instantiated function template declaration to the function + // template from which it was instantiated. + FunctionTemplateDecl *InstTemplate + = Instantiated->getDescribedFunctionTemplate(); + InstTemplate->setAccess(D->getAccess()); + assert(InstTemplate && + "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); + if (!InstTemplate->getInstantiatedFromMemberTemplate()) + InstTemplate->setInstantiatedFromMemberTemplate(D); + + // Add non-friends into the owner. + if (!InstTemplate->getFriendObjectKind()) + Owner->addDecl(InstTemplate); + return InstTemplate; +} + Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *PrevDecl = 0; if (D->isInjectedClassName()) PrevDecl = cast<CXXRecordDecl>(Owner); CXXRecordDecl *Record - = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, - D->getLocation(), D->getIdentifier(), PrevDecl); + = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, + D->getLocation(), D->getIdentifier(), + D->getTagKeywordLoc(), PrevDecl); Record->setImplicit(D->isImplicit()); - Record->setAccess(D->getAccess()); + // FIXME: Check against AS_none is an ugly hack to work around the issue that + // the tag decls introduced by friend class declarations don't have an access + // specifier. Remove once this area of the code gets sorted out. + if (D->getAccess() != AS_none) + Record->setAccess(D->getAccess()); if (!D->isInjectedClassName()) - Record->setInstantiationOfMemberClass(D); + Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation); + + // If the original function was part of a friend declaration, + // inherit its namespace state. + if (Decl::FriendObjectKind FOK = D->getFriendObjectKind()) + Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared); + + Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion()); Owner->addDecl(Record); return Record; } -Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { +/// Normal class members are of more specific types and therefore +/// don't make it here. This function serves two purposes: +/// 1) instantiating function templates +/// 2) substituting friend declarations +/// FIXME: preserve function definitions in case #2 + Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, + TemplateParameterList *TemplateParams) { // Check whether there is already a function template specialization for // this declaration. FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); void *InsertPos = 0; - if (FunctionTemplate) { + if (FunctionTemplate && !TemplateParams) { llvm::FoldingSetNodeID ID; - FunctionTemplateSpecializationInfo::Profile(ID, - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size()); - - FunctionTemplateSpecializationInfo *Info - = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID, + FunctionTemplateSpecializationInfo::Profile(ID, + TemplateArgs.getInnermost().getFlatArgumentList(), + TemplateArgs.getInnermost().flat_size(), + SemaRef.Context); + + FunctionTemplateSpecializationInfo *Info + = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); - + // If we already have a function template specialization, return it. if (Info) return Info->Function; } - + Sema::LocalInstantiationScope Scope(SemaRef); - + llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = InstantiateFunctionType(D, Params); + QualType T = SubstFunctionType(D, Params); if (T.isNull()) return 0; - + // Build the instantiated method declaration. - FunctionDecl *Function - = FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getDeclName(), T, D->getStorageClass(), - D->isInline(), D->hasWrittenPrototype(), - D->getTypeSpecStartLoc()); - - // FIXME: friend functions - + DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(), + TemplateArgs); + FunctionDecl *Function = + FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), + D->getDeclName(), T, D->getDeclaratorInfo(), + D->getStorageClass(), + D->isInline(), D->hasWrittenPrototype()); + Function->setLexicalDeclContext(Owner); + // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Function); Function->setParams(SemaRef.Context, Params.data(), Params.size()); - + + if (TemplateParams) { + // Our resulting instantiation is actually a function template, since we + // are substituting only the outer template parameters. For example, given + // + // template<typename T> + // struct X { + // template<typename U> friend void f(T, U); + // }; + // + // X<int> x; + // + // We are instantiating the friend function template "f" within X<int>, + // which means substituting int for T, but leaving "f" as a friend function + // template. + // Build the function template itself. + FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner, + Function->getLocation(), + Function->getDeclName(), + TemplateParams, Function); + Function->setDescribedFunctionTemplate(FunctionTemplate); + FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + } + if (InitFunctionInstantiation(Function, D)) Function->setInvalidDecl(); - + bool Redeclaration = false; bool OverloadableAttrRequired = false; + NamedDecl *PrevDecl = 0; - SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration, + if (TemplateParams || !FunctionTemplate) { + // Look only into the namespace where the friend would be declared to + // find a previous declaration. This is the innermost enclosing namespace, + // as described in ActOnFriendFunctionDecl. + Sema::LookupResult R; + SemaRef.LookupQualifiedName(R, DC, Function->getDeclName(), + Sema::LookupOrdinaryName, true); + + PrevDecl = R.getAsSingleDecl(SemaRef.Context); + + // In C++, the previous declaration we find might be a tag type + // (class or enum). In this case, the new declaration will hide the + // tag type. Note that this does does not apply if we're declaring a + // typedef (C++ [dcl.typedef]p4). + if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) + PrevDecl = 0; + } + + SemaRef.CheckFunctionDeclaration(Function, PrevDecl, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); - if (FunctionTemplate) { + // If the original function was part of a friend declaration, + // inherit its namespace state and add it to the owner. + NamedDecl *FromFriendD + = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D; + if (FromFriendD->getFriendObjectKind()) { + NamedDecl *ToFriendD = 0; + if (TemplateParams) { + ToFriendD = cast<NamedDecl>(FunctionTemplate); + PrevDecl = FunctionTemplate->getPreviousDeclaration(); + } else { + ToFriendD = Function; + PrevDecl = Function->getPreviousDeclaration(); + } + ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL); + if (!Owner->isDependentContext() && !PrevDecl) + DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false); + + if (!TemplateParams) + Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + } + + if (FunctionTemplate && !TemplateParams) { // Record this function template specialization. Function->setFunctionTemplateSpecialization(SemaRef.Context, FunctionTemplate, - &TemplateArgs, + &TemplateArgs.getInnermost(), InsertPos); - } + } return Function; } -Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { - // FIXME: Look for existing, explicit specializations. +Decl * +TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams) { + FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); + void *InsertPos = 0; + if (FunctionTemplate && !TemplateParams) { + // We are creating a function template specialization from a function + // template. Check whether there is already a function template + // specialization for this particular set of template arguments. + llvm::FoldingSetNodeID ID; + FunctionTemplateSpecializationInfo::Profile(ID, + TemplateArgs.getInnermost().getFlatArgumentList(), + TemplateArgs.getInnermost().flat_size(), + SemaRef.Context); + + FunctionTemplateSpecializationInfo *Info + = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID, + InsertPos); + + // If we already have a function template specialization, return it. + if (Info) + return Info->Function; + } + Sema::LocalInstantiationScope Scope(SemaRef); llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = InstantiateFunctionType(D, Params); + QualType T = SubstFunctionType(D, Params); if (T.isNull()) return 0; // Build the instantiated method declaration. CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); - CXXMethodDecl *Method - = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), - D->getDeclName(), T, D->isStatic(), - D->isInline()); - Method->setInstantiationOfMemberFunction(D); + CXXMethodDecl *Method = 0; + + DeclarationName Name = D->getDeclName(); + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); + Name = SemaRef.Context.DeclarationNames.getCXXConstructorName( + SemaRef.Context.getCanonicalType(ClassTy)); + Method = CXXConstructorDecl::Create(SemaRef.Context, Record, + Constructor->getLocation(), + Name, T, + Constructor->getDeclaratorInfo(), + Constructor->isExplicit(), + Constructor->isInline(), false); + } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { + QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); + Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( + SemaRef.Context.getCanonicalType(ClassTy)); + Method = CXXDestructorDecl::Create(SemaRef.Context, Record, + Destructor->getLocation(), Name, + T, Destructor->isInline(), false); + } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { + CanQualType ConvTy + = SemaRef.Context.getCanonicalType( + T->getAs<FunctionType>()->getResultType()); + Name = SemaRef.Context.DeclarationNames.getCXXConversionFunctionName( + ConvTy); + Method = CXXConversionDecl::Create(SemaRef.Context, Record, + Conversion->getLocation(), Name, + T, Conversion->getDeclaratorInfo(), + Conversion->isInline(), + Conversion->isExplicit()); + } else { + Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), + D->getDeclName(), T, D->getDeclaratorInfo(), + D->isStatic(), D->isInline()); + } + + if (TemplateParams) { + // Our resulting instantiation is actually a function template, since we + // are substituting only the outer template parameters. For example, given + // + // template<typename T> + // struct X { + // template<typename U> void f(T, U); + // }; + // + // X<int> x; + // + // We are instantiating the member template "f" within X<int>, which means + // substituting int for T, but leaving "f" as a member function template. + // Build the function template itself. + FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Record, + Method->getLocation(), + Method->getDeclName(), + TemplateParams, Method); + if (D->isOutOfLine()) + FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + Method->setDescribedFunctionTemplate(FunctionTemplate); + } else if (!FunctionTemplate) + Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + + // If we are instantiating a member function defined + // out-of-line, the instantiation will have the same lexical + // context (which will be a namespace scope) as the template. + if (D->isOutOfLine()) + Method->setLexicalDeclContext(D->getLexicalDeclContext()); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) @@ -379,167 +724,78 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { if (InitMethodInstantiation(Method, D)) Method->setInvalidDecl(); - NamedDecl *PrevDecl - = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(), - Sema::LookupOrdinaryName, true); - // In C++, the previous declaration we find might be a tag type - // (class or enum). In this case, the new declaration will hide the - // tag type. Note that this does does not apply if we're declaring a - // typedef (C++ [dcl.typedef]p4). - if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) - PrevDecl = 0; + NamedDecl *PrevDecl = 0; + + if (!FunctionTemplate || TemplateParams) { + Sema::LookupResult R; + SemaRef.LookupQualifiedName(R, Owner, Name, Sema::LookupOrdinaryName, true); + PrevDecl = R.getAsSingleDecl(SemaRef.Context); + + // In C++, the previous declaration we find might be a tag type + // (class or enum). In this case, the new declaration will hide the + // tag type. Note that this does does not apply if we're declaring a + // typedef (C++ [dcl.typedef]p4). + if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) + PrevDecl = 0; + } + + if (FunctionTemplate && !TemplateParams) + // Record this function template specialization. + Method->setFunctionTemplateSpecialization(SemaRef.Context, + FunctionTemplate, + &TemplateArgs.getInnermost(), + InsertPos); + bool Redeclaration = false; bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration, + SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); - if (!Method->isInvalidDecl() || !PrevDecl) + if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) && + !Method->getFriendObjectKind()) Owner->addDecl(Method); + return Method; } Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { - // FIXME: Look for existing, explicit specializations. - Sema::LocalInstantiationScope Scope(SemaRef); - - llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = InstantiateFunctionType(D, Params); - if (T.isNull()) - return 0; - - // Build the instantiated method declaration. - CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); - QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); - DeclarationName Name - = SemaRef.Context.DeclarationNames.getCXXConstructorName( - SemaRef.Context.getCanonicalType(ClassTy)); - CXXConstructorDecl *Constructor - = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(), - Name, T, D->isExplicit(), D->isInline(), - false); - Constructor->setInstantiationOfMemberFunction(D); - - // Attach the parameters - for (unsigned P = 0; P < Params.size(); ++P) - Params[P]->setOwningFunction(Constructor); - Constructor->setParams(SemaRef.Context, Params.data(), Params.size()); - - if (InitMethodInstantiation(Constructor, D)) - Constructor->setInvalidDecl(); - - NamedDecl *PrevDecl - = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true); - - // In C++, the previous declaration we find might be a tag type - // (class or enum). In this case, the new declaration will hide the - // tag type. Note that this does does not apply if we're declaring a - // typedef (C++ [dcl.typedef]p4). - if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) - PrevDecl = 0; - bool Redeclaration = false; - bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); - - Record->addedConstructor(SemaRef.Context, Constructor); - Owner->addDecl(Constructor); - return Constructor; + return VisitCXXMethodDecl(D); } Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { - // FIXME: Look for existing, explicit specializations. - Sema::LocalInstantiationScope Scope(SemaRef); - - llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = InstantiateFunctionType(D, Params); - if (T.isNull()) - return 0; - assert(Params.size() == 0 && "Destructor with parameters?"); - - // Build the instantiated destructor declaration. - CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); - QualType ClassTy = - SemaRef.Context.getCanonicalType(SemaRef.Context.getTypeDeclType(Record)); - CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(SemaRef.Context, Record, - D->getLocation(), - SemaRef.Context.DeclarationNames.getCXXDestructorName(ClassTy), - T, D->isInline(), false); - Destructor->setInstantiationOfMemberFunction(D); - if (InitMethodInstantiation(Destructor, D)) - Destructor->setInvalidDecl(); - - bool Redeclaration = false; - bool OverloadableAttrRequired = false; - NamedDecl *PrevDecl = 0; - SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); - Owner->addDecl(Destructor); - return Destructor; + return VisitCXXMethodDecl(D); } Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { - // FIXME: Look for existing, explicit specializations. - Sema::LocalInstantiationScope Scope(SemaRef); - - llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = InstantiateFunctionType(D, Params); - if (T.isNull()) - return 0; - assert(Params.size() == 0 && "Destructor with parameters?"); - - // Build the instantiated conversion declaration. - CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); - QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); - QualType ConvTy - = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType()); - CXXConversionDecl *Conversion - = CXXConversionDecl::Create(SemaRef.Context, Record, - D->getLocation(), - SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy), - T, D->isInline(), D->isExplicit()); - Conversion->setInstantiationOfMemberFunction(D); - if (InitMethodInstantiation(Conversion, D)) - Conversion->setInvalidDecl(); - - bool Redeclaration = false; - bool OverloadableAttrRequired = false; - NamedDecl *PrevDecl = 0; - SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); - Owner->addDecl(Conversion); - return Conversion; + return VisitCXXMethodDecl(D); } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs, + QualType OrigT = SemaRef.SubstType(D->getOriginalType(), TemplateArgs, D->getLocation(), D->getDeclName()); if (OrigT.isNull()) return 0; QualType T = SemaRef.adjustParameterType(OrigT); - if (D->getDefaultArg()) { - // FIXME: Leave a marker for "uninstantiated" default - // arguments. They only get instantiated on demand at the call - // site. - unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning, - "sorry, dropping default argument during template instantiation"); - SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID) - << D->getDefaultArg()->getSourceRange(); - } - // Allocate the parameter ParmVarDecl *Param = 0; if (T == OrigT) Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), T, D->getStorageClass(), - 0); + D->getIdentifier(), T, D->getDeclaratorInfo(), + D->getStorageClass(), 0); else - Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner, + Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), - T, OrigT, D->getStorageClass(), 0); - + T, D->getDeclaratorInfo(), OrigT, + D->getStorageClass(), 0); + + // Mark the default argument as being uninstantiated. + if (D->hasUninstantiatedDefaultArg()) + Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg()); + else if (Expr *Arg = D->getDefaultArg()) + Param->setUninstantiatedDefaultArg(Arg); + // Note: we don't try to instantiate function parameters until after // we've instantiated the function's type. Therefore, we don't have // to check for 'void' parameter types here. @@ -556,41 +812,130 @@ TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { return VisitParmVarDecl(D); } -Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner, - const TemplateArgumentList &TemplateArgs) { +Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( + TemplateTypeParmDecl *D) { + // TODO: don't always clone when decls are refcounted. + const Type* T = D->getTypeForDecl(); + assert(T->isTemplateTypeParmType()); + const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>(); + + TemplateTypeParmDecl *Inst = + TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + TTPT->getDepth(), TTPT->getIndex(), + TTPT->getName(), + D->wasDeclaredWithTypename(), + D->isParameterPack()); + + if (D->hasDefaultArgument()) { + QualType DefaultPattern = D->getDefaultArgument(); + QualType DefaultInst + = SemaRef.SubstType(DefaultPattern, TemplateArgs, + D->getDefaultArgumentLoc(), + D->getDeclName()); + + Inst->setDefaultArgument(DefaultInst, + D->getDefaultArgumentLoc(), + D->defaultArgumentWasInherited() /* preserve? */); + } + + return Inst; +} + +Decl * +TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { + NestedNameSpecifier *NNS = + SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(), + D->getTargetNestedNameRange(), + TemplateArgs); + if (!NNS) + return 0; + + CXXScopeSpec SS; + SS.setRange(D->getTargetNestedNameRange()); + SS.setScopeRep(NNS); + + NamedDecl *UD = + SemaRef.BuildUsingDeclaration(D->getLocation(), SS, + D->getTargetNameLocation(), + D->getTargetName(), 0, D->isTypeName()); + if (UD) + SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD), + D); + return UD; +} + +Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); return Instantiator.Visit(D); } -/// \brief Instantiates the type of the given function, including -/// instantiating all of the function parameters. +/// \brief Instantiates a nested template parameter list in the current +/// instantiation context. /// -/// \param D The function that we will be instantiated +/// \param L The parameter list to instantiate +/// +/// \returns NULL if there was an error +TemplateParameterList * +TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { + // Get errors for all the parameters before bailing out. + bool Invalid = false; + + unsigned N = L->size(); + typedef llvm::SmallVector<NamedDecl *, 8> ParamVector; + ParamVector Params; + Params.reserve(N); + for (TemplateParameterList::iterator PI = L->begin(), PE = L->end(); + PI != PE; ++PI) { + NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI)); + Params.push_back(D); + Invalid = Invalid || !D; + } + + // Clean up if we had an error. + if (Invalid) { + for (ParamVector::iterator PI = Params.begin(), PE = Params.end(); + PI != PE; ++PI) + if (*PI) + (*PI)->Destroy(SemaRef.Context); + return NULL; + } + + TemplateParameterList *InstL + = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), + L->getLAngleLoc(), &Params.front(), N, + L->getRAngleLoc()); + return InstL; +} + +/// \brief Does substitution on the type of the given function, including +/// all of the function parameters. +/// +/// \param D The function whose type will be the basis of the substitution /// /// \param Params the instantiated parameter declarations -/// \returns the instantiated function's type if successfull, a NULL +/// \returns the instantiated function's type if successful, a NULL /// type if there was an error. -QualType -TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, +QualType +TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, llvm::SmallVectorImpl<ParmVarDecl *> &Params) { bool InvalidDecl = false; - // Instantiate the function parameters + // Substitute all of the function's formal parameter types. TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs); llvm::SmallVector<QualType, 4> ParamTys; - for (FunctionDecl::param_iterator P = D->param_begin(), + for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) { if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) { if (PInst->getType()->isVoidType()) { SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type); PInst->setInvalidDecl(); - } - else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), - PInst->getType(), - diag::err_abstract_type_in_decl, - Sema::AbstractParamType)) + } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), + PInst->getType(), + diag::err_abstract_type_in_decl, + Sema::AbstractParamType)) PInst->setInvalidDecl(); Params.push_back(PInst); @@ -598,7 +943,7 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, if (PInst->isInvalidDecl()) InvalidDecl = true; - } else + } else InvalidDecl = true; } @@ -606,11 +951,11 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, if (InvalidDecl) return QualType(); - const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType(); + const FunctionProtoType *Proto = D->getType()->getAs<FunctionProtoType>(); assert(Proto && "Missing prototype?"); - QualType ResultType - = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs, - D->getLocation(), D->getDeclName()); + QualType ResultType + = SemaRef.SubstType(Proto->getResultType(), TemplateArgs, + D->getLocation(), D->getDeclName()); if (ResultType.isNull()) return QualType(); @@ -619,21 +964,21 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, D->getLocation(), D->getDeclName()); } -/// \brief Initializes the common fields of an instantiation function +/// \brief Initializes the common fields of an instantiation function /// declaration (New) from the corresponding fields of its template (Tmpl). /// /// \returns true if there was an error -bool -TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, +bool +TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl) { if (Tmpl->isDeleted()) New->setDeleted(); - + // If we are performing substituting explicitly-specified template arguments // or deduced template arguments into a function template and we reach this // point, we are now past the point where SFINAE applies and have committed - // to keeping the new function template specialization. We therefore - // convert the active template instantiation for the function template + // to keeping the new function template specialization. We therefore + // convert the active template instantiation for the function template // into a template instantiation for this specific function template // specialization, which is not a SFINAE context, so that we diagnose any // further errors in the declaration itself. @@ -641,15 +986,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back(); if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { - if (FunctionTemplateDecl *FunTmpl + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) { - assert(FunTmpl->getTemplatedDecl() == Tmpl && + assert(FunTmpl->getTemplatedDecl() == Tmpl && "Deduction from the wrong function template?"); + (void) FunTmpl; ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = reinterpret_cast<uintptr_t>(New); } } - + return false; } @@ -658,18 +1004,19 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, /// (Tmpl). /// /// \returns true if there was an error -bool -TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, +bool +TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl) { if (InitFunctionInstantiation(New, Tmpl)) return true; - + CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); New->setAccess(Tmpl->getAccess()); if (Tmpl->isVirtualAsWritten()) { New->setVirtualAsWritten(true); Record->setAggregate(false); Record->setPOD(false); + Record->setEmpty(false); Record->setPolymorphic(true); } if (Tmpl->isPure()) { @@ -702,12 +1049,25 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, 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 = 0; - if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) + if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) { + while (Primary->getInstantiatedFromMemberTemplate()) { + // If we have hit a point where the user provided a specialization of + // this template, we're done looking. + if (Primary->isMemberSpecialization()) + break; + + Primary = Primary->getInstantiatedFromMemberTemplate(); + } + PatternDecl = Primary->getTemplatedDecl(); - else + } else PatternDecl = Function->getInstantiatedFromMemberFunction(); Stmt *Pattern = 0; if (PatternDecl) @@ -716,6 +1076,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (!Pattern) return; + // C++0x [temp.explicit]p9: + // Except for inline functions, other explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. + if (Function->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration && + PatternDecl->isOutOfLine() && !PatternDecl->isInline()) + return; + InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) return; @@ -726,13 +1095,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations; if (Recursive) PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); - + ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be // recorded. LocalInstantiationScope Scope(*this); - + // Introduce the instantiated function parameters into the local // instantiation scope. for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) @@ -744,23 +1113,35 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, DeclContext *PreviousContext = CurContext; CurContext = Function; + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Function); + + // If this is a constructor, instantiate the member initializers. + if (const CXXConstructorDecl *Ctor = + dyn_cast<CXXConstructorDecl>(PatternDecl)) { + InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor, + TemplateArgs); + } + // Instantiate the function body. - OwningStmtResult Body - = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function)); + OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs); - ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), + if (Body.isInvalid()) + Function->setInvalidDecl(); + + ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), /*IsInstantiation=*/true); CurContext = PreviousContext; DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); - + if (Recursive) { // Instantiate any pending implicit instantiations found during the - // instantiation of this template. + // instantiation of this template. PerformPendingImplicitInstantiations(); - + // Restore the set of pending implicit instantiations. PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); } @@ -769,35 +1150,296 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, /// \brief Instantiate the definition of the given variable from its /// template. /// -/// \param Var the already-instantiated declaration of a variable. -void Sema::InstantiateVariableDefinition(VarDecl *Var) { - // FIXME: Implement this! +/// \param PointOfInstantiation the point at which the instantiation was +/// required. Note that this is not precisely a "point of instantiation" +/// for the function, but it's close. +/// +/// \param Var the already-instantiated declaration of a static member +/// variable of a class template specialization. +/// +/// \param Recursive if true, recursively instantiates any functions that +/// are required by this instantiation. +void Sema::InstantiateStaticDataMemberDefinition( + SourceLocation PointOfInstantiation, + VarDecl *Var, + bool Recursive) { + if (Var->isInvalidDecl()) + return; + + // Find the out-of-line definition of this static data member. + VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); + bool FoundOutOfLineDef = false; + assert(Def && "This data member was not instantiated from a template?"); + assert(Def->isStaticDataMember() && "Not a static data member?"); + for (VarDecl::redecl_iterator RD = Def->redecls_begin(), + RDEnd = Def->redecls_end(); + RD != RDEnd; ++RD) { + if (RD->getLexicalDeclContext()->isFileContext()) { + Def = *RD; + FoundOutOfLineDef = true; + } + } + + if (!FoundOutOfLineDef) { + // We did not find an out-of-line definition of this static data member, + // so we won't perform any instantiation. Rather, we rely on the user to + // instantiate this definition (or provide a specialization for it) in + // another translation unit. + return; + } + + // Never instantiate an explicit specialization. + if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + + // C++0x [temp.explicit]p9: + // Except for inline functions, other explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. + if (Def->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return; + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); + if (Inst) + return; + + // If we're performing recursive template instantiation, create our own + // queue of pending implicit instantiations that we will instantiate later, + // while we're still within our own instantiation context. + std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations; + if (Recursive) + PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + DeclContext *PreviousContext = CurContext; + CurContext = Var->getDeclContext(); + + Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), + getTemplateInstantiationArgs(Var))); + + CurContext = PreviousContext; + + if (Var) { + DeclGroupRef DG(Var); + Consumer.HandleTopLevelDecl(DG); + } + + if (Recursive) { + // Instantiate any pending implicit instantiations found during the + // instantiation of this template. + PerformPendingImplicitInstantiations(); + + // Restore the set of pending implicit instantiations. + PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + } +} + +void +Sema::InstantiateMemInitializers(CXXConstructorDecl *New, + const CXXConstructorDecl *Tmpl, + const MultiLevelTemplateArgumentList &TemplateArgs) { + + llvm::SmallVector<MemInitTy*, 4> NewInits; + + // Instantiate all the initializers. + for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(), + InitsEnd = Tmpl->init_end(); + Inits != InitsEnd; ++Inits) { + CXXBaseOrMemberInitializer *Init = *Inits; + + ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this); + + // Instantiate all the arguments. + for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end(); + Args != ArgsEnd; ++Args) { + OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs); + + if (NewArg.isInvalid()) + New->setInvalidDecl(); + else + NewArgs.push_back(NewArg.takeAs<Expr>()); + } + + MemInitResult NewInit; + + if (Init->isBaseInitializer()) { + QualType BaseType(Init->getBaseClass(), 0); + BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(), + New->getDeclName()); + + NewInit = BuildBaseInitializer(BaseType, + (Expr **)NewArgs.data(), + NewArgs.size(), + Init->getSourceLocation(), + Init->getRParenLoc(), + New->getParent()); + } else if (Init->isMemberInitializer()) { + FieldDecl *Member; + + // Is this an anonymous union? + if (FieldDecl *UnionInit = Init->getAnonUnionMember()) + Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit, TemplateArgs)); + else + Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember(), + TemplateArgs)); + + NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), + NewArgs.size(), + Init->getSourceLocation(), + Init->getRParenLoc()); + } + + if (NewInit.isInvalid()) + New->setInvalidDecl(); + else { + // FIXME: It would be nice if ASTOwningVector had a release function. + NewArgs.take(); + + NewInits.push_back((MemInitTy *)NewInit.get()); + } + } + + // Assign all the initializers to the new constructor. + ActOnMemInitializers(DeclPtrTy::make(New), + /*FIXME: ColonLoc */ + SourceLocation(), + NewInits.data(), NewInits.size()); +} + +// TODO: this could be templated if the various decl types used the +// same method name. +static bool isInstantiationOf(ClassTemplateDecl *Pattern, + ClassTemplateDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberTemplate(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(FunctionTemplateDecl *Pattern, + FunctionTemplateDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberTemplate(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(CXXRecordDecl *Pattern, + CXXRecordDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberClass(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(FunctionDecl *Pattern, + FunctionDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberFunction(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(EnumDecl *Pattern, + EnumDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberEnum(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(UnresolvedUsingDecl *Pattern, + UsingDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; +} + +static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, + VarDecl *Instance) { + assert(Instance->isStaticDataMember()); + + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromStaticDataMember(); + } while (Instance); + + return false; } static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { - if (D->getKind() != Other->getKind()) + if (D->getKind() != Other->getKind()) { + if (UnresolvedUsingDecl *UUD = dyn_cast<UnresolvedUsingDecl>(D)) { + if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { + return isInstantiationOf(UUD, UD, Ctx); + } + } + return false; + } if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other)) - return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass()) - == Ctx.getCanonicalDecl(D); + return isInstantiationOf(cast<CXXRecordDecl>(D), Record); if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other)) - return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction()) - == Ctx.getCanonicalDecl(D); + return isInstantiationOf(cast<FunctionDecl>(D), Function); if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other)) - return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum()) - == Ctx.getCanonicalDecl(D); + return isInstantiationOf(cast<EnumDecl>(D), Enum); + + if (VarDecl *Var = dyn_cast<VarDecl>(Other)) + if (Var->isStaticDataMember()) + return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var); + + if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other)) + return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp); + + if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other)) + return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp); - // FIXME: How can we find instantiations of anonymous unions? + if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) { + if (!Field->getDeclName()) { + // This is an unnamed field. + return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) == + cast<FieldDecl>(D); + } + } return D->getDeclName() && isa<NamedDecl>(Other) && D->getDeclName() == cast<NamedDecl>(Other)->getDeclName(); } template<typename ForwardIterator> -static NamedDecl *findInstantiationOf(ASTContext &Ctx, +static NamedDecl *findInstantiationOf(ASTContext &Ctx, NamedDecl *D, ForwardIterator first, ForwardIterator last) { @@ -808,6 +1450,18 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx, return 0; } +/// \brief Finds the instantiation of the given declaration context +/// within the current instantiation. +/// +/// \returns NULL if there was an error +DeclContext *Sema::FindInstantiatedContext(DeclContext* DC, + const MultiLevelTemplateArgumentList &TemplateArgs) { + if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) { + Decl* ID = FindInstantiatedDecl(D, TemplateArgs); + return cast_or_null<DeclContext>(ID); + } else return DC; +} + /// \brief Find the instantiation of the given declaration within the /// current instantiation. /// @@ -834,7 +1488,24 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx, /// X<T>::<Kind>::KnownValue) to its instantiation /// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs /// this mapping from within the instantiation of X<int>. -NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) { +NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs) { + if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) { + // Transform all of the elements of the overloaded function set. + OverloadedFunctionDecl *Result + = OverloadedFunctionDecl::Create(Context, CurContext, Ovl->getDeclName()); + + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) { + Result->addOverload( + AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F, + TemplateArgs))); + } + + return Result; + } + DeclContext *ParentDC = D->getDeclContext(); if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) { // D is a local of some kind. Look into the map of local @@ -842,14 +1513,71 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) { return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D)); } - if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) { - ParentDecl = InstantiateCurrentDeclRef(ParentDecl); - if (!ParentDecl) - return 0; + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { + if (!Record->isDependentContext()) + return D; + + // If the RecordDecl is actually the injected-class-name or a "templated" + // declaration for a class template or class template partial + // specialization, substitute into the injected-class-name of the + // class template or partial specialization to find the new DeclContext. + QualType T; + ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); + + if (ClassTemplate) { + T = ClassTemplate->getInjectedClassNameType(Context); + } else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) { + T = Context.getTypeDeclType(Record); + ClassTemplate = PartialSpec->getSpecializedTemplate(); + } + + if (!T.isNull()) { + // Substitute into the injected-class-name to get the type corresponding + // to the instantiation we want. This substitution should never fail, + // since we know we can instantiate the injected-class-name or we wouldn't + // have gotten to the injected-class-name! + // FIXME: Can we use the CurrentInstantiationScope to avoid this extra + // instantiation in the common case? + T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName()); + assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); + + if (!T->isDependentType()) { + assert(T->isRecordType() && "Instantiation must produce a record type"); + return T->getAs<RecordType>()->getDecl(); + } + + // We are performing "partial" template instantiation to create the + // member declarations for the members of a class template + // specialization. Therefore, D is actually referring to something in + // the current instantiation. Look through the current context, + // which contains actual instantiations, to find the instantiation of + // the "current instantiation" that D refers to. + for (DeclContext *DC = CurContext; !DC->isFileContext(); + DC = DC->getParent()) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) + if (isInstantiationOf(ClassTemplate, + Spec->getSpecializedTemplate())) + return Spec; + } - ParentDC = cast<DeclContext>(ParentDecl); + assert(false && + "Unable to find declaration for the current instantiation"); + return Record; + } + + // Fall through to deal with other dependent record types (e.g., + // anonymous unions in class templates). } + if (!ParentDC->isDependentContext()) + return D; + + ParentDC = FindInstantiatedContext(ParentDC, TemplateArgs); + if (!ParentDC) + return 0; + if (ParentDC != D->getDeclContext()) { // We performed some kind of instantiation in the parent context, // so now we need to look into the instantiated parent context to @@ -867,51 +1595,47 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) { // - unnamed class/struct/union/enum within a template // // FIXME: Find a better way to find these instantiations! - Result = findInstantiationOf(Context, D, + Result = findInstantiationOf(Context, D, ParentDC->decls_begin(), ParentDC->decls_end()); } + assert(Result && "Unable to find instantiation of declaration!"); D = Result; } - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) - if (ClassTemplateDecl *ClassTemplate - = Record->getDescribedClassTemplate()) { - // When the declaration D was parsed, it referred to the current - // instantiation. Therefore, look through the current context, - // which contains actual instantiations, to find the - // instantiation of the "current instantiation" that D refers - // to. Alternatively, we could just instantiate the - // injected-class-name with the current template arguments, but - // such an instantiation is far more expensive. - for (DeclContext *DC = CurContext; !DC->isFileContext(); - DC = DC->getParent()) { - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(DC)) - if (Context.getCanonicalDecl(Spec->getSpecializedTemplate()) - == Context.getCanonicalDecl(ClassTemplate)) - return Spec; - } - - assert(false && - "Unable to find declaration for the current instantiation"); - } - return D; } -/// \brief Performs template instantiation for all implicit template +/// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. void Sema::PerformPendingImplicitInstantiations() { while (!PendingImplicitInstantiations.empty()) { PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front(); PendingImplicitInstantiations.pop_front(); - - if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) + + // Instantiate function definitions + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) { + PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Function), + Function->getLocation(), *this, + Context.getSourceManager(), + "instantiating function definition"); + if (!Function->getBody()) InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); - - // FIXME: instantiate static member variables + continue; + } + + // Instantiate static data member definitions. + VarDecl *Var = cast<VarDecl>(Inst.first); + assert(Var->isStaticDataMember() && "Not a static data member?"); + + PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Var), + Var->getLocation(), *this, + Context.getSourceManager(), + "instantiating static data member " + "definition"); + + InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true); } } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 3756df870c2c2..3cdf6154232bd 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -13,9 +13,12 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/Expr.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/SmallPtrSet.h" using namespace clang; @@ -23,8 +26,8 @@ using namespace clang; /// \brief Perform adjustment on the parameter type of a function. /// /// This routine adjusts the given parameter type @p T to the actual -/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], -/// C++ [dcl.fct]p3). The adjusted parameter type is returned. +/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], +/// C++ [dcl.fct]p3). The adjusted parameter type is returned. QualType Sema::adjustParameterType(QualType T) { // C99 6.7.5.3p7: if (T->isArrayType()) { @@ -48,15 +51,17 @@ QualType Sema::adjustParameterType(QualType T) { /// object. /// \param DS the declaration specifiers /// \param DeclLoc The location of the declarator identifier or invalid if none. +/// \param SourceTy QualType representing the type as written in source form. /// \returns The type described by the declaration specifiers. This function /// never returns null. QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &isInvalid) { + bool &isInvalid, QualType &SourceTy) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. QualType Result; - + SourceTy = Result; + switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: Result = Context.VoidTy; @@ -87,14 +92,28 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = Context.getUnsignedWCharType(); } break; + case DeclSpec::TST_char16: + assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && + "Unknown TSS value"); + Result = Context.Char16Ty; + break; + case DeclSpec::TST_char32: + assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && + "Unknown TSS value"); + Result = Context.Char32Ty; + break; case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ, + SourceTy = Context.getObjCProtocolListType(QualType(), + (ObjCProtocolDecl**)PQ, + DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, + (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); break; } - + // Unspecified typespec defaults to int in C90. However, the C90 grammar // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, // type-qualifier, or storage-class-specifier. If not, emit an extwarn. @@ -125,7 +144,7 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) { Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); - + // When this occurs in C++ code, often something is very broken with the // value being declared, poison it as invalid so we don't get chains of // errors. @@ -135,8 +154,8 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, << DS.getSourceRange(); } } - - // FALL THROUGH. + + // FALL THROUGH. case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { switch (DS.getTypeSpecWidth()) { @@ -175,40 +194,64 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_union: case DeclSpec::TST_struct: { Decl *D = static_cast<Decl *>(DS.getTypeRep()); - assert(D && "Didn't get a decl for a class/enum/union/struct?"); + if (!D) { + // This can happen in C++ with ambiguous lookups. + Result = Context.IntTy; + isInvalid = true; + break; + } + assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); // TypeQuals handled by caller. Result = Context.getTypeDeclType(cast<TypeDecl>(D)); - + + // In C++, make an ElaboratedType. + if (getLangOptions().CPlusPlus) { + TagDecl::TagKind Tag + = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType()); + Result = Context.getElaboratedType(Result, Tag); + } + if (D->isInvalidDecl()) isInvalid = true; break; - } + } case DeclSpec::TST_typename: { assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); - Result = QualType::getFromOpaquePtr(DS.getTypeRep()); + Result = GetTypeFromParser(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have - // this "hack" for now... - if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType()) - Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(), - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); - else if (Result == Context.getObjCIdType()) - // id<protocol-list> - Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ, + SourceTy = Context.getObjCProtocolListType(Result, + (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); - else if (Result == Context.getObjCClassType()) { + 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()) + // id<protocol-list> + Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, + (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); + else if (Result->isObjCClassType()) { if (DeclLoc.isInvalid()) DeclLoc = DS.getSourceRange().getBegin(); // Class<protocol-list> - Diag(DeclLoc, diag::err_qualified_class_unsupported) - << DS.getSourceRange(); + Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy, + (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); } else { if (DeclLoc.isInvalid()) DeclLoc = DS.getSourceRange().getBegin(); @@ -217,17 +260,18 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, isInvalid = true; } } - + // If this is a reference to an invalid typedef, propagate the invalidity. if (TypedefType *TDT = dyn_cast<TypedefType>(Result)) if (TDT->getDecl()->isInvalidDecl()) isInvalid = true; - + // TypeQuals handled by caller. break; } case DeclSpec::TST_typeofType: - Result = QualType::getFromOpaquePtr(DS.getTypeRep()); + // FIXME: Preserve type source info. + Result = GetTypeFromParser(DS.getTypeRep()); assert(!Result.isNull() && "Didn't get a type for typeof?"); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); @@ -255,73 +299,75 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = Context.UndeducedAutoTy; break; } - + case DeclSpec::TST_error: Result = Context.IntTy; isInvalid = true; break; } - + // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { if (getLangOptions().Freestanding) Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } - + assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && "FIXME: imaginary types not supported yet!"); - + // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) ProcessTypeAttributeList(Result, AL); - + // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." C++ also allows // restrict-qualified references. - if (TypeQuals & QualType::Restrict) { + if (TypeQuals & DeclSpec::TQ_restrict) { if (Result->isPointerType() || Result->isReferenceType()) { - QualType EltTy = Result->isPointerType() ? - Result->getAsPointerType()->getPointeeType() : - Result->getAsReferenceType()->getPointeeType(); - + QualType EltTy = Result->isPointerType() ? + Result->getAs<PointerType>()->getPointeeType() : + Result->getAs<ReferenceType>()->getPointeeType(); + // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); - TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. + TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } else { Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); - TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. + TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } - + // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification // of a function type includes any type qualifiers, the behavior is // undefined." if (Result->isFunctionType() && TypeQuals) { // Get some location to point at, either the C or V location. SourceLocation Loc; - if (TypeQuals & QualType::Const) + if (TypeQuals & DeclSpec::TQ_const) Loc = DS.getConstSpecLoc(); - else { - assert((TypeQuals & QualType::Volatile) && - "Has CV quals but not C or V?"); + else if (TypeQuals & DeclSpec::TQ_volatile) Loc = DS.getVolatileSpecLoc(); + else { + assert((TypeQuals & DeclSpec::TQ_restrict) && + "Has CVR quals but not C, V, or R?"); + Loc = DS.getRestrictSpecLoc(); } Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); } - + // C++ [dcl.ref]p1: // Cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef @@ -330,19 +376,23 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // FIXME: Shouldn't we be checking SCS_typedef here? if (DS.getTypeSpecType() == DeclSpec::TST_typename && TypeQuals && Result->isReferenceType()) { - TypeQuals &= ~QualType::Const; - TypeQuals &= ~QualType::Volatile; - } - - Result = Result.getQualifiedType(TypeQuals); + TypeQuals &= ~DeclSpec::TQ_const; + TypeQuals &= ~DeclSpec::TQ_volatile; + } + + Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals); + Result = Context.getQualifiedType(Result, Quals); } + + if (SourceTy.isNull()) + SourceTy = Result; return Result; } static std::string getPrintableNameForEntity(DeclarationName Entity) { if (Entity) return Entity.getAsString(); - + return "type name"; } @@ -361,7 +411,7 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) { /// /// \returns A suitable pointer type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildPointerType(QualType T, unsigned Quals, +QualType Sema::BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity) { if (T->isReferenceType()) { // C++ 8.3.2p4: There shall be no ... pointers to references ... @@ -370,23 +420,25 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, return QualType(); } + Qualifiers Qs = Qualifiers::fromCVRMask(Quals); + // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." - if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + if (Qs.hasRestrict() && !T->isIncompleteOrObjectType()) { Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; - Quals &= ~QualType::Restrict; + Qs.removeRestrict(); } // Build the pointer type. - return Context.getPointerType(T).getQualifiedType(Quals); + return Context.getQualifiedType(Context.getPointerType(T), Qs); } /// \brief Build a reference type. /// /// \param T The type to which we'll be building a reference. /// -/// \param Quals The cvr-qualifiers to be applied to the reference type. +/// \param CVR The cvr-qualifiers to be applied to the reference type. /// /// \param Loc The location of the entity whose type involves this /// reference type or, if there is no such entity, the location of the @@ -397,22 +449,23 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, /// /// \returns A suitable reference type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, +QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR, SourceLocation Loc, DeclarationName Entity) { + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); if (LValueRef) { - if (const RValueReferenceType *R = T->getAsRValueReferenceType()) { + if (const RValueReferenceType *R = T->getAs<RValueReferenceType>()) { // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a // reference to a type T, and attempt to create the type "lvalue // reference to cv TD" creates the type "lvalue reference to T". // We use the qualifiers (restrict or none) of the original reference, // not the new ones. This is consistent with GCC. - return Context.getLValueReferenceType(R->getPointeeType()). - getQualifiedType(T.getCVRQualifiers()); + QualType LVRT = Context.getLValueReferenceType(R->getPointeeType()); + return Context.getQualifiedType(LVRT, T.getQualifiers()); } } if (T->isReferenceType()) { // C++ [dcl.ref]p4: There shall be no references to references. - // + // // According to C++ DR 106, references to references are only // diagnosed when they are written directly (e.g., "int & &"), // but not when they happen via a typedef: @@ -420,7 +473,7 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, // typedef int& intref; // typedef intref& intref2; // - // Parser::ParserDeclaratorInternal diagnoses the case where + // Parser::ParseDeclaratorInternal diagnoses the case where // references are written directly; here, we handle the // collapsing of references-to-references as described in C++ // DR 106 and amended by C++ DR 540. @@ -428,7 +481,7 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, } // C++ [dcl.ref]p1: - // A declarator that specifies the type “reference to cv void” + // A declarator that specifies the type "reference to cv void" // is ill-formed. if (T->isVoidType()) { Diag(Loc, diag::err_reference_to_void); @@ -437,10 +490,10 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." - if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) { Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; - Quals &= ~QualType::Restrict; + Quals.removeRestrict(); } // C++ [dcl.ref]p1: @@ -452,13 +505,13 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, // We diagnose extraneous cv-qualifiers for the non-typedef, // non-template type argument case within the parser. Here, we just // ignore any extraneous cv-qualifiers. - Quals &= ~QualType::Const; - Quals &= ~QualType::Volatile; + Quals.removeConst(); + Quals.removeVolatile(); // Handle restrict on references. if (LValueRef) - return Context.getLValueReferenceType(T).getQualifiedType(Quals); - return Context.getRValueReferenceType(T).getQualifiedType(Quals); + return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals); + return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals); } /// \brief Build an array type. @@ -466,8 +519,8 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, /// \param T The type of each element in the array. /// /// \param ASM C99 array size modifier (e.g., '*', 'static'). -/// -/// \param ArraySize Expression describing the size of the array. +/// +/// \param ArraySize Expression describing the size of the array. /// /// \param Quals The cvr-qualifiers to be applied to the array's /// element type. @@ -483,10 +536,12 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, /// returns a NULL type. QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, - SourceLocation Loc, DeclarationName Entity) { - // C99 6.7.5.2p1: If the element type is an incomplete or function type, + SourceRange Brackets, DeclarationName Entity) { + + SourceLocation Loc = Brackets.getBegin(); + // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (RequireCompleteType(Loc, T, + if (RequireCompleteType(Loc, T, diag::err_illegal_decl_array_incomplete_type)) return QualType(); @@ -495,21 +550,21 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, << getPrintableNameForEntity(Entity); return QualType(); } - + // C++ 8.3.2p4: There shall be no ... arrays of references ... if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_array_of_references) << getPrintableNameForEntity(Entity); return QualType(); - } + } if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) { - Diag(Loc, diag::err_illegal_decl_array_of_auto) + Diag(Loc, diag::err_illegal_decl_array_of_auto) << getPrintableNameForEntity(Entity); return QualType(); } - - if (const RecordType *EltTy = T->getAsRecordType()) { + + if (const RecordType *EltTy = T->getAs<RecordType>()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. if (EltTy->getDecl()->hasFlexibleArrayMember()) @@ -518,7 +573,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Diag(Loc, diag::err_objc_array_of_interfaces) << T; return QualType(); } - + // C99 6.7.5.2p1: The size expression shall have integer type. if (ArraySize && !ArraySize->isTypeDependent() && !ArraySize->getType()->isIntegerType()) { @@ -530,16 +585,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, llvm::APSInt ConstVal(32); if (!ArraySize) { if (ASM == ArrayType::Star) - T = Context.getVariableArrayType(T, 0, ASM, Quals); + T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets); else T = Context.getIncompleteArrayType(T, ASM, Quals); } else if (ArraySize->isValueDependent()) { - T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals); + T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || (!T->isDependentType() && !T->isConstantSizeType())) { // Per C99, a variable array is an array with either a non-constant // size or an element type that has a non-constant-size - T = Context.getVariableArrayType(T, ArraySize, ASM, Quals); + T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. @@ -554,17 +609,20 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); } - } - T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); + } + T = Context.getConstantArrayWithExprType(T, ConstVal, ArraySize, + ASM, Quals, Brackets); } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOptions().C99) { - if (ArraySize && !ArraySize->isTypeDependent() && - !ArraySize->isValueDependent() && + if (ArraySize && !ArraySize->isTypeDependent() && + !ArraySize->isValueDependent() && !ArraySize->isIntegerConstantExpr(Context)) - Diag(Loc, diag::ext_vla); + Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla); else if (ASM != ArrayType::Normal || Quals != 0) - Diag(Loc, diag::ext_c99_array_usage); + Diag(Loc, + getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx + : diag::ext_c99_array_usage); } return T; @@ -573,14 +631,14 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, /// \brief Build an ext-vector type. /// /// Run the required checks for the extended vector type. -QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize, +QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize, SourceLocation AttrLoc) { Expr *Arg = (Expr *)ArraySize.get(); // unlike gcc's vector_size attribute, we do not allow vectors to be defined // in conjunction with complex types (pointers, arrays, functions, etc.). - if (!T->isDependentType() && + if (!T->isDependentType() && !T->isIntegerType() && !T->isRealFloatingType()) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T; return QualType(); @@ -593,25 +651,25 @@ QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize, << "ext_vector_type" << Arg->getSourceRange(); return QualType(); } - - // unlike gcc's vector_size attribute, the size is specified as the + + // unlike gcc's vector_size attribute, the size is specified as the // number of elements, not the number of bytes. - unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); - + unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); + if (vectorSize == 0) { Diag(AttrLoc, diag::err_attribute_zero_size) << Arg->getSourceRange(); return QualType(); } - + if (!T->isDependentType()) return Context.getExtVectorType(T, vectorSize); - } - - return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(), + } + + return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(), AttrLoc); } - + /// \brief Build a function type. /// /// This routine checks the function type according to C++ rules and @@ -642,7 +700,7 @@ QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize, /// \returns A suitable function type, if there are no /// errors. Otherwise, returns a NULL type. QualType Sema::BuildFunctionType(QualType T, - QualType *ParamTypes, + QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, SourceLocation Loc, DeclarationName Entity) { @@ -650,7 +708,7 @@ QualType Sema::BuildFunctionType(QualType T, Diag(Loc, diag::err_func_returning_array_function) << T; return QualType(); } - + bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { QualType ParamType = adjustParameterType(ParamTypes[Idx]); @@ -659,29 +717,31 @@ QualType Sema::BuildFunctionType(QualType T, Invalid = true; } - ParamTypes[Idx] = ParamType; + ParamTypes[Idx] = adjustFunctionParamType(ParamType); } if (Invalid) return QualType(); - return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, + return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, Quals); } - + /// \brief Build a member pointer type \c T Class::*. /// /// \param T the type to which the member pointer refers. /// \param Class the class type into which the member pointer points. -/// \param Quals Qualifiers applied to the member pointer type +/// \param CVR Qualifiers applied to the member pointer type /// \param Loc the location where this type begins /// \param Entity the name of the entity that will have this member pointer type /// /// \returns a member pointer type, if successful, or a NULL type if there was /// an error. -QualType Sema::BuildMemberPointerType(QualType T, QualType Class, - unsigned Quals, SourceLocation Loc, +QualType Sema::BuildMemberPointerType(QualType T, QualType Class, + unsigned CVR, SourceLocation Loc, DeclarationName Entity) { + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + // Verify that we're not building a pointer to pointer to function with // exception specification. if (CheckDistantExceptionSpec(T)) { @@ -711,13 +771,13 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." - if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) { Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; // FIXME: If we're doing this as part of template instantiation, // we should return immediately. - Quals &= ~QualType::Restrict; + Quals.removeRestrict(); } if (!Class->isDependentType() && !Class->isRecordType()) { @@ -725,15 +785,15 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, return QualType(); } - return Context.getMemberPointerType(T, Class.getTypePtr()) - .getQualifiedType(Quals); + return Context.getQualifiedType( + Context.getMemberPointerType(T, Class.getTypePtr()), Quals); } - + /// \brief Build a block pointer type. /// /// \param T The type to which we'll be building a block pointer. /// -/// \param Quals The cvr-qualifiers to be applied to the block pointer type. +/// \param CVR The cvr-qualifiers to be applied to the block pointer type. /// /// \param Loc The location of the entity whose type involves this /// block pointer type or, if there is no such entity, the location of the @@ -744,15 +804,28 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, /// /// \returns A suitable block pointer type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals, - SourceLocation Loc, +QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR, + SourceLocation Loc, DeclarationName Entity) { - if (!T.getTypePtr()->isFunctionType()) { + if (!T->isFunctionType()) { Diag(Loc, diag::err_nonfunction_block_type); return QualType(); } - - return Context.getBlockPointerType(T).getQualifiedType(Quals); + + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + return Context.getQualifiedType(Context.getBlockPointerType(T), Quals); +} + +QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { + QualType QT = QualType::getFromOpaquePtr(Ty); + DeclaratorInfo *DI = 0; + if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) { + QT = LIT->getType(); + DI = LIT->getDeclaratorInfo(); + } + + if (DInfo) *DInfo = DI; + return QT; } /// GetTypeForDeclarator - Convert the type for the specified @@ -762,7 +835,8 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals, /// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq /// owns the declaration of a type (e.g., the definition of a struct /// type), then *OwnedDecl will receive the owned declaration. -QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, +QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, + DeclaratorInfo **DInfo, unsigned Skip, TagDecl **OwnedDecl) { bool OmittedReturnType = false; @@ -782,10 +856,15 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; + // The QualType referring to the type as written in source code. We can't use + // T because it can change due to semantic analysis. + QualType SourceTy; + switch (D.getKind()) { case Declarator::DK_Abstract: case Declarator::DK_Normal: - case Declarator::DK_Operator: { + case Declarator::DK_Operator: + case Declarator::DK_TemplateId: { const DeclSpec &DS = D.getDeclSpec(); if (OmittedReturnType) { // We default to a dependent type initially. Can be modified by @@ -793,7 +872,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, T = Context.DependentTy; } else { bool isInvalid = false; - T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid); + T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid, SourceTy); if (isInvalid) D.setInvalidType(true); else if (OwnedDecl && DS.isTypeSpecOwned()) @@ -811,10 +890,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, T = Context.VoidTy; break; } + + if (SourceTy.isNull()) + SourceTy = T; if (T == Context.UndeducedAutoTy) { int Error = -1; - + switch (D.getContext()) { case Declarator::KNRTypeListContext: assert(0 && "K&R type lists aren't allowed in C++"); @@ -828,7 +910,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, 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; - } + } break; case Declarator::CXXCatchContext: Error = 4; // Exception declaration @@ -854,12 +936,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, D.setInvalidType(true); } } - + // The name we're declaring, if any. DeclarationName Name; if (D.getIdentifier()) Name = D.getIdentifier(); + bool ShouldBuildInfo = DInfo != 0; + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -868,14 +952,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::BlockPointer: + if (ShouldBuildInfo) { + if (SourceTy->isFunctionType()) + SourceTy + = Context.getQualifiedType(Context.getBlockPointerType(SourceTy), + Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals)); + else + // If not function type Context::getBlockPointerType asserts, + // so just give up. + ShouldBuildInfo = false; + } + // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(DeclType.Loc, diag::err_blocks_disable); - - T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(), + + T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(), Name); break; case DeclaratorChunk::Pointer: + //FIXME: Use ObjCObjectPointer for info when appropriate. + if (ShouldBuildInfo) + SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy), + Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals)); // Verify that we're not building a pointer to pointer to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -883,9 +982,27 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, D.setInvalidType(true); // Build the type anyway. } + if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) { + const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>(); + T = Context.getObjCObjectPointerType(T, + (ObjCProtocolDecl **)OIT->qual_begin(), + OIT->getNumProtocols()); + break; + } T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); break; - case DeclaratorChunk::Reference: + case DeclaratorChunk::Reference: { + Qualifiers Quals; + if (DeclType.Ref.HasRestrict) Quals.addRestrict(); + + if (ShouldBuildInfo) { + if (DeclType.Ref.LValueRef) + SourceTy = Context.getLValueReferenceType(SourceTy); + else + SourceTy = Context.getRValueReferenceType(SourceTy); + SourceTy = Context.getQualifiedType(SourceTy, Quals); + } + // Verify that we're not building a reference to pointer to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -893,11 +1010,16 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, D.setInvalidType(true); // Build the type anyway. } - T = BuildReferenceType(T, DeclType.Ref.LValueRef, - DeclType.Ref.HasRestrict ? QualType::Restrict : 0, + T = BuildReferenceType(T, DeclType.Ref.LValueRef, Quals, DeclType.Loc, Name); break; + } case DeclaratorChunk::Array: { + if (ShouldBuildInfo) + // We just need to get an array type, the exact type doesn't matter. + SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal, + DeclType.Arr.TypeQuals); + // Verify that we're not building an array of pointers to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -923,10 +1045,30 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, ASM = ArrayType::Normal; D.setInvalidType(true); } - T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name); + T = BuildArrayType(T, ASM, ArraySize, + Qualifiers::fromCVRMask(ATI.TypeQuals), + SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; } case DeclaratorChunk::Function: { + if (ShouldBuildInfo) { + const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; + llvm::SmallVector<QualType, 16> ArgTys; + + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); + if (Param) { + QualType ArgTy = adjustFunctionParamType(Param->getType()); + + ArgTys.push_back(ArgTy); + } + } + SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(), + ArgTys.size(), + FTI.isVariadic, + FTI.TypeQuals); + } + // If the function declarator has a prototype (i.e. it is not () and // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). @@ -960,8 +1102,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, // function takes no arguments. llvm::SmallVector<QualType, 4> Exceptions; Exceptions.reserve(FTI.NumExceptions); - for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { - QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty); + for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { + // FIXME: Preserve type source info. + QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty); // Check that the type is valid for an exception spec, and drop it // if not. if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) @@ -993,12 +1136,12 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, } } else if (FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. - Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); + Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); } else { // Otherwise, we have a function with an argument list that is // potentially variadic. llvm::SmallVector<QualType, 16> ArgTys; - + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param.getAs<Decl>()); @@ -1027,28 +1170,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, Param->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. - if (ArgTy.getCVRQualifiers()) + if (ArgTy.hasQualifiers()) Diag(DeclType.Loc, diag::err_void_param_qualified); - + // Do not add 'void' to the ArgTys list. break; } } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { - ArgTy = Context.IntTy; - } else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) { + ArgTy = Context.getPromotedIntegerType(ArgTy); + } else if (const BuiltinType* BTy = ArgTy->getAs<BuiltinType>()) { if (BTy->getKind() == BuiltinType::Float) ArgTy = Context.DoubleTy; } } - - ArgTys.push_back(ArgTy); + + ArgTys.push_back(adjustFunctionParamType(ArgTy)); } llvm::SmallVector<QualType, 4> Exceptions; Exceptions.reserve(FTI.NumExceptions); - for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { - QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty); + for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { + // FIXME: Preserve type source info. + QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty); // Check that the type is valid for an exception spec, and drop it if // not. if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) @@ -1074,11 +1218,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, // The scope spec must refer to a class, or be dependent. QualType ClsType; if (isDependentScopeSpecifier(DeclType.Mem.Scope())) { - NestedNameSpecifier *NNS + NestedNameSpecifier *NNS = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep(); assert(NNS->getAsType() && "Nested-name-specifier must name a type"); ClsType = QualType(NNS->getAsType(), 0); - } else if (CXXRecordDecl *RD + } else if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>( computeDeclContext(DeclType.Mem.Scope()))) { ClsType = Context.getTagDeclType(RD); @@ -1090,6 +1234,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, D.setInvalidType(true); } + if (ShouldBuildInfo) { + QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy; + SourceTy = Context.getQualifiedType( + Context.getMemberPointerType(SourceTy, cls.getTypePtr()), + Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals)); + } + if (!ClsType.isNull()) T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals, DeclType.Loc, D.getIdentifier()); @@ -1111,7 +1262,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, } if (getLangOptions().CPlusPlus && T->isFunctionType()) { - const FunctionProtoType *FnTy = T->getAsFunctionProtoType(); + const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>(); assert(FnTy && "Why oh why is there not a FunctionProtoType here ?"); // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type @@ -1122,7 +1273,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && ((D.getContext() != Declarator::MemberContext && (!D.getCXXScopeSpec().isSet() || - !computeDeclContext(D.getCXXScopeSpec())->isRecord())) || + !computeDeclContext(D.getCXXScopeSpec(), /*FIXME:*/true) + ->isRecord())) || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { if (D.isFunctionDeclarator()) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); @@ -1135,103 +1287,130 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, FnTy->getNumArgs(), FnTy->isVariadic(), 0); } } - + // If there were any type attributes applied to the decl itself (not the // type, apply the type attribute to the type!) if (const AttributeList *Attrs = D.getAttributes()) ProcessTypeAttributeList(T, Attrs); - + + if (ShouldBuildInfo) + *DInfo = GetDeclaratorInfoForDeclarator(D, SourceTy, Skip); + return T; } -/// CheckSpecifiedExceptionType - Check if the given type is valid in an -/// exception specification. Incomplete types, or pointers to incomplete types -/// other than void are not allowed. -bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { - // FIXME: This may not correctly work with the fix for core issue 437, - // where a class's own type is considered complete within its body. - - // C++ 15.4p2: A type denoted in an exception-specification shall not denote - // an incomplete type. - if (T->isIncompleteType()) - return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec) - << Range << T << /*direct*/0; - - // C++ 15.4p2: A type denoted in an exception-specification shall not denote - // an incomplete type a pointer or reference to an incomplete type, other - // than (cv) void*. - int kind; - if (const PointerType* IT = T->getAsPointerType()) { - T = IT->getPointeeType(); - kind = 1; - } else if (const ReferenceType* IT = T->getAsReferenceType()) { - T = IT->getPointeeType(); - kind = 2; - } else - return false; +static void FillTypeSpecLoc(TypeLoc TSL, const DeclSpec &DS) { + if (TSL.isNull()) return; - if (T->isIncompleteType() && !T->isVoidType()) - return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec) - << Range << T << /*indirect*/kind; + if (TypedefLoc *TL = dyn_cast<TypedefLoc>(&TSL)) { + TL->setNameLoc(DS.getTypeSpecTypeLoc()); - return false; -} + } else if (ObjCInterfaceLoc *TL = dyn_cast<ObjCInterfaceLoc>(&TSL)) { + TL->setNameLoc(DS.getTypeSpecTypeLoc()); -/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer -/// to member to a function with an exception specification. This means that -/// it is invalid to add another level of indirection. -bool Sema::CheckDistantExceptionSpec(QualType T) { - if (const PointerType *PT = T->getAsPointerType()) - T = PT->getPointeeType(); - else if (const MemberPointerType *PT = T->getAsMemberPointerType()) - T = PT->getPointeeType(); - else - return false; + } else if (ObjCProtocolListLoc *PLL = dyn_cast<ObjCProtocolListLoc>(&TSL)) { + assert(PLL->getNumProtocols() == DS.getNumProtocolQualifiers()); + PLL->setLAngleLoc(DS.getProtocolLAngleLoc()); + PLL->setRAngleLoc(DS.getSourceRange().getEnd()); + for (unsigned i = 0; i != DS.getNumProtocolQualifiers(); ++i) + PLL->setProtocolLoc(i, DS.getProtocolLocs()[i]); + FillTypeSpecLoc(PLL->getBaseTypeLoc(), DS); - const FunctionProtoType *FnT = T->getAsFunctionProtoType(); - if (!FnT) - return false; - - return FnT->hasExceptionSpec(); + } else { + //FIXME: Other typespecs. + DefaultTypeSpecLoc &DTL = cast<DefaultTypeSpecLoc>(TSL); + DTL.setStartLoc(DS.getSourceRange().getBegin()); + } } -/// CheckEquivalentExceptionSpec - Check if the two types have equivalent -/// exception specifications. Exception specifications are equivalent if -/// they allow exactly the same set of exception types. It does not matter how -/// that is achieved. See C++ [except.spec]p2. -bool Sema::CheckEquivalentExceptionSpec( - const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc) { - bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec(); - bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec(); - if (OldAny && NewAny) - return false; - if (OldAny || NewAny) { - Diag(NewLoc, diag::err_mismatched_exception_spec); - Diag(OldLoc, diag::note_previous_declaration); - return true; - } +/// \brief Create and instantiate a DeclaratorInfo with type source information. +/// +/// \param T QualType referring to the type as written in source code. +DeclaratorInfo * +Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) { + DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); + TypeLoc CurrTL = DInfo->getTypeLoc(); - bool Success = true; - // Both have a definite exception spec. Collect the first set, then compare - // to the second. - llvm::SmallPtrSet<const Type*, 8> Types; - for (FunctionProtoType::exception_iterator I = Old->exception_begin(), - E = Old->exception_end(); I != E; ++I) - Types.insert(Context.getCanonicalType(*I).getTypePtr()); + for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { + assert(!CurrTL.isNull()); - for (FunctionProtoType::exception_iterator I = New->exception_begin(), - E = New->exception_end(); I != E && Success; ++I) - Success = Types.erase(Context.getCanonicalType(*I).getTypePtr()); + DeclaratorChunk &DeclType = D.getTypeObject(i); + switch (DeclType.Kind) { + default: assert(0 && "Unknown decltype!"); + case DeclaratorChunk::BlockPointer: { + BlockPointerLoc &BPL = cast<BlockPointerLoc>(CurrTL); + BPL.setCaretLoc(DeclType.Loc); + break; + } + case DeclaratorChunk::Pointer: { + //FIXME: ObjCObject pointers. + PointerLoc &PL = cast<PointerLoc>(CurrTL); + PL.setStarLoc(DeclType.Loc); + break; + } + case DeclaratorChunk::Reference: { + ReferenceLoc &RL = cast<ReferenceLoc>(CurrTL); + RL.setAmpLoc(DeclType.Loc); + break; + } + case DeclaratorChunk::Array: { + DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; + ArrayLoc &AL = cast<ArrayLoc>(CurrTL); + AL.setLBracketLoc(DeclType.Loc); + AL.setRBracketLoc(DeclType.EndLoc); + AL.setSizeExpr(static_cast<Expr*>(ATI.NumElts)); + //FIXME: Star location for [*]. + break; + } + case DeclaratorChunk::Function: { + const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; + FunctionLoc &FL = cast<FunctionLoc>(CurrTL); + FL.setLParenLoc(DeclType.Loc); + FL.setRParenLoc(DeclType.EndLoc); + for (unsigned i = 0, e = FTI.NumArgs, tpi = 0; i != e; ++i) { + ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); + if (Param) { + assert(tpi < FL.getNumArgs()); + FL.setArg(tpi++, Param); + } + } + break; + //FIXME: Exception specs. + } + case DeclaratorChunk::MemberPointer: { + MemberPointerLoc &MPL = cast<MemberPointerLoc>(CurrTL); + MPL.setStarLoc(DeclType.Loc); + //FIXME: Class location. + break; + } - Success = Success && Types.empty(); + } - if (Success) { - return false; + CurrTL = CurrTL.getNextTypeLoc(); } - Diag(NewLoc, diag::err_mismatched_exception_spec); - Diag(OldLoc, diag::note_previous_declaration); - return true; + + FillTypeSpecLoc(CurrTL, D.getDeclSpec()); + + return DInfo; +} + +/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. +QualType Sema::CreateLocInfoType(QualType T, DeclaratorInfo *DInfo) { + // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser + // and Sema during declaration parsing. Try deallocating/caching them when + // it's appropriate, instead of allocating them and keeping them around. + LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), 8); + new (LocT) LocInfoType(T, DInfo); + assert(LocT->getTypeClass() != T->getTypeClass() && + "LocInfoType's TypeClass conflicts with an existing Type class"); + return QualType(LocT, 0); +} + +void LocInfoType::getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const { + assert(false && "LocInfoType leaked into the type system; an opaque TypeTy*" + " was used directly instead of getting the QualType through" + " GetTypeFromParser"); } /// ObjCGetTypeForMethodDefinition - Builds the type for a method definition @@ -1240,7 +1419,7 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>()); QualType T = MDecl->getResultType(); llvm::SmallVector<QualType, 16> ArgTys; - + // Add the first two invisible argument types for self and _cmd. if (MDecl->isInstanceMethod()) { QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface()); @@ -1249,7 +1428,7 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { } else ArgTys.push_back(Context.getObjCIdType()); ArgTys.push_back(Context.getObjCSelType()); - + for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(), E = MDecl->param_end(); PI != E; ++PI) { QualType ArgTy = (*PI)->getType(); @@ -1271,16 +1450,16 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { /// be called in a loop that successively "unwraps" pointer and /// pointer-to-member types to compare them at each level. bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) { - const PointerType *T1PtrType = T1->getAsPointerType(), - *T2PtrType = T2->getAsPointerType(); + const PointerType *T1PtrType = T1->getAs<PointerType>(), + *T2PtrType = T2->getAs<PointerType>(); if (T1PtrType && T2PtrType) { T1 = T1PtrType->getPointeeType(); T2 = T2PtrType->getPointeeType(); return true; } - const MemberPointerType *T1MPType = T1->getAsMemberPointerType(), - *T2MPType = T2->getAsMemberPointerType(); + const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(), + *T2MPType = T2->getAs<MemberPointerType>(); if (T1MPType && T2MPType && Context.getCanonicalType(T1MPType->getClass()) == Context.getCanonicalType(T2MPType->getClass())) { @@ -1295,9 +1474,10 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // C99 6.7.6: Type names have no identifier. This is already validated by // the parser. assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); - + + DeclaratorInfo *DInfo = 0; TagDecl *OwnedTag = 0; - QualType T = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedTag); + QualType T = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag); if (D.isInvalidType()) return true; @@ -1314,6 +1494,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { << Context.getTypeDeclType(OwnedTag); } + if (DInfo) + T = CreateLocInfoType(T, DInfo); + return T.getAsOpaquePtr(); } @@ -1326,8 +1509,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. -static void HandleAddressSpaceTypeAttribute(QualType &Type, +static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ + // If this type is already address space qualified, reject it. // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers // for two or more different address spaces." @@ -1335,7 +1519,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); return; } - + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -1349,43 +1533,76 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, return; } - unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()); + // Bounds checking. + if (addrSpace.isSigned()) { + if (addrSpace.isNegative()) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative) + << ASArgExpr->getSourceRange(); + return; + } + addrSpace.setIsSigned(false); + } + llvm::APSInt max(addrSpace.getBitWidth()); + max = Qualifiers::MaxAddressSpace; + if (addrSpace > max) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high) + << Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange(); + return; + } + + unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()); Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } /// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the /// specified type. The attribute contains 1 argument, weak or strong. -static void HandleObjCGCTypeAttribute(QualType &Type, +static void HandleObjCGCTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S) { - if (Type.getObjCGCAttr() != QualType::GCNone) { + if (Type.getObjCGCAttr() != Qualifiers::GCNone) { S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); return; } - + // Check the attribute arguments. - if (!Attr.getParameterName()) { + if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_gc" << 1; return; } - QualType::GCAttrTypes GCAttr; + Qualifiers::GC GCAttr; if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - if (Attr.getParameterName()->isStr("weak")) - GCAttr = QualType::Weak; + if (Attr.getParameterName()->isStr("weak")) + GCAttr = Qualifiers::Weak; else if (Attr.getParameterName()->isStr("strong")) - GCAttr = QualType::Strong; + GCAttr = Qualifiers::Strong; else { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "objc_gc" << Attr.getParameterName(); return; } - + Type = S.Context.getObjCGCQualType(Type, GCAttr); } +/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the +/// specified type. The attribute contains 0 arguments. +static void HandleNoReturnTypeAttribute(QualType &Type, + const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) + return; + + // We only apply this to a pointer to function or a pointer to block. + if (!Type->isFunctionPointerType() + && !Type->isBlockPointerType() + && !Type->isFunctionType()) + return; + + Type = S.Context.getNoReturnType(Type); +} + void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the @@ -1402,11 +1619,14 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { case AttributeList::AT_objc_gc: HandleObjCGCTypeAttribute(Result, *AL, *this); break; + case AttributeList::AT_noreturn: + HandleNoReturnTypeAttribute(Result, *AL, *this); + break; } } } -/// @brief Ensure that the type T is a complete type. +/// @brief Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any /// context where a complete type is required. If @p T is a complete @@ -1421,31 +1641,21 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { /// /// @param T The type that this routine is examining for completeness. /// -/// @param diag The diagnostic value (e.g., -/// @c diag::err_typecheck_decl_incomplete_type) that will be used -/// for the error message if @p T is incomplete. -/// -/// @param Range1 An optional range in the source code that will be a -/// part of the "incomplete type" error message. -/// -/// @param Range2 An optional range in the source code that will be a -/// part of the "incomplete type" error message. -/// -/// @param PrintType If non-NULL, the type that should be printed -/// instead of @p T. This parameter should be used when the type that -/// we're checking for incompleteness isn't the type that should be -/// displayed to the user, e.g., when T is a type and PrintType is a -/// pointer to T. +/// @param PD The partial diagnostic that will be printed out if T is not a +/// complete type. /// /// @returns @c true if @p T is incomplete and a diagnostic was emitted, /// @c false otherwise. -bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, - SourceRange Range1, SourceRange Range2, - QualType PrintType) { +bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD, + std::pair<SourceLocation, + PartialDiagnostic> Note) { + unsigned diag = PD.getDiagID(); + // FIXME: Add this assertion to help us flush out problems with // checking for dependent types and type-dependent expressions. // - // assert(!T->isDependentType() && + // assert(!T->isDependentType() && // "Can't ask whether a dependent type is complete"); // If we have a complete type, we're done. @@ -1454,49 +1664,54 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, // If we have a class template specialization or a class member of a // class template specialization, try to instantiate it. - if (const RecordType *Record = T->getAsRecordType()) { + if (const RecordType *Record = T->getAs<RecordType>()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) { - // Update the class template specialization's location to - // refer to the point of instantiation. if (Loc.isValid()) - ClassTemplateSpec->setLocation(Loc); + ClassTemplateSpec->setPointOfInstantiation(Loc); return InstantiateClassTemplateSpecialization(ClassTemplateSpec, - /*ExplicitInstantiation=*/false); + TSK_ImplicitInstantiation, + /*Complain=*/diag != 0); } - } else if (CXXRecordDecl *Rec + } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Record->getDecl())) { if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) { - // Find the class template specialization that surrounds this - // member class. - ClassTemplateSpecializationDecl *Spec = 0; - for (DeclContext *Parent = Rec->getDeclContext(); - Parent && !Spec; Parent = Parent->getParent()) - Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent); - assert(Spec && "Not a member of a class template specialization?"); - return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), - /*ExplicitInstantiation=*/false); + MemberSpecializationInfo *MSInfo = Rec->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); + // This record was instantiated from a class within a template. + if (MSInfo->getTemplateSpecializationKind() + != TSK_ExplicitSpecialization) { + MSInfo->setPointOfInstantiation(Loc); + return InstantiateClass(Loc, Rec, Pattern, + getTemplateInstantiationArgs(Rec), + TSK_ImplicitInstantiation, + /*Complain=*/diag != 0); + } } } } - if (PrintType.isNull()) - PrintType = T; + if (diag == 0) + return true; // We have an incomplete type. Produce a diagnostic. - Diag(Loc, diag) << PrintType << Range1 << Range2; + Diag(Loc, PD) << T; + // If we have a note, produce it. + if (!Note.first.isInvalid()) + Diag(Note.first, Note.second); + // If the type was a forward declaration of a class/struct/union - // type, produce + // type, produce const TagType *Tag = 0; - if (const RecordType *Record = T->getAsRecordType()) + if (const RecordType *Record = T->getAs<RecordType>()) Tag = Record; - else if (const EnumType *Enum = T->getAsEnumType()) + else if (const EnumType *Enum = T->getAs<EnumType>()) Tag = Enum; if (Tag && !Tag->getDecl()->isInvalidDecl()) - Diag(Tag->getDecl()->getLocation(), + Diag(Tag->getDecl()->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined : diag::note_forward_declaration) << QualType(Tag, 0); @@ -1509,7 +1724,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { if (!SS.isSet() || SS.isInvalid() || T.isNull()) return T; - + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); return Context.getQualifiedNameType(NNS, T); @@ -1521,7 +1736,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) { QualType Sema::BuildDecltypeType(Expr *E) { if (E->getType() == Context.OverloadTy) { - Diag(E->getLocStart(), + Diag(E->getLocStart(), diag::err_cannot_determine_declared_type_of_overloaded_function); return QualType(); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h new file mode 100644 index 0000000000000..ec5c6676f5d20 --- /dev/null +++ b/lib/Sema/TreeTransform.h @@ -0,0 +1,4829 @@ +//===------- TreeTransform.h - Semantic Tree Transformation ---------------===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements a semantic tree transformation that takes a given +// AST and rebuilds it, possibly transforming some nodes in the process. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H +#define LLVM_CLANG_SEMA_TREETRANSFORM_H + +#include "Sema.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/Parse/Ownership.h" +#include "clang/Parse/Designator.h" +#include "clang/Lex/Preprocessor.h" +#include <algorithm> + +namespace clang { + +/// \brief A semantic tree transformation that allows one to transform one +/// abstract syntax tree into another. +/// +/// A new tree transformation is defined by creating a new subclass \c X of +/// \c TreeTransform<X> and then overriding certain operations to provide +/// behavior specific to that transformation. For example, template +/// instantiation is implemented as a tree transformation where the +/// transformation of TemplateTypeParmType nodes involves substituting the +/// template arguments for their corresponding template parameters; a similar +/// transformation is performed for non-type template parameters and +/// template template parameters. +/// +/// This tree-transformation template uses static polymorphism to allow +/// subclasses to customize any of its operations. Thus, a subclass can +/// override any of the transformation or rebuild operators by providing an +/// operation with the same signature as the default implementation. The +/// overridding function should not be virtual. +/// +/// Semantic tree transformations are split into two stages, either of which +/// can be replaced by a subclass. The "transform" step transforms an AST node +/// or the parts of an AST node using the various transformation functions, +/// then passes the pieces on to the "rebuild" step, which constructs a new AST +/// node of the appropriate kind from the pieces. The default transformation +/// routines recursively transform the operands to composite AST nodes (e.g., +/// the pointee type of a PointerType node) and, if any of those operand nodes +/// were changed by the transformation, invokes the rebuild operation to create +/// a new AST node. +/// +/// Subclasses can customize the transformation at various levels. The +/// most coarse-grained transformations involve replacing TransformType(), +/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifier(), +/// TransformTemplateName(), or TransformTemplateArgument() with entirely +/// new implementations. +/// +/// For more fine-grained transformations, subclasses can replace any of the +/// \c TransformXXX functions (where XXX is the name of an AST node, e.g., +/// PointerType, StmtExpr) to alter the transformation. As mentioned previously, +/// replacing TransformTemplateTypeParmType() allows template instantiation +/// to substitute template arguments for their corresponding template +/// parameters. Additionally, subclasses can override the \c RebuildXXX +/// functions to control how AST nodes are rebuilt when their operands change. +/// By default, \c TreeTransform will invoke semantic analysis to rebuild +/// AST nodes. However, certain other tree transformations (e.g, cloning) may +/// be able to use more efficient rebuild steps. +/// +/// There are a handful of other functions that can be overridden, allowing one +/// to avoid traversing nodes that don't need any transformation +/// (\c AlreadyTransformed()), force rebuilding AST nodes even when their +/// operands have not changed (\c AlwaysRebuild()), and customize the +/// default locations and entity names used for type-checking +/// (\c getBaseLocation(), \c getBaseEntity()). +template<typename Derived> +class TreeTransform { +protected: + Sema &SemaRef; + +public: + typedef Sema::OwningStmtResult OwningStmtResult; + typedef Sema::OwningExprResult OwningExprResult; + typedef Sema::StmtArg StmtArg; + typedef Sema::ExprArg ExprArg; + typedef Sema::MultiExprArg MultiExprArg; + typedef Sema::MultiStmtArg MultiStmtArg; + + /// \brief Initializes a new tree transformer. + TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } + + /// \brief Retrieves a reference to the derived class. + Derived &getDerived() { return static_cast<Derived&>(*this); } + + /// \brief Retrieves a reference to the derived class. + const Derived &getDerived() const { + return static_cast<const Derived&>(*this); + } + + /// \brief Retrieves a reference to the semantic analysis object used for + /// this tree transform. + Sema &getSema() const { return SemaRef; } + + /// \brief Whether the transformation should always rebuild AST nodes, even + /// if none of the children have changed. + /// + /// Subclasses may override this function to specify when the transformation + /// should rebuild all AST nodes. + bool AlwaysRebuild() { return false; } + + /// \brief Returns the location of the entity being transformed, if that + /// information was not available elsewhere in the AST. + /// + /// By default, returns no source-location information. Subclasses can + /// provide an alternative implementation that provides better location + /// information. + SourceLocation getBaseLocation() { return SourceLocation(); } + + /// \brief Returns the name of the entity being transformed, if that + /// information was not available elsewhere in the AST. + /// + /// By default, returns an empty name. Subclasses can provide an alternative + /// implementation with a more precise name. + DeclarationName getBaseEntity() { return DeclarationName(); } + + /// \brief Sets the "base" location and entity when that + /// information is known based on another transformation. + /// + /// By default, the source location and entity are ignored. Subclasses can + /// override this function to provide a customized implementation. + void setBase(SourceLocation Loc, DeclarationName Entity) { } + + /// \brief RAII object that temporarily sets the base location and entity + /// used for reporting diagnostics in types. + class TemporaryBase { + TreeTransform &Self; + SourceLocation OldLocation; + DeclarationName OldEntity; + + public: + TemporaryBase(TreeTransform &Self, SourceLocation Location, + DeclarationName Entity) : Self(Self) { + OldLocation = Self.getDerived().getBaseLocation(); + OldEntity = Self.getDerived().getBaseEntity(); + Self.getDerived().setBase(Location, Entity); + } + + ~TemporaryBase() { + Self.getDerived().setBase(OldLocation, OldEntity); + } + }; + + /// \brief Determine whether the given type \p T has already been + /// transformed. + /// + /// Subclasses can provide an alternative implementation of this routine + /// to short-circuit evaluation when it is known that a given type will + /// not change. For example, template instantiation need not traverse + /// non-dependent types. + bool AlreadyTransformed(QualType T) { + return T.isNull(); + } + + /// \brief Transforms the given type into another type. + /// + /// By default, this routine transforms a type by delegating to the + /// appropriate TransformXXXType to build a new type, then applying + /// the qualifiers on \p T to the resulting type with AddTypeQualifiers. + /// Subclasses may override this function (to take over all type + /// transformations), some set of the TransformXXXType functions, or + /// the AddTypeQualifiers function to alter the transformation. + /// + /// \returns the transformed type. + QualType TransformType(QualType T); + + /// \brief Transform the given type by adding the given set of qualifiers + /// and returning the result. + /// + /// FIXME: By default, this routine adds type qualifiers only to types that + /// can have qualifiers, and silently suppresses those qualifiers that are + /// not permitted (e.g., qualifiers on reference or function types). This + /// is the right thing for template instantiation, but probably not for + /// other clients. + QualType AddTypeQualifiers(QualType T, Qualifiers Qs); + + /// \brief Transform the given statement. + /// + /// By default, this routine transforms a statement by delegating to the + /// appropriate TransformXXXStmt function to transform a specific kind of + /// statement or the TransformExpr() function to transform an expression. + /// Subclasses may override this function to transform statements using some + /// other mechanism. + /// + /// \returns the transformed statement. + OwningStmtResult TransformStmt(Stmt *S); + + /// \brief Transform the given expression. + /// + /// By default, this routine transforms an expression by delegating to the + /// appropriate TransformXXXExpr function to build a new expression. + /// Subclasses may override this function to transform expressions using some + /// other mechanism. + /// + /// \returns the transformed expression. + OwningExprResult TransformExpr(Expr *E) { + return getDerived().TransformExpr(E, /*isAddressOfOperand=*/false); + } + + /// \brief Transform the given expression. + /// + /// By default, this routine transforms an expression by delegating to the + /// appropriate TransformXXXExpr function to build a new expression. + /// Subclasses may override this function to transform expressions using some + /// other mechanism. + /// + /// \returns the transformed expression. + OwningExprResult TransformExpr(Expr *E, bool isAddressOfOperand); + + /// \brief Transform the given declaration, which is referenced from a type + /// or expression. + /// + /// By default, acts as the identity function on declarations. Subclasses + /// may override this function to provide alternate behavior. + Decl *TransformDecl(Decl *D) { return D; } + + /// \brief Transform the definition of the given declaration. + /// + /// By default, invokes TransformDecl() to transform the declaration. + /// Subclasses may override this function to provide alternate behavior. + Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); } + + /// \brief Transform the given nested-name-specifier. + /// + /// By default, transforms all of the types and declarations within the + /// nested-name-specifier. Subclasses may override this function to provide + /// alternate behavior. + NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = 0); + + /// \brief Transform the given declaration name. + /// + /// By default, transforms the types of conversion function, constructor, + /// and destructor names and then (if needed) rebuilds the declaration name. + /// Identifiers and selectors are returned unmodified. Sublcasses may + /// override this function to provide alternate behavior. + DeclarationName TransformDeclarationName(DeclarationName Name, + SourceLocation Loc); + + /// \brief Transform the given template name. + /// + /// By default, transforms the template name by transforming the declarations + /// and nested-name-specifiers that occur within the template name. + /// Subclasses may override this function to provide alternate behavior. + TemplateName TransformTemplateName(TemplateName Name, + QualType ObjectType = QualType()); + + /// \brief Transform the given template argument. + /// + /// By default, this operation transforms the type, expression, or + /// declaration stored within the template argument and constructs a + /// new template argument from the transformed result. Subclasses may + /// override this function to provide alternate behavior. + TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg); + +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) \ + QualType Transform##CLASS##Type(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); + +#define STMT(Node, Parent) \ + OwningStmtResult Transform##Node(Node *S); +#define EXPR(Node, Parent) \ + OwningExprResult Transform##Node(Node *E); +#define ABSTRACT_EXPR(Node, Parent) +#include "clang/AST/StmtNodes.def" + + /// \brief Build a new pointer type given its pointee type. + /// + /// By default, performs semantic analysis when building the pointer type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildPointerType(QualType PointeeType); + + /// \brief Build a new block pointer type given its pointee type. + /// + /// By default, performs semantic analysis when building the block pointer + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildBlockPointerType(QualType PointeeType); + + /// \brief Build a new lvalue reference type given the type it references. + /// + /// By default, performs semantic analysis when building the lvalue reference + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildLValueReferenceType(QualType ReferentType); + + /// \brief Build a new rvalue reference type given the type it references. + /// + /// By default, performs semantic analysis when building the rvalue reference + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildRValueReferenceType(QualType ReferentType); + + /// \brief Build a new member pointer type given the pointee type and the + /// class type it refers into. + /// + /// By default, performs semantic analysis when building the member pointer + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType); + + /// \brief Build a new array type given the element type, size + /// modifier, size of the array (if known), size expression, and index type + /// qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + /// Also by default, all of the other Rebuild*Array + QualType RebuildArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt *Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new constant array type given the element type, size + /// modifier, (known) size of the array, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildConstantArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals); + + /// \brief Build a new constant array type given the element type, size + /// modifier, (known) size of the array, size expression, and index type + /// qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildConstantArrayWithExprType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new constant array type given the element type, size + /// modifier, (known) size of the array, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildConstantArrayWithoutExprType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals); + + /// \brief Build a new incomplete array type given the element type, size + /// modifier, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildIncompleteArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + unsigned IndexTypeQuals); + + /// \brief Build a new variable-length array type given the element type, + /// size modifier, size expression, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildVariableArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new dependent-sized array type given the element type, + /// size modifier, size expression, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildDependentSizedArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new vector type given the element type and + /// number of elements. + /// + /// By default, performs semantic analysis when building the vector type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildVectorType(QualType ElementType, unsigned NumElements); + + /// \brief Build a new extended vector type given the element type and + /// number of elements. + /// + /// By default, performs semantic analysis when building the vector type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildExtVectorType(QualType ElementType, unsigned NumElements, + SourceLocation AttributeLoc); + + /// \brief Build a new potentially dependently-sized extended vector type + /// given the element type and number of elements. + /// + /// By default, performs semantic analysis when building the vector type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildDependentSizedExtVectorType(QualType ElementType, + ExprArg SizeExpr, + SourceLocation AttributeLoc); + + /// \brief Build a new function type. + /// + /// By default, performs semantic analysis when building the function type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildFunctionProtoType(QualType T, + QualType *ParamTypes, + unsigned NumParamTypes, + bool Variadic, unsigned Quals); + + /// \brief Build a new typedef type. + QualType RebuildTypedefType(TypedefDecl *Typedef) { + return SemaRef.Context.getTypeDeclType(Typedef); + } + + /// \brief Build a new class/struct/union type. + QualType RebuildRecordType(RecordDecl *Record) { + return SemaRef.Context.getTypeDeclType(Record); + } + + /// \brief Build a new Enum type. + QualType RebuildEnumType(EnumDecl *Enum) { + 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. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildTypeOfExprType(ExprArg Underlying); + + /// \brief Build a new typeof(type) type. + /// + /// By default, builds a new TypeOfType with the given underlying type. + QualType RebuildTypeOfType(QualType Underlying); + + /// \brief Build a new C++0x decltype type. + /// + /// By default, performs semantic analysis when building the decltype type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildDecltypeType(ExprArg Underlying); + + /// \brief Build a new template specialization type. + /// + /// By default, performs semantic analysis when building the template + /// specialization type. Subclasses may override this routine to provide + /// different behavior. + QualType RebuildTemplateSpecializationType(TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs); + + /// \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); + } + + /// \brief Build a new typename type that refers to a template-id. + /// + /// By default, builds a new TypenameType type from the nested-name-specifier + /// and the given type. Subclasses may override this routine to provide + /// different behavior. + QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) { + if (NNS->isDependent()) + return SemaRef.Context.getTypenameType(NNS, + cast<TemplateSpecializationType>(T)); + + return SemaRef.Context.getQualifiedNameType(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 + /// different behavior. + QualType RebuildTypenameType(NestedNameSpecifier *NNS, + const IdentifierInfo *Id) { + return SemaRef.CheckTypenameType(NNS, *Id, + SourceRange(getDerived().getBaseLocation())); + } + + /// \brief Build a new nested-name-specifier given the prefix and an + /// identifier that names the next step in the nested-name-specifier. + /// + /// By default, performs semantic analysis when building the new + /// nested-name-specifier. Subclasses may override this routine to provide + /// different behavior. + NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, + SourceRange Range, + IdentifierInfo &II, + QualType ObjectType, + NamedDecl *FirstQualifierInScope); + + /// \brief Build a new nested-name-specifier given the prefix and the + /// namespace named in the next step in the nested-name-specifier. + /// + /// By default, performs semantic analysis when building the new + /// nested-name-specifier. Subclasses may override this routine to provide + /// different behavior. + NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, + SourceRange Range, + NamespaceDecl *NS); + + /// \brief Build a new nested-name-specifier given the prefix and the + /// type named in the next step in the nested-name-specifier. + /// + /// By default, performs semantic analysis when building the new + /// nested-name-specifier. Subclasses may override this routine to provide + /// different behavior. + NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, + SourceRange Range, + bool TemplateKW, + QualType T); + + /// \brief Build a new template name given a nested name specifier, a flag + /// indicating whether the "template" keyword was provided, and the template + /// that the template name refers to. + /// + /// By default, builds the new template name directly. Subclasses may override + /// this routine to provide different behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + TemplateDecl *Template); + + /// \brief Build a new template name given a nested name specifier, a flag + /// indicating whether the "template" keyword was provided, and a set of + /// overloaded function templates. + /// + /// By default, builds the new template name directly. Subclasses may override + /// this routine to provide different behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + OverloadedFunctionDecl *Ovl); + + /// \brief Build a new template name given a nested name specifier and the + /// name that is referred to as a template. + /// + /// By default, performs semantic analysis to determine whether the name can + /// be resolved to a specific template, then builds the appropriate kind of + /// template name. Subclasses may override this routine to provide different + /// behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo &II, + QualType ObjectType); + + + /// \brief Build a new compound statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildCompoundStmt(SourceLocation LBraceLoc, + MultiStmtArg Statements, + SourceLocation RBraceLoc, + bool IsStmtExpr) { + return getSema().ActOnCompoundStmt(LBraceLoc, RBraceLoc, move(Statements), + IsStmtExpr); + } + + /// \brief Build a new case statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildCaseStmt(SourceLocation CaseLoc, + ExprArg LHS, + SourceLocation EllipsisLoc, + ExprArg RHS, + SourceLocation ColonLoc) { + return getSema().ActOnCaseStmt(CaseLoc, move(LHS), EllipsisLoc, move(RHS), + ColonLoc); + } + + /// \brief Attach the body to a new case statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildCaseStmtBody(StmtArg S, StmtArg Body) { + getSema().ActOnCaseStmtBody(S.get(), move(Body)); + return move(S); + } + + /// \brief Build a new default statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, + StmtArg SubStmt) { + return getSema().ActOnDefaultStmt(DefaultLoc, ColonLoc, move(SubStmt), + /*CurScope=*/0); + } + + /// \brief Build a new label statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildLabelStmt(SourceLocation IdentLoc, + IdentifierInfo *Id, + SourceLocation ColonLoc, + StmtArg SubStmt) { + return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, move(SubStmt)); + } + + /// \brief Build a new "if" statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond, + StmtArg Then, SourceLocation ElseLoc, + StmtArg Else) { + return getSema().ActOnIfStmt(IfLoc, Cond, move(Then), ElseLoc, move(Else)); + } + + /// \brief Start building a new switch statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildSwitchStmtStart(ExprArg Cond) { + return getSema().ActOnStartOfSwitchStmt(move(Cond)); + } + + /// \brief Attach the body to the switch statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildSwitchStmtBody(SourceLocation SwitchLoc, + StmtArg Switch, StmtArg Body) { + return getSema().ActOnFinishSwitchStmt(SwitchLoc, move(Switch), + move(Body)); + } + + /// \brief Build a new while statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc, + Sema::FullExprArg Cond, + StmtArg Body) { + return getSema().ActOnWhileStmt(WhileLoc, Cond, move(Body)); + } + + /// \brief Build a new do-while statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildDoStmt(SourceLocation DoLoc, StmtArg Body, + SourceLocation WhileLoc, + SourceLocation LParenLoc, + ExprArg Cond, + SourceLocation RParenLoc) { + return getSema().ActOnDoStmt(DoLoc, move(Body), WhileLoc, LParenLoc, + move(Cond), RParenLoc); + } + + /// \brief Build a new for statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg Init, ExprArg Cond, ExprArg Inc, + SourceLocation RParenLoc, StmtArg Body) { + return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), move(Cond), + move(Inc), RParenLoc, move(Body)); + } + + /// \brief Build a new goto statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + LabelStmt *Label) { + return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getID()); + } + + /// \brief Build a new indirect goto statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + ExprArg Target) { + return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(Target)); + } + + /// \brief Build a new return statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildReturnStmt(SourceLocation ReturnLoc, + ExprArg Result) { + + return getSema().ActOnReturnStmt(ReturnLoc, move(Result)); + } + + /// \brief Build a new declaration statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildDeclStmt(Decl **Decls, unsigned NumDecls, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().Owned( + new (getSema().Context) DeclStmt( + DeclGroupRef::Create(getSema().Context, + Decls, NumDecls), + StartLoc, EndLoc)); + } + + /// \brief Build a new C++ exception declaration. + /// + /// By default, performs semantic analysis to build the new decaration. + /// Subclasses may override this routine to provide different behavior. + VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, + DeclaratorInfo *Declarator, + IdentifierInfo *Name, + SourceLocation Loc, + SourceRange TypeRange) { + return getSema().BuildExceptionDeclaration(0, T, Declarator, Name, Loc, + TypeRange); + } + + /// \brief Build a new C++ catch statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildCXXCatchStmt(SourceLocation CatchLoc, + VarDecl *ExceptionDecl, + StmtArg Handler) { + return getSema().Owned( + new (getSema().Context) CXXCatchStmt(CatchLoc, ExceptionDecl, + Handler.takeAs<Stmt>())); + } + + /// \brief Build a new C++ try statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildCXXTryStmt(SourceLocation TryLoc, + StmtArg TryBlock, + MultiStmtArg Handlers) { + return getSema().ActOnCXXTryBlock(TryLoc, move(TryBlock), move(Handlers)); + } + + /// \brief Build a new expression that references a declaration. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildDeclRefExpr(NamedDecl *ND, SourceLocation Loc) { + return getSema().BuildDeclarationNameExpr(Loc, ND, + /*FIXME:*/false, + /*SS=*/0, + /*FIXME:*/false); + } + + /// \brief Build a new expression in parentheses. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildParenExpr(ExprArg SubExpr, SourceLocation LParen, + SourceLocation RParen) { + return getSema().ActOnParenExpr(LParen, RParen, move(SubExpr)); + } + + /// \brief Build a new pseudo-destructor expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base, + SourceLocation OperatorLoc, + bool isArrow, + SourceLocation DestroyedTypeLoc, + QualType DestroyedType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange) { + CXXScopeSpec SS; + if (Qualifier) { + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + } + + DeclarationName Name + = SemaRef.Context.DeclarationNames.getCXXDestructorName( + SemaRef.Context.getCanonicalType(DestroyedType)); + + return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), + OperatorLoc, + isArrow? tok::arrow : tok::period, + DestroyedTypeLoc, + Name, + Sema::DeclPtrTy::make((Decl *)0), + &SS); + } + + /// \brief Build a new unary operator expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildUnaryOperator(SourceLocation OpLoc, + UnaryOperator::Opcode Opc, + ExprArg SubExpr) { + return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(SubExpr)); + } + + /// \brief Build a new sizeof or alignof expression with a type argument. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildSizeOfAlignOf(QualType T, SourceLocation OpLoc, + bool isSizeOf, SourceRange R) { + return getSema().CreateSizeOfAlignOfExpr(T, OpLoc, isSizeOf, R); + } + + /// \brief Build a new sizeof or alignof expression with an expression + /// argument. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildSizeOfAlignOf(ExprArg SubExpr, SourceLocation OpLoc, + bool isSizeOf, SourceRange R) { + OwningExprResult Result + = getSema().CreateSizeOfAlignOfExpr((Expr *)SubExpr.get(), + OpLoc, isSizeOf, R); + if (Result.isInvalid()) + return getSema().ExprError(); + + SubExpr.release(); + return move(Result); + } + + /// \brief Build a new array subscript expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildArraySubscriptExpr(ExprArg LHS, + SourceLocation LBracketLoc, + ExprArg RHS, + SourceLocation RBracketLoc) { + return getSema().ActOnArraySubscriptExpr(/*Scope=*/0, move(LHS), + LBracketLoc, move(RHS), + RBracketLoc); + } + + /// \brief Build a new call expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCallExpr(ExprArg Callee, SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + return getSema().ActOnCallExpr(/*Scope=*/0, move(Callee), LParenLoc, + move(Args), CommaLocs, RParenLoc); + } + + /// \brief Build a new member access expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildMemberExpr(ExprArg Base, SourceLocation OpLoc, + bool isArrow, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + SourceLocation MemberLoc, + NamedDecl *Member) { + if (!Member->getDeclName()) { + // We have a reference to an unnamed field. + assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); + + MemberExpr *ME = + new (getSema().Context) MemberExpr(Base.takeAs<Expr>(), isArrow, + Member, MemberLoc, + cast<FieldDecl>(Member)->getType()); + return getSema().Owned(ME); + } + + CXXScopeSpec SS; + if (Qualifier) { + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + } + + return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, + isArrow? tok::arrow : tok::period, + MemberLoc, + Member->getDeclName(), + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), + &SS); + } + + /// \brief Build a new binary operator expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildBinaryOperator(SourceLocation OpLoc, + BinaryOperator::Opcode Opc, + ExprArg LHS, ExprArg RHS) { + OwningExprResult Result + = getSema().CreateBuiltinBinOp(OpLoc, Opc, (Expr *)LHS.get(), + (Expr *)RHS.get()); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + LHS.release(); + RHS.release(); + return move(Result); + } + + /// \brief Build a new conditional operator expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildConditionalOperator(ExprArg Cond, + SourceLocation QuestionLoc, + ExprArg LHS, + SourceLocation ColonLoc, + ExprArg RHS) { + return getSema().ActOnConditionalOp(QuestionLoc, ColonLoc, move(Cond), + move(LHS), move(RHS)); + } + + /// \brief Build a new implicit cast expression. + /// + /// By default, builds a new implicit cast without any semantic analysis. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildImplicitCastExpr(QualType T, CastExpr::CastKind Kind, + ExprArg SubExpr, bool isLvalue) { + ImplicitCastExpr *ICE + = new (getSema().Context) ImplicitCastExpr(T, Kind, + (Expr *)SubExpr.release(), + isLvalue); + return getSema().Owned(ICE); + } + + /// \brief Build a new C-style cast expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc, + QualType ExplicitTy, + SourceLocation RParenLoc, + ExprArg SubExpr) { + return getSema().ActOnCastExpr(/*Scope=*/0, + LParenLoc, + ExplicitTy.getAsOpaquePtr(), + RParenLoc, + move(SubExpr)); + } + + /// \brief Build a new compound literal expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc, + QualType T, + SourceLocation RParenLoc, + ExprArg Init) { + return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(), + RParenLoc, move(Init)); + } + + /// \brief Build a new extended vector element access expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildExtVectorElementExpr(ExprArg Base, + SourceLocation OpLoc, + SourceLocation AccessorLoc, + IdentifierInfo &Accessor) { + return getSema().ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, + tok::period, AccessorLoc, + Accessor, + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); + } + + /// \brief Build a new initializer list expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildInitList(SourceLocation LBraceLoc, + MultiExprArg Inits, + SourceLocation RBraceLoc) { + return SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc); + } + + /// \brief Build a new designated initializer expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildDesignatedInitExpr(Designation &Desig, + MultiExprArg ArrayExprs, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, + ExprArg Init) { + OwningExprResult Result + = SemaRef.ActOnDesignatedInitializer(Desig, EqualOrColonLoc, GNUSyntax, + move(Init)); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + ArrayExprs.release(); + return move(Result); + } + + /// \brief Build a new value-initialized expression. + /// + /// By default, builds the implicit value initialization without performing + /// any semantic analysis. Subclasses may override this routine to provide + /// different behavior. + OwningExprResult RebuildImplicitValueInitExpr(QualType T) { + return SemaRef.Owned(new (SemaRef.Context) ImplicitValueInitExpr(T)); + } + + /// \brief Build a new \c va_arg expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildVAArgExpr(SourceLocation BuiltinLoc, ExprArg SubExpr, + QualType T, SourceLocation RParenLoc) { + return getSema().ActOnVAArg(BuiltinLoc, move(SubExpr), T.getAsOpaquePtr(), + RParenLoc); + } + + /// \brief Build a new expression list in parentheses. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildParenListExpr(SourceLocation LParenLoc, + MultiExprArg SubExprs, + SourceLocation RParenLoc) { + return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs)); + } + + /// \brief Build a new address-of-label expression. + /// + /// By default, performs semantic analysis, using the name of the label + /// rather than attempting to map the label statement itself. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildAddrLabelExpr(SourceLocation AmpAmpLoc, + SourceLocation LabelLoc, + LabelStmt *Label) { + return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label->getID()); + } + + /// \brief Build a new GNU statement expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildStmtExpr(SourceLocation LParenLoc, + StmtArg SubStmt, + SourceLocation RParenLoc) { + return getSema().ActOnStmtExpr(LParenLoc, move(SubStmt), RParenLoc); + } + + /// \brief Build a new __builtin_types_compatible_p expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildTypesCompatibleExpr(SourceLocation BuiltinLoc, + QualType T1, QualType T2, + SourceLocation RParenLoc) { + return getSema().ActOnTypesCompatibleExpr(BuiltinLoc, + T1.getAsOpaquePtr(), + T2.getAsOpaquePtr(), + RParenLoc); + } + + /// \brief Build a new __builtin_choose_expr expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildChooseExpr(SourceLocation BuiltinLoc, + ExprArg Cond, ExprArg LHS, ExprArg RHS, + SourceLocation RParenLoc) { + return SemaRef.ActOnChooseExpr(BuiltinLoc, + move(Cond), move(LHS), move(RHS), + RParenLoc); + } + + /// \brief Build a new overloaded operator call expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// The semantic analysis provides the behavior of template instantiation, + /// copying with transformations that turn what looks like an overloaded + /// operator call into a use of a builtin operator, performing + /// argument-dependent lookup, etc. Subclasses may override this routine to + /// provide different behavior. + OwningExprResult RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, + SourceLocation OpLoc, + ExprArg Callee, + ExprArg First, + ExprArg Second); + + /// \brief Build a new C++ "named" cast expression, such as static_cast or + /// reinterpret_cast. + /// + /// By default, this routine dispatches to one of the more-specific routines + /// for a particular named case, e.g., RebuildCXXStaticCastExpr(). + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc, + Stmt::StmtClass Class, + SourceLocation LAngleLoc, + QualType T, + SourceLocation RAngleLoc, + SourceLocation LParenLoc, + ExprArg SubExpr, + SourceLocation RParenLoc) { + switch (Class) { + case Stmt::CXXStaticCastExprClass: + return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T, + RAngleLoc, LParenLoc, + move(SubExpr), RParenLoc); + + case Stmt::CXXDynamicCastExprClass: + return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T, + RAngleLoc, LParenLoc, + move(SubExpr), RParenLoc); + + case Stmt::CXXReinterpretCastExprClass: + return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T, + RAngleLoc, LParenLoc, + move(SubExpr), + RParenLoc); + + case Stmt::CXXConstCastExprClass: + return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T, + RAngleLoc, LParenLoc, + move(SubExpr), RParenLoc); + + default: + assert(false && "Invalid C++ named cast"); + break; + } + + return getSema().ExprError(); + } + + /// \brief Build a new C++ static_cast expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc, + SourceLocation LAngleLoc, + QualType T, + SourceLocation RAngleLoc, + SourceLocation LParenLoc, + ExprArg SubExpr, + SourceLocation RParenLoc) { + return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast, + LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, + LParenLoc, move(SubExpr), RParenLoc); + } + + /// \brief Build a new C++ dynamic_cast expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc, + SourceLocation LAngleLoc, + QualType T, + SourceLocation RAngleLoc, + SourceLocation LParenLoc, + ExprArg SubExpr, + SourceLocation RParenLoc) { + return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast, + LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, + LParenLoc, move(SubExpr), RParenLoc); + } + + /// \brief Build a new C++ reinterpret_cast expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc, + SourceLocation LAngleLoc, + QualType T, + SourceLocation RAngleLoc, + SourceLocation LParenLoc, + ExprArg SubExpr, + SourceLocation RParenLoc) { + return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, + LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, + LParenLoc, move(SubExpr), RParenLoc); + } + + /// \brief Build a new C++ const_cast expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc, + SourceLocation LAngleLoc, + QualType T, + SourceLocation RAngleLoc, + SourceLocation LParenLoc, + ExprArg SubExpr, + SourceLocation RParenLoc) { + return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast, + LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, + LParenLoc, move(SubExpr), RParenLoc); + } + + /// \brief Build a new C++ functional-style cast expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange, + QualType T, + SourceLocation LParenLoc, + ExprArg SubExpr, + SourceLocation RParenLoc) { + void *Sub = SubExpr.takeAs<Expr>(); + return getSema().ActOnCXXTypeConstructExpr(TypeRange, + T.getAsOpaquePtr(), + LParenLoc, + Sema::MultiExprArg(getSema(), &Sub, 1), + /*CommaLocs=*/0, + RParenLoc); + } + + /// \brief Build a new C++ typeid(type) expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc, + SourceLocation LParenLoc, + QualType T, + SourceLocation RParenLoc) { + return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true, + T.getAsOpaquePtr(), RParenLoc); + } + + /// \brief Build a new C++ typeid(expr) expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc, + SourceLocation LParenLoc, + ExprArg Operand, + SourceLocation RParenLoc) { + OwningExprResult Result + = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(), + RParenLoc); + if (Result.isInvalid()) + return getSema().ExprError(); + + Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership + return move(Result); + } + + /// \brief Build a new C++ "this" expression. + /// + /// By default, builds a new "this" expression without performing any + /// semantic analysis. Subclasses may override this routine to provide + /// different behavior. + OwningExprResult RebuildCXXThisExpr(SourceLocation ThisLoc, + QualType ThisType) { + return getSema().Owned( + new (getSema().Context) CXXThisExpr(ThisLoc, ThisType)); + } + + /// \brief Build a new C++ throw expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, ExprArg Sub) { + return getSema().ActOnCXXThrow(ThrowLoc, move(Sub)); + } + + /// \brief Build a new C++ default-argument expression. + /// + /// By default, builds a new default-argument expression, which does not + /// require any semantic analysis. Subclasses may override this routine to + /// provide different behavior. + OwningExprResult RebuildCXXDefaultArgExpr(ParmVarDecl *Param) { + return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Param)); + } + + /// \brief Build a new C++ zero-initialization expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXZeroInitValueExpr(SourceLocation TypeStartLoc, + SourceLocation LParenLoc, + QualType T, + SourceLocation RParenLoc) { + return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeStartLoc), + T.getAsOpaquePtr(), LParenLoc, + MultiExprArg(getSema(), 0, 0), + 0, RParenLoc); + } + + /// \brief Build a new C++ conditional declaration expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXConditionDeclExpr(SourceLocation StartLoc, + SourceLocation EqLoc, + VarDecl *Var) { + return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr(StartLoc, + EqLoc, + Var)); + } + + /// \brief Build a new C++ "new" expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXNewExpr(SourceLocation StartLoc, + bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + bool ParenTypeId, + QualType AllocType, + SourceLocation TypeLoc, + SourceRange TypeRange, + ExprArg ArraySize, + SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen) { + return getSema().BuildCXXNew(StartLoc, UseGlobal, + PlacementLParen, + move(PlacementArgs), + PlacementRParen, + ParenTypeId, + AllocType, + TypeLoc, + TypeRange, + move(ArraySize), + ConstructorLParen, + move(ConstructorArgs), + ConstructorRParen); + } + + /// \brief Build a new C++ "delete" expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXDeleteExpr(SourceLocation StartLoc, + bool IsGlobalDelete, + bool IsArrayForm, + ExprArg Operand) { + return getSema().ActOnCXXDelete(StartLoc, IsGlobalDelete, IsArrayForm, + move(Operand)); + } + + /// \brief Build a new unary type trait expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildUnaryTypeTrait(UnaryTypeTrait Trait, + SourceLocation StartLoc, + SourceLocation LParenLoc, + QualType T, + SourceLocation RParenLoc) { + return getSema().ActOnUnaryTypeTrait(Trait, StartLoc, LParenLoc, + T.getAsOpaquePtr(), RParenLoc); + } + + /// \brief Build a new qualified declaration reference expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildQualifiedDeclRefExpr(NestedNameSpecifier *NNS, + SourceRange QualifierRange, + NamedDecl *ND, + SourceLocation Location, + bool IsAddressOfOperand) { + CXXScopeSpec SS; + SS.setRange(QualifierRange); + SS.setScopeRep(NNS); + return getSema().ActOnDeclarationNameExpr(/*Scope=*/0, + Location, + ND->getDeclName(), + /*Trailing lparen=*/false, + &SS, + IsAddressOfOperand); + } + + /// \brief Build a new (previously unresolved) declaration reference + /// expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildUnresolvedDeclRefExpr(NestedNameSpecifier *NNS, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation Location, + bool IsAddressOfOperand) { + CXXScopeSpec SS; + SS.setRange(QualifierRange); + SS.setScopeRep(NNS); + return getSema().ActOnDeclarationNameExpr(/*Scope=*/0, + Location, + Name, + /*Trailing lparen=*/false, + &SS, + IsAddressOfOperand); + } + + /// \brief Build a new template-id expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildTemplateIdExpr(TemplateName Template, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { + return getSema().BuildTemplateIdExpr(Template, TemplateLoc, + LAngleLoc, + TemplateArgs, NumTemplateArgs, + RAngleLoc); + } + + /// \brief Build a new object-construction expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXConstructExpr(QualType T, + CXXConstructorDecl *Constructor, + bool IsElidable, + MultiExprArg Args) { + return getSema().BuildCXXConstructExpr(/*FIXME:ConstructLoc*/ + SourceLocation(), + T, Constructor, IsElidable, + move(Args)); + } + + /// \brief Build a new object-construction expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXTemporaryObjectExpr(SourceLocation TypeBeginLoc, + QualType T, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation *Commas, + SourceLocation RParenLoc) { + return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc), + T.getAsOpaquePtr(), + LParenLoc, + move(Args), + Commas, + RParenLoc); + } + + /// \brief Build a new object-construction expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXUnresolvedConstructExpr(SourceLocation TypeBeginLoc, + QualType T, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation *Commas, + SourceLocation RParenLoc) { + return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc, + /*FIXME*/LParenLoc), + T.getAsOpaquePtr(), + LParenLoc, + move(Args), + Commas, + RParenLoc); + } + + /// \brief Build a new member reference expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation MemberLoc, + NamedDecl *FirstQualifierInScope) { + OwningExprResult Base = move(BaseE); + tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; + + CXXScopeSpec SS; + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + + return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, + move(Base), OperatorLoc, OpKind, + MemberLoc, + Name, + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), + &SS, + FirstQualifierInScope); + } + + /// \brief Build a new member reference expression with explicit template + /// arguments. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, + SourceLocation TemplateNameLoc, + NamedDecl *FirstQualifierInScope, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { + OwningExprResult Base = move(BaseE); + tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; + + CXXScopeSpec SS; + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + + // FIXME: We're going to end up looking up the template based on its name, + // twice! Also, duplicates part of Sema::ActOnMemberTemplateIdReferenceExpr. + DeclarationName Name; + if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) + Name = ActualTemplate->getDeclName(); + else if (OverloadedFunctionDecl *Ovl + = Template.getAsOverloadedFunctionDecl()) + Name = Ovl->getDeclName(); + else + Name = Template.getAsDependentTemplateName()->getName(); + + return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base), + OperatorLoc, OpKind, + TemplateNameLoc, Name, true, + LAngleLoc, TemplateArgs, + NumTemplateArgs, RAngleLoc, + Sema::DeclPtrTy(), &SS); + } + + /// \brief Build a new Objective-C @encode expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc, + QualType T, + SourceLocation RParenLoc) { + return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, T, + RParenLoc)); + } + + /// \brief Build a new Objective-C protocol expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCProtocolExpr(ObjCProtocolDecl *Protocol, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return SemaRef.Owned(SemaRef.ParseObjCProtocolExpression( + Protocol->getIdentifier(), + AtLoc, + ProtoLoc, + LParenLoc, + RParenLoc)); + } + + /// \brief Build a new shuffle vector expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildShuffleVectorExpr(SourceLocation BuiltinLoc, + MultiExprArg SubExprs, + SourceLocation RParenLoc) { + // Find the declaration for __builtin_shufflevector + const IdentifierInfo &Name + = SemaRef.Context.Idents.get("__builtin_shufflevector"); + TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl(); + DeclContext::lookup_result Lookup = TUDecl->lookup(DeclarationName(&Name)); + assert(Lookup.first != Lookup.second && "No __builtin_shufflevector?"); + + // Build a reference to the __builtin_shufflevector builtin + FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first); + Expr *Callee + = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(), + BuiltinLoc, false, false); + SemaRef.UsualUnaryConversions(Callee); + + // Build the CallExpr + unsigned NumSubExprs = SubExprs.size(); + Expr **Subs = (Expr **)SubExprs.release(); + CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, + Subs, NumSubExprs, + Builtin->getResultType(), + RParenLoc); + OwningExprResult OwnedCall(SemaRef.Owned(TheCall)); + + // Type-check the __builtin_shufflevector expression. + OwningExprResult Result = SemaRef.SemaBuiltinShuffleVector(TheCall); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + OwnedCall.release(); + return move(Result); + } +}; + +template<typename Derived> +Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { + if (!S) + return SemaRef.Owned(S); + + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: break; + + // Transform individual statement nodes +#define STMT(Node, Parent) \ + case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S)); +#define EXPR(Node, Parent) +#include "clang/AST/StmtNodes.def" + + // Transform expressions by calling TransformExpr. +#define STMT(Node, Parent) +#define EXPR(Node, Parent) case Stmt::Node##Class: +#include "clang/AST/StmtNodes.def" + { + Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S)); + if (E.isInvalid()) + return getSema().StmtError(); + + return getSema().Owned(E.takeAs<Stmt>()); + } + } + + return SemaRef.Owned(S->Retain()); +} + + +template<typename Derived> +Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E, + bool isAddressOfOperand) { + if (!E) + return SemaRef.Owned(E); + + switch (E->getStmtClass()) { + case Stmt::NoStmtClass: break; +#define STMT(Node, Parent) case Stmt::Node##Class: break; +#define EXPR(Node, Parent) \ + case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E)); +#include "clang/AST/StmtNodes.def" + } + + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +NestedNameSpecifier * +TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range, + QualType ObjectType, + NamedDecl *FirstQualifierInScope) { + if (!NNS) + return 0; + + // Transform the prefix of this nested name specifier. + NestedNameSpecifier *Prefix = NNS->getPrefix(); + if (Prefix) { + Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range, + ObjectType, + FirstQualifierInScope); + if (!Prefix) + return 0; + + // Clear out the object type and the first qualifier in scope; they only + // apply to the first element in the nested-name-specifier. + ObjectType = QualType(); + FirstQualifierInScope = 0; + } + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + assert((Prefix || !ObjectType.isNull()) && + "Identifier nested-name-specifier with no prefix or object type"); + if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() && + ObjectType.isNull()) + return NNS; + + return getDerived().RebuildNestedNameSpecifier(Prefix, Range, + *NNS->getAsIdentifier(), + ObjectType, + FirstQualifierInScope); + + case NestedNameSpecifier::Namespace: { + NamespaceDecl *NS + = cast_or_null<NamespaceDecl>( + getDerived().TransformDecl(NNS->getAsNamespace())); + if (!getDerived().AlwaysRebuild() && + Prefix == NNS->getPrefix() && + NS == NNS->getAsNamespace()) + return NNS; + + return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS); + } + + case NestedNameSpecifier::Global: + // There is no meaningful transformation that one could perform on the + // global scope. + return NNS; + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::TypeSpec: { + QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0)); + if (T.isNull()) + return 0; + + if (!getDerived().AlwaysRebuild() && + Prefix == NNS->getPrefix() && + T == QualType(NNS->getAsType(), 0)) + return NNS; + + return getDerived().RebuildNestedNameSpecifier(Prefix, Range, + NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, + T); + } + } + + // Required to silence a GCC warning + return 0; +} + +template<typename Derived> +DeclarationName +TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name, + SourceLocation Loc) { + if (!Name) + return Name; + + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXUsingDirective: + return Name; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: { + TemporaryBase Rebase(*this, Loc, Name); + QualType T = getDerived().TransformType(Name.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return SemaRef.Context.DeclarationNames.getCXXSpecialName( + Name.getNameKind(), + SemaRef.Context.getCanonicalType(T)); + } + } + + return DeclarationName(); +} + +template<typename Derived> +TemplateName +TreeTransform<Derived>::TransformTemplateName(TemplateName Name, + QualType ObjectType) { + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), + /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + if (!NNS) + return TemplateName(); + + if (TemplateDecl *Template = QTN->getTemplateDecl()) { + TemplateDecl *TransTemplate + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template)); + if (!TransTemplate) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + NNS == QTN->getQualifier() && + TransTemplate == Template) + return Name; + + return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(), + TransTemplate); + } + + OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl(); + assert(Ovl && "Not a template name or an overload set?"); + OverloadedFunctionDecl *TransOvl + = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl)); + if (!TransOvl) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + NNS == QTN->getQualifier() && + TransOvl == Ovl) + return Name; + + return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(), + TransOvl); + } + + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(), + /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + if (!NNS && DTN->getQualifier()) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + NNS == DTN->getQualifier()) + return Name; + + return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType); + } + + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + TemplateDecl *TransTemplate + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template)); + if (!TransTemplate) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + TransTemplate == Template) + return Name; + + return TemplateName(TransTemplate); + } + + OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl(); + assert(Ovl && "Not a template name or an overload set?"); + OverloadedFunctionDecl *TransOvl + = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl)); + if (!TransOvl) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + TransOvl == Ovl) + return Name; + + return TemplateName(TransOvl); +} + +template<typename Derived> +TemplateArgument +TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + return Arg; + + case TemplateArgument::Type: { + QualType T = getDerived().TransformType(Arg.getAsType()); + if (T.isNull()) + return TemplateArgument(); + return TemplateArgument(Arg.getLocation(), T); + } + + case TemplateArgument::Declaration: { + Decl *D = getDerived().TransformDecl(Arg.getAsDecl()); + if (!D) + return TemplateArgument(); + return TemplateArgument(Arg.getLocation(), D); + } + + case TemplateArgument::Expression: { + // Template argument expressions are not potentially evaluated. + EnterExpressionEvaluationContext Unevaluated(getSema(), + Action::Unevaluated); + + Sema::OwningExprResult E = getDerived().TransformExpr(Arg.getAsExpr()); + if (E.isInvalid()) + return TemplateArgument(); + return TemplateArgument(E.takeAs<Expr>()); + } + + case TemplateArgument::Pack: { + llvm::SmallVector<TemplateArgument, 4> TransformedArgs; + TransformedArgs.reserve(Arg.pack_size()); + for (TemplateArgument::pack_iterator A = Arg.pack_begin(), + AEnd = Arg.pack_end(); + A != AEnd; ++A) { + TemplateArgument TA = getDerived().TransformTemplateArgument(*A); + if (TA.isNull()) + return TA; + + TransformedArgs.push_back(TA); + } + TemplateArgument Result; + Result.setArgumentPack(TransformedArgs.data(), TransformedArgs.size(), + true); + return Result; + } + } + + // Work around bogus GCC warning + return TemplateArgument(); +} + +//===----------------------------------------------------------------------===// +// Type transformation +//===----------------------------------------------------------------------===// + +template<typename Derived> +QualType TreeTransform<Derived>::TransformType(QualType T) { + if (getDerived().AlreadyTransformed(T)) + return T; + + QualifierCollector Qs; + const Type *Ty = Qs.strip(T); + + QualType Result; + switch (Ty->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + Result = getDerived().Transform##CLASS##Type( \ + static_cast<const CLASS##Type*>(Ty)); \ + break; +#include "clang/AST/TypeNodes.def" + } + + if (Result.isNull() || T == Result) + return Result; + + return getDerived().AddTypeQualifiers(Result, Qs); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::AddTypeQualifiers(QualType T, Qualifiers Quals) { + if (!Quals.empty() && !T->isFunctionType() && !T->isReferenceType()) + return SemaRef.Context.getQualifiedType(T, Quals); + + return T; +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformBuiltinType(const BuiltinType *T) { + // Nothing to do + return QualType(T, 0); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformFixedWidthIntType( + const FixedWidthIntType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformComplexType(const ComplexType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformPointerType(const PointerType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildPointerType(PointeeType); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformBlockPointerType(const BlockPointerType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildBlockPointerType(PointeeType); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformLValueReferenceType( + const LValueReferenceType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildLValueReferenceType(PointeeType); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformRValueReferenceType( + const RValueReferenceType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildRValueReferenceType(PointeeType); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformMemberPointerType(const MemberPointerType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + QualType ClassType = getDerived().TransformType(QualType(T->getClass(), 0)); + if (ClassType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType() && + ClassType == QualType(T->getClass(), 0)) + return QualType(T, 0); + + return getDerived().RebuildMemberPointerType(PointeeType, ClassType); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformConstantArrayType(const ConstantArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildConstantArrayType(ElementType, + T->getSizeModifier(), + T->getSize(), + T->getIndexTypeCVRQualifiers()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformConstantArrayWithExprType( + const ConstantArrayWithExprType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + // Array bounds are not potentially evaluated contexts + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + if (Size.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType() && + Size.get() == T->getSizeExpr()) + return QualType(T, 0); + + return getDerived().RebuildConstantArrayWithExprType(ElementType, + T->getSizeModifier(), + T->getSize(), + Size.takeAs<Expr>(), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformConstantArrayWithoutExprType( + const ConstantArrayWithoutExprType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildConstantArrayWithoutExprType(ElementType, + T->getSizeModifier(), + T->getSize(), + T->getIndexTypeCVRQualifiers()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformIncompleteArrayType( + const IncompleteArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildIncompleteArrayType(ElementType, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformVariableArrayType( + const VariableArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + // Array bounds are not potentially evaluated contexts + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + if (Size.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType() && + Size.get() == T->getSizeExpr()) { + Size.take(); + return QualType(T, 0); + } + + return getDerived().RebuildVariableArrayType(ElementType, + T->getSizeModifier(), + move(Size), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformDependentSizedArrayType( + const DependentSizedArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + // Array bounds are not potentially evaluated contexts + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + if (Size.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType() && + Size.get() == T->getSizeExpr()) { + Size.take(); + return QualType(T, 0); + } + + return getDerived().RebuildDependentSizedArrayType(ElementType, + T->getSizeModifier(), + move(Size), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + // Vector sizes are not potentially evaluated contexts + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + if (Size.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType() && + Size.get() == T->getSizeExpr()) { + Size.take(); + return QualType(T, 0); + } + + return getDerived().RebuildDependentSizedExtVectorType(ElementType, + move(Size), + T->getAttributeLoc()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformVectorType(const VectorType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildVectorType(ElementType, T->getNumElements()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformExtVectorType(const ExtVectorType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildExtVectorType(ElementType, T->getNumElements(), + /*FIXME*/SourceLocation()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformFunctionProtoType( + const FunctionProtoType *T) { + QualType ResultType = getDerived().TransformType(T->getResultType()); + if (ResultType.isNull()) + return QualType(); + + llvm::SmallVector<QualType, 4> ParamTypes; + for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(), + ParamEnd = T->arg_type_end(); + Param != ParamEnd; ++Param) { + QualType P = getDerived().TransformType(*Param); + if (P.isNull()) + return QualType(); + + ParamTypes.push_back(P); + } + + if (!getDerived().AlwaysRebuild() && + ResultType == T->getResultType() && + std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) + return QualType(T, 0); + + return getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(), + ParamTypes.size(), T->isVariadic(), + T->getTypeQuals()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformFunctionNoProtoType( + const FunctionNoProtoType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformTypedefType(const TypedefType *T) { + TypedefDecl *Typedef + = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl())); + if (!Typedef) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Typedef == T->getDecl()) + return QualType(T, 0); + + return getDerived().RebuildTypedefType(Typedef); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformTypeOfExprType( + const TypeOfExprType *T) { + // typeof expressions are not potentially evaluated contexts + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); + if (E.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + E.get() == T->getUnderlyingExpr()) { + E.take(); + return QualType(T, 0); + } + + return getDerived().RebuildTypeOfExprType(move(E)); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformTypeOfType(const TypeOfType *T) { + QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); + if (Underlying.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Underlying == T->getUnderlyingType()) + return QualType(T, 0); + + return getDerived().RebuildTypeOfType(Underlying); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) { + // decltype expressions are not potentially evaluated contexts + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); + if (E.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + E.get() == T->getUnderlyingExpr()) { + E.take(); + return QualType(T, 0); + } + + return getDerived().RebuildDecltypeType(move(E)); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformRecordType(const RecordType *T) { + RecordDecl *Record + = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl())); + if (!Record) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Record == T->getDecl()) + return QualType(T, 0); + + return getDerived().RebuildRecordType(Record); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformEnumType(const EnumType *T) { + EnumDecl *Enum + = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl())); + if (!Enum) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Enum == T->getDecl()) + return QualType(T, 0); + + return getDerived().RebuildEnumType(Enum); +} + +template <typename Derived> +QualType TreeTransform<Derived>::TransformElaboratedType( + const ElaboratedType *T) { + QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); + if (Underlying.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Underlying == T->getUnderlyingType()) + return QualType(T, 0); + + return getDerived().RebuildElaboratedType(Underlying, T->getTagKind()); +} + + +template<typename Derived> +QualType TreeTransform<Derived>::TransformTemplateTypeParmType( + const TemplateTypeParmType *T) { + // Nothing to do + return QualType(T, 0); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformTemplateSpecializationType( + const TemplateSpecializationType *T) { + TemplateName Template + = getDerived().TransformTemplateName(T->getTemplateName()); + if (Template.isNull()) + return QualType(); + + llvm::SmallVector<TemplateArgument, 4> NewTemplateArgs; + NewTemplateArgs.reserve(T->getNumArgs()); + for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); + Arg != ArgEnd; ++Arg) { + TemplateArgument NewArg = getDerived().TransformTemplateArgument(*Arg); + if (NewArg.isNull()) + return QualType(); + + NewTemplateArgs.push_back(NewArg); + } + + // FIXME: early abort if all of the template arguments and such are the + // same. + + // FIXME: We're missing the locations of the template name, '<', and '>'. + return getDerived().RebuildTemplateSpecializationType(Template, + NewTemplateArgs.data(), + NewTemplateArgs.size()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformQualifiedNameType( + const QualifiedNameType *T) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + SourceRange()); + if (!NNS) + return QualType(); + + QualType Named = getDerived().TransformType(T->getNamedType()); + if (Named.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + NNS == T->getQualifier() && + Named == T->getNamedType()) + return QualType(T, 0); + + return getDerived().RebuildQualifiedNameType(NNS, Named); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + SourceRange(/*FIXME:*/getDerived().getBaseLocation())); + if (!NNS) + return QualType(); + + if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { + QualType NewTemplateId + = getDerived().TransformType(QualType(TemplateId, 0)); + if (NewTemplateId.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + NNS == T->getQualifier() && + NewTemplateId == QualType(TemplateId, 0)) + return QualType(T, 0); + + return getDerived().RebuildTypenameType(NNS, NewTemplateId); + } + + return getDerived().RebuildTypenameType(NNS, T->getIdentifier()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformObjCInterfaceType( + const ObjCInterfaceType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformObjCObjectPointerType( + const ObjCObjectPointerType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformObjCProtocolListType( + const ObjCProtocolListType *T) { + assert(false && "Should not see ObjCProtocolList types"); + return QualType(T, 0); +} + +//===----------------------------------------------------------------------===// +// Statement transformation +//===----------------------------------------------------------------------===// +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformNullStmt(NullStmt *S) { + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S) { + return getDerived().TransformCompoundStmt(S, false); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S, + bool IsStmtExpr) { + bool SubStmtChanged = false; + ASTOwningVector<&ActionBase::DeleteStmt> Statements(getSema()); + for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end(); + B != BEnd; ++B) { + OwningStmtResult Result = getDerived().TransformStmt(*B); + if (Result.isInvalid()) + return getSema().StmtError(); + + SubStmtChanged = SubStmtChanged || Result.get() != *B; + Statements.push_back(Result.takeAs<Stmt>()); + } + + if (!getDerived().AlwaysRebuild() && + !SubStmtChanged) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildCompoundStmt(S->getLBracLoc(), + move_arg(Statements), + S->getRBracLoc(), + IsStmtExpr); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) { + // The case value expressions are not potentially evaluated. + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + // Transform the left-hand case value. + OwningExprResult LHS = getDerived().TransformExpr(S->getLHS()); + if (LHS.isInvalid()) + return SemaRef.StmtError(); + + // Transform the right-hand case value (for the GNU case-range extension). + OwningExprResult RHS = getDerived().TransformExpr(S->getRHS()); + if (RHS.isInvalid()) + return SemaRef.StmtError(); + + // Build the case statement. + // Case statements are always rebuilt so that they will attached to their + // transformed switch statement. + OwningStmtResult Case = getDerived().RebuildCaseStmt(S->getCaseLoc(), + move(LHS), + S->getEllipsisLoc(), + move(RHS), + S->getColonLoc()); + if (Case.isInvalid()) + return SemaRef.StmtError(); + + // Transform the statement following the case + OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + // Attach the body to the case statement + return getDerived().RebuildCaseStmtBody(move(Case), move(SubStmt)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) { + // Transform the statement following the default case + OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + // Default statements are always rebuilt + return getDerived().RebuildDefaultStmt(S->getDefaultLoc(), S->getColonLoc(), + move(SubStmt)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { + OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + // FIXME: Pass the real colon location in. + SourceLocation ColonLoc = SemaRef.PP.getLocForEndOfToken(S->getIdentLoc()); + return getDerived().RebuildLabelStmt(S->getIdentLoc(), S->getID(), ColonLoc, + move(SubStmt)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { + // Transform the condition + OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); + + // Transform the "then" branch. + OwningStmtResult Then = getDerived().TransformStmt(S->getThen()); + if (Then.isInvalid()) + return SemaRef.StmtError(); + + // Transform the "else" branch. + OwningStmtResult Else = getDerived().TransformStmt(S->getElse()); + if (Else.isInvalid()) + return SemaRef.StmtError(); + + if (!getDerived().AlwaysRebuild() && + FullCond->get() == S->getCond() && + Then.get() == S->getThen() && + Else.get() == S->getElse()) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, move(Then), + S->getElseLoc(), move(Else)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { + // Transform the condition. + OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Rebuild the switch statement. + OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(move(Cond)); + if (Switch.isInvalid()) + return SemaRef.StmtError(); + + // Transform the body of the switch statement. + OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // Complete the switch statement. + return getDerived().RebuildSwitchStmtBody(S->getSwitchLoc(), move(Switch), + move(Body)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { + // Transform the condition + OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); + + // Transform the body + OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + if (!getDerived().AlwaysRebuild() && + FullCond->get() == S->getCond() && + Body.get() == S->getBody()) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, 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(); + + if (!getDerived().AlwaysRebuild() && + Cond.get() == S->getCond() && + Body.get() == S->getBody()) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(), + /*FIXME:*/S->getWhileLoc(), move(Cond), + S->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformForStmt(ForStmt *S) { + // Transform the initialization statement + OwningStmtResult Init = getDerived().TransformStmt(S->getInit()); + if (Init.isInvalid()) + return SemaRef.StmtError(); + + // Transform the condition + OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Transform the increment + OwningExprResult Inc = getDerived().TransformExpr(S->getInc()); + if (Inc.isInvalid()) + return SemaRef.StmtError(); + + // Transform the body + OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + if (!getDerived().AlwaysRebuild() && + Init.get() == S->getInit() && + Cond.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), move(Cond), move(Inc), + S->getRParenLoc(), move(Body)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) { + // Goto statements must always be rebuilt, to resolve the label. + return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(), + S->getLabel()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) { + OwningExprResult Target = getDerived().TransformExpr(S->getTarget()); + if (Target.isInvalid()) + return SemaRef.StmtError(); + + if (!getDerived().AlwaysRebuild() && + Target.get() == S->getTarget()) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(), + move(Target)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) { + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) { + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformReturnStmt(ReturnStmt *S) { + Sema::OwningExprResult Result = getDerived().TransformExpr(S->getRetValue()); + if (Result.isInvalid()) + return SemaRef.StmtError(); + + // FIXME: We always rebuild the return statement because there is no way + // to tell whether the return type of the function has changed. + return getDerived().RebuildReturnStmt(S->getReturnLoc(), move(Result)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { + bool DeclChanged = false; + llvm::SmallVector<Decl *, 4> Decls; + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + Decl *Transformed = getDerived().TransformDefinition(*D); + if (!Transformed) + return SemaRef.StmtError(); + + if (Transformed != *D) + DeclChanged = true; + + Decls.push_back(Transformed); + } + + if (!getDerived().AlwaysRebuild() && !DeclChanged) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildDeclStmt(Decls.data(), Decls.size(), + S->getStartLoc(), S->getEndLoc()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) { + assert(false && "SwitchCase is abstract and cannot be transformed"); + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { + // FIXME: Implement! + assert(false && "Inline assembly cannot be transformed"); + return SemaRef.Owned(S->Retain()); +} + + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { + // FIXME: Implement this + assert(false && "Cannot transform an Objective-C @try statement"); + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) { + // FIXME: Implement this + assert(false && "Cannot transform an Objective-C @catch statement"); + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + // FIXME: Implement this + assert(false && "Cannot transform an Objective-C @finally statement"); + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) { + // FIXME: Implement this + assert(false && "Cannot transform an Objective-C @throw statement"); + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformObjCAtSynchronizedStmt( + ObjCAtSynchronizedStmt *S) { + // FIXME: Implement this + assert(false && "Cannot transform an Objective-C @synchronized statement"); + return SemaRef.Owned(S->Retain()); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformObjCForCollectionStmt( + ObjCForCollectionStmt *S) { + // FIXME: Implement this + assert(false && "Cannot transform an Objective-C for-each statement"); + return SemaRef.Owned(S->Retain()); +} + + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) { + // Transform the exception declaration, if any. + VarDecl *Var = 0; + if (S->getExceptionDecl()) { + VarDecl *ExceptionDecl = S->getExceptionDecl(); + TemporaryBase Rebase(*this, ExceptionDecl->getLocation(), + ExceptionDecl->getDeclName()); + + QualType T = getDerived().TransformType(ExceptionDecl->getType()); + if (T.isNull()) + return SemaRef.StmtError(); + + Var = getDerived().RebuildExceptionDecl(ExceptionDecl, + T, + ExceptionDecl->getDeclaratorInfo(), + ExceptionDecl->getIdentifier(), + ExceptionDecl->getLocation(), + /*FIXME: Inaccurate*/ + SourceRange(ExceptionDecl->getLocation())); + if (!Var || Var->isInvalidDecl()) { + if (Var) + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + } + + // Transform the actual exception handler. + OwningStmtResult Handler = getDerived().TransformStmt(S->getHandlerBlock()); + if (Handler.isInvalid()) { + if (Var) + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + if (!getDerived().AlwaysRebuild() && + !Var && + Handler.get() == S->getHandlerBlock()) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(), + Var, + move(Handler)); +} + +template<typename Derived> +Sema::OwningStmtResult +TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { + // Transform the try block itself. + OwningStmtResult TryBlock + = getDerived().TransformCompoundStmt(S->getTryBlock()); + if (TryBlock.isInvalid()) + return SemaRef.StmtError(); + + // Transform the handlers. + bool HandlerChanged = false; + ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef); + for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) { + OwningStmtResult Handler + = getDerived().TransformCXXCatchStmt(S->getHandler(I)); + if (Handler.isInvalid()) + return SemaRef.StmtError(); + + HandlerChanged = HandlerChanged || Handler.get() != S->getHandler(I); + Handlers.push_back(Handler.takeAs<Stmt>()); + } + + if (!getDerived().AlwaysRebuild() && + TryBlock.get() == S->getTryBlock() && + !HandlerChanged) + return SemaRef.Owned(S->Retain()); + + return getDerived().RebuildCXXTryStmt(S->getTryLoc(), move(TryBlock), + move_arg(Handlers)); +} + +//===----------------------------------------------------------------------===// +// Expression transformation +//===----------------------------------------------------------------------===// +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { + NamedDecl *ND + = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl())); + if (!ND) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && ND == E->getDecl()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildDeclRefExpr(ND, E->getLocation()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildParenExpr(move(SubExpr), E->getLParen(), + E->getRParen()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildUnaryOperator(E->getOperatorLoc(), + E->getOpcode(), + move(SubExpr)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { + if (E->isArgumentType()) { + QualType T = getDerived().TransformType(E->getArgumentType()); + if (T.isNull()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && T == E->getArgumentType()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildSizeOfAlignOf(T, E->getOperatorLoc(), + E->isSizeOf(), + E->getSourceRange()); + } + + Sema::OwningExprResult SubExpr(SemaRef); + { + // C++0x [expr.sizeof]p1: + // The operand is either an expression, which is an unevaluated operand + // [...] + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + + SubExpr = getDerived().TransformExpr(E->getArgumentExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr()) + return SemaRef.Owned(E->Retain()); + } + + return getDerived().RebuildSizeOfAlignOf(move(SubExpr), E->getOperatorLoc(), + E->isSizeOf(), + E->getSourceRange()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { + OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult RHS = getDerived().TransformExpr(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + + if (!getDerived().AlwaysRebuild() && + LHS.get() == E->getLHS() && + RHS.get() == E->getRHS()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildArraySubscriptExpr(move(LHS), + /*FIXME:*/E->getLHS()->getLocStart(), + move(RHS), + E->getRBracketLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { + // Transform the callee. + OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); + if (Callee.isInvalid()) + return SemaRef.ExprError(); + + // Transform arguments. + bool ArgChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { + OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: Wrong source location information for the ','. + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken(E->getArg(I)->getSourceRange().getEnd())); + + ArgChanged = ArgChanged || Arg.get() != E->getArg(I); + Args.push_back(Arg.takeAs<Expr>()); + } + + if (!getDerived().AlwaysRebuild() && + Callee.get() == E->getCallee() && + !ArgChanged) + return SemaRef.Owned(E->Retain()); + + // FIXME: Wrong source location information for the '('. + SourceLocation FakeLParenLoc + = ((Expr *)Callee.get())->getSourceRange().getBegin(); + return getDerived().RebuildCallExpr(move(Callee), FakeLParenLoc, + move_arg(Args), + FakeCommaLocs.data(), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + NestedNameSpecifier *Qualifier = 0; + if (E->hasQualifier()) { + Qualifier + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (Qualifier == 0) + return SemaRef.ExprError(); + } + + NamedDecl *Member + = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getMemberDecl())); + if (!Member) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase() && + Qualifier == E->getQualifier() && + Member == E->getMemberDecl()) + return SemaRef.Owned(E->Retain()); + + // FIXME: Bogus source location for the operator + SourceLocation FakeOperatorLoc + = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); + + return getDerived().RebuildMemberExpr(move(Base), FakeOperatorLoc, + E->isArrow(), + Qualifier, + E->getQualifierRange(), + E->getMemberLoc(), + Member); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCastExpr(CastExpr *E) { + assert(false && "Cannot transform abstract class"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { + OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult RHS = getDerived().TransformExpr(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + LHS.get() == E->getLHS() && + RHS.get() == E->getRHS()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), + move(LHS), move(RHS)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCompoundAssignOperator( + CompoundAssignOperator *E) { + return getDerived().TransformBinaryOperator(E); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { + OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); + if (Cond.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult RHS = getDerived().TransformExpr(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + Cond.get() == E->getCond() && + LHS.get() == E->getLHS() && + RHS.get() == E->getRHS()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildConditionalOperator(move(Cond), + E->getQuestionLoc(), + move(LHS), + E->getColonLoc(), + move(RHS)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { + QualType T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getType() && + SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildImplicitCastExpr(T, E->getCastKind(), + move(SubExpr), + E->isLvalueCast()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { + assert(false && "Cannot transform abstract class"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { + QualType T; + { + // FIXME: Source location isn't quite accurate. + SourceLocation TypeStartLoc + = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); + TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); + + T = getDerived().TransformType(E->getTypeAsWritten()); + if (T.isNull()) + return SemaRef.ExprError(); + } + + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getTypeAsWritten() && + SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T, + E->getRParenLoc(), + move(SubExpr)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { + QualType T; + { + // FIXME: Source location isn't quite accurate. + SourceLocation FakeTypeLoc + = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); + TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName()); + + T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + } + + OwningExprResult Init = getDerived().TransformExpr(E->getInitializer()); + if (Init.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getType() && + Init.get() == E->getInitializer()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T, + /*FIXME:*/E->getInitializer()->getLocEnd(), + move(Init)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + // FIXME: Bad source location + SourceLocation FakeOperatorLoc + = SemaRef.PP.getLocForEndOfToken(E->getBase()->getLocEnd()); + return getDerived().RebuildExtVectorElementExpr(move(Base), FakeOperatorLoc, + E->getAccessorLoc(), + E->getAccessor()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { + bool InitChanged = false; + + ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); + for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) { + OwningExprResult Init = getDerived().TransformExpr(E->getInit(I)); + if (Init.isInvalid()) + return SemaRef.ExprError(); + + InitChanged = InitChanged || Init.get() != E->getInit(I); + Inits.push_back(Init.takeAs<Expr>()); + } + + if (!getDerived().AlwaysRebuild() && !InitChanged) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits), + E->getRBraceLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { + Designation Desig; + + // transform the initializer value + OwningExprResult Init = getDerived().TransformExpr(E->getInit()); + if (Init.isInvalid()) + return SemaRef.ExprError(); + + // transform the designators. + ASTOwningVector<&ActionBase::DeleteExpr, 4> ArrayExprs(SemaRef); + bool ExprChanged = false; + for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), + DEnd = E->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + Desig.AddDesignator(Designator::getField(D->getFieldName(), + D->getDotLoc(), + D->getFieldLoc())); + continue; + } + + if (D->isArrayDesignator()) { + OwningExprResult Index = getDerived().TransformExpr(E->getArrayIndex(*D)); + if (Index.isInvalid()) + return SemaRef.ExprError(); + + Desig.AddDesignator(Designator::getArray(Index.get(), + D->getLBracketLoc())); + + ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(*D); + ArrayExprs.push_back(Index.release()); + continue; + } + + assert(D->isArrayRangeDesignator() && "New kind of designator?"); + OwningExprResult Start + = getDerived().TransformExpr(E->getArrayRangeStart(*D)); + if (Start.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(*D)); + if (End.isInvalid()) + return SemaRef.ExprError(); + + Desig.AddDesignator(Designator::getArrayRange(Start.get(), + End.get(), + D->getLBracketLoc(), + D->getEllipsisLoc())); + + ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(*D) || + End.get() != E->getArrayRangeEnd(*D); + + ArrayExprs.push_back(Start.release()); + ArrayExprs.push_back(End.release()); + } + + if (!getDerived().AlwaysRebuild() && + Init.get() == E->getInit() && + !ExprChanged) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildDesignatedInitExpr(Desig, move_arg(ArrayExprs), + E->getEqualOrColonLoc(), + E->usesGNUSyntax(), move(Init)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformImplicitValueInitExpr( + ImplicitValueInitExpr *E) { + QualType T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getType()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildImplicitValueInitExpr(T); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) { + // FIXME: Do we want the type as written? + QualType T; + + { + // FIXME: Source location isn't quite accurate. + TemporaryBase Rebase(*this, E->getBuiltinLoc(), DeclarationName()); + T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + } + + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getType() && + SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildVAArgExpr(E->getBuiltinLoc(), move(SubExpr), + T, E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { + bool ArgumentChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); + for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) { + OwningExprResult Init = getDerived().TransformExpr(E->getExpr(I)); + if (Init.isInvalid()) + return SemaRef.ExprError(); + + ArgumentChanged = ArgumentChanged || Init.get() != E->getExpr(I); + Inits.push_back(Init.takeAs<Expr>()); + } + + return getDerived().RebuildParenListExpr(E->getLParenLoc(), + move_arg(Inits), + E->getRParenLoc()); +} + +/// \brief Transform an address-of-label expression. +/// +/// By default, the transformation of an address-of-label expression always +/// rebuilds the expression, so that the label identifier can be resolved to +/// the corresponding label statement by semantic analysis. +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) { + return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(), + E->getLabel()); +} + +template<typename Derived> +Sema::OwningExprResult TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { + OwningStmtResult SubStmt + = getDerived().TransformCompoundStmt(E->getSubStmt(), true); + if (SubStmt.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + SubStmt.get() == E->getSubStmt()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildStmtExpr(E->getLParenLoc(), + move(SubStmt), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { + QualType T1, T2; + { + // FIXME: Source location isn't quite accurate. + TemporaryBase Rebase(*this, E->getBuiltinLoc(), DeclarationName()); + + T1 = getDerived().TransformType(E->getArgType1()); + if (T1.isNull()) + return SemaRef.ExprError(); + + T2 = getDerived().TransformType(E->getArgType2()); + if (T2.isNull()) + return SemaRef.ExprError(); + } + + if (!getDerived().AlwaysRebuild() && + T1 == E->getArgType1() && + T2 == E->getArgType2()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildTypesCompatibleExpr(E->getBuiltinLoc(), + T1, T2, E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { + OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); + if (Cond.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult RHS = getDerived().TransformExpr(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + Cond.get() == E->getCond() && + LHS.get() == E->getLHS() && + RHS.get() == E->getRHS()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildChooseExpr(E->getBuiltinLoc(), + move(Cond), move(LHS), move(RHS), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); + if (Callee.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult First = getDerived().TransformExpr(E->getArg(0)); + if (First.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult Second(SemaRef); + if (E->getNumArgs() == 2) { + Second = getDerived().TransformExpr(E->getArg(1)); + if (Second.isInvalid()) + return SemaRef.ExprError(); + } + + if (!getDerived().AlwaysRebuild() && + Callee.get() == E->getCallee() && + First.get() == E->getArg(0) && + (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), + E->getOperatorLoc(), + move(Callee), + move(First), + move(Second)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { + return getDerived().TransformCallExpr(E); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { + QualType ExplicitTy; + { + // FIXME: Source location isn't quite accurate. + SourceLocation TypeStartLoc + = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); + TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); + + ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); + if (ExplicitTy.isNull()) + return SemaRef.ExprError(); + } + + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + ExplicitTy == E->getTypeAsWritten() && + SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + // FIXME: Poor source location information here. + SourceLocation FakeLAngleLoc + = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); + SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin(); + SourceLocation FakeRParenLoc + = SemaRef.PP.getLocForEndOfToken( + E->getSubExpr()->getSourceRange().getEnd()); + return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), + E->getStmtClass(), + FakeLAngleLoc, + ExplicitTy, + FakeRAngleLoc, + FakeRAngleLoc, + move(SubExpr), + FakeRParenLoc); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXReinterpretCastExpr( + CXXReinterpretCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXFunctionalCastExpr( + CXXFunctionalCastExpr *E) { + QualType ExplicitTy; + { + TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); + + ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); + if (ExplicitTy.isNull()) + return SemaRef.ExprError(); + } + + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + ExplicitTy == E->getTypeAsWritten() && + SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + // FIXME: The end of the type's source range is wrong + return getDerived().RebuildCXXFunctionalCastExpr( + /*FIXME:*/SourceRange(E->getTypeBeginLoc()), + ExplicitTy, + /*FIXME:*/E->getSubExpr()->getLocStart(), + move(SubExpr), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { + if (E->isTypeOperand()) { + TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); + + QualType T = getDerived().TransformType(E->getTypeOperand()); + if (T.isNull()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getTypeOperand()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXTypeidExpr(E->getLocStart(), + /*FIXME:*/E->getLocStart(), + T, + E->getLocEnd()); + } + + // We don't know whether the expression is potentially evaluated until + // after we perform semantic analysis, so the expression is potentially + // potentially evaluated. + EnterExpressionEvaluationContext Unevaluated(SemaRef, + Action::PotentiallyPotentiallyEvaluated); + + OwningExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + SubExpr.get() == E->getExprOperand()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXTypeidExpr(E->getLocStart(), + /*FIXME:*/E->getLocStart(), + move(SubExpr), + E->getLocEnd()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr( + CXXNullPtrLiteralExpr *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { + TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); + + QualType T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getType()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXThisExpr(E->getLocStart(), T); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + SubExpr.get() == E->getSubExpr()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), move(SubExpr)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + ParmVarDecl *Param + = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam())); + if (!Param) + return SemaRef.ExprError(); + + if (getDerived().AlwaysRebuild() && + Param == E->getParam()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXDefaultArgExpr(Param); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); + + QualType T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getType()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXZeroInitValueExpr(E->getTypeBeginLoc(), + /*FIXME:*/E->getTypeBeginLoc(), + T, + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) { + VarDecl *Var + = cast_or_null<VarDecl>(getDerived().TransformDefinition(E->getVarDecl())); + if (!Var) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + Var == E->getVarDecl()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXConditionDeclExpr(E->getStartLoc(), + /*FIXME:*/E->getStartLoc(), + Var); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { + // Transform the type that we're allocating + TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); + QualType AllocType = getDerived().TransformType(E->getAllocatedType()); + if (AllocType.isNull()) + return SemaRef.ExprError(); + + // Transform the size of the array we're allocating (if any). + OwningExprResult ArraySize = getDerived().TransformExpr(E->getArraySize()); + if (ArraySize.isInvalid()) + return SemaRef.ExprError(); + + // Transform the placement arguments (if any). + bool ArgumentChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> PlacementArgs(SemaRef); + for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) { + OwningExprResult Arg = getDerived().TransformExpr(E->getPlacementArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + ArgumentChanged = ArgumentChanged || Arg.get() != E->getPlacementArg(I); + PlacementArgs.push_back(Arg.take()); + } + + // transform the constructor arguments (if any). + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef); + for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) { + OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + ArgumentChanged = ArgumentChanged || Arg.get() != E->getConstructorArg(I); + ConstructorArgs.push_back(Arg.take()); + } + + if (!getDerived().AlwaysRebuild() && + AllocType == E->getAllocatedType() && + ArraySize.get() == E->getArraySize() && + !ArgumentChanged) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXNewExpr(E->getLocStart(), + E->isGlobalNew(), + /*FIXME:*/E->getLocStart(), + move_arg(PlacementArgs), + /*FIXME:*/E->getLocStart(), + E->isParenTypeId(), + AllocType, + /*FIXME:*/E->getLocStart(), + /*FIXME:*/SourceRange(), + move(ArraySize), + /*FIXME:*/E->getLocStart(), + move_arg(ConstructorArgs), + E->getLocEnd()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { + OwningExprResult Operand = getDerived().TransformExpr(E->getArgument()); + if (Operand.isInvalid()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + Operand.get() == E->getArgument()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXDeleteExpr(E->getLocStart(), + E->isGlobalDelete(), + E->isArrayForm(), + move(Operand)); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( + CXXPseudoDestructorExpr *E) { + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + NestedNameSpecifier *Qualifier + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (E->getQualifier() && !Qualifier) + return SemaRef.ExprError(); + + QualType DestroyedType; + { + TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName()); + DestroyedType = getDerived().TransformType(E->getDestroyedType()); + if (DestroyedType.isNull()) + return SemaRef.ExprError(); + } + + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase() && + Qualifier == E->getQualifier() && + DestroyedType == E->getDestroyedType()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXPseudoDestructorExpr(move(Base), + E->getOperatorLoc(), + E->isArrow(), + E->getDestroyedTypeLoc(), + DestroyedType, + Qualifier, + E->getQualifierRange()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr( + UnresolvedFunctionNameExpr *E) { + // There is no transformation we can apply to an unresolved function name. + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { + TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); + + QualType T = getDerived().TransformType(E->getQueriedType()); + if (T.isNull()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getQueriedType()) + return SemaRef.Owned(E->Retain()); + + // FIXME: Bad location information + SourceLocation FakeLParenLoc + = SemaRef.PP.getLocForEndOfToken(E->getLocStart()); + + return getDerived().RebuildUnaryTypeTrait(E->getTrait(), + E->getLocStart(), + /*FIXME:*/FakeLParenLoc, + T, + E->getLocEnd()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!NNS) + return SemaRef.ExprError(); + + NamedDecl *ND + = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl())); + if (!ND) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + NNS == E->getQualifier() && + ND == E->getDecl()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildQualifiedDeclRefExpr(NNS, + E->getQualifierRange(), + ND, + E->getLocation(), + /*FIXME:*/false); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformUnresolvedDeclRefExpr( + UnresolvedDeclRefExpr *E) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!NNS) + return SemaRef.ExprError(); + + DeclarationName Name + = getDerived().TransformDeclarationName(E->getDeclName(), E->getLocation()); + if (!Name) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + NNS == E->getQualifier() && + Name == E->getDeclName()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildUnresolvedDeclRefExpr(NNS, + E->getQualifierRange(), + Name, + E->getLocation(), + /*FIXME:*/false); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { + TemplateName Template + = getDerived().TransformTemplateName(E->getTemplateName()); + if (Template.isNull()) + return SemaRef.ExprError(); + + llvm::SmallVector<TemplateArgument, 4> TransArgs; + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + TemplateArgument TransArg + = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]); + if (TransArg.isNull()) + return SemaRef.ExprError(); + + TransArgs.push_back(TransArg); + } + + // FIXME: Would like to avoid rebuilding if nothing changed, but we can't + // compare template arguments (yet). + + // FIXME: It's possible that we'll find out now that the template name + // actually refers to a type, in which case the caller is actually dealing + // with a functional cast. Give a reasonable error message! + return getDerived().RebuildTemplateIdExpr(Template, E->getTemplateNameLoc(), + E->getLAngleLoc(), + TransArgs.data(), + TransArgs.size(), + E->getRAngleLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { + TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); + + QualType T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + + CXXConstructorDecl *Constructor + = cast_or_null<CXXConstructorDecl>( + getDerived().TransformDecl(E->getConstructor())); + if (!Constructor) + return SemaRef.ExprError(); + + bool ArgumentChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(), + ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) { + OwningExprResult TransArg = getDerived().TransformExpr(*Arg); + if (TransArg.isInvalid()) + return SemaRef.ExprError(); + + ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg; + Args.push_back(TransArg.takeAs<Expr>()); + } + + if (!getDerived().AlwaysRebuild() && + T == E->getType() && + Constructor == E->getConstructor() && + !ArgumentChanged) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXConstructExpr(T, Constructor, E->isElidable(), + move_arg(Args)); +} + +/// \brief Transform a C++ temporary-binding expression. +/// +/// The transformation of a temporary-binding expression always attempts to +/// bind a new temporary variable to its subexpression, even if the +/// subexpression itself did not change, because the temporary variable itself +/// must be unique. +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>()); +} + +/// \brief Transform a C++ expression that contains temporaries that should +/// be destroyed after the expression is evaluated. +/// +/// The transformation of a full expression always attempts to build a new +/// CXXExprWithTemporaries expression, even if the +/// subexpression itself did not change, because it will need to capture the +/// the new temporary variables introduced in the subexpression. +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXExprWithTemporaries( + CXXExprWithTemporaries *E) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.Owned( + SemaRef.MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>(), + E->shouldDestroyTemporaries())); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( + CXXTemporaryObjectExpr *E) { + TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); + QualType T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return SemaRef.ExprError(); + + CXXConstructorDecl *Constructor + = cast_or_null<CXXConstructorDecl>( + getDerived().TransformDecl(E->getConstructor())); + if (!Constructor) + return SemaRef.ExprError(); + + bool ArgumentChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + Args.reserve(E->getNumArgs()); + for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(), + ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) { + OwningExprResult TransArg = getDerived().TransformExpr(*Arg); + if (TransArg.isInvalid()) + return SemaRef.ExprError(); + + ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg; + Args.push_back((Expr *)TransArg.release()); + } + + if (!getDerived().AlwaysRebuild() && + T == E->getType() && + Constructor == E->getConstructor() && + !ArgumentChanged) + return SemaRef.Owned(E->Retain()); + + // FIXME: Bogus location information + SourceLocation CommaLoc; + if (Args.size() > 1) { + Expr *First = (Expr *)Args[0]; + CommaLoc + = SemaRef.PP.getLocForEndOfToken(First->getSourceRange().getEnd()); + } + return getDerived().RebuildCXXTemporaryObjectExpr(E->getTypeBeginLoc(), + T, + /*FIXME:*/E->getTypeBeginLoc(), + move_arg(Args), + &CommaLoc, + E->getLocEnd()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *E) { + TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); + QualType T = getDerived().TransformType(E->getTypeAsWritten()); + if (T.isNull()) + return SemaRef.ExprError(); + + bool ArgumentChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + llvm::SmallVector<SourceLocation, 8> FakeCommaLocs; + for (CXXUnresolvedConstructExpr::arg_iterator Arg = E->arg_begin(), + ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) { + OwningExprResult TransArg = getDerived().TransformExpr(*Arg); + if (TransArg.isInvalid()) + return SemaRef.ExprError(); + + ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg; + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken((*Arg)->getLocEnd())); + Args.push_back(TransArg.takeAs<Expr>()); + } + + if (!getDerived().AlwaysRebuild() && + T == E->getTypeAsWritten() && + !ArgumentChanged) + return SemaRef.Owned(E->Retain()); + + // FIXME: we're faking the locations of the commas + return getDerived().RebuildCXXUnresolvedConstructExpr(E->getTypeBeginLoc(), + T, + E->getLParenLoc(), + move_arg(Args), + FakeCommaLocs.data(), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( + CXXUnresolvedMemberExpr *E) { + // Transform the base of the expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + Sema::TypeTy *ObjectType = 0; + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), + E->getOperatorLoc(), + E->isArrow()? tok::arrow : tok::period, + ObjectType); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: The first qualifier found might be a template type parameter, + // in which case there is no transformed declaration to refer to (it might + // refer to a built-in type!). + NamedDecl *FirstQualifierInScope + = cast_or_null<NamedDecl>( + getDerived().TransformDecl(E->getFirstQualifierFoundInScope())); + + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange(), + QualType::getFromOpaquePtr(ObjectType), + FirstQualifierInScope); + if (!Qualifier) + return SemaRef.ExprError(); + } + + DeclarationName Name + = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc()); + if (!Name) + return SemaRef.ExprError(); + + if (!E->hasExplicitTemplateArgumentList()) { + // This is a reference to a member without an explicitly-specified + // template argument list. Optimize for this common case. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase() && + Qualifier == E->getQualifier() && + Name == E->getMember() && + FirstQualifierInScope == E->getFirstQualifierFoundInScope()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base), + E->isArrow(), + E->getOperatorLoc(), + Qualifier, + E->getQualifierRange(), + Name, + E->getMemberLoc(), + FirstQualifierInScope); + } + + // FIXME: This is an ugly hack, which forces the same template name to + // be looked up multiple times. Yuck! + // FIXME: This also won't work for, e.g., x->template operator+<int> + TemplateName OrigTemplateName + = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo()); + + TemplateName Template + = getDerived().TransformTemplateName(OrigTemplateName, + QualType::getFromOpaquePtr(ObjectType)); + if (Template.isNull()) + return SemaRef.ExprError(); + + llvm::SmallVector<TemplateArgument, 4> TransArgs; + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + TemplateArgument TransArg + = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]); + if (TransArg.isNull()) + return SemaRef.ExprError(); + + TransArgs.push_back(TransArg); + } + + return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base), + E->isArrow(), + E->getOperatorLoc(), + Qualifier, + E->getQualifierRange(), + Template, + E->getMemberLoc(), + FirstQualifierInScope, + E->getLAngleLoc(), + TransArgs.data(), + TransArgs.size(), + E->getRAngleLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { + // FIXME: poor source location + TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName()); + QualType EncodedType = getDerived().TransformType(E->getEncodedType()); + if (EncodedType.isNull()) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + EncodedType == E->getEncodedType()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(), + EncodedType, + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform Objective-C expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { + ObjCProtocolDecl *Protocol + = cast_or_null<ObjCProtocolDecl>( + getDerived().TransformDecl(E->getProtocol())); + if (!Protocol) + return SemaRef.ExprError(); + + if (!getDerived().AlwaysRebuild() && + Protocol == E->getProtocol()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCProtocolExpr(Protocol, + E->getAtLoc(), + /*FIXME:*/E->getAtLoc(), + /*FIXME:*/E->getAtLoc(), + E->getRParenLoc()); + +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform Objective-C expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform Objective-C expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform Objective-C expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform Objective-C expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform Objective-C expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { + bool ArgumentChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef); + for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getExpr(I)); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + ArgumentChanged = ArgumentChanged || SubExpr.get() != E->getExpr(I); + SubExprs.push_back(SubExpr.takeAs<Expr>()); + } + + if (!getDerived().AlwaysRebuild() && + !ArgumentChanged) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(), + move_arg(SubExprs), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform block expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { + // FIXME: Implement this! + assert(false && "Cannot transform block-related expressions yet"); + return SemaRef.Owned(E->Retain()); +} + +//===----------------------------------------------------------------------===// +// Type reconstruction +//===----------------------------------------------------------------------===// + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType) { + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType) { + return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(), + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildLValueReferenceType(QualType ReferentType) { + return SemaRef.BuildReferenceType(ReferentType, true, Qualifiers(), + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildRValueReferenceType(QualType ReferentType) { + return SemaRef.BuildReferenceType(ReferentType, false, Qualifiers(), + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, + QualType ClassType) { + return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Qualifiers(), + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt *Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + if (SizeExpr || !Size) + return SemaRef.BuildArrayType(ElementType, SizeMod, SizeExpr, + IndexTypeQuals, BracketsRange, + getDerived().getBaseEntity()); + + QualType Types[] = { + SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy, + SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy, + SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty + }; + const unsigned NumTypes = sizeof(Types) / sizeof(QualType); + QualType SizeType; + for (unsigned I = 0; I != NumTypes; ++I) + if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) { + SizeType = Types[I]; + break; + } + + if (SizeType.isNull()) + SizeType = SemaRef.Context.getFixedWidthIntType(Size->getBitWidth(), false); + + IntegerLiteral ArraySize(*Size, SizeType, /*FIXME*/BracketsRange.getBegin()); + return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize, + IndexTypeQuals, BracketsRange, + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals) { + return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, + IndexTypeQuals, SourceRange()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildConstantArrayWithExprType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr, + IndexTypeQuals, BracketsRange); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildConstantArrayWithoutExprType( + QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals) { + return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, + IndexTypeQuals, SourceRange()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + unsigned IndexTypeQuals) { + return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0, + IndexTypeQuals, SourceRange()); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildVariableArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + return getDerived().RebuildArrayType(ElementType, SizeMod, 0, + SizeExpr.takeAs<Expr>(), + IndexTypeQuals, BracketsRange); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + return getDerived().RebuildArrayType(ElementType, SizeMod, 0, + SizeExpr.takeAs<Expr>(), + IndexTypeQuals, BracketsRange); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType, + unsigned NumElements) { + // FIXME: semantic checking! + return SemaRef.Context.getVectorType(ElementType, NumElements); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildExtVectorType(QualType ElementType, + unsigned NumElements, + SourceLocation AttributeLoc) { + llvm::APInt numElements(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy), + NumElements, true); + IntegerLiteral *VectorSize + = new (SemaRef.Context) IntegerLiteral(numElements, SemaRef.Context.IntTy, + AttributeLoc); + return SemaRef.BuildExtVectorType(ElementType, SemaRef.Owned(VectorSize), + AttributeLoc); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType, + ExprArg SizeExpr, + SourceLocation AttributeLoc) { + return SemaRef.BuildExtVectorType(ElementType, move(SizeExpr), AttributeLoc); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T, + QualType *ParamTypes, + unsigned NumParamTypes, + bool Variadic, + unsigned Quals) { + return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic, + Quals, + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) { + return SemaRef.BuildTypeofExprType(E.takeAs<Expr>()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) { + return SemaRef.Context.getTypeOfType(Underlying); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildDecltypeType(ExprArg E) { + return SemaRef.BuildDecltypeType(E.takeAs<Expr>()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( + TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs) { + // FIXME: Missing source locations for the template name, <, >. + return SemaRef.CheckTemplateIdType(Template, getDerived().getBaseLocation(), + SourceLocation(), Args, NumArgs, + SourceLocation()); +} + +template<typename Derived> +NestedNameSpecifier * +TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, + SourceRange Range, + IdentifierInfo &II, + QualType ObjectType, + NamedDecl *FirstQualifierInScope) { + CXXScopeSpec SS; + // FIXME: The source location information is all wrong. + SS.setRange(Range); + SS.setScopeRep(Prefix); + return static_cast<NestedNameSpecifier *>( + SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(), + Range.getEnd(), II, + ObjectType, + FirstQualifierInScope, + false)); +} + +template<typename Derived> +NestedNameSpecifier * +TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, + SourceRange Range, + NamespaceDecl *NS) { + return NestedNameSpecifier::Create(SemaRef.Context, Prefix, NS); +} + +template<typename Derived> +NestedNameSpecifier * +TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, + SourceRange Range, + bool TemplateKW, + QualType T) { + if (T->isDependentType() || T->isRecordType() || + (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) { + assert(!T.hasQualifiers() && "Can't get cv-qualifiers here"); + return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW, + T.getTypePtr()); + } + + SemaRef.Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T; + return 0; +} + +template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + TemplateDecl *Template) { + return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, + Template); +} + +template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + OverloadedFunctionDecl *Ovl) { + return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl); +} + +template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo &II, + QualType ObjectType) { + CXXScopeSpec SS; + SS.setRange(SourceRange(getDerived().getBaseLocation())); + SS.setScopeRep(Qualifier); + return getSema().ActOnDependentTemplateName( + /*FIXME:*/getDerived().getBaseLocation(), + II, + /*FIXME:*/getDerived().getBaseLocation(), + SS, + ObjectType.getAsOpaquePtr()) + .template getAsVal<TemplateName>(); +} + +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, + SourceLocation OpLoc, + ExprArg Callee, + ExprArg First, + ExprArg Second) { + Expr *FirstExpr = (Expr *)First.get(); + Expr *SecondExpr = (Expr *)Second.get(); + bool isPostIncDec = SecondExpr && (Op == OO_PlusPlus || Op == OO_MinusMinus); + + // Determine whether this should be a builtin operation. + if (SecondExpr == 0 || isPostIncDec) { + if (!FirstExpr->getType()->isOverloadableType()) { + // The argument is not of overloadable type, so try to create a + // built-in unary operation. + UnaryOperator::Opcode Opc + = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); + + return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(First)); + } + } else { + if (!FirstExpr->getType()->isOverloadableType() && + !SecondExpr->getType()->isOverloadableType()) { + // Neither of the arguments is an overloadable type, so try to + // create a built-in binary operation. + BinaryOperator::Opcode Opc = BinaryOperator::getOverloadedOpcode(Op); + OwningExprResult Result + = SemaRef.CreateBuiltinBinOp(OpLoc, Opc, FirstExpr, SecondExpr); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + First.release(); + Second.release(); + return move(Result); + } + } + + // Compute the transformed set of functions (and function templates) to be + // used during overload resolution. + Sema::FunctionSet Functions; + + DeclRefExpr *DRE + = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts()); + + // FIXME: Do we have to check + // IsAcceptableNonMemberOperatorCandidate for each of these? + for (OverloadIterator F(DRE->getDecl()), FEnd; F != FEnd; ++F) + Functions.insert(*F); + + // Add any functions found via argument-dependent lookup. + Expr *Args[2] = { FirstExpr, SecondExpr }; + unsigned NumArgs = 1 + (SecondExpr != 0); + DeclarationName OpName + = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); + SemaRef.ArgumentDependentLookup(OpName, Args, NumArgs, Functions); + + // Create the overloaded operator invocation for unary operators. + if (NumArgs == 1 || isPostIncDec) { + UnaryOperator::Opcode Opc + = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); + return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(First)); + } + + // Create the overloaded operator invocation for binary operators. + BinaryOperator::Opcode Opc = + BinaryOperator::getOverloadedOpcode(Op); + OwningExprResult Result + = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + First.release(); + Second.release(); + return move(Result); +} + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H |